From 53f50b28f7b36fac2e050d741a23eb7e9f18fbd8 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Tue, 14 Nov 2023 08:01:25 +0300 Subject: [PATCH 1/9] feat!: provision using a proof --- account.js | 67 ++++++++++++++++++++++++++ package-lock.json | 18 +++---- package.json | 2 +- space.js | 36 ++++++++++---- test/bin.spec.js | 94 +++++++++++++++++++++++++++++++++++++ test/helpers/context.js | 11 ++++- test/helpers/http-server.js | 54 +++++++++++++++------ test/helpers/ucanto.js | 19 ++++++-- 8 files changed, 259 insertions(+), 42 deletions(-) diff --git a/account.js b/account.js index 895707f..4284739 100644 --- a/account.js +++ b/account.js @@ -3,6 +3,10 @@ import * as Result from '@web3-storage/w3up-client/result' import * as DidMailto from '@web3-storage/did-mailto' import { getClient } from './lib.js' import ora from 'ora' +import { AccountDID } from '@web3-storage/access/provider' +import { Delegation } from '@web3-storage/access' +import * as ED25519 from '@ucanto/principal/ed25519' +import { sha256 } from '@ucanto/core' /** * @typedef {Awaited>['ok']&{}} View @@ -54,3 +58,66 @@ export const list = async () => { ) } } + +/** + * Loads account from the the external proof delegated to the ED25519 principal + * derived from the sha256 of the password. Delegation must be encoded in a CAR + * format produced by `Delegation.archive` function. External delegation MAY + * be fetched from a remote URL or from a local file system (if file:// URL is + * provided). + * + * Loaded account and delegations side-loaded are expected to be short-lived + * given that delegations are effectively usable by anyone who knows the URL. + * + * + * @param {import('@web3-storage/w3up-client').Client} client + * @param {object} options + * @param {URL} options.url + * @param {string} [options.password] + */ +export const load = async (client, { url, password = '' }) => { + const { ok: bytes, error: fetchError } = await fetch(url) + .then((response) => response.arrayBuffer()) + .then((buffer) => Result.ok(new Uint8Array(buffer))) + .catch((error) => Result.error(/** @type {Error} */ (error))) + + if (fetchError) { + return Result.error(fetchError) + } + + const { error: extractError, ok: delegation } = + await Delegation.extract(bytes) + if (extractError) { + return Result.error(extractError) + } + + const [capability] = delegation.capabilities + + const { ok: customer, error } = AccountDID.read(capability.with) + if (error) { + return Result.error(error) + } + + const { digest } = await sha256.digest(new TextEncoder().encode(password)) + const audience = await ED25519.Signer.derive(digest) + + if (delegation.audience.did() !== audience.did()) { + return Result.error(new RangeError('Invalid password')) + } + + const account = new Account.Account({ + agent: client.agent, + id: /** @type {DidMailto.DidMailto} */ (customer), + proofs: [ + await Delegation.delegate({ + issuer: audience, + audience: client.agent, + capabilities: [capability], + expiration: delegation.expiration, + proofs: [delegation], + }), + ], + }) + + return Result.ok(account) +} diff --git a/package-lock.json b/package-lock.json index 579c894..c64d973 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@ucanto/transport": "^9.0.0", "@web3-storage/access": "^17.0.0", "@web3-storage/did-mailto": "^2.1.0", - "@web3-storage/w3up-client": "^10.0.0", + "@web3-storage/w3up-client": "^10.1.0", "ansi-escapes": "^6.2.0", "chalk": "^5.3.0", "files-from-path": "^1.0.0", @@ -1827,9 +1827,9 @@ } }, "node_modules/@web3-storage/w3up-client": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-10.0.0.tgz", - "integrity": "sha512-kQW1gl1zr8IX5bGwiNd4XTAXd8hUCx/YIXDFO9UACrZtyxoady3vdLs2r3fKbHmhhmBc6NIlpb9gTkkTTqu51g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-10.1.0.tgz", + "integrity": "sha512-Dqf/tfWTFeDegS738wqWuT6SDSjmpFWAYCWkgFDWbyCU+RY5OKR7XSDBjNrbPxavlnfKJrfMVl61GSEDK2uM0w==", "dependencies": { "@ipld/dag-ucan": "^3.4.0", "@ucanto/client": "^9.0.0", @@ -1839,7 +1839,7 @@ "@ucanto/transport": "^9.0.0", "@web3-storage/access": "^17.0.0", "@web3-storage/capabilities": "^11.4.0", - "@web3-storage/did-mailto": "^2.0.2", + "@web3-storage/did-mailto": "^2.1.0", "@web3-storage/filecoin-client": "^3.1.0", "@web3-storage/upload-client": "^12.0.0" } @@ -8108,9 +8108,9 @@ } }, "@web3-storage/w3up-client": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-10.0.0.tgz", - "integrity": "sha512-kQW1gl1zr8IX5bGwiNd4XTAXd8hUCx/YIXDFO9UACrZtyxoady3vdLs2r3fKbHmhhmBc6NIlpb9gTkkTTqu51g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-10.1.0.tgz", + "integrity": "sha512-Dqf/tfWTFeDegS738wqWuT6SDSjmpFWAYCWkgFDWbyCU+RY5OKR7XSDBjNrbPxavlnfKJrfMVl61GSEDK2uM0w==", "requires": { "@ipld/dag-ucan": "^3.4.0", "@ucanto/client": "^9.0.0", @@ -8120,7 +8120,7 @@ "@ucanto/transport": "^9.0.0", "@web3-storage/access": "^17.0.0", "@web3-storage/capabilities": "^11.4.0", - "@web3-storage/did-mailto": "^2.0.2", + "@web3-storage/did-mailto": "^2.1.0", "@web3-storage/filecoin-client": "^3.1.0", "@web3-storage/upload-client": "^12.0.0" } diff --git a/package.json b/package.json index 6716ddc..ecb493b 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@ucanto/transport": "^9.0.0", "@web3-storage/access": "^17.0.0", "@web3-storage/did-mailto": "^2.1.0", - "@web3-storage/w3up-client": "^10.0.0", + "@web3-storage/w3up-client": "^10.1.0", "chalk": "^5.3.0", "ansi-escapes": "^6.2.0", "@inquirer/prompts": "^3.3.0", diff --git a/space.js b/space.js index 1aef3fb..80f1117 100644 --- a/space.js +++ b/space.js @@ -143,6 +143,7 @@ const setupBilling = async ( /** * @typedef {object} ProvisionOptions * @property {DIDMailto.EmailAddress} [customer] + * @property {string} [proof] * @property {string} [provider] * * @param {string} name @@ -158,18 +159,33 @@ export const provision = async (name = '', options = {}) => { process.exit(1) } - const setup = await setupBilling(client, { - customer: options.customer, - space, - }) + let result + if (options.proof) { + const { ok: account, error } = await Account.load(client, { + url: new URL(options.proof), + }) - if (setup.ok) { - console.log(`✨ Billing account is set`) - } else if (setup.error?.reason === 'error') { + if (error) { + result = { error } + } else { + result = await account.provision(space) + } + } else { + result = await setupBilling(client, { + customer: options.customer, + space, + }) + } + + if (result.error) { console.error( - `⚠️ Failed to set billing account - ${setup.error.cause.message}` + `⚠️ Failed to set up billing account,\n ${ + Object(result.error).message ?? '' + }` ) process.exit(1) + } else { + console.log(`✨ Billing account is set`) } } @@ -265,8 +281,8 @@ const chooseName = async (name, spaces) => { name === '' ? 'What would you like to call this space?' : space - ? `Name "${space.name}" is already taken, please choose a different one` - : null + ? `Name "${space.name}" is already taken, please choose a different one` + : null if (message == null) { return name diff --git a/test/bin.spec.js b/test/bin.spec.js index b06da84..311f5f9 100644 --- a/test/bin.spec.js +++ b/test/bin.spec.js @@ -12,7 +12,12 @@ import { test } from './helpers/context.js' import * as Test from './helpers/context.js' import { pattern, match } from './helpers/util.js' import * as Command from './helpers/process.js' +import { Absentee, ed25519 } from '@ucanto/principal' import * as DIDMailto from '@web3-storage/did-mailto' +import { UCAN, Provider } from '@web3-storage/capabilities' +import * as ED25519 from '@ucanto/principal/ed25519' +import { sha256, delegate } from '@ucanto/core' +import * as Result from '@web3-storage/w3up-client/result' const w3 = Command.create('./bin.js') @@ -485,6 +490,41 @@ export const testSpace = { 'added provider shows up in the space info' ) }), + + 'only w3 space provision': test(async (assert, context) => { + const spaceDID = await createSpace(context, { customer: null }) + + assert.deepEqual( + await context.provisionsStorage.getStorageProviders(spaceDID), + { ok: [] }, + 'space has no providers yet' + ) + + const archive = await createCustomerSession(context) + context.router['/proof.car'] = async () => { + return { + status: 200, + headers: { 'content-type': 'application/car' }, + body: archive, + } + } + + const url = new URL('/proof.car', context.serverURL) + const provision = await w3 + .env(context.env.alice) + .args(['space', 'provision', '--proof', url.href]) + .join() + + assert.match(provision.output, /Billing account is set/) + + const info = await w3.env(context.env.alice).args(['space', 'info']).join() + + assert.match( + info.output, + pattern`Providers: ${context.service.did()}`, + 'space got provisioned' + ) + }), } export const testW3Up = { @@ -1123,3 +1163,57 @@ export const createSpace = async ( return SpaceDID.from(did) } + +/** + * @param {Test.Context} context + * @param {object} options + * @param {string} [options.password] + */ +export const createCustomerSession = async ( + context, + { password = '' } = {} +) => { + // Derive delegation audience from the password + const { digest } = await sha256.digest(new TextEncoder().encode(password)) + const audience = await ED25519.derive(digest) + + // Generate the agent that will be authorized to act on behalf of the customer + const agent = await ed25519.generate() + + const customer = Absentee.from({ id: 'did:mailto:web.mail:workshop' }) + + // First we create delegation from the customer to the agent that authorizing + // it to perform `provider/add` on their behalf. + const delegation = await delegate({ + issuer: customer, + audience: agent, + capabilities: [ + { + with: 'ucan:*', + can: '*', + }, + ], + expiration: Infinity, + }) + + // Then we create an attestation from the service to proof that agent has + // been authorized + const attestation = await UCAN.attest.delegate({ + issuer: context.service, + audience: agent, + with: context.service.did(), + nb: { proof: delegation.cid }, + expiration: delegation.expiration, + }) + + // Finally we create a short lived session that authorizes the audience to + // provider/add with their billing account. + const session = await Provider.add.delegate({ + issuer: agent, + audience, + with: customer.did(), + proofs: [delegation, attestation], + }) + + return Result.try(await session.archive()) +} diff --git a/test/helpers/context.js b/test/helpers/context.js index 7cf3559..567a95f 100644 --- a/test/helpers/context.js +++ b/test/helpers/context.js @@ -50,17 +50,24 @@ export const provisionSpace = async (context, { space, account, provider }) => { * @typedef {import('@web3-storage/w3up-client/types').StoreAddSuccess} StoreAddSuccess * @typedef {UcantoServerTestContext & { * server: import('./http-server').TestingServer['server'] + * router: import('./http-server').Router * env: { alice: Record, bob: Record } + * serverURL: URL * }} Context * * @returns {Promise} */ export const setup = async () => { - const { server, serverURL, setRequestListener } = await createHTTPServer() const context = await createContext({ http }) - setRequestListener(createHTTPListener(context.connection.channel)) + const { server, serverURL, router } = await createHTTPServer({ + '/': context.connection.channel.request.bind(context.connection.channel), + }) + return Object.assign(context, { server, + serverURL, + router, + serverRouter: router, env: { alice: createEnv({ storeName: `w3cli-test-alice-${context.service.did()}`, diff --git a/test/helpers/http-server.js b/test/helpers/http-server.js index 208fe88..ef68714 100644 --- a/test/helpers/http-server.js +++ b/test/helpers/http-server.js @@ -2,36 +2,60 @@ import http from 'http' import { once } from 'events' /** + * @typedef {import('@ucanto/interface').HTTPRequest} HTTPRequest + * @typedef {import('@ucanto/server').HTTPResponse} HTTPResponse + * @typedef {Record PromiseLike|HTTPResponse>} Router + * * @typedef {{ * server: http.Server * serverURL: URL - * setRequestListener: (l: http.RequestListener) => void + * router: Router * }} TestingServer */ -/** @returns {Promise} */ -export async function createServer() { - /** @type {http.RequestListener} */ - let listener = (_, response) => { - response.statusCode = 500 - response.write('no request listener set') +/** + * @param {Router} router + * @returns {Promise} + */ +export async function createServer(router) { + /** + * @param {http.IncomingMessage} request + * @param {http.ServerResponse} response + */ + const listener = async (request, response) => { + const chunks = [] + for await (const chunk of request) { + chunks.push(chunk) + } + + const handler = router[request.url ?? '/'] + if (!handler) { + response.writeHead(404) + response.end() + return undefined + } + + const { headers, body } = await handler({ + headers: /** @type {Readonly>} */ ( + request.headers + ), + body: Buffer.concat(chunks), + }) + + response.writeHead(200, headers) + response.write(body) response.end() + return undefined } - const server = http - .createServer((request, response) => { - listener(request, response) - }) - .listen() + const server = http.createServer(listener).listen() await once(server, 'listening') return { server, + router, // @ts-expect-error serverURL: new URL(`http://127.0.0.1:${server.address().port}`), - setRequestListener: (l) => { - listener = l - }, } } diff --git a/test/helpers/ucanto.js b/test/helpers/ucanto.js index d7e37ba..c3829f4 100644 --- a/test/helpers/ucanto.js +++ b/test/helpers/ucanto.js @@ -1,16 +1,25 @@ /** - * @template {Record} T - * @param {import('@ucanto/server').Transport.Channel} server + * @typedef {import('@ucanto/interface').HTTPRequest} HTTPRequest + * @typedef {import('@ucanto/server').HTTPResponse} HTTPResponse + * + * @param {Record PromiseLike|HTTPResponse>} router + * @returns {import('http').RequestListener} */ -export function createHTTPListener(server) { - /** @type {import('http').RequestListener} */ +export function createHTTPListener(router) { return async (request, response) => { const chunks = [] for await (const chunk of request) { chunks.push(chunk) } - const { headers, body } = await server.request({ + const handler = router[request.url ?? '/'] + if (!handler) { + response.writeHead(404) + response.end() + return + } + + const { headers, body } = await handler({ // @ts-ignore headers: request.headers, body: Buffer.concat(chunks), From 40fcde43420e83bc5d7ba2277eec63febf790dbc Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Tue, 14 Nov 2023 08:30:36 +0300 Subject: [PATCH 2/9] fix: lint issue --- account.js | 1 - 1 file changed, 1 deletion(-) diff --git a/account.js b/account.js index 4284739..beae130 100644 --- a/account.js +++ b/account.js @@ -69,7 +69,6 @@ export const list = async () => { * Loaded account and delegations side-loaded are expected to be short-lived * given that delegations are effectively usable by anyone who knows the URL. * - * * @param {import('@web3-storage/w3up-client').Client} client * @param {object} options * @param {URL} options.url From 4625f89076f30030d7726cfb56e6cc85425ed15f Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Tue, 14 Nov 2023 08:30:44 +0300 Subject: [PATCH 3/9] chore: remove obsolete helper --- test/helpers/context.js | 1 - test/helpers/ucanto.js | 32 -------------------------------- 2 files changed, 33 deletions(-) delete mode 100644 test/helpers/ucanto.js diff --git a/test/helpers/context.js b/test/helpers/context.js index 567a95f..dfe20b7 100644 --- a/test/helpers/context.js +++ b/test/helpers/context.js @@ -8,7 +8,6 @@ import { createEnv } from './env.js' import { Signer } from '@ucanto/principal/ed25519' import { createServer as createHTTPServer } from './http-server.js' import http from 'node:http' -import { createHTTPListener } from './ucanto.js' import { StoreConf } from '@web3-storage/access/stores/store-conf' import * as FS from 'node:fs/promises' diff --git a/test/helpers/ucanto.js b/test/helpers/ucanto.js deleted file mode 100644 index c3829f4..0000000 --- a/test/helpers/ucanto.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @typedef {import('@ucanto/interface').HTTPRequest} HTTPRequest - * @typedef {import('@ucanto/server').HTTPResponse} HTTPResponse - * - * @param {Record PromiseLike|HTTPResponse>} router - * @returns {import('http').RequestListener} - */ -export function createHTTPListener(router) { - return async (request, response) => { - const chunks = [] - for await (const chunk of request) { - chunks.push(chunk) - } - - const handler = router[request.url ?? '/'] - if (!handler) { - response.writeHead(404) - response.end() - return - } - - const { headers, body } = await handler({ - // @ts-ignore - headers: request.headers, - body: Buffer.concat(chunks), - }) - - response.writeHead(200, headers) - response.write(body) - response.end() - } -} From 7f7cfa6b90977b4116e63450e8883e321c298ad2 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 15 Nov 2023 10:06:01 +0300 Subject: [PATCH 4/9] Update test/bin.spec.js --- test/bin.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bin.spec.js b/test/bin.spec.js index d0f1181..ade2d32 100644 --- a/test/bin.spec.js +++ b/test/bin.spec.js @@ -520,7 +520,7 @@ export const testSpace = { ) }), - 'only w3 space provision': test(async (assert, context) => { + 'w3 space provision': test(async (assert, context) => { const spaceDID = await createSpace(context, { customer: null }) assert.deepEqual( From 318f9f39195ce46cbf20ae363fc5e3db483dbc0a Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 15 Nov 2023 22:12:27 +0300 Subject: [PATCH 5/9] feat! integrate client changes --- bin.js | 26 +++++++- coupon.js | 55 ++++++++++++++++ index.js | 59 ++++++++++++++--- package-lock.json | 158 ++++++++++++++++++++++++++++++++-------------- package.json | 8 +-- space.js | 65 +++++++++++++------ test/bin.spec.js | 21 +++++- 7 files changed, 308 insertions(+), 84 deletions(-) create mode 100644 coupon.js diff --git a/bin.js b/bin.js index ca2ab86..7019bce 100755 --- a/bin.js +++ b/bin.js @@ -7,6 +7,7 @@ import { getPkg } from './lib.js' import { Account, Space, + Coupon, accessClaim, addSpace, listSpaces, @@ -21,7 +22,8 @@ import { remove, list, whoami, - usageReport + usageReport, + getPlan, } from './index.js' import { storeAdd, @@ -51,6 +53,12 @@ cli ) .action(Account.login) +cli + .command('plan get [email]') + .example('plan get user@example.com') + .describe('Displays plan given account is on') + .action(getPlan) + cli .command('account ls') .alias('account list') @@ -121,6 +129,8 @@ cli .command('space provision [name]') .describe('Associating space with a billing account') .option('-c, --customer', 'The email address of the billing account') + .option('--coupon', 'Coupon URL to provision space with') + .option('-p, -password', 'Coupon password') .option( '-p, --provider', 'The storage provider to associate with this space.' @@ -151,6 +161,20 @@ cli .describe('Set the current space in use by the agent') .action(useSpace) +cli + .command('coupon create ') + .option('-c, --can', 'One or more abilities to delegate.') + .option( + '-e, --expiration', + 'Unix timestamp when the delegation is no longer valid. Zero indicates no expiration.', + 0 + ) + .option( + '-o, --output', + 'Path of file to write the exported delegation data to.' + ) + .action(Coupon.issue) + cli .command('delegation create ') .describe( diff --git a/coupon.js b/coupon.js new file mode 100644 index 0000000..0be7032 --- /dev/null +++ b/coupon.js @@ -0,0 +1,55 @@ +import fs from 'node:fs/promises' +import * as DID from '@ipld/dag-ucan/did' +import * as Account from './account.js' +import * as Space from './space.js' +import { getClient } from './lib.js' +import * as ucanto from '@ucanto/core' + +export { Account, Space } + +/** + * @typedef {object} CouponIssueOptions + * @property {string} customer + * @property {string[]|string} [can] + * @property {string} [password] + * @property {number} [expiration] + * @property {string} [output] + * + * @param {string} customer + * @param {CouponIssueOptions} options + */ +export const issue = async ( + customer, + { can = 'provider/add', expiration, password, output } +) => { + const client = await getClient() + + const audience = DID.parse(customer) + const abilities = can ? [can].flat() : [] + if (!abilities.length) { + console.error('Error: missing capabilities for delegation') + process.exit(1) + } + + const capabilities = /** @type {ucanto.API.Capabilities} */ ( + abilities.map((can) => ({ can, with: audience.did() })) + ) + + const coupon = await client.coupon.issue({ + capabilities, + expiration: expiration === 0 ? Infinity : expiration, + password, + }) + + const { ok: bytes, error } = await coupon.archive() + if (!bytes) { + console.error(error) + return process.exit(1) + } + + if (output) { + await fs.writeFile(output, bytes) + } else { + process.stdout.write(bytes) + } +} diff --git a/index.js b/index.js index 3693a9d..5225f43 100644 --- a/index.js +++ b/index.js @@ -19,7 +19,8 @@ import { } from './lib.js' import * as ucanto from '@ucanto/core' import chalk from 'chalk' - +import { select } from '@inquirer/prompts' +export * as Coupon from './coupon.js' export { Account, Space } /** @@ -30,6 +31,31 @@ export async function accessClaim() { await client.capability.access.claim() } +/** + * @param {string} email + */ +export const getPlan = async (email = '') => { + const client = await getClient() + const account = + email === '' + ? await Space.selectAccount(client) + : await Space.useAccount(client, { email }) + + if (account) { + const { ok: plan, error } = await account.plan.get() + if (plan) { + console.log(`⁂ ${plan.product}`) + } else if (error?.name === 'PlanNotFound') { + console.log('⁂ no plan has been selected yet') + } else { + console.error(`Failed to get plan - ${error.message}`) + process.exit(1) + } + } else { + process.exit(1) + } +} + /** * @param {`${string}@${string}`} email * @param {object} [opts] @@ -94,8 +120,8 @@ export async function upload(firstPath, opts) { const uploadFn = opts?.car ? client.uploadCAR.bind(client, files[0]) : files.length === 1 && opts?.['no-wrap'] - ? client.uploadFile.bind(client, files[0]) - : client.uploadDirectory.bind(client, files) + ? client.uploadFile.bind(client, files[0]) + : client.uploadDirectory.bind(client, files) const root = await uploadFn({ onShardStored: ({ cid, size, piece }) => { @@ -488,18 +514,31 @@ export async function usageReport(opts) { const period = { // we may not have done a snapshot for this month _yet_, so get report from last month -> now from: startOfLastMonth(now), - to: now + to: now, } let total = 0 - for await (const { account, provider, space, size } of getSpaceUsageReports(client, period)) { + for await (const { account, provider, space, size } of getSpaceUsageReports( + client, + period + )) { if (opts?.json) { - console.log(dagJSON.stringify({ account, provider, space, size, reportedAt: now.toISOString() })) + console.log( + dagJSON.stringify({ + account, + provider, + space, + size, + reportedAt: now.toISOString(), + }) + ) } else { console.log(` Account: ${account}`) console.log(`Provider: ${provider}`) console.log(` Space: ${space}`) - console.log(` Size: ${opts?.human ? filesize(size.final) : size.final}\n`) + console.log( + ` Size: ${opts?.human ? filesize(size.final) : size.final}\n` + ) } total += size.final } @@ -512,9 +551,11 @@ export async function usageReport(opts) { * @param {import('@web3-storage/w3up-client').Client} client * @param {{ from: Date, to: Date }} period */ -async function * getSpaceUsageReports (client, period) { +async function* getSpaceUsageReports(client, period) { for (const account of Object.values(client.accounts())) { - const subscriptions = await client.capability.subscription.list(account.did()) + const subscriptions = await client.capability.subscription.list( + account.did() + ) for (const { consumers } of subscriptions.results) { for (const space of consumers) { const result = await client.capability.usage.report(space, period) diff --git a/package-lock.json b/package-lock.json index 1bb7115..0a7c78d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,9 +17,9 @@ "@ucanto/client": "^9.0.0", "@ucanto/core": "^9.0.0", "@ucanto/transport": "^9.0.0", - "@web3-storage/access": "^17.0.0", + "@web3-storage/access": "^18.0.0", "@web3-storage/did-mailto": "^2.1.0", - "@web3-storage/w3up-client": "^10.2.0", + "@web3-storage/w3up-client": "^11.0.0", "ansi-escapes": "^6.2.0", "chalk": "^5.3.0", "files-from-path": "^1.0.0", @@ -39,10 +39,10 @@ "@ucanto/principal": "^9.0.0", "@ucanto/server": "^9.0.1", "@web-std/blob": "^3.0.5", - "@web3-storage/capabilities": "^11.4.0", + "@web3-storage/capabilities": "^12.0.0", "@web3-storage/eslint-config-w3up": "^1.0.0", "@web3-storage/sigv4": "^1.0.2", - "@web3-storage/upload-api": "^7.3.1", + "@web3-storage/upload-api": "^7.3.2", "@web3-storage/upload-client": "^12.0.0", "entail": "^2.1.1", "multiformats": "^12.0.1", @@ -1484,9 +1484,9 @@ } }, "node_modules/@ucanto/core": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@ucanto/core/-/core-9.0.0.tgz", - "integrity": "sha512-O2c+UOQ5wAvUsuN7BbZR6QAoUgYpWzN0HAAVbNBLT4I8/OUzMcxSYeu08/ph0sNtLGlOPDcPn+ANclTwxc5UcA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@ucanto/core/-/core-9.0.1.tgz", + "integrity": "sha512-SsYvKCO3FD27roTVcg8ASxnixjn+j96sPlijpVq1uBUxq7SmuNxNPYFZqpxXKj2R4gty/Oc8XTse12ebB9Kofg==", "dependencies": { "@ipld/car": "^5.1.0", "@ipld/dag-cbor": "^9.0.0", @@ -1615,21 +1615,21 @@ } }, "node_modules/@web3-storage/access": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@web3-storage/access/-/access-17.0.0.tgz", - "integrity": "sha512-5tU7cD7tZx1Izv3EzQMhhd9BPxBk7b6AZu97fYQNqNgXPxKEnD4nJ/RrQGqAn82aAOM8tMPn/D7jb6IA1nsApg==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@web3-storage/access/-/access-18.0.0.tgz", + "integrity": "sha512-zDw5zlowMytd9HXCUwisYgBhjHohD4wx+Mzq33GfrJyjZOe203CzkuHG2JSsD3d9hx/HxJG2U/NlIJlFRMatSA==", "dependencies": { "@ipld/car": "^5.1.1", "@ipld/dag-ucan": "^3.4.0", "@scure/bip39": "^1.2.1", "@ucanto/client": "^9.0.0", - "@ucanto/core": "^9.0.0", + "@ucanto/core": "^9.0.1", "@ucanto/interface": "^9.0.0", "@ucanto/principal": "^9.0.0", "@ucanto/transport": "^9.0.0", "@ucanto/validator": "^9.0.0", - "@web3-storage/capabilities": "^11.4.0", - "@web3-storage/did-mailto": "^2.0.2", + "@web3-storage/capabilities": "^12.0.0", + "@web3-storage/did-mailto": "^2.1.0", "bigint-mod-arith": "^3.1.2", "conf": "11.0.2", "multiformats": "^12.1.2", @@ -1640,11 +1640,11 @@ } }, "node_modules/@web3-storage/capabilities": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-11.4.0.tgz", - "integrity": "sha512-OGiNVBcivotl05PcQTK/9cqzS3vZ68LUKmwmvyXZkNziCv+09/mneHdLVOCXwEFJdk8IQNVeejB35KWSiEUuGQ==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-12.0.0.tgz", + "integrity": "sha512-pn7scBIE/ZKc0F8nJlUjMfxU27E7WbRdxyiaSVN2obaKTB5/+QnHkaXv0wvlOzOiM0kpchrcIasJCdyCQdvWJQ==", "dependencies": { - "@ucanto/core": "^9.0.0", + "@ucanto/core": "^9.0.1", "@ucanto/interface": "^9.0.0", "@ucanto/principal": "^9.0.0", "@ucanto/transport": "^9.0.0", @@ -1694,24 +1694,49 @@ } }, "node_modules/@web3-storage/filecoin-api": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@web3-storage/filecoin-api/-/filecoin-api-4.1.0.tgz", - "integrity": "sha512-HVToL9T685G4Gjqwzt9wN+/9E2+9gp9rZvNhB8HCrZCBBsCjv8AJRBHhFgo4liNHmLiJFZbRQpbEQ43Cx38+IA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@web3-storage/filecoin-api/-/filecoin-api-4.1.1.tgz", + "integrity": "sha512-VOVo+0eigelqHC/vitwEO7wG7oVNhWur9t7LGFKVqjlVZKMuXGS2xtkF7oUn5yRwmckh+4ip3/5Bp+YbpEP/Zg==", "dev": true, "dependencies": { "@ipld/dag-ucan": "^3.4.0", "@ucanto/client": "^9.0.0", - "@ucanto/core": "^9.0.0", + "@ucanto/core": "^9.0.1", "@ucanto/interface": "^9.0.0", "@ucanto/server": "^9.0.1", "@ucanto/transport": "^9.0.0", - "@web3-storage/capabilities": "^11.3.0", + "@web3-storage/capabilities": "^11.4.1", "@web3-storage/data-segment": "^4.0.0" }, "engines": { "node": ">=16.15" } }, + "node_modules/@web3-storage/filecoin-api/node_modules/@web3-storage/capabilities": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-11.4.1.tgz", + "integrity": "sha512-PjIewEg/T3wfNavxzsZZ5MpH2WBldNz94qOQOKg5iH/4UrS8SPWWGsJx/Tu760O+PFhpTFwvi5cHCtkb08OdAA==", + "dev": true, + "dependencies": { + "@ucanto/core": "^9.0.1", + "@ucanto/interface": "^9.0.0", + "@ucanto/principal": "^9.0.0", + "@ucanto/transport": "^9.0.0", + "@ucanto/validator": "^9.0.0", + "@web3-storage/data-segment": "^3.2.0" + } + }, + "node_modules/@web3-storage/filecoin-api/node_modules/@web3-storage/capabilities/node_modules/@web3-storage/data-segment": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@web3-storage/data-segment/-/data-segment-3.2.0.tgz", + "integrity": "sha512-SM6eNumXzrXiQE2/J59+eEgCRZNYPxKhRoHX2QvV3/scD4qgcf4g+paWBc3UriLEY1rCboygGoPsnqYJNyZyfA==", + "dev": true, + "dependencies": { + "@ipld/dag-cbor": "^9.0.5", + "multiformats": "^11.0.2", + "sync-multihash-sha2": "^1.0.0" + } + }, "node_modules/@web3-storage/filecoin-api/node_modules/@web3-storage/data-segment": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@web3-storage/data-segment/-/data-segment-4.0.0.tgz", @@ -1734,16 +1759,29 @@ } }, "node_modules/@web3-storage/filecoin-client": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@web3-storage/filecoin-client/-/filecoin-client-3.1.0.tgz", - "integrity": "sha512-hR+uEpYpKNv4kcpx1PpAFC2p+hJ27XwVPnP6bc7ZC5p/JMjIAwa2TBm479WdncH/v2uJDqn06J4ux9vYNEFkfw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@web3-storage/filecoin-client/-/filecoin-client-3.1.1.tgz", + "integrity": "sha512-UVSke3IiBHrEvKkwyAjCkttOE2VC+ILEAQg5qVAm7CxApKkhjVHJRh9Xpm8JYI7gZcb6m8/YdgFLOXTjtz3zvQ==", "dependencies": { "@ipld/dag-ucan": "^3.4.0", "@ucanto/client": "^9.0.0", - "@ucanto/core": "^9.0.0", + "@ucanto/core": "^9.0.1", + "@ucanto/interface": "^9.0.0", + "@ucanto/transport": "^9.0.0", + "@web3-storage/capabilities": "^11.4.1" + } + }, + "node_modules/@web3-storage/filecoin-client/node_modules/@web3-storage/capabilities": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-11.4.1.tgz", + "integrity": "sha512-PjIewEg/T3wfNavxzsZZ5MpH2WBldNz94qOQOKg5iH/4UrS8SPWWGsJx/Tu760O+PFhpTFwvi5cHCtkb08OdAA==", + "dependencies": { + "@ucanto/core": "^9.0.1", "@ucanto/interface": "^9.0.0", + "@ucanto/principal": "^9.0.0", "@ucanto/transport": "^9.0.0", - "@web3-storage/capabilities": "^11.3.0" + "@ucanto/validator": "^9.0.0", + "@web3-storage/data-segment": "^3.2.0" } }, "node_modules/@web3-storage/sigv4": { @@ -1756,9 +1794,9 @@ } }, "node_modules/@web3-storage/upload-api": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@web3-storage/upload-api/-/upload-api-7.3.1.tgz", - "integrity": "sha512-SO0KWshPWKmLDcHfNhCKVtrcoBWpzzx2NsM1s12BI4ZWP2oBrYQeY3MZaaMu5GnArg6PHnSGNK1QaMvBKzXA/Q==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@web3-storage/upload-api/-/upload-api-7.3.2.tgz", + "integrity": "sha512-qCkXosQnkpCiLa1HzeGRPjwgScOUSll2Y+jY18MaKaT7RdWw8kmlTYxnesLXw/+nwTwgFeG0hQ2WFTGGNrKpCA==", "dev": true, "dependencies": { "@ucanto/client": "^9.0.0", @@ -1767,10 +1805,10 @@ "@ucanto/server": "^9.0.1", "@ucanto/transport": "^9.0.0", "@ucanto/validator": "^9.0.0", - "@web3-storage/access": "^16.5.1", - "@web3-storage/capabilities": "^11.4.0", - "@web3-storage/did-mailto": "^2.0.2", - "@web3-storage/filecoin-api": "^4.1.0", + "@web3-storage/access": "^17.1.0", + "@web3-storage/capabilities": "^11.4.1", + "@web3-storage/did-mailto": "^2.1.0", + "@web3-storage/filecoin-api": "^4.1.1", "multiformats": "^12.1.2", "p-retry": "^5.1.2" }, @@ -1779,10 +1817,9 @@ } }, "node_modules/@web3-storage/upload-api/node_modules/@web3-storage/access": { - "version": "16.5.1", - "resolved": "https://registry.npmjs.org/@web3-storage/access/-/access-16.5.1.tgz", - "integrity": "sha512-dbqujfXIdETCVfpPQ3b07A2k7aHnxUtK7LMs9d0clbKl3MUQM1wdfBgkEvsMogOikIDN2Db8Av7H6xJI2wlreg==", - "deprecated": "backwards incompatible changes", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@web3-storage/access/-/access-17.1.0.tgz", + "integrity": "sha512-CRVjMfO3LynU9wwCy1XHvWSVlOrccCaqAPPO1siLS/UVYLb4ZT+XuHrM9cYhqZMsBD7yewQ5JG0TDoy/UP7wOQ==", "dev": true, "dependencies": { "@ipld/car": "^5.1.1", @@ -1794,8 +1831,8 @@ "@ucanto/principal": "^9.0.0", "@ucanto/transport": "^9.0.0", "@ucanto/validator": "^9.0.0", - "@web3-storage/capabilities": "^11.2.0", - "@web3-storage/did-mailto": "^2.0.2", + "@web3-storage/capabilities": "^11.4.0", + "@web3-storage/did-mailto": "^2.1.0", "bigint-mod-arith": "^3.1.2", "conf": "11.0.2", "multiformats": "^12.1.2", @@ -1805,6 +1842,20 @@ "uint8arrays": "^4.0.6" } }, + "node_modules/@web3-storage/upload-api/node_modules/@web3-storage/capabilities": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-11.4.1.tgz", + "integrity": "sha512-PjIewEg/T3wfNavxzsZZ5MpH2WBldNz94qOQOKg5iH/4UrS8SPWWGsJx/Tu760O+PFhpTFwvi5cHCtkb08OdAA==", + "dev": true, + "dependencies": { + "@ucanto/core": "^9.0.1", + "@ucanto/interface": "^9.0.0", + "@ucanto/principal": "^9.0.0", + "@ucanto/transport": "^9.0.0", + "@ucanto/validator": "^9.0.0", + "@web3-storage/data-segment": "^3.2.0" + } + }, "node_modules/@web3-storage/upload-client": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/@web3-storage/upload-client/-/upload-client-12.0.0.tgz", @@ -1826,21 +1877,34 @@ "varint": "^6.0.0" } }, + "node_modules/@web3-storage/upload-client/node_modules/@web3-storage/capabilities": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-11.4.1.tgz", + "integrity": "sha512-PjIewEg/T3wfNavxzsZZ5MpH2WBldNz94qOQOKg5iH/4UrS8SPWWGsJx/Tu760O+PFhpTFwvi5cHCtkb08OdAA==", + "dependencies": { + "@ucanto/core": "^9.0.1", + "@ucanto/interface": "^9.0.0", + "@ucanto/principal": "^9.0.0", + "@ucanto/transport": "^9.0.0", + "@ucanto/validator": "^9.0.0", + "@web3-storage/data-segment": "^3.2.0" + } + }, "node_modules/@web3-storage/w3up-client": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-10.2.0.tgz", - "integrity": "sha512-fi5tteUty4fVpIdcyIG6v4Lg8dA/RvG9xWLO1PC3QV0dpVUt/q3RUelihpzkgr5cksigmIwhH1lCBzz5FjjPOg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-11.0.0.tgz", + "integrity": "sha512-VpS3xBhidcAdsLJdlp/lIAinRq7hug7wXL8M2dMKGG1zus11E4lzJ/uZOHLDbtjXfx58niQcHspZRpMJVCGuaw==", "dependencies": { "@ipld/dag-ucan": "^3.4.0", "@ucanto/client": "^9.0.0", - "@ucanto/core": "^9.0.0", + "@ucanto/core": "^9.0.1", "@ucanto/interface": "^9.0.0", "@ucanto/principal": "^9.0.0", "@ucanto/transport": "^9.0.0", - "@web3-storage/access": "^17.0.0", - "@web3-storage/capabilities": "^11.4.0", + "@web3-storage/access": "^18.0.0", + "@web3-storage/capabilities": "^12.0.0", "@web3-storage/did-mailto": "^2.1.0", - "@web3-storage/filecoin-client": "^3.1.0", + "@web3-storage/filecoin-client": "^3.1.1", "@web3-storage/upload-client": "^12.0.0" } }, diff --git a/package.json b/package.json index fb0fe4d..e62b685 100644 --- a/package.json +++ b/package.json @@ -36,10 +36,10 @@ "@ucanto/principal": "^9.0.0", "@ucanto/server": "^9.0.1", "@web-std/blob": "^3.0.5", - "@web3-storage/capabilities": "^11.4.0", + "@web3-storage/capabilities": "^12.0.0", "@web3-storage/eslint-config-w3up": "^1.0.0", "@web3-storage/sigv4": "^1.0.2", - "@web3-storage/upload-api": "^7.3.1", + "@web3-storage/upload-api": "^7.3.2", "@web3-storage/upload-client": "^12.0.0", "entail": "^2.1.1", "multiformats": "^12.0.1", @@ -54,9 +54,9 @@ "@ucanto/client": "^9.0.0", "@ucanto/core": "^9.0.0", "@ucanto/transport": "^9.0.0", - "@web3-storage/access": "^17.0.0", + "@web3-storage/access": "^18.0.0", "@web3-storage/did-mailto": "^2.1.0", - "@web3-storage/w3up-client": "^10.2.0", + "@web3-storage/w3up-client": "^11.0.0", "chalk": "^5.3.0", "ansi-escapes": "^6.2.0", "@inquirer/prompts": "^3.3.0", diff --git a/space.js b/space.js index 597552c..41cea8d 100644 --- a/space.js +++ b/space.js @@ -9,6 +9,7 @@ import ora from 'ora' import { select, input } from '@inquirer/prompts' import { mnemonic } from './dialog.js' import { API } from '@ucanto/core' +import * as Result from '@web3-storage/w3up-client/result' /** * @typedef {object} CreateOptions @@ -163,8 +164,9 @@ const setupBilling = async ( /** * @typedef {object} ProvisionOptions * @property {DIDMailto.EmailAddress} [customer] - * @property {string} [proof] + * @property {string} [coupon] * @property {string} [provider] + * @property {string} [password] * * @param {string} name * @param {ProvisionOptions} options @@ -179,34 +181,55 @@ export const provision = async (name = '', options = {}) => { process.exit(1) } - let result - if (options.proof) { - const { ok: account, error } = await Account.load(client, { - url: new URL(options.proof), - }) + if (options.coupon) { + const { ok: bytes, error: fetchError } = await fetch(options.coupon) + .then((response) => response.arrayBuffer()) + .then((buffer) => Result.ok(new Uint8Array(buffer))) + .catch((error) => Result.error(/** @type {Error} */ (error))) - if (error) { - result = { error } - } else { - result = await account.provision(space) + if (fetchError) { + console.error(`Failed to fetch coupon from ${options.coupon}`) + process.exit(1) + } + + const { ok: access, error: couponError } = await client.coupon + .redeem(bytes, options) + .then(Result.ok, Result.error) + + if (!access) { + console.error(`Failed to redeem coupon: ${couponError.message}}`) + process.exit(1) + } + + const result = await W3Space.provision( + { did: () => space }, + { + proofs: access.proofs, + agent: client.agent, + } + ) + + if (result.error) { + console.log(`Failed to provision space: ${result.error.message}`) + process.exit(1) } } else { - result = await setupBilling(client, { + const result = await setupBilling(client, { customer: options.customer, space, }) - } - if (result.error) { - console.error( - `⚠️ Failed to set up billing account,\n ${ - Object(result.error).message ?? '' - }` - ) - process.exit(1) - } else { - console.log(`✨ Billing account is set`) + if (result.error) { + console.error( + `⚠️ Failed to set up billing account,\n ${ + Object(result.error).message ?? '' + }` + ) + process.exit(1) + } } + + console.log(`✨ Billing account is set`) } /** diff --git a/test/bin.spec.js b/test/bin.spec.js index ade2d32..4122eda 100644 --- a/test/bin.spec.js +++ b/test/bin.spec.js @@ -520,7 +520,7 @@ export const testSpace = { ) }), - 'w3 space provision': test(async (assert, context) => { + 'w3 space provision --coupon': test(async (assert, context) => { const spaceDID = await createSpace(context, { customer: null }) assert.deepEqual( @@ -541,7 +541,7 @@ export const testSpace = { const url = new URL('/proof.car', context.serverURL) const provision = await w3 .env(context.env.alice) - .args(['space', 'provision', '--proof', url.href]) + .args(['space', 'provision', '--coupon', url.href]) .join() assert.match(provision.output, /Billing account is set/) @@ -1135,6 +1135,23 @@ export const testCan = { }), } +export const testPlan = { + 'w3 plan get': test(async (assert, context) => { + await login(context) + const notFound = await w3 + .args(['plan', 'get']) + .env(context.env.alice) + .join() + + assert.match(notFound.output, /no plan/i) + + await selectPlan(context) + + const plan = await w3.args(['plan', 'get']).env(context.env.alice).join() + assert.match(plan.output, /did:web:free.web3.storage/) + }), +} + /** * @param {Test.Context} context * @param {object} options From 8a01e82873c61c3b0af8a1bfd2d08394bb5b6479 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 15 Nov 2023 22:21:44 +0300 Subject: [PATCH 6/9] chore: remove obsolete changes --- account.js | 66 ------------------------------------------------------ 1 file changed, 66 deletions(-) diff --git a/account.js b/account.js index beae130..895707f 100644 --- a/account.js +++ b/account.js @@ -3,10 +3,6 @@ import * as Result from '@web3-storage/w3up-client/result' import * as DidMailto from '@web3-storage/did-mailto' import { getClient } from './lib.js' import ora from 'ora' -import { AccountDID } from '@web3-storage/access/provider' -import { Delegation } from '@web3-storage/access' -import * as ED25519 from '@ucanto/principal/ed25519' -import { sha256 } from '@ucanto/core' /** * @typedef {Awaited>['ok']&{}} View @@ -58,65 +54,3 @@ export const list = async () => { ) } } - -/** - * Loads account from the the external proof delegated to the ED25519 principal - * derived from the sha256 of the password. Delegation must be encoded in a CAR - * format produced by `Delegation.archive` function. External delegation MAY - * be fetched from a remote URL or from a local file system (if file:// URL is - * provided). - * - * Loaded account and delegations side-loaded are expected to be short-lived - * given that delegations are effectively usable by anyone who knows the URL. - * - * @param {import('@web3-storage/w3up-client').Client} client - * @param {object} options - * @param {URL} options.url - * @param {string} [options.password] - */ -export const load = async (client, { url, password = '' }) => { - const { ok: bytes, error: fetchError } = await fetch(url) - .then((response) => response.arrayBuffer()) - .then((buffer) => Result.ok(new Uint8Array(buffer))) - .catch((error) => Result.error(/** @type {Error} */ (error))) - - if (fetchError) { - return Result.error(fetchError) - } - - const { error: extractError, ok: delegation } = - await Delegation.extract(bytes) - if (extractError) { - return Result.error(extractError) - } - - const [capability] = delegation.capabilities - - const { ok: customer, error } = AccountDID.read(capability.with) - if (error) { - return Result.error(error) - } - - const { digest } = await sha256.digest(new TextEncoder().encode(password)) - const audience = await ED25519.Signer.derive(digest) - - if (delegation.audience.did() !== audience.did()) { - return Result.error(new RangeError('Invalid password')) - } - - const account = new Account.Account({ - agent: client.agent, - id: /** @type {DidMailto.DidMailto} */ (customer), - proofs: [ - await Delegation.delegate({ - issuer: audience, - audience: client.agent, - capabilities: [capability], - expiration: delegation.expiration, - proofs: [delegation], - }), - ], - }) - - return Result.ok(account) -} From 1e05968a13b654ff358ecf4aca6c713f5985db30 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 15 Nov 2023 22:26:03 +0300 Subject: [PATCH 7/9] fix: package json and lock --- package-lock.json | 75 ++++++----------------------------------------- package.json | 4 +-- 2 files changed, 11 insertions(+), 68 deletions(-) diff --git a/package-lock.json b/package-lock.json index f7dec3b..a3af989 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,10 +17,10 @@ "@ucanto/client": "^9.0.0", "@ucanto/core": "^9.0.0", "@ucanto/transport": "^9.0.0", - "@web3-storage/access": "^18.0.0", + "@web3-storage/access": "18.0.0", "@web3-storage/data-segment": "^5.0.0", "@web3-storage/did-mailto": "^2.1.0", - "@web3-storage/w3up-client": "^10.0.0", + "@web3-storage/w3up-client": "^11.0.0", "ansi-escapes": "^6.2.0", "chalk": "^5.3.0", "files-from-path": "^1.0.0", @@ -1970,80 +1970,23 @@ } }, "node_modules/@web3-storage/w3up-client": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-10.3.0.tgz", - "integrity": "sha512-Alx14cQYYD6h8fmx/E2wBIGHWZZgcr/N6BgvwnxkyNpefH7PQp9BAeCQe1sKljkhHfxT85cqCsSV9mfpS7vAAw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-11.0.0.tgz", + "integrity": "sha512-VpS3xBhidcAdsLJdlp/lIAinRq7hug7wXL8M2dMKGG1zus11E4lzJ/uZOHLDbtjXfx58niQcHspZRpMJVCGuaw==", "dependencies": { "@ipld/dag-ucan": "^3.4.0", "@ucanto/client": "^9.0.0", - "@ucanto/core": "^9.0.0", + "@ucanto/core": "^9.0.1", "@ucanto/interface": "^9.0.0", "@ucanto/principal": "^9.0.0", "@ucanto/transport": "^9.0.0", - "@web3-storage/access": "^17.1.0", - "@web3-storage/capabilities": "^11.4.0", + "@web3-storage/access": "^18.0.0", + "@web3-storage/capabilities": "^12.0.0", "@web3-storage/did-mailto": "^2.1.0", - "@web3-storage/filecoin-client": "^3.1.0", + "@web3-storage/filecoin-client": "^3.1.1", "@web3-storage/upload-client": "^12.0.0" } }, - "node_modules/@web3-storage/w3up-client/node_modules/@web3-storage/access": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@web3-storage/access/-/access-17.1.0.tgz", - "integrity": "sha512-CRVjMfO3LynU9wwCy1XHvWSVlOrccCaqAPPO1siLS/UVYLb4ZT+XuHrM9cYhqZMsBD7yewQ5JG0TDoy/UP7wOQ==", - "dependencies": { - "@ipld/car": "^5.1.1", - "@ipld/dag-ucan": "^3.4.0", - "@scure/bip39": "^1.2.1", - "@ucanto/client": "^9.0.0", - "@ucanto/core": "^9.0.0", - "@ucanto/interface": "^9.0.0", - "@ucanto/principal": "^9.0.0", - "@ucanto/transport": "^9.0.0", - "@ucanto/validator": "^9.0.0", - "@web3-storage/capabilities": "^11.4.0", - "@web3-storage/did-mailto": "^2.1.0", - "bigint-mod-arith": "^3.1.2", - "conf": "11.0.2", - "multiformats": "^12.1.2", - "one-webcrypto": "git://github.com/web3-storage/one-webcrypto.git", - "p-defer": "^4.0.0", - "type-fest": "^3.3.0", - "uint8arrays": "^4.0.6" - } - }, - "node_modules/@web3-storage/w3up-client/node_modules/@web3-storage/capabilities": { - "version": "11.4.1", - "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-11.4.1.tgz", - "integrity": "sha512-PjIewEg/T3wfNavxzsZZ5MpH2WBldNz94qOQOKg5iH/4UrS8SPWWGsJx/Tu760O+PFhpTFwvi5cHCtkb08OdAA==", - "dependencies": { - "@ucanto/core": "^9.0.1", - "@ucanto/interface": "^9.0.0", - "@ucanto/principal": "^9.0.0", - "@ucanto/transport": "^9.0.0", - "@ucanto/validator": "^9.0.0", - "@web3-storage/data-segment": "^3.2.0" - } - }, - "node_modules/@web3-storage/w3up-client/node_modules/@web3-storage/data-segment": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@web3-storage/data-segment/-/data-segment-3.2.0.tgz", - "integrity": "sha512-SM6eNumXzrXiQE2/J59+eEgCRZNYPxKhRoHX2QvV3/scD4qgcf4g+paWBc3UriLEY1rCboygGoPsnqYJNyZyfA==", - "dependencies": { - "@ipld/dag-cbor": "^9.0.5", - "multiformats": "^11.0.2", - "sync-multihash-sha2": "^1.0.0" - } - }, - "node_modules/@web3-storage/w3up-client/node_modules/@web3-storage/data-segment/node_modules/multiformats": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", - "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/@zxing/text-encoding": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", diff --git a/package.json b/package.json index 8d4272f..1bcd8b6 100644 --- a/package.json +++ b/package.json @@ -54,9 +54,9 @@ "@ucanto/client": "^9.0.0", "@ucanto/core": "^9.0.0", "@ucanto/transport": "^9.0.0", - "@web3-storage/access": "^18.0.0", + "@web3-storage/access": "18.0.0", "@web3-storage/data-segment": "^5.0.0", - "@web3-storage/w3up-client": "^10.0.0", + "@web3-storage/w3up-client": "^11.0.0", "@web3-storage/did-mailto": "^2.1.0", "chalk": "^5.3.0", "ansi-escapes": "^6.2.0", From 1d5433939b842b4c4d74da16c6ec116a6fc2090a Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 15 Nov 2023 22:26:37 +0300 Subject: [PATCH 8/9] cleanup --- index.js | 1 - test/bin.spec.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/index.js b/index.js index d963e2d..6dab1e1 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,6 @@ import { } from './lib.js' import * as ucanto from '@ucanto/core' import chalk from 'chalk' -import { select } from '@inquirer/prompts' export * as Coupon from './coupon.js' export { Account, Space } diff --git a/test/bin.spec.js b/test/bin.spec.js index c86d6ee..22d8c37 100644 --- a/test/bin.spec.js +++ b/test/bin.spec.js @@ -3,7 +3,7 @@ import os from 'os' import path from 'path' import * as Signer from '@ucanto/principal/ed25519' import { importDAG } from '@ucanto/core/delegation' -import { parseLink, provide } from '@ucanto/server' +import { parseLink } from '@ucanto/server' import * as DID from '@ipld/dag-ucan/did' import * as dagJSON from '@ipld/dag-json' import { SpaceDID } from '@web3-storage/capabilities/utils' From 86355f8a97a32919eaa016bc050fe2c1a1184d22 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Thu, 16 Nov 2023 05:28:51 +0300 Subject: [PATCH 9/9] chore: add password flag --- bin.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin.js b/bin.js index 388d59e..ee95a07 100755 --- a/bin.js +++ b/bin.js @@ -32,7 +32,7 @@ import { uploadAdd, uploadList, uploadRemove, - filecoinInfo + filecoinInfo, } from './can.js' const pkg = getPkg() @@ -164,6 +164,7 @@ cli cli .command('coupon create ') + .option('--password', 'Password for created coupon.') .option('-c, --can', 'One or more abilities to delegate.') .option( '-e, --expiration',