From 84269fa2a4298fb602023ad3a9287aa3f5014b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 22 Apr 2024 16:27:54 +0200 Subject: [PATCH 01/14] feat: add act property to upload.ts --- src/command/upload.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/command/upload.ts b/src/command/upload.ts index b106eb66..5479b178 100644 --- a/src/command/upload.ts +++ b/src/command/upload.ts @@ -48,6 +48,9 @@ export class Upload extends RootCommand implements LeafCommand { @Option({ key: 'deferred', type: 'boolean', description: 'Do not wait for network sync', default: true }) public deferred!: boolean + @Option({ key: 'act', type: 'boolean', description: 'Upload with ACT', default: false }) + public act!: boolean + @Option({ key: 'sync', type: 'boolean', @@ -206,6 +209,7 @@ export class Upload extends RootCommand implements LeafCommand { if (this.fileName) { const contentType = this.contentType || getMime(this.fileName) || undefined const { reference } = await this.bee.uploadFile(this.stamp, this.stdinData, this.fileName, { + act: this.act, tag: tag && tag.uid, pin: this.pin, encrypt: this.encrypt, @@ -237,6 +241,7 @@ export class Upload extends RootCommand implements LeafCommand { errorDocument: this.errorDocument, tag: tag && tag.uid, pin: this.pin, + act: this.act, encrypt: this.encrypt, deferred: this.deferred, }) @@ -255,6 +260,7 @@ export class Upload extends RootCommand implements LeafCommand { const readable = FS.createReadStream(this.path) const parsedPath = parse(this.path) const { reference } = await this.bee.uploadFile(this.stamp, readable, this.determineFileName(parsedPath.base), { + act: this.act, tag: tag && tag.uid, pin: this.pin, encrypt: this.encrypt, @@ -361,6 +367,13 @@ export class Upload extends RootCommand implements LeafCommand { return false } + if (this.act) { + this.console.error('You are trying to upload to the gateway which does not support ACT.') + this.console.error('Please try again without the --act option.') + + return true + } + if (this.pin) { this.console.error('You are trying to upload to the gateway which does not support pinning.') this.console.error('Please try again without the --pin option.') From ae0213020ed2a2a7ebb1c5aedfa9be7c2c8cc9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 29 Apr 2024 12:07:51 +0200 Subject: [PATCH 02/14] feat: add response parsing --- src/command/upload.ts | 24 ++++++++++++++++++++---- test/command/upload.spec.ts | 7 +++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/command/upload.ts b/src/command/upload.ts index 5479b178..3db07e2b 100644 --- a/src/command/upload.ts +++ b/src/command/upload.ts @@ -110,6 +110,7 @@ export class Upload extends RootCommand implements LeafCommand { // CLASS FIELDS public hash!: string + public history_address!: string public stdinData!: Buffer @@ -157,6 +158,9 @@ export class Upload extends RootCommand implements LeafCommand { this.console.dim('Data has been sent to the Bee node successfully!') this.console.log(createKeyValue('Swarm hash', this.hash)) + if (this.act) { + this.console.log(createKeyValue('Swarm history address', this.history_address)) + } this.console.dim('Waiting for file chunks to be synced on Swarm network...') if (this.sync && tag) { @@ -208,7 +212,7 @@ export class Upload extends RootCommand implements LeafCommand { private async uploadStdin(tag?: Tag): Promise { if (this.fileName) { const contentType = this.contentType || getMime(this.fileName) || undefined - const { reference } = await this.bee.uploadFile(this.stamp, this.stdinData, this.fileName, { + const { reference, history_address } = await this.bee.uploadFile(this.stamp, this.stdinData, this.fileName, { act: this.act, tag: tag && tag.uid, pin: this.pin, @@ -217,14 +221,20 @@ export class Upload extends RootCommand implements LeafCommand { deferred: this.deferred, }) this.hash = reference + if (this.act && history_address !== undefined) { + this.history_address = history_address + } return `${this.bee.url}/bzz/${this.hash}/` } else { - const { reference } = await this.bee.uploadData(this.stamp, this.stdinData, { + const { reference, history_address } = await this.bee.uploadData(this.stamp, this.stdinData, { tag: tag?.uid, deferred: this.deferred, }) this.hash = reference + if (this.act && history_address !== undefined) { + this.history_address = history_address + } return `${this.bee.url}/bytes/${this.hash}` } @@ -236,7 +246,7 @@ export class Upload extends RootCommand implements LeafCommand { folder: true, type: 'buffer', }) - const { reference } = await this.bee.uploadFilesFromDirectory(this.stamp, this.path, { + const { reference, history_address } = await this.bee.uploadFilesFromDirectory(this.stamp, this.path, { indexDocument: this.indexDocument, errorDocument: this.errorDocument, tag: tag && tag.uid, @@ -246,6 +256,9 @@ export class Upload extends RootCommand implements LeafCommand { deferred: this.deferred, }) this.hash = reference + if (this.act && history_address !== undefined) { + this.history_address = history_address + } return `${this.bee.url}/bzz/${this.hash}/` } @@ -259,7 +272,7 @@ export class Upload extends RootCommand implements LeafCommand { }) const readable = FS.createReadStream(this.path) const parsedPath = parse(this.path) - const { reference } = await this.bee.uploadFile(this.stamp, readable, this.determineFileName(parsedPath.base), { + const { reference, history_address } = await this.bee.uploadFile(this.stamp, readable, this.determineFileName(parsedPath.base), { act: this.act, tag: tag && tag.uid, pin: this.pin, @@ -268,6 +281,9 @@ export class Upload extends RootCommand implements LeafCommand { deferred: this.deferred, }) this.hash = reference + if (this.act && history_address !== undefined) { + this.history_address = history_address + } return `${this.bee.url}/bzz/${this.hash}/` } diff --git a/test/command/upload.spec.ts b/test/command/upload.spec.ts index 0cb4245c..b62818ef 100644 --- a/test/command/upload.spec.ts +++ b/test/command/upload.spec.ts @@ -37,6 +37,13 @@ describeCommand('Test Upload command', ({ consoleMessages, hasMessageContaining expect(uploadCommand.hash).toHaveLength(128) }) + it('should upload file with act', async () => { + const commandBuilder = await invokeTestCli(['upload', 'README.md', '--act', ...getStampOption()]) + const uploadCommand = commandBuilder.runnable as Upload + expect(uploadCommand.hash).toHaveLength(64) + //expect(uploadCommand.history_address).toHaveLength(64) + }) + it('should upload folder and encrypt', async () => { const commandBuilder = await invokeTestCli(['upload', 'test/testpage', '--encrypt', ...getStampOption()]) const uploadCommand = commandBuilder.runnable as Upload From c8bf3754bef0a5aefdfec305a5840803bfb13c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 6 May 2024 09:17:50 +0200 Subject: [PATCH 03/14] test: add upload test for history address --- src/command/upload.ts | 2 +- test/command/upload.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command/upload.ts b/src/command/upload.ts index 3db07e2b..e9c61b8b 100644 --- a/src/command/upload.ts +++ b/src/command/upload.ts @@ -249,9 +249,9 @@ export class Upload extends RootCommand implements LeafCommand { const { reference, history_address } = await this.bee.uploadFilesFromDirectory(this.stamp, this.path, { indexDocument: this.indexDocument, errorDocument: this.errorDocument, + act: this.act, tag: tag && tag.uid, pin: this.pin, - act: this.act, encrypt: this.encrypt, deferred: this.deferred, }) diff --git a/test/command/upload.spec.ts b/test/command/upload.spec.ts index b62818ef..f512874b 100644 --- a/test/command/upload.spec.ts +++ b/test/command/upload.spec.ts @@ -41,7 +41,7 @@ describeCommand('Test Upload command', ({ consoleMessages, hasMessageContaining const commandBuilder = await invokeTestCli(['upload', 'README.md', '--act', ...getStampOption()]) const uploadCommand = commandBuilder.runnable as Upload expect(uploadCommand.hash).toHaveLength(64) - //expect(uploadCommand.history_address).toHaveLength(64) + expect(uploadCommand.history_address).toHaveLength(64) }) it('should upload folder and encrypt', async () => { From 8a2a2558172b8d1c2117e06b23a300c94998745e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 13 May 2024 13:44:53 +0200 Subject: [PATCH 04/14] feat: add ACT support to download command --- src/command/download.ts | 20 ++++++++++++++++++-- src/command/grantee.ts | 23 +++++++++++++++++++++++ src/command/manifest/download.ts | 18 ++++++++++++++++++ src/command/upload.ts | 22 ++++++++++++++-------- src/config.ts | 2 ++ src/utils/bzz-address.ts | 15 ++++++++------- 6 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 src/command/grantee.ts diff --git a/src/command/download.ts b/src/command/download.ts index ba0693eb..80a8cf6e 100644 --- a/src/command/download.ts +++ b/src/command/download.ts @@ -14,11 +14,22 @@ export class Download extends RootCommand implements LeafCommand { public manifestDownload!: ManifestDownload private address!: BzzAddress + private actReqHeaders: Record = {} public async run(): Promise { await super.init() + const { act, actTimestamp, actHistoryAddress, actPublisher } = this.manifestDownload - this.address = await makeBzzAddress(this.bee, this.manifestDownload.bzzUrl) + if (act) { + this.actReqHeaders = { + 'Swarm-Act': 'true', + 'Swarm-Act-Timestamp': actTimestamp, + 'Swarm-Act-History-Address': actHistoryAddress, + 'Swarm-Act-Publisher': actPublisher, + } + } + + this.address = await makeBzzAddress(this.bee, this.manifestDownload.bzzUrl, this.actReqHeaders) if (await this.isManifest()) { this.manifestDownload.address = this.address @@ -29,7 +40,12 @@ export class Download extends RootCommand implements LeafCommand { } private async downloadFile(): Promise { - const response = await this.bee.downloadFile(this.address.hash) + const response = await (this.manifestDownload.act + ? this.bee.downloadFile(this.address.hash, '', { + headers: this.actReqHeaders, + }) + : this.bee.downloadFile(this.address.hash)) + const { name, data } = response if (this.manifestDownload.stdout) { diff --git a/src/command/grantee.ts b/src/command/grantee.ts new file mode 100644 index 00000000..fefc8176 --- /dev/null +++ b/src/command/grantee.ts @@ -0,0 +1,23 @@ +import { Argument, LeafCommand, Option } from "furious-commander"; +import { RootCommand } from "./root-command"; + +export class Grantee extends RootCommand implements LeafCommand { + public readonly name = 'grantee' + public readonly description = 'Grantee managment' + + @Argument({ + key: 'path', + description: 'Path to the file with grantee list', + required: true, + autocompletePath: true, + conflicts: 'stdin', + }) + public path!: string + + @Option({ key: 'stdin', type: 'boolean', description: 'Take data from standard input', conflicts: 'path' }) + public stdin!: boolean + + run(): void | Promise { + throw new Error("Method not implemented."); + } +} \ No newline at end of file diff --git a/src/command/manifest/download.ts b/src/command/manifest/download.ts index ca9e6a1f..f67b2d91 100644 --- a/src/command/manifest/download.ts +++ b/src/command/manifest/download.ts @@ -24,6 +24,24 @@ export class Download extends ManifestCommand implements LeafCommand { @Option({ key: 'stdout', type: 'boolean', description: 'Print to stdout (single files only)' }) public stdout!: boolean + @Option({ key: 'act', type: 'boolean', description: 'Download with ACT', default: false }) + public act!: boolean + + @Option({ key: 'act-timestamp', type: 'string', description: 'ACT history timestamp', default: '1'}) + public actTimestamp!: string + + // required if act is true + @Option({ key: 'act-history-address', type: 'string', description: 'ACT history address', + required: { when: 'act' } }) + public actHistoryAddress!: string + + // required if act is true + @Option({ key: 'act-publisher', type: 'string', description: 'ACT publisher', + required: { when: 'act' } }) + public actPublisher!: string + + + public async run(): Promise { await super.init() diff --git a/src/command/upload.ts b/src/command/upload.ts index e9c61b8b..a8977b4e 100644 --- a/src/command/upload.ts +++ b/src/command/upload.ts @@ -158,6 +158,7 @@ export class Upload extends RootCommand implements LeafCommand { this.console.dim('Data has been sent to the Bee node successfully!') this.console.log(createKeyValue('Swarm hash', this.hash)) + if (this.act) { this.console.log(createKeyValue('Swarm history address', this.history_address)) } @@ -232,6 +233,7 @@ export class Upload extends RootCommand implements LeafCommand { deferred: this.deferred, }) this.hash = reference + if (this.act && history_address !== undefined) { this.history_address = history_address } @@ -272,14 +274,18 @@ export class Upload extends RootCommand implements LeafCommand { }) const readable = FS.createReadStream(this.path) const parsedPath = parse(this.path) - const { reference, history_address } = await this.bee.uploadFile(this.stamp, readable, this.determineFileName(parsedPath.base), { - act: this.act, - tag: tag && tag.uid, - pin: this.pin, - encrypt: this.encrypt, - contentType, - deferred: this.deferred, - }) + const { reference, history_address } = await this.bee.uploadFile( + this.stamp, + readable, + this.determineFileName(parsedPath.base), + { + act: this.act, + tag: tag && tag.uid, + pin: this.pin, + encrypt: this.encrypt, + contentType, + deferred: this.deferred, + }) this.hash = reference if (this.act && history_address !== undefined) { this.history_address = history_address diff --git a/src/config.ts b/src/config.ts index fa4a0e66..77cdaec8 100644 --- a/src/config.ts +++ b/src/config.ts @@ -14,6 +14,7 @@ import { Stamp } from './command/stamp' import { Status } from './command/status' import { Upload } from './command/upload' import { Utility } from './command/utility' +import { Grantee } from './command/grantee' export const beeApiUrl: IOption = { key: 'bee-api-url', @@ -127,4 +128,5 @@ export const rootCommandClasses = [ Manifest, Stake, Utility, + Grantee, ] diff --git a/src/utils/bzz-address.ts b/src/utils/bzz-address.ts index 181c3b5b..5b893c89 100644 --- a/src/utils/bzz-address.ts +++ b/src/utils/bzz-address.ts @@ -27,10 +27,9 @@ export class BzzAddress { } } -export async function makeBzzAddress(bee: Bee, url: string): Promise { +export async function makeBzzAddress(bee: Bee, url: string, headers?: Record): Promise { const address = new BzzAddress(url) - - const feedReference = await resolveFeedManifest(bee, address.hash) + const feedReference = await resolveFeedManifest(bee, address.hash, headers) if (feedReference) { address.hash = feedReference @@ -39,8 +38,8 @@ export async function makeBzzAddress(bee: Bee, url: string): Promise return address } -async function resolveFeedManifest(bee: Bee, hash: string): Promise { - const metadata = await getRootSlashMetadata(bee, hash) +async function resolveFeedManifest(bee: Bee, hash: string, headers?: Record): Promise { + const metadata = await getRootSlashMetadata(bee, hash, headers) if (!metadata) { return null @@ -59,8 +58,10 @@ async function resolveFeedManifest(bee: Bee, hash: string): Promise { - const data = await bee.downloadData(hash) +async function getRootSlashMetadata(bee: Bee, hash: string, reqHeaders?: Record): Promise { + const data = await bee.downloadData(hash, { + headers: reqHeaders, + }) const node = new MantarayNode() node.deserialize(data) From ba71f9abfe48db4a02ae98d2e5f7f369be321e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Wed, 22 May 2024 14:26:55 +0200 Subject: [PATCH 05/14] feat: add ACT history address option to upload command --- src/command/upload.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/command/upload.ts b/src/command/upload.ts index a8977b4e..21b959e2 100644 --- a/src/command/upload.ts +++ b/src/command/upload.ts @@ -48,9 +48,12 @@ export class Upload extends RootCommand implements LeafCommand { @Option({ key: 'deferred', type: 'boolean', description: 'Do not wait for network sync', default: true }) public deferred!: boolean - @Option({ key: 'act', type: 'boolean', description: 'Upload with ACT', default: false }) + @Option({ key: 'act', type: 'boolean', description: 'Upload with ACT', default: false, required: {when: 'act-history-address'} }) public act!: boolean + @Option({ key: 'act-history-address', type: 'string', description: 'ACT history address' }) + public optHistoryAddress!: string + @Option({ key: 'sync', type: 'boolean', @@ -210,6 +213,13 @@ export class Upload extends RootCommand implements LeafCommand { } } + private actHeaders(): Record { + if (this.act && this.optHistoryAddress) { + return { 'swarm-act-history-address': this.optHistoryAddress }; + } + return {}; + } + private async uploadStdin(tag?: Tag): Promise { if (this.fileName) { const contentType = this.contentType || getMime(this.fileName) || undefined @@ -220,7 +230,8 @@ export class Upload extends RootCommand implements LeafCommand { encrypt: this.encrypt, contentType, deferred: this.deferred, - }) + + }, { headers: this.actHeaders()} ) this.hash = reference if (this.act && history_address !== undefined) { this.history_address = history_address @@ -231,7 +242,7 @@ export class Upload extends RootCommand implements LeafCommand { const { reference, history_address } = await this.bee.uploadData(this.stamp, this.stdinData, { tag: tag?.uid, deferred: this.deferred, - }) + }, { headers: this.actHeaders() }) this.hash = reference if (this.act && history_address !== undefined) { @@ -256,7 +267,7 @@ export class Upload extends RootCommand implements LeafCommand { pin: this.pin, encrypt: this.encrypt, deferred: this.deferred, - }) + }, { headers: this.actHeaders() }) this.hash = reference if (this.act && history_address !== undefined) { this.history_address = history_address @@ -285,7 +296,7 @@ export class Upload extends RootCommand implements LeafCommand { encrypt: this.encrypt, contentType, deferred: this.deferred, - }) + }, { headers: this.actHeaders() }) this.hash = reference if (this.act && history_address !== undefined) { this.history_address = history_address From 00e5406a7e46c8ff315e1b388357a05f4eb37fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 27 May 2024 13:31:36 +0200 Subject: [PATCH 06/14] feat: add grantee group with add command --- src/command/grantee.ts | 23 --------------- src/command/grantee/add.ts | 39 ++++++++++++++++++++++++++ src/command/grantee/get.ts | 23 +++++++++++++++ src/command/grantee/grantee-command.ts | 4 +++ src/command/grantee/index.ts | 11 ++++++++ 5 files changed, 77 insertions(+), 23 deletions(-) delete mode 100644 src/command/grantee.ts create mode 100644 src/command/grantee/add.ts create mode 100644 src/command/grantee/get.ts create mode 100644 src/command/grantee/grantee-command.ts create mode 100644 src/command/grantee/index.ts diff --git a/src/command/grantee.ts b/src/command/grantee.ts deleted file mode 100644 index fefc8176..00000000 --- a/src/command/grantee.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Argument, LeafCommand, Option } from "furious-commander"; -import { RootCommand } from "./root-command"; - -export class Grantee extends RootCommand implements LeafCommand { - public readonly name = 'grantee' - public readonly description = 'Grantee managment' - - @Argument({ - key: 'path', - description: 'Path to the file with grantee list', - required: true, - autocompletePath: true, - conflicts: 'stdin', - }) - public path!: string - - @Option({ key: 'stdin', type: 'boolean', description: 'Take data from standard input', conflicts: 'path' }) - public stdin!: boolean - - run(): void | Promise { - throw new Error("Method not implemented."); - } -} \ No newline at end of file diff --git a/src/command/grantee/add.ts b/src/command/grantee/add.ts new file mode 100644 index 00000000..23b4d50a --- /dev/null +++ b/src/command/grantee/add.ts @@ -0,0 +1,39 @@ +import { Argument, LeafCommand, Option } from "furious-commander"; +import { GranteeCommand } from "./grantee-command"; +import { stampProperties } from "../../utils/option"; +import { createKeyValue } from "../../utils/text"; +const fs = require('fs'); + +export class Add extends GranteeCommand implements LeafCommand { + public readonly name = 'add' + public readonly description = 'Add grantee list' + private actReqHeaders: Record = {} + + @Argument({ + key: 'path', + description: 'Path to the file with grantee list', + required: true, + autocompletePath: true, + conflicts: 'stdin', + }) + public path!: string + + @Option({ key: 'stdin', type: 'boolean', description: 'Take data from standard input', conflicts: 'path' }) + public stdin!: boolean + + @Option(stampProperties) + public stamp!: string + + public async run(): Promise { + await super.init() + this.actReqHeaders = { + 'Swarm-Act': 'true', + } + const fileContent = fs.readFileSync(this.path, 'utf8'); + const grantees = fileContent.split('\n'); + + const response = await this.bee.addGrantees(this.stamp, grantees); + this.console.log(createKeyValue('Grantee reference', response.ref)) + this.console.log(createKeyValue('Grantee history reference', response.historyref)) + } +} \ No newline at end of file diff --git a/src/command/grantee/get.ts b/src/command/grantee/get.ts new file mode 100644 index 00000000..dd1c912a --- /dev/null +++ b/src/command/grantee/get.ts @@ -0,0 +1,23 @@ +import { Argument, LeafCommand, Option } from "furious-commander"; +import { GranteeCommand } from "./grantee-command"; +import { stampProperties } from "../../utils/option"; +const fs = require('fs'); + +export class Get extends GranteeCommand implements LeafCommand { + public readonly name = 'get' + public readonly description = 'Get grantee list' + private actReqHeaders: Record = {} + + @Argument({ + key: 'path', + description: 'Path to the file with grantee list', + required: true, + autocompletePath: true, + conflicts: 'stdin', + }) + public path!: string + + public async run(): Promise { + await super.init() + } +} \ No newline at end of file diff --git a/src/command/grantee/grantee-command.ts b/src/command/grantee/grantee-command.ts new file mode 100644 index 00000000..118aefca --- /dev/null +++ b/src/command/grantee/grantee-command.ts @@ -0,0 +1,4 @@ +import { RootCommand } from '../root-command' + +export class GranteeCommand extends RootCommand { +} diff --git a/src/command/grantee/index.ts b/src/command/grantee/index.ts new file mode 100644 index 00000000..c09669cb --- /dev/null +++ b/src/command/grantee/index.ts @@ -0,0 +1,11 @@ +import { GroupCommand } from 'furious-commander' +import { Add } from './add' +import { Get } from './get' + +export class Grantee implements GroupCommand { + public readonly name = 'grantee' + + public readonly description = 'Add, Get grantee list' + + public subCommandClasses = [Add, Get] +} From 624340729139cae2cf20696b9407368bd9ca33ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 27 May 2024 13:43:54 +0200 Subject: [PATCH 07/14] style: lint files --- src/command/grantee/add.ts | 64 ++++++++++---------- src/command/grantee/get.ts | 35 +++++------ src/command/grantee/grantee-command.ts | 3 +- src/command/manifest/download.ts | 10 +--- src/command/upload.ts | 81 +++++++++++++++++--------- src/utils/bzz-address.ts | 6 +- 6 files changed, 111 insertions(+), 88 deletions(-) diff --git a/src/command/grantee/add.ts b/src/command/grantee/add.ts index 23b4d50a..94c3abe2 100644 --- a/src/command/grantee/add.ts +++ b/src/command/grantee/add.ts @@ -1,39 +1,39 @@ -import { Argument, LeafCommand, Option } from "furious-commander"; -import { GranteeCommand } from "./grantee-command"; -import { stampProperties } from "../../utils/option"; -import { createKeyValue } from "../../utils/text"; -const fs = require('fs'); +import { Argument, LeafCommand, Option } from 'furious-commander' +import { GranteeCommand } from './grantee-command' +import { stampProperties } from '../../utils/option' +import { createKeyValue } from '../../utils/text' +import fs from 'fs' export class Add extends GranteeCommand implements LeafCommand { - public readonly name = 'add' - public readonly description = 'Add grantee list' - private actReqHeaders: Record = {} + public readonly name = 'add' + public readonly description = 'Add grantee list' + private actReqHeaders: Record = {} - @Argument({ - key: 'path', - description: 'Path to the file with grantee list', - required: true, - autocompletePath: true, - conflicts: 'stdin', - }) - public path!: string + @Argument({ + key: 'path', + description: 'Path to the file with grantee list', + required: true, + autocompletePath: true, + conflicts: 'stdin', + }) + public path!: string - @Option({ key: 'stdin', type: 'boolean', description: 'Take data from standard input', conflicts: 'path' }) - public stdin!: boolean + @Option({ key: 'stdin', type: 'boolean', description: 'Take data from standard input', conflicts: 'path' }) + public stdin!: boolean - @Option(stampProperties) - public stamp!: string + @Option(stampProperties) + public stamp!: string - public async run(): Promise { - await super.init() - this.actReqHeaders = { - 'Swarm-Act': 'true', - } - const fileContent = fs.readFileSync(this.path, 'utf8'); - const grantees = fileContent.split('\n'); - - const response = await this.bee.addGrantees(this.stamp, grantees); - this.console.log(createKeyValue('Grantee reference', response.ref)) - this.console.log(createKeyValue('Grantee history reference', response.historyref)) + public async run(): Promise { + await super.init() + this.actReqHeaders = { + 'Swarm-Act': 'true', } -} \ No newline at end of file + const fileContent = fs.readFileSync(this.path, 'utf8') + const grantees = fileContent.split('\n') + + const response = await this.bee.addGrantees(this.stamp, grantees) + this.console.log(createKeyValue('Grantee reference', response.ref)) + this.console.log(createKeyValue('Grantee history reference', response.historyref)) + } +} diff --git a/src/command/grantee/get.ts b/src/command/grantee/get.ts index dd1c912a..b1d8284f 100644 --- a/src/command/grantee/get.ts +++ b/src/command/grantee/get.ts @@ -1,23 +1,20 @@ -import { Argument, LeafCommand, Option } from "furious-commander"; -import { GranteeCommand } from "./grantee-command"; -import { stampProperties } from "../../utils/option"; -const fs = require('fs'); +import { Argument, LeafCommand } from 'furious-commander' +import { GranteeCommand } from './grantee-command' export class Get extends GranteeCommand implements LeafCommand { - public readonly name = 'get' - public readonly description = 'Get grantee list' - private actReqHeaders: Record = {} + public readonly name = 'get' + public readonly description = 'Get grantee list' - @Argument({ - key: 'path', - description: 'Path to the file with grantee list', - required: true, - autocompletePath: true, - conflicts: 'stdin', - }) - public path!: string + @Argument({ + key: 'path', + description: 'Path to the file with grantee list', + required: true, + autocompletePath: true, + conflicts: 'stdin', + }) + public path!: string - public async run(): Promise { - await super.init() - } -} \ No newline at end of file + public async run(): Promise { + await super.init() + } +} diff --git a/src/command/grantee/grantee-command.ts b/src/command/grantee/grantee-command.ts index 118aefca..9ff05600 100644 --- a/src/command/grantee/grantee-command.ts +++ b/src/command/grantee/grantee-command.ts @@ -1,4 +1,3 @@ import { RootCommand } from '../root-command' -export class GranteeCommand extends RootCommand { -} +export class GranteeCommand extends RootCommand {} diff --git a/src/command/manifest/download.ts b/src/command/manifest/download.ts index f67b2d91..26a299cc 100644 --- a/src/command/manifest/download.ts +++ b/src/command/manifest/download.ts @@ -27,21 +27,17 @@ export class Download extends ManifestCommand implements LeafCommand { @Option({ key: 'act', type: 'boolean', description: 'Download with ACT', default: false }) public act!: boolean - @Option({ key: 'act-timestamp', type: 'string', description: 'ACT history timestamp', default: '1'}) + @Option({ key: 'act-timestamp', type: 'string', description: 'ACT history timestamp', default: '1' }) public actTimestamp!: string // required if act is true - @Option({ key: 'act-history-address', type: 'string', description: 'ACT history address', - required: { when: 'act' } }) + @Option({ key: 'act-history-address', type: 'string', description: 'ACT history address', required: { when: 'act' } }) public actHistoryAddress!: string // required if act is true - @Option({ key: 'act-publisher', type: 'string', description: 'ACT publisher', - required: { when: 'act' } }) + @Option({ key: 'act-publisher', type: 'string', description: 'ACT publisher', required: { when: 'act' } }) public actPublisher!: string - - public async run(): Promise { await super.init() diff --git a/src/command/upload.ts b/src/command/upload.ts index 21b959e2..96fef9ba 100644 --- a/src/command/upload.ts +++ b/src/command/upload.ts @@ -48,10 +48,16 @@ export class Upload extends RootCommand implements LeafCommand { @Option({ key: 'deferred', type: 'boolean', description: 'Do not wait for network sync', default: true }) public deferred!: boolean - @Option({ key: 'act', type: 'boolean', description: 'Upload with ACT', default: false, required: {when: 'act-history-address'} }) + @Option({ + key: 'act', + type: 'boolean', + description: 'Upload with ACT', + default: false, + required: { when: 'act-history-address' }, + }) public act!: boolean - @Option({ key: 'act-history-address', type: 'string', description: 'ACT history address' }) + @Option({ key: 'act-history-address', type: 'string', description: 'ACT history address' }) public optHistoryAddress!: string @Option({ @@ -215,34 +221,46 @@ export class Upload extends RootCommand implements LeafCommand { private actHeaders(): Record { if (this.act && this.optHistoryAddress) { - return { 'swarm-act-history-address': this.optHistoryAddress }; + return { 'swarm-act-history-address': this.optHistoryAddress } } - return {}; + + return {} } private async uploadStdin(tag?: Tag): Promise { if (this.fileName) { const contentType = this.contentType || getMime(this.fileName) || undefined - const { reference, history_address } = await this.bee.uploadFile(this.stamp, this.stdinData, this.fileName, { - act: this.act, - tag: tag && tag.uid, - pin: this.pin, - encrypt: this.encrypt, - contentType, - deferred: this.deferred, - - }, { headers: this.actHeaders()} ) + const { reference, history_address } = await this.bee.uploadFile( + this.stamp, + this.stdinData, + this.fileName, + { + act: this.act, + tag: tag && tag.uid, + pin: this.pin, + encrypt: this.encrypt, + contentType, + deferred: this.deferred, + }, + { headers: this.actHeaders() }, + ) this.hash = reference + if (this.act && history_address !== undefined) { this.history_address = history_address } return `${this.bee.url}/bzz/${this.hash}/` } else { - const { reference, history_address } = await this.bee.uploadData(this.stamp, this.stdinData, { - tag: tag?.uid, - deferred: this.deferred, - }, { headers: this.actHeaders() }) + const { reference, history_address } = await this.bee.uploadData( + this.stamp, + this.stdinData, + { + tag: tag?.uid, + deferred: this.deferred, + }, + { headers: this.actHeaders() }, + ) this.hash = reference if (this.act && history_address !== undefined) { @@ -259,16 +277,22 @@ export class Upload extends RootCommand implements LeafCommand { folder: true, type: 'buffer', }) - const { reference, history_address } = await this.bee.uploadFilesFromDirectory(this.stamp, this.path, { - indexDocument: this.indexDocument, - errorDocument: this.errorDocument, - act: this.act, - tag: tag && tag.uid, - pin: this.pin, - encrypt: this.encrypt, - deferred: this.deferred, - }, { headers: this.actHeaders() }) + const { reference, history_address } = await this.bee.uploadFilesFromDirectory( + this.stamp, + this.path, + { + indexDocument: this.indexDocument, + errorDocument: this.errorDocument, + act: this.act, + tag: tag && tag.uid, + pin: this.pin, + encrypt: this.encrypt, + deferred: this.deferred, + }, + { headers: this.actHeaders() }, + ) this.hash = reference + if (this.act && history_address !== undefined) { this.history_address = history_address } @@ -296,8 +320,11 @@ export class Upload extends RootCommand implements LeafCommand { encrypt: this.encrypt, contentType, deferred: this.deferred, - }, { headers: this.actHeaders() }) + }, + { headers: this.actHeaders() }, + ) this.hash = reference + if (this.act && history_address !== undefined) { this.history_address = history_address } diff --git a/src/utils/bzz-address.ts b/src/utils/bzz-address.ts index 5b893c89..e928212b 100644 --- a/src/utils/bzz-address.ts +++ b/src/utils/bzz-address.ts @@ -58,7 +58,11 @@ async function resolveFeedManifest(bee: Bee, hash: string, headers?: Record): Promise { +async function getRootSlashMetadata( + bee: Bee, + hash: string, + reqHeaders?: Record, +): Promise { const data = await bee.downloadData(hash, { headers: reqHeaders, }) From d63bdac6d309103467dbd77feafee14f5b9dcd13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Wed, 5 Jun 2024 09:25:34 +0200 Subject: [PATCH 08/14] feat: add patch command to grantee group --- src/command/grantee/get.ts | 10 +++++---- src/command/grantee/index.ts | 5 +++-- src/command/grantee/patch.ts | 39 ++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 src/command/grantee/patch.ts diff --git a/src/command/grantee/get.ts b/src/command/grantee/get.ts index b1d8284f..a3eb2a1d 100644 --- a/src/command/grantee/get.ts +++ b/src/command/grantee/get.ts @@ -1,20 +1,22 @@ import { Argument, LeafCommand } from 'furious-commander' import { GranteeCommand } from './grantee-command' +import { createKeyValue } from '../../utils/text' export class Get extends GranteeCommand implements LeafCommand { public readonly name = 'get' public readonly description = 'Get grantee list' @Argument({ - key: 'path', - description: 'Path to the file with grantee list', + key: 'reference', + description: 'Grantee list reference', required: true, - autocompletePath: true, conflicts: 'stdin', }) - public path!: string + public reference!: string public async run(): Promise { await super.init() + const response = await this.bee.getGrantees(this.reference) + this.console.log(createKeyValue('Grantee public keys', response.data.join('\n'))) } } diff --git a/src/command/grantee/index.ts b/src/command/grantee/index.ts index c09669cb..66e0b911 100644 --- a/src/command/grantee/index.ts +++ b/src/command/grantee/index.ts @@ -1,11 +1,12 @@ import { GroupCommand } from 'furious-commander' import { Add } from './add' import { Get } from './get' +import { Patch } from './patch' export class Grantee implements GroupCommand { public readonly name = 'grantee' - public readonly description = 'Add, Get grantee list' + public readonly description = 'Add, Get, Patch grantee list' - public subCommandClasses = [Add, Get] + public subCommandClasses = [Add, Get, Patch] } diff --git a/src/command/grantee/patch.ts b/src/command/grantee/patch.ts new file mode 100644 index 00000000..8cc785b2 --- /dev/null +++ b/src/command/grantee/patch.ts @@ -0,0 +1,39 @@ +import { Argument, LeafCommand, Option } from 'furious-commander' +import { GranteeCommand } from './grantee-command' +import { stampProperties } from '../../utils/option' +import { createKeyValue } from '../../utils/text' +import fs from 'fs' + +export class Patch extends GranteeCommand implements LeafCommand { + public readonly name = 'patch' + public readonly description = 'Patch grantee list' + private actReqHeaders: Record = {} + + @Argument({ + key: 'path', + description: 'Path to the file with grantee list', + required: true, + autocompletePath: true, + conflicts: 'stdin', + }) + public path!: string + + @Option({ key: 'stdin', type: 'boolean', description: 'Take data from standard input', conflicts: 'path' }) + public stdin!: boolean + + @Option(stampProperties) + public stamp!: string + + public async run(): Promise { + await super.init() + this.actReqHeaders = { + 'Swarm-Act': 'true', + } + const fileContent = fs.readFileSync(this.path, 'utf8') + const grantees = fileContent.split('\n') + + const response = await this.bee.addGrantees(this.stamp, grantees) + //this.console.log(createKeyValue('Grantee reference', response.ref)) + //this.console.log(createKeyValue('Grantee history reference', response.historyref)) + } +} From fc9c88808e85249965fdd36b0340c2fca7c5e077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 10 Jun 2024 09:39:11 +0200 Subject: [PATCH 09/14] feat: add options for encrypted grantee patch and ACT history reference --- src/command/grantee/patch.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/command/grantee/patch.ts b/src/command/grantee/patch.ts index 8cc785b2..43e7776b 100644 --- a/src/command/grantee/patch.ts +++ b/src/command/grantee/patch.ts @@ -11,7 +11,7 @@ export class Patch extends GranteeCommand implements LeafCommand { @Argument({ key: 'path', - description: 'Path to the file with grantee list', + description: 'Path to the JSON file with grantee patch (add, revoke)', required: true, autocompletePath: true, conflicts: 'stdin', @@ -24,16 +24,22 @@ export class Patch extends GranteeCommand implements LeafCommand { @Option(stampProperties) public stamp!: string + @Option({ key: 'reference', type: 'string', description: 'Encrypted grantee list reference with 128 characters length', length: 128, required: true}) + public eref!: string; + + @Option({ key: 'history', type: 'string', description: 'Swarm address reference to the ACT history entry', length: 64, required: true}) + public history!: string; + public async run(): Promise { await super.init() this.actReqHeaders = { 'Swarm-Act': 'true', + 'Swarm-Act-Timestamp': Date.now().toString(), } - const fileContent = fs.readFileSync(this.path, 'utf8') - const grantees = fileContent.split('\n') + const patch = fs.readFileSync(this.path, 'utf8') - const response = await this.bee.addGrantees(this.stamp, grantees) - //this.console.log(createKeyValue('Grantee reference', response.ref)) - //this.console.log(createKeyValue('Grantee history reference', response.historyref)) + const response = await this.bee.patchGrantees(this.eref, this.history, this.stamp, patch, this.actReqHeaders) + this.console.log(createKeyValue('Grantee reference', response.ref)) + this.console.log(createKeyValue('Grantee history reference', response.historyref)) } } From 48d90b2938a1aca0e62b758433ec6f1850c038ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 30 Sep 2024 14:16:13 +0200 Subject: [PATCH 10/14] feat: refactor to bee-js 8 --- package-lock.json | 2 +- src/command/grantee/patch.ts | 5 +++-- src/command/upload.ts | 28 ++++++++++++++-------------- test/command/upload.spec.ts | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index c22ebcc4..0d109225 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "@ethersphere/swarm-cli", - "version": "2.15.0", + "version": "2.16.0", "license": "BSD-3-Clause", "dependencies": { "@ethersphere/bee-js": "^8.0.2", diff --git a/src/command/grantee/patch.ts b/src/command/grantee/patch.ts index d700f885..ae714327 100644 --- a/src/command/grantee/patch.ts +++ b/src/command/grantee/patch.ts @@ -48,9 +48,10 @@ export class Patch extends GranteeCommand implements LeafCommand { 'Swarm-Act': 'true', 'Swarm-Act-Timestamp': Date.now().toString(), } - const patch = fs.readFileSync(this.path, 'utf8') + const patchContent = fs.readFileSync(this.path, 'utf8') + const patch = JSON.parse(patchContent) - const response = await this.bee.patchGrantees(this.eref, this.history, this.stamp, patch, this.actReqHeaders) + const response = await this.bee.patchGrantees(this.stamp, this.eref, this.history, patch, this.actReqHeaders) this.console.log(createKeyValue('Grantee reference', response.ref)) this.console.log(createKeyValue('Grantee history reference', response.historyref)) } diff --git a/src/command/upload.ts b/src/command/upload.ts index a58ca7e3..934364be 100644 --- a/src/command/upload.ts +++ b/src/command/upload.ts @@ -125,7 +125,7 @@ export class Upload extends RootCommand implements LeafCommand { // CLASS FIELDS public hash!: string - public history_address!: string + public historyAddress!: string public stdinData!: Buffer @@ -175,7 +175,7 @@ export class Upload extends RootCommand implements LeafCommand { this.console.log(createKeyValue('Swarm hash', this.hash)) if (this.act) { - this.console.log(createKeyValue('Swarm history address', this.history_address)) + this.console.log(createKeyValue('Swarm history address', this.historyAddress)) } this.console.dim('Waiting for file chunks to be synced on Swarm network...') @@ -236,7 +236,7 @@ export class Upload extends RootCommand implements LeafCommand { private async uploadStdin(tag?: Tag): Promise { if (this.fileName) { const contentType = this.contentType || getMime(this.fileName) || undefined - const { reference, history_address } = await this.bee.uploadFile( + const { reference, historyAddress } = await this.bee.uploadFile( this.stamp, this.stdinData, this.fileName, @@ -253,13 +253,13 @@ export class Upload extends RootCommand implements LeafCommand { ) this.hash = reference - if (this.act && history_address !== undefined) { - this.history_address = history_address + if (this.act && historyAddress !== undefined) { + this.historyAddress = historyAddress } return `${this.bee.url}/bzz/${this.hash}/` } else { - const { reference, history_address } = await this.bee.uploadData( + const { reference, historyAddress } = await this.bee.uploadData( this.stamp, this.stdinData, { @@ -272,8 +272,8 @@ export class Upload extends RootCommand implements LeafCommand { ) this.hash = reference - if (this.act && history_address !== undefined) { - this.history_address = history_address + if (this.act && historyAddress !== undefined) { + this.historyAddress = historyAddress } return `${this.bee.url}/bytes/${this.hash}` @@ -286,7 +286,7 @@ export class Upload extends RootCommand implements LeafCommand { folder: true, type: 'buffer', }) - const { reference, history_address } = await this.bee.uploadFilesFromDirectory( + const { reference, historyAddress } = await this.bee.uploadFilesFromDirectory( this.stamp, this.path, { @@ -303,8 +303,8 @@ export class Upload extends RootCommand implements LeafCommand { ) this.hash = reference - if (this.act && history_address !== undefined) { - this.history_address = history_address + if (this.act && historyAddress !== undefined) { + this.historyAddress = historyAddress } return `${this.bee.url}/bzz/${this.hash}/` @@ -319,7 +319,7 @@ export class Upload extends RootCommand implements LeafCommand { }) const readable = FS.createReadStream(this.path) const parsedPath = parse(this.path) - const { reference, history_address } = await this.bee.uploadFile( + const { reference, historyAddress } = await this.bee.uploadFile( this.stamp, readable, this.determineFileName(parsedPath.base), @@ -336,8 +336,8 @@ export class Upload extends RootCommand implements LeafCommand { ) this.hash = reference - if (this.act && history_address !== undefined) { - this.history_address = history_address + if (this.act && historyAddress !== undefined) { + this.historyAddress = historyAddress } return `${this.bee.url}/bzz/${this.hash}/` diff --git a/test/command/upload.spec.ts b/test/command/upload.spec.ts index bcc519ec..c28bb7dc 100644 --- a/test/command/upload.spec.ts +++ b/test/command/upload.spec.ts @@ -40,7 +40,7 @@ describeCommand('Test Upload command', ({ consoleMessages, hasMessageContaining const commandBuilder = await invokeTestCli(['upload', 'README.md', '--act', ...getStampOption()]) const uploadCommand = commandBuilder.runnable as Upload expect(uploadCommand.hash).toHaveLength(64) - expect(uploadCommand.history_address).toHaveLength(64) + expect(uploadCommand.historyAddress).toHaveLength(64) }) it('should upload folder and encrypt', async () => { From d35fe3d2859458116a71b911ae549e2ebb80d289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 7 Oct 2024 15:43:53 +0200 Subject: [PATCH 11/14] feat(act): rename grantee add to grantee create --- src/command/grantee/{add.ts => create.ts} | 6 +++--- src/command/grantee/index.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) rename src/command/grantee/{add.ts => create.ts} (87%) diff --git a/src/command/grantee/add.ts b/src/command/grantee/create.ts similarity index 87% rename from src/command/grantee/add.ts rename to src/command/grantee/create.ts index c06e38d6..fcbf8f38 100644 --- a/src/command/grantee/add.ts +++ b/src/command/grantee/create.ts @@ -4,9 +4,9 @@ import { stampProperties } from '../../utils/option' import { createKeyValue } from '../../utils/text' import fs from 'fs' -export class Add extends GranteeCommand implements LeafCommand { - public readonly name = 'add' - public readonly description = 'Add grantee list' +export class Create extends GranteeCommand implements LeafCommand { + public readonly name = 'create' + public readonly description = 'Create grantee list' private actReqHeaders: Record = {} @Argument({ diff --git a/src/command/grantee/index.ts b/src/command/grantee/index.ts index 66e0b911..336e8a2a 100644 --- a/src/command/grantee/index.ts +++ b/src/command/grantee/index.ts @@ -1,12 +1,12 @@ import { GroupCommand } from 'furious-commander' -import { Add } from './add' +import { Create } from './create' import { Get } from './get' import { Patch } from './patch' export class Grantee implements GroupCommand { public readonly name = 'grantee' - public readonly description = 'Add, Get, Patch grantee list' + public readonly description = 'Create, Get, Patch grantee list' - public subCommandClasses = [Add, Get, Patch] + public subCommandClasses = [Create, Get, Patch] } From 13de02602ddeff4e3628cfbe10f9f9651102e91d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 7 Oct 2024 16:05:42 +0200 Subject: [PATCH 12/14] feat(act): use json instead of txt format in the grantee create subcommand --- src/command/grantee/create.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/command/grantee/create.ts b/src/command/grantee/create.ts index fcbf8f38..408df187 100644 --- a/src/command/grantee/create.ts +++ b/src/command/grantee/create.ts @@ -29,8 +29,9 @@ export class Create extends GranteeCommand implements LeafCommand { this.actReqHeaders = { 'Swarm-Act': 'true', } - const fileContent = fs.readFileSync(this.path, 'utf8') - const grantees = fileContent.split('\n') + const granteesFile = fs.readFileSync(this.path, 'utf8') + const createGrantees = JSON.parse(granteesFile) + const grantees = createGrantees.grantees const response = await this.bee.createGrantees(this.stamp, grantees) this.console.log(createKeyValue('Grantee reference', response.ref)) From 3b612156d8e95af4336d47997a59b1eb05aee30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 14 Oct 2024 08:50:16 +0200 Subject: [PATCH 13/14] feat(act): modify README.md with ACT examples --- README.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/README.md b/README.md index 7de51c6a..8aa09fee 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,11 @@ the [releases tab](https://github.com/ethersphere/swarm-cli/releases). - [Uploading a File](#uploading-a-file) - [Creating an Identity](#creating-an-identity) - [Uploading to a Feed](#uploading-to-a-feed) + - [Upload file with ACT](#upload-file-with-act) + - [Download file with ACT](#download-file-with-act) + - [Create grantees list](#create-grantees-list) + - [Get grantees list](#get-grantees-list) + - [Patch grantees list](#patch-grantees-list) - [Description](#description) - [Installation](#installation) - [From npm](#from-npm) @@ -68,6 +73,64 @@ the [releases tab](https://github.com/ethersphere/swarm-cli/releases). ![Swarm CLI Feed Upload Command](./docs/feed-upload.gif) +## Upload file with ACT + +```sh +swarm-cli upload --act --stamp +``` + +## Download file with ACT + +```sh +swarm-cli download --act --act-history-address --act-publisher +``` + +## Create grantees list + +```sh +swarm-cli grantee create grantees.json --stamp +``` + +`grantees.json`: + +```json +{ "grantees": [ + "02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12e8", + "02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12e9", + "02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12ee" +] +} +``` + +## Get grantees list + +```sh +swarm-cli grantee get +``` + +## Patch grantees list + +```sh +swarm-cli grantee patch grantees-patch.json \ + --reference \ + --history \ + --stamp +``` + +`grantees-patch.json`: + +```json +{ + "add": [ + "02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12e7" + ], + "revoke": [ + "02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12e9", + "02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12ee" + ] +} +``` + # Description > Manage your Bee node and interact with the Swarm network via the CLI From 985f93805ff25e57ae83e3f62c88d264366dd6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Mon, 14 Oct 2024 09:56:17 +0200 Subject: [PATCH 14/14] feat(act): fix typos --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8aa09fee..6ec5ea98 100644 --- a/README.md +++ b/README.md @@ -73,19 +73,19 @@ the [releases tab](https://github.com/ethersphere/swarm-cli/releases). ![Swarm CLI Feed Upload Command](./docs/feed-upload.gif) -## Upload file with ACT +## Upload a file with ACT ```sh swarm-cli upload --act --stamp ``` -## Download file with ACT +## Download a file with ACT ```sh swarm-cli download --act --act-history-address --act-publisher ``` -## Create grantees list +## Create a grantees list ```sh swarm-cli grantee create grantees.json --stamp @@ -102,13 +102,13 @@ swarm-cli grantee create grantees.json --stamp } ``` -## Get grantees list +## Get a grantees list ```sh swarm-cli grantee get ``` -## Patch grantees list +## Patch a grantees list ```sh swarm-cli grantee patch grantees-patch.json \