From 52faac5cb7207fd6515da19ab7f7af96a7bbd3f7 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Mon, 28 Oct 2024 14:13:27 -0400 Subject: [PATCH 01/12] `withAuthorizedSpace()` authorizes --- src/index.js | 6 +- src/middleware/index.js | 2 +- src/middleware/withAuthToken.js | 5 +- src/middleware/withAuthToken.types.ts | 4 +- src/middleware/withAuthorizedSpace.js | 125 +++++++ src/middleware/withAuthorizedSpace.types.ts | 36 ++ src/middleware/withNotFound.js | 28 -- test/unit/middleware/util/createTestCID.js | 14 + test/unit/middleware/withAuthToken.spec.js | 5 +- .../middleware/withAuthorizedSpace.spec.js | 311 ++++++++++++++++++ test/unit/middleware/withNotFound.spec.js | 155 --------- 11 files changed, 496 insertions(+), 195 deletions(-) create mode 100644 src/middleware/withAuthorizedSpace.js create mode 100644 src/middleware/withAuthorizedSpace.types.ts delete mode 100644 src/middleware/withNotFound.js create mode 100644 test/unit/middleware/util/createTestCID.js create mode 100644 test/unit/middleware/withAuthorizedSpace.spec.js delete mode 100644 test/unit/middleware/withNotFound.spec.js diff --git a/src/index.js b/src/index.js index 3ed7d69..85fa13f 100644 --- a/src/index.js +++ b/src/index.js @@ -21,9 +21,9 @@ import { withAuthToken, withCarBlockHandler, withRateLimit, - withNotFound, - withLocator, withEgressTracker + withAuthorizedSpace, + withLocator } from './middleware/index.js' import { instrument } from '@microlabs/otel-cf-workers' import { NoopSpanProcessor } from '@opentelemetry/sdk-trace-base' @@ -65,7 +65,7 @@ const handler = { // Fetch data withCarBlockHandler, - withNotFound, + withAuthorizedSpace, withContentClaimsDagula, withFormatRawHandler, withFormatCarHandler, diff --git a/src/middleware/index.js b/src/middleware/index.js index 6fe437e..cd79d16 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -3,6 +3,6 @@ export { withCarBlockHandler } from './withCarBlockHandler.js' export { withContentClaimsDagula } from './withContentClaimsDagula.js' export { withRateLimit } from './withRateLimit.js' export { withVersionHeader } from './withVersionHeader.js' -export { withNotFound } from './withNotFound.js' +export { withAuthorizedSpace } from './withAuthorizedSpace.js' export { withLocator } from './withLocator.js' export { withEgressTracker } from './withEgressTracker.js' diff --git a/src/middleware/withAuthToken.js b/src/middleware/withAuthToken.js index 424066e..ab73d8d 100644 --- a/src/middleware/withAuthToken.js +++ b/src/middleware/withAuthToken.js @@ -5,8 +5,7 @@ * } from '@web3-storage/gateway-lib' * @import { * Environment, - * InContext, - * OutContext, + * AuthTokenContext, * } from './withAuthToken.types.js' */ @@ -14,7 +13,7 @@ * Finds an authentication token in the URL query parameters or the * `Authorization` header and adds it to the context as `authToken`. * - * @type {Middleware, InContext, Environment>} + * @type {Middleware} */ export function withAuthToken (handler) { return async (req, env, ctx) => { diff --git a/src/middleware/withAuthToken.types.ts b/src/middleware/withAuthToken.types.ts index c830355..c89ddb8 100644 --- a/src/middleware/withAuthToken.types.ts +++ b/src/middleware/withAuthToken.types.ts @@ -5,8 +5,8 @@ import { export interface Environment extends MiddlewareEnvironment {} -export interface InContext extends MiddlewareContext {} +export interface AuthTokenContextIn extends MiddlewareContext {} -export type OutContext = IncomingContext & { +export interface AuthTokenContext extends MiddlewareContext { authToken: string | null } diff --git a/src/middleware/withAuthorizedSpace.js b/src/middleware/withAuthorizedSpace.js new file mode 100644 index 0000000..8de3686 --- /dev/null +++ b/src/middleware/withAuthorizedSpace.js @@ -0,0 +1,125 @@ +/* eslint-disable no-throw-literal --- TK */ +import { Verifier } from '@ucanto/principal' +import { + capability, + Schema, + DID, + nullable, + string, + ok, + access +} from '@ucanto/validator' +import { HttpError } from '@web3-storage/gateway-lib/util' + +/** + * @import * as Ucanto from '@ucanto/interface' + * @import { IpfsUrlContext, Middleware } from '@web3-storage/gateway-lib' + * @import { LocatorContext } from './withLocator.types.js' + * @import { AuthTokenContext } from './withAuthToken.types.js' + * @import { SpaceContext, DelegationsStorageContext } from './withAuthorizedSpace.types.js' + */ + +/** + * "Serve content owned by the subject Space." + * + * A Principal who may `space/content/serve` is permitted to serve any + * content owned by the Space, in the manner of an [IPFS Gateway]. The + * content may be a Blob stored by a Storage Node, or indexed content stored + * within such Blobs (ie, Shards). + * + * Note that the args do not currently specify *what* content should be + * served. Invoking this command does not currently *serve* the content in + * any way, but merely validates the authority to do so. Currently, the + * entirety of a Space must use the same authorization, thus the content does + * not need to be identified. In the future, this command may refer directly + * to a piece of content by CID. + * + * [IPFS Gateway]: https://specs.ipfs.tech/http-gateways/path-gateway/ + */ +export const serve = capability({ + can: 'space/content/serve', + /** + * The Space which contains the content. This Space will be charged egress + * fees if content is actually retrieved by way of this invocation. + */ + with: DID.match({ method: 'key' }), + nb: Schema.struct({ + /** The authorization token, if any, used for this request. */ + token: nullable(string()) + }) +}) + +/** + * @param {string} space + * @returns {space is Ucanto.DIDKey} + */ +const isDIDKey = (space) => space.startsWith('did:key:') + +/** + * Attempts to locate the {@link IpfsUrlContext.dataCid}. If it's able to, + * attempts to authorize the request to access the data. + * + * @throws {HttpError} (404) If the locator tells us the data is not found, or + * if no located space is one the request is authorized to access. + * @throws {Error} If the locator fails in any other way. + * @type {( + * Middleware< + * LocatorContext & IpfsUrlContext & AuthTokenContext & DelegationsStorageContext & SpaceContext, + * LocatorContext & IpfsUrlContext & AuthTokenContext & DelegationsStorageContext, + * {} + * > + * )} + */ +export function withAuthorizedSpace (handler) { + return async (request, env, ctx) => { + const { locator, dataCid } = ctx + const locRes = await locator.locate(dataCid.multihash) + if (locRes.error) { + if (locRes.error.name === 'NotFound') { + throw new HttpError('Not Found', { status: 404, cause: locRes.error }) + } + throw new Error(`failed to locate: ${dataCid}`, { cause: locRes.error }) + } + + const spaces = locRes.ok.site.map((site) => site.space) + const space = spaces[0] + if (!space) throw 'TK' + if (!isDIDKey(space)) throw 'TK' + + const relevantDelegations = await ctx.delegationsStorage.find({ + audience: ctx.gatewayIdentity.did(), + can: 'space/content/serve', + with: space + }) + + if (relevantDelegations.error) throw 'TK' + + const invocation = await serve + .invoke({ + issuer: ctx.gatewayIdentity, + audience: ctx.gatewayIdentity, + with: space, + nb: { + token: ctx.authToken + }, + proofs: relevantDelegations.ok + }) + .delegate() + + const accessResult = await access(invocation, { + capability: serve, + authority: ctx.gatewayIdentity, + principal: Verifier, + validateAuthorization: () => ok({}) + }) + + if (accessResult.error) { + throw new HttpError('Not Found', { + status: 404, + cause: accessResult.error + }) + } + + return handler(request, env, { ...ctx, space }) + } +} diff --git a/src/middleware/withAuthorizedSpace.types.ts b/src/middleware/withAuthorizedSpace.types.ts new file mode 100644 index 0000000..20587b0 --- /dev/null +++ b/src/middleware/withAuthorizedSpace.types.ts @@ -0,0 +1,36 @@ +import * as Ucanto from '@ucanto/interface' +import { Context as MiddlewareContext } from '@web3-storage/gateway-lib' + +export interface DelegationsStorageContext extends MiddlewareContext { + /** The identity of the gateway itself */ + gatewayIdentity: Ucanto.Signer + delegationsStorage: DelegationsStorage +} + +export interface SpaceContext extends MiddlewareContext { + space: Ucanto.DID +} + +// TEMP: https://github.com/storacha/blob-fetcher/pull/13/files +declare module '@web3-storage/blob-fetcher' { + interface Site { + space?: Ucanto.DID + } +} + +// TEMP + +export interface Query { + audience?: Ucanto.DID + can: string + with: Ucanto.Resource +} + +export interface DelegationsStorage { + /** + * find all items that match the query + */ + find: ( + query: Query + ) => Promise> +} diff --git a/src/middleware/withNotFound.js b/src/middleware/withNotFound.js deleted file mode 100644 index b12d515..0000000 --- a/src/middleware/withNotFound.js +++ /dev/null @@ -1,28 +0,0 @@ -import { HttpError } from '@web3-storage/gateway-lib/util' - -/** - * @import { IpfsUrlContext, Middleware } from '@web3-storage/gateway-lib' - * @import { LocatorContext } from './withLocator.types.js' - */ - -/** - * Attempts to locate the {@link IpfsUrlContext.dataCid} and stops the request - * if it cannot. - * - * @throws {HttpError} If the locator tells us the data is not found. - * @throws {Error} If the locator fails. - * @type {Middleware} - */ -export function withNotFound (handler) { - return async (request, env, ctx) => { - const { locator, dataCid } = ctx - const locRes = await locator.locate(dataCid.multihash) - if (locRes.error) { - if (locRes.error.name === 'NotFound') { - throw new HttpError('Not Found', { status: 404 }) - } - throw new Error(`failed to locate: ${dataCid}`, { cause: locRes.error }) - } - return handler(request, env, ctx) - } -} diff --git a/test/unit/middleware/util/createTestCID.js b/test/unit/middleware/util/createTestCID.js new file mode 100644 index 0000000..b861100 --- /dev/null +++ b/test/unit/middleware/util/createTestCID.js @@ -0,0 +1,14 @@ +import { CID } from 'multiformats' +import * as raw from 'multiformats/codecs/raw' +import { identity } from 'multiformats/hashes/identity' + +/** + * Creates a CID from an integer. The CID should be both unique and consistent + * for any value of {@link n}, making it useful for testing. + * + * @param {number} n + * @returns {CID} + */ +export const createTestCID = (n) => { + return CID.createV1(raw.code, identity.digest(Uint8Array.of(n))) +} diff --git a/test/unit/middleware/withAuthToken.spec.js b/test/unit/middleware/withAuthToken.spec.js index ae6ee0b..39031d6 100644 --- a/test/unit/middleware/withAuthToken.spec.js +++ b/test/unit/middleware/withAuthToken.spec.js @@ -3,15 +3,14 @@ import { expect } from 'chai' import { withAuthToken } from '../../../src/middleware/withAuthToken.js' /** - * @import { OutContext } from '../../../src/middleware/withAuthToken.types.js' + * @import { AuthTokenContext } from '../../../src/middleware/withAuthToken.types.js' * @import { * Handler, - * Context as MiddlewareContext, * Environment as MiddlewareEnvironment, * } from '@web3-storage/gateway-lib' */ -/** @type {Handler, MiddlewareEnvironment>} */ +/** @type {Handler} */ const innerHandler = async (_req, _env, ctx) => new Response( ctx.authToken === null ? 'No token given' : `Got token: ${ctx.authToken}` diff --git a/test/unit/middleware/withAuthorizedSpace.spec.js b/test/unit/middleware/withAuthorizedSpace.spec.js new file mode 100644 index 0000000..c3d4648 --- /dev/null +++ b/test/unit/middleware/withAuthorizedSpace.spec.js @@ -0,0 +1,311 @@ +/* eslint-disable no-unused-expressions + --- + `no-unused-expressions` doesn't understand that several of Chai's assertions + are implemented as getters rather than explicit function calls; it thinks + the assertions are unused expressions. */ +import { describe, it } from 'mocha' +import { expect } from 'chai' +import sinon from 'sinon' +import * as ed25519 from '@ucanto/principal/ed25519' +import { Unauthorized } from '@ucanto/validator' +import { + serve, + withAuthorizedSpace +} from '../../../src/middleware/withAuthorizedSpace.js' +import * as Digest from 'multiformats/hashes/digest' +import { base64 } from 'multiformats/bases/base64' +import { rejection } from './util/rejection.js' +import { expectToBeInstanceOf } from './util/expectToBeInstanceOf.js' +import { HttpError } from '@web3-storage/gateway-lib/util' +import { createTestCID } from './util/createTestCID.js' + +/** + * @import { MultihashDigest } from 'multiformats' + * @import { Locator } from '@web3-storage/blob-fetcher' + * @import { + * Handler, + * Environment as MiddlewareEnvironment, + * IpfsUrlContext + * } from '@web3-storage/gateway-lib' + * @import { DelegationsStorage, SpaceContext } from '../../../src/middleware/withAuthorizedSpace.types.js' + * @import { AuthTokenContext } from '../../../src/middleware/withAuthToken.types.js' + */ + +/** @type {Handler} */ +const innerHandler = async (_req, _env, ctx) => + new Response( + `Served ${ctx.dataCid.toString()} from ${ + ctx.space ? `space ${ctx.space}` : 'no space' + } with ${ctx.authToken ? `token ${ctx.authToken}` : 'no token'}` + ) + +const request = new Request('http://example.com/') + +const ctx = { + waitUntil: () => {}, + path: '', + searchParams: new URLSearchParams() +} + +/** + * @param {MultihashDigest} expectedDigest + * @param {Awaited>} locateResponse + * @returns {Locator} + * */ +const createLocator = (expectedDigest, locateResponse) => ({ + locate: async (digest) => { + if (Digest.equals(digest, expectedDigest)) { + return locateResponse + } else { + expect.fail( + `Got unexpected digest in test locator: ${base64.baseEncode( + digest.bytes + )}` + ) + } + } +}) + +/** @import * as Ucanto from '@ucanto/interface' */ + +const gatewayIdentity = (await ed25519.Signer.generate()).withDID( + 'did:web:test.w3s.link' +) + +/** + * @param {Ucanto.Delegation[]} delegations + * @returns {DelegationsStorage} + * */ +const createDelegationStorage = (delegations) => ({ + find: async (query) => ({ + ok: delegations.filter((delegation) => { + return ( + (!query.audience || delegation.audience.did() === query.audience) && + delegation.capabilities.some( + (cap) => + (!query.can || cap.can === query.can) && + (!query.with || cap.with === query.with) + ) + ) + }) + }) +}) + +describe('withAuthorizedSpace', async () => { + it('should serve a found CID from an authorized Space using a token', async () => { + const cid = createTestCID(0) + const space = await ed25519.Signer.generate() + + const response = await withAuthorizedSpace(innerHandler)( + request, + {}, + { + ...ctx, + dataCid: cid, + authToken: 'a1b2c3', + locator: createLocator(cid.multihash, { + ok: { + digest: cid.multihash, + site: [ + { + location: [new URL('http://example.com/blob')], + range: { offset: 0, length: 100 }, + space: space.did() + } + ] + }, + error: undefined + }), + delegationsStorage: createDelegationStorage([ + await serve.delegate({ + issuer: space, + audience: gatewayIdentity, + with: space.did(), + nb: { token: 'a1b2c3' } + }) + ]), + gatewayIdentity + } + ) + + expect(await response.text()).to.equal( + `Served ${cid} from space ${space.did()} with token a1b2c3` + ) + }) + + it('should not serve a found CID from an unauthorized Space using a token', async () => { + const handler = sinon.fake(innerHandler) + const cid = createTestCID(0) + const space = await ed25519.Signer.generate() + + const error = await rejection( + withAuthorizedSpace(innerHandler)( + request, + {}, + { + ...ctx, + dataCid: cid, + authToken: 'not-valid-token', + locator: createLocator(cid.multihash, { + ok: { + digest: cid.multihash, + site: [ + { + location: [new URL('http://example.com/blob')], + range: { offset: 0, length: 100 }, + space: space.did() + } + ] + }, + error: undefined + }), + delegationsStorage: createDelegationStorage([ + await serve.delegate({ + issuer: space, + audience: gatewayIdentity, + with: space.did(), + nb: { token: 'a1b2c3' } + }) + ]), + gatewayIdentity + } + ) + ) + + expect(handler.notCalled).to.be.true + expectToBeInstanceOf(error, HttpError) + expect(error.status).to.equal(404) + expect(error.message).to.equal('Not Found') + expectToBeInstanceOf(error.cause, Unauthorized) + }) + + it('should throw a 404 error if the content is not found', async () => { + const handler = sinon.fake(innerHandler) + const cid = createTestCID(0) + const space = await ed25519.Signer.generate() + + const error = await rejection( + withAuthorizedSpace(innerHandler)( + request, + {}, + { + ...ctx, + dataCid: cid, + authToken: 'a1b2c3', + locator: createLocator(cid.multihash, { + error: { + name: 'NotFound', + message: 'Not found', + digest: cid.multihash.bytes + } + }), + delegationsStorage: createDelegationStorage([ + await serve.delegate({ + issuer: space, + audience: gatewayIdentity, + with: space.did(), + nb: { token: 'a1b2c3' } + }) + ]), + gatewayIdentity + } + ) + ) + + expect(handler.notCalled).to.be.true + expectToBeInstanceOf(error, HttpError) + expect(error.status).to.equal(404) + expect(error.message).to.equal('Not Found') + expect(error.cause).to.deep.equal({ + name: 'NotFound', + message: 'Not found', + digest: cid.multihash.bytes + }) + }) + + it('should throw an error if the locator aborts', async () => { + const handler = sinon.fake(innerHandler) + const cid = createTestCID(0) + const space = await ed25519.Signer.generate() + + const error = await rejection( + withAuthorizedSpace(innerHandler)( + request, + {}, + { + ...ctx, + dataCid: cid, + authToken: 'a1b2c3', + locator: createLocator(cid.multihash, { + error: { + name: 'Aborted', + message: 'Aborted', + digest: cid.multihash.bytes + } + }), + delegationsStorage: createDelegationStorage([ + await serve.delegate({ + issuer: space, + audience: gatewayIdentity, + with: space.did(), + nb: { token: 'a1b2c3' } + }) + ]), + gatewayIdentity + } + ) + ) + + expect(handler.notCalled).to.be.true + expectToBeInstanceOf(error, Error) + expect(error.message).to.equal('failed to locate: bafkqaaia') + expect(error.cause).to.deep.equal({ + name: 'Aborted', + message: 'Aborted', + digest: cid.multihash.bytes + }) + }) + + it('should throw an error if the locator has a network error', async () => { + const handler = sinon.fake(innerHandler) + const cid = createTestCID(0) + const space = await ed25519.Signer.generate() + + const error = await rejection( + withAuthorizedSpace(innerHandler)( + request, + {}, + { + ...ctx, + dataCid: cid, + authToken: 'a1b2c3', + locator: createLocator(cid.multihash, { + error: { + name: 'NetworkError', + message: 'Network error', + url: 'http://example.com/blob' + } + }), + delegationsStorage: createDelegationStorage([ + await serve.delegate({ + issuer: space, + audience: gatewayIdentity, + with: space.did(), + nb: { token: 'a1b2c3' } + }) + ]), + gatewayIdentity + } + ) + ) + + expect(handler.notCalled).to.be.true + expectToBeInstanceOf(error, Error) + expect(error.message).to.equal('failed to locate: bafkqaaia') + expect(error.cause).to.deep.equal({ + name: 'NetworkError', + message: 'Network error', + url: 'http://example.com/blob' + }) + }) +}) diff --git a/test/unit/middleware/withNotFound.spec.js b/test/unit/middleware/withNotFound.spec.js deleted file mode 100644 index a6b6ddf..0000000 --- a/test/unit/middleware/withNotFound.spec.js +++ /dev/null @@ -1,155 +0,0 @@ -/* eslint-disable no-unused-expressions - --- - `no-unused-expressions` doesn't understand that several of Chai's assertions - are implemented as getters rather than explicit function calls; it thinks - the assertions are unused expressions. */ -import { describe, it } from 'mocha' -import { expect } from 'chai' -import sinon from 'sinon' -import { CID } from 'multiformats' -import * as raw from 'multiformats/codecs/raw' -import { identity } from 'multiformats/hashes/identity' -import { withNotFound } from '../../../src/middleware/withNotFound.js' -import * as Digest from 'multiformats/hashes/digest' -import { base64 } from 'multiformats/bases/base64' -import { rejection } from './util/rejection.js' -import { expectToBeInstanceOf } from './util/expectToBeInstanceOf.js' -import { HttpError } from '@web3-storage/gateway-lib/util' - -/** - * @import { LocatorContext } from '../../../src/middleware/withLocator.types.js' - * @import { - * Handler, - * Environment as MiddlewareEnvironment, - * IpfsUrlContext - * } from '@web3-storage/gateway-lib' - */ - -/** @type {Handler} */ -const innerHandler = async (_req, _env, ctx) => - new Response(`Served ${ctx.dataCid.toString()}`) - -const request = new Request('http://example.com/') - -const ctx = { - waitUntil: () => {} -} - -const [foundCid, notFoundCid, abortedCid, networkErrorCid] = [...Array(4)].map( - (_, i) => CID.createV1(raw.code, identity.digest(Uint8Array.of(i))) -) - -/** @type {LocatorContext['locator']} */ -const locator = { - locate: async (digest) => { - if (Digest.equals(digest, foundCid.multihash)) { - return { - ok: { digest, site: [] }, - error: undefined - } - } else if (Digest.equals(digest, notFoundCid.multihash)) { - return { - ok: undefined, - error: { name: 'NotFound', digest: digest.bytes, message: 'Not found' } - } - } else if (Digest.equals(digest, abortedCid.multihash)) { - return { - ok: undefined, - error: { name: 'Aborted', digest: digest.bytes, message: 'Aborted' } - } - } else if (Digest.equals(digest, networkErrorCid.multihash)) { - return { - ok: undefined, - error: { - name: 'NetworkError', - url: 'http://example.com/', - message: 'Network Error' - } - } - } else { - expect.fail( - `Got unexpected digest in test locator: ${base64.baseEncode( - digest.bytes - )}` - ) - } - } -} - -describe('withNotFound', async () => { - it('should locate the content by `dataCid`', async () => { - const response = await withNotFound(innerHandler)( - request, - {}, - { - ...ctx, - locator, - dataCid: foundCid, - path: '', - searchParams: new URLSearchParams() - } - ) - expect(await response.text()).to.equal(`Served ${foundCid}`) - }) - - it('should throw a 404 error if the content is not found', async () => { - const handler = sinon.fake(innerHandler) - const error = await rejection( - withNotFound(handler)( - request, - {}, - { - ...ctx, - locator, - dataCid: notFoundCid, - path: '', - searchParams: new URLSearchParams() - } - ) - ) - expect(handler.notCalled).to.be.true - expectToBeInstanceOf(error, HttpError) - expect(error.status).to.equal(404) - expect(error.message).to.equal('Not Found') - }) - - it('should throw an error if the locator aborts', async () => { - const handler = sinon.fake(innerHandler) - const error = await rejection( - withNotFound(handler)( - request, - {}, - { - ...ctx, - locator, - dataCid: abortedCid, - path: '', - searchParams: new URLSearchParams() - } - ) - ) - expect(handler.notCalled).to.be.true - expectToBeInstanceOf(error, Error) - expect(error.message).to.equal(`failed to locate: ${abortedCid}`) - }) - - it('should throw an error if the locator has a network error', async () => { - const handler = sinon.fake(innerHandler) - const error = await rejection( - withNotFound(handler)( - request, - {}, - { - ...ctx, - locator, - dataCid: networkErrorCid, - path: '', - searchParams: new URLSearchParams() - } - ) - ) - expect(handler.notCalled).to.be.true - expectToBeInstanceOf(error, Error) - expect(error.message).to.equal(`failed to locate: ${networkErrorCid}`) - }) -}) From d52d27f210dfce516144740f522d276f92f20849 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Mon, 28 Oct 2024 17:22:04 -0400 Subject: [PATCH 02/12] Handle multiple indexer hits --- package-lock.json | 259 +----------------- package.json | 2 +- src/middleware/withAuthorizedSpace.js | 97 ++++--- .../middleware/withAuthorizedSpace.spec.js | 144 +++++++++- 4 files changed, 209 insertions(+), 293 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0dc8411..e765221 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "@types/mocha": "^10.0.9", "@types/node-fetch": "^2.6.11", "@types/sinon": "^17.0.3", - "@ucanto/principal": "^8.1.0", + "@ucanto/principal": "^9.0.1", "@web3-storage/content-claims": "^5.0.0", "@web3-storage/public-bucket": "^1.1.0", "@web3-storage/upload-client": "^16.1.1", @@ -3688,24 +3688,6 @@ "@ucanto/interface": "^10.0.0" } }, - "node_modules/@ucanto/client/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@ucanto/client/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/@ucanto/core": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/@ucanto/core/-/core-10.0.1.tgz", @@ -3718,15 +3700,6 @@ "multiformats": "^11.0.2" } }, - "node_modules/@ucanto/core/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, "node_modules/@ucanto/core/node_modules/multiformats": { "version": "11.0.2", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", @@ -3737,10 +3710,10 @@ } }, "node_modules/@ucanto/interface": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-8.1.0.tgz", - "integrity": "sha512-n6WL9miVcN1PUq+e41hKUgZR0+Xn5sHHMQfXnt4YuLnGbh93tIgQkeGWmfUBJI+Y6C0vAFfaSCZnM6Z+kedskA==", - "dev": true, + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", + "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", + "license": "(Apache-2.0 AND MIT)", "dependencies": { "@ipld/dag-ucan": "^3.4.0", "multiformats": "^11.0.2" @@ -3750,23 +3723,23 @@ "version": "11.0.2", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", - "dev": true, + "license": "Apache-2.0 OR MIT", "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" } }, "node_modules/@ucanto/principal": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@ucanto/principal/-/principal-8.1.0.tgz", - "integrity": "sha512-tSkqpxRXP/M+GXNKqQLCmMAP+7zX7l/tKb3uygAaQwTnev4nRauklXgWx6EYDK+2d8tiOyPdL3SlG54GQPFcLQ==", - "dev": true, + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@ucanto/principal/-/principal-9.0.1.tgz", + "integrity": "sha512-8eAvaZHW1vyET4X90rkJv6pmW1IOdEYlZYwO3wDgTkC5m9VytBEywCvpzP57cavdYIbbPse5QS9nMEGvk87zhw==", + "license": "(Apache-2.0 AND MIT)", "dependencies": { "@ipld/dag-ucan": "^3.4.0", "@noble/curves": "^1.2.0", "@noble/ed25519": "^1.7.3", "@noble/hashes": "^1.3.2", - "@ucanto/interface": "^8.1.0", + "@ucanto/interface": "^10.0.0", "multiformats": "^11.0.2", "one-webcrypto": "^1.0.3" } @@ -3775,7 +3748,6 @@ "version": "11.0.2", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", - "dev": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -3792,38 +3764,6 @@ "@ucanto/validator": "^9.0.1" } }, - "node_modules/@ucanto/server/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@ucanto/server/node_modules/@ucanto/principal": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/principal/-/principal-9.0.1.tgz", - "integrity": "sha512-8eAvaZHW1vyET4X90rkJv6pmW1IOdEYlZYwO3wDgTkC5m9VytBEywCvpzP57cavdYIbbPse5QS9nMEGvk87zhw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "@noble/curves": "^1.2.0", - "@noble/ed25519": "^1.7.3", - "@noble/hashes": "^1.3.2", - "@ucanto/interface": "^10.0.0", - "multiformats": "^11.0.2", - "one-webcrypto": "^1.0.3" - } - }, - "node_modules/@ucanto/server/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/@ucanto/transport": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/@ucanto/transport/-/transport-9.1.1.tgz", @@ -3833,24 +3773,6 @@ "@ucanto/interface": "^10.0.0" } }, - "node_modules/@ucanto/transport/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@ucanto/transport/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/@ucanto/validator": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/@ucanto/validator/-/validator-9.0.2.tgz", @@ -3863,15 +3785,6 @@ "multiformats": "^11.0.2" } }, - "node_modules/@ucanto/validator/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, "node_modules/@ucanto/validator/node_modules/multiformats": { "version": "11.0.2", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", @@ -3902,24 +3815,6 @@ "p-queue": "^8.0.1" } }, - "node_modules/@web3-storage/blob-fetcher/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@web3-storage/blob-fetcher/node_modules/@ucanto/interface/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/@web3-storage/blob-index": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@web3-storage/blob-index/-/blob-index-1.0.3.tgz", @@ -3937,24 +3832,6 @@ "node": ">=16.15" } }, - "node_modules/@web3-storage/blob-index/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@web3-storage/blob-index/node_modules/@ucanto/interface/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/@web3-storage/blob-index/node_modules/uint8arrays": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", @@ -3977,47 +3854,6 @@ "uint8arrays": "^5.0.3" } }, - "node_modules/@web3-storage/capabilities/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@web3-storage/capabilities/node_modules/@ucanto/interface/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/@web3-storage/capabilities/node_modules/@ucanto/principal": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/principal/-/principal-9.0.1.tgz", - "integrity": "sha512-8eAvaZHW1vyET4X90rkJv6pmW1IOdEYlZYwO3wDgTkC5m9VytBEywCvpzP57cavdYIbbPse5QS9nMEGvk87zhw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "@noble/curves": "^1.2.0", - "@noble/ed25519": "^1.7.3", - "@noble/hashes": "^1.3.2", - "@ucanto/interface": "^10.0.0", - "multiformats": "^11.0.2", - "one-webcrypto": "^1.0.3" - } - }, - "node_modules/@web3-storage/capabilities/node_modules/@ucanto/principal/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/@web3-storage/capabilities/node_modules/uint8arrays": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", @@ -4039,24 +3875,6 @@ "multiformats": "^13.1.0" } }, - "node_modules/@web3-storage/content-claims/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@web3-storage/content-claims/node_modules/@ucanto/interface/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/@web3-storage/data-segment": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@web3-storage/data-segment/-/data-segment-3.2.0.tgz", @@ -4090,31 +3908,6 @@ "@web3-storage/capabilities": "^16.0.0" } }, - "node_modules/@web3-storage/filecoin-client/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dev": true, - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@web3-storage/filecoin-client/node_modules/@ucanto/principal": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/principal/-/principal-9.0.1.tgz", - "integrity": "sha512-8eAvaZHW1vyET4X90rkJv6pmW1IOdEYlZYwO3wDgTkC5m9VytBEywCvpzP57cavdYIbbPse5QS9nMEGvk87zhw==", - "dev": true, - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "@noble/curves": "^1.2.0", - "@noble/ed25519": "^1.7.3", - "@noble/hashes": "^1.3.2", - "@ucanto/interface": "^10.0.0", - "multiformats": "^11.0.2", - "one-webcrypto": "^1.0.3" - } - }, "node_modules/@web3-storage/filecoin-client/node_modules/@web3-storage/capabilities": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-16.0.0.tgz", @@ -4130,16 +3923,6 @@ "uint8arrays": "^5.0.3" } }, - "node_modules/@web3-storage/filecoin-client/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==", - "dev": true, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/@web3-storage/filecoin-client/node_modules/uint8arrays": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", @@ -4246,26 +4029,6 @@ "varint": "^6.0.0" } }, - "node_modules/@web3-storage/upload-client/node_modules/@ucanto/interface": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@ucanto/interface/-/interface-10.0.1.tgz", - "integrity": "sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==", - "dev": true, - "dependencies": { - "@ipld/dag-ucan": "^3.4.0", - "multiformats": "^11.0.2" - } - }, - "node_modules/@web3-storage/upload-client/node_modules/@ucanto/interface/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==", - "dev": true, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/@web3-storage/upload-client/node_modules/@web3-storage/data-segment": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@web3-storage/data-segment/-/data-segment-5.1.0.tgz", diff --git a/package.json b/package.json index 45a9567..2736f9b 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@types/mocha": "^10.0.9", "@types/node-fetch": "^2.6.11", "@types/sinon": "^17.0.3", - "@ucanto/principal": "^8.1.0", + "@ucanto/principal": "^9.0.1", "@web3-storage/content-claims": "^5.0.0", "@web3-storage/public-bucket": "^1.1.0", "@web3-storage/upload-client": "^16.1.1", diff --git a/src/middleware/withAuthorizedSpace.js b/src/middleware/withAuthorizedSpace.js index 8de3686..c445435 100644 --- a/src/middleware/withAuthorizedSpace.js +++ b/src/middleware/withAuthorizedSpace.js @@ -7,7 +7,8 @@ import { nullable, string, ok, - access + access, + Unauthorized } from '@ucanto/validator' import { HttpError } from '@web3-storage/gateway-lib/util' @@ -81,45 +82,73 @@ export function withAuthorizedSpace (handler) { throw new Error(`failed to locate: ${dataCid}`, { cause: locRes.error }) } - const spaces = locRes.ok.site.map((site) => site.space) - const space = spaces[0] - if (!space) throw 'TK' - if (!isDIDKey(space)) throw 'TK' + const spaces = locRes.ok.site + .map((site) => site.space) + .filter((s) => s !== undefined) - const relevantDelegations = await ctx.delegationsStorage.find({ - audience: ctx.gatewayIdentity.did(), - can: 'space/content/serve', - with: space - }) + try { + // First space to successfully authorize is the one we'll use. + const space = await Promise.any( + spaces.map(async (space) => { + const result = await authorize(space, ctx) + if (result.error) throw result.error + return space + }) + ) + return handler(request, env, { ...ctx, space }) + } catch (error) { + // If all spaces failed to authorize, throw the first error. + if ( + error instanceof AggregateError && + error.errors.every((e) => e instanceof Unauthorized) + ) { + throw new HttpError('Not Found', { status: 404, cause: error }) + } else { + throw error + } + } + } +} - if (relevantDelegations.error) throw 'TK' +/** + * @param {string} space + * @param {AuthTokenContext & DelegationsStorageContext} ctx + * @returns {Promise>} + */ +const authorize = async (space, ctx) => { + if (!space) throw 'TK' + if (!isDIDKey(space)) throw 'TK' + + const relevantDelegations = await ctx.delegationsStorage.find({ + audience: ctx.gatewayIdentity.did(), + can: 'space/content/serve', + with: space + }) - const invocation = await serve - .invoke({ - issuer: ctx.gatewayIdentity, - audience: ctx.gatewayIdentity, - with: space, - nb: { - token: ctx.authToken - }, - proofs: relevantDelegations.ok - }) - .delegate() + if (relevantDelegations.error) throw 'TK' - const accessResult = await access(invocation, { - capability: serve, - authority: ctx.gatewayIdentity, - principal: Verifier, - validateAuthorization: () => ok({}) + const invocation = await serve + .invoke({ + issuer: ctx.gatewayIdentity, + audience: ctx.gatewayIdentity, + with: space, + nb: { + token: ctx.authToken + }, + proofs: relevantDelegations.ok }) + .delegate() - if (accessResult.error) { - throw new HttpError('Not Found', { - status: 404, - cause: accessResult.error - }) - } + const accessResult = await access(invocation, { + capability: serve, + authority: ctx.gatewayIdentity, + principal: Verifier, + validateAuthorization: () => ok({}) + }) - return handler(request, env, { ...ctx, space }) + if (accessResult.error) { + return accessResult } + + return { ok: {} } } diff --git a/test/unit/middleware/withAuthorizedSpace.spec.js b/test/unit/middleware/withAuthorizedSpace.spec.js index c3d4648..ad0ccb7 100644 --- a/test/unit/middleware/withAuthorizedSpace.spec.js +++ b/test/unit/middleware/withAuthorizedSpace.spec.js @@ -7,7 +7,6 @@ import { describe, it } from 'mocha' import { expect } from 'chai' import sinon from 'sinon' import * as ed25519 from '@ucanto/principal/ed25519' -import { Unauthorized } from '@ucanto/validator' import { serve, withAuthorizedSpace @@ -41,7 +40,7 @@ const innerHandler = async (_req, _env, ctx) => const request = new Request('http://example.com/') -const ctx = { +const context = { waitUntil: () => {}, path: '', searchParams: new URLSearchParams() @@ -92,7 +91,7 @@ const createDelegationStorage = (delegations) => ({ }) describe('withAuthorizedSpace', async () => { - it('should serve a found CID from an authorized Space using a token', async () => { + it('should serve a found CID from a Space authorized using a token', async () => { const cid = createTestCID(0) const space = await ed25519.Signer.generate() @@ -100,7 +99,7 @@ describe('withAuthorizedSpace', async () => { request, {}, { - ...ctx, + ...context, dataCid: cid, authToken: 'a1b2c3', locator: createLocator(cid.multihash, { @@ -133,7 +132,48 @@ describe('withAuthorizedSpace', async () => { ) }) - it('should not serve a found CID from an unauthorized Space using a token', async () => { + it('should serve a found CID from a Space authorized using no token', async () => { + const cid = createTestCID(0) + const space = await ed25519.Signer.generate() + + const response = await withAuthorizedSpace(innerHandler)( + request, + {}, + { + ...context, + dataCid: cid, + authToken: null, + locator: createLocator(cid.multihash, { + ok: { + digest: cid.multihash, + site: [ + { + location: [new URL('http://example.com/blob')], + range: { offset: 0, length: 100 }, + space: space.did() + } + ] + }, + error: undefined + }), + delegationsStorage: createDelegationStorage([ + await serve.delegate({ + issuer: space, + audience: gatewayIdentity, + with: space.did(), + nb: { token: null } + }) + ]), + gatewayIdentity + } + ) + + expect(await response.text()).to.equal( + `Served ${cid} from space ${space.did()} with no token` + ) + }) + + it('should not serve a found CID using a token authorizing no Space', async () => { const handler = sinon.fake(innerHandler) const cid = createTestCID(0) const space = await ed25519.Signer.generate() @@ -143,7 +183,7 @@ describe('withAuthorizedSpace', async () => { request, {}, { - ...ctx, + ...context, dataCid: cid, authToken: 'not-valid-token', locator: createLocator(cid.multihash, { @@ -176,7 +216,91 @@ describe('withAuthorizedSpace', async () => { expectToBeInstanceOf(error, HttpError) expect(error.status).to.equal(404) expect(error.message).to.equal('Not Found') - expectToBeInstanceOf(error.cause, Unauthorized) + }) + + it('should serve a found CID when stored in multiple Spaces', async () => { + const cid = createTestCID(0) + const space1 = await ed25519.Signer.generate() + const space2 = await ed25519.Signer.generate() + const space3 = await ed25519.Signer.generate() + + const ctx = { + ...context, + dataCid: cid, + locator: createLocator(cid.multihash, { + ok: { + digest: cid.multihash, + site: [ + { + location: [new URL('http://example.com/1/blob')], + range: { offset: 0, length: 100 }, + space: space1.did() + }, + { + location: [new URL('http://example.com/2/blob')], + range: { offset: 0, length: 100 }, + space: space2.did() + }, + { + location: [new URL('http://example.com/3/blob')], + range: { offset: 0, length: 100 }, + space: space3.did() + } + ] + }, + error: undefined + }), + delegationsStorage: createDelegationStorage([ + await serve.delegate({ + issuer: space1, + audience: gatewayIdentity, + with: space1.did(), + nb: { token: 'space1-token' } + }), + // No authorization for space2 + await serve.delegate({ + issuer: space3, + audience: gatewayIdentity, + with: space3.did(), + nb: { token: 'space3-token' } + }) + ]), + gatewayIdentity + } + + const response1 = await withAuthorizedSpace(innerHandler)( + request, + {}, + { ...ctx, authToken: 'space1-token' } + ) + + expect(await response1.text()).to.equal( + `Served ${cid} from space ${space1.did()} with token space1-token` + ) + + const handler = sinon.fake(innerHandler) + const error = await rejection( + withAuthorizedSpace(handler)( + request, + {}, + { ...ctx, authToken: 'space2-token' } + ) + ) + + expect(handler.notCalled).to.be.true + expectToBeInstanceOf(error, HttpError) + expect(error.status).to.equal(404) + expect(error.message).to.equal('Not Found') + + const response3 = await withAuthorizedSpace(innerHandler)( + request, + {}, + { ...ctx, authToken: 'space3-token' } + ) + + expect(await response3.text()).to.equal( + `Served ${cid} from space ${space3.did()} with token space3-token` + ) }) it('should throw a 404 error if the content is not found', async () => { @@ -189,7 +313,7 @@ describe('withAuthorizedSpace', async () => { request, {}, { - ...ctx, + ...context, dataCid: cid, authToken: 'a1b2c3', locator: createLocator(cid.multihash, { @@ -233,7 +357,7 @@ describe('withAuthorizedSpace', async () => { request, {}, { - ...ctx, + ...context, dataCid: cid, authToken: 'a1b2c3', locator: createLocator(cid.multihash, { @@ -276,7 +400,7 @@ describe('withAuthorizedSpace', async () => { request, {}, { - ...ctx, + ...context, dataCid: cid, authToken: 'a1b2c3', locator: createLocator(cid.multihash, { From 900aefc291950f644bbb57cb40ae1707f18f423b Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Mon, 28 Oct 2024 17:29:37 -0400 Subject: [PATCH 03/12] Serves legacy content --- src/middleware/withAuthorizedSpace.js | 8 +++ src/middleware/withAuthorizedSpace.types.ts | 2 +- .../middleware/withAuthorizedSpace.spec.js | 52 +++++++++++++++++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/middleware/withAuthorizedSpace.js b/src/middleware/withAuthorizedSpace.js index c445435..3c686d1 100644 --- a/src/middleware/withAuthorizedSpace.js +++ b/src/middleware/withAuthorizedSpace.js @@ -82,6 +82,14 @@ export function withAuthorizedSpace (handler) { throw new Error(`failed to locate: ${dataCid}`, { cause: locRes.error }) } + const shouldServeLegacy = + locRes.ok.site.some((site) => site.space === undefined) && + ctx.authToken === null + + if (shouldServeLegacy) { + return handler(request, env, { ...ctx, space: null }) + } + const spaces = locRes.ok.site .map((site) => site.space) .filter((s) => s !== undefined) diff --git a/src/middleware/withAuthorizedSpace.types.ts b/src/middleware/withAuthorizedSpace.types.ts index 20587b0..9050003 100644 --- a/src/middleware/withAuthorizedSpace.types.ts +++ b/src/middleware/withAuthorizedSpace.types.ts @@ -8,7 +8,7 @@ export interface DelegationsStorageContext extends MiddlewareContext { } export interface SpaceContext extends MiddlewareContext { - space: Ucanto.DID + space: Ucanto.DID | null } // TEMP: https://github.com/storacha/blob-fetcher/pull/13/files diff --git a/test/unit/middleware/withAuthorizedSpace.spec.js b/test/unit/middleware/withAuthorizedSpace.spec.js index ad0ccb7..6ce65e7 100644 --- a/test/unit/middleware/withAuthorizedSpace.spec.js +++ b/test/unit/middleware/withAuthorizedSpace.spec.js @@ -278,16 +278,15 @@ describe('withAuthorizedSpace', async () => { `Served ${cid} from space ${space1.did()} with token space1-token` ) - const handler = sinon.fake(innerHandler) const error = await rejection( - withAuthorizedSpace(handler)( + withAuthorizedSpace(sinon.fake(innerHandler))( request, {}, { ...ctx, authToken: 'space2-token' } ) ) - expect(handler.notCalled).to.be.true + expect(sinon.fake(innerHandler).notCalled).to.be.true expectToBeInstanceOf(error, HttpError) expect(error.status).to.equal(404) expect(error.message).to.equal('Not Found') @@ -303,6 +302,53 @@ describe('withAuthorizedSpace', async () => { ) }) + it('should serve a found legacy CID only using no token', async () => { + const cid = createTestCID(0) + + const ctx = { + ...context, + dataCid: cid, + locator: createLocator(cid.multihash, { + ok: { + digest: cid.multihash, + site: [ + { + location: [new URL('http://example.com/1/blob')], + range: { offset: 0, length: 100 } + // No `space` value means it's legacy + } + ] + }, + error: undefined + }), + delegationsStorage: createDelegationStorage([]), + gatewayIdentity + } + + const responseWithoutToken = await withAuthorizedSpace(innerHandler)( + request, + {}, + { ...ctx, authToken: null } + ) + + expect(await responseWithoutToken.text()).to.equal( + `Served ${cid} from no space with no token` + ) + + const errorWithToken = await rejection( + withAuthorizedSpace(sinon.fake(innerHandler))( + request, + {}, + { ...ctx, authToken: 'a1b2c3' } + ) + ) + + expect(sinon.fake(innerHandler).notCalled).to.be.true + expectToBeInstanceOf(errorWithToken, HttpError) + expect(errorWithToken.status).to.equal(404) + expect(errorWithToken.message).to.equal('Not Found') + }) + it('should throw a 404 error if the content is not found', async () => { const handler = sinon.fake(innerHandler) const cid = createTestCID(0) From 271cf8968299b3a2650daa125557ee451904c953 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Tue, 29 Oct 2024 10:17:52 -0400 Subject: [PATCH 04/12] Throw errors encountered by `delegationsStorage` --- src/middleware/withAuthorizedSpace.js | 22 +++------- .../middleware/withAuthorizedSpace.spec.js | 43 ++++++++++++++++++- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/middleware/withAuthorizedSpace.js b/src/middleware/withAuthorizedSpace.js index 3c686d1..c56c9d6 100644 --- a/src/middleware/withAuthorizedSpace.js +++ b/src/middleware/withAuthorizedSpace.js @@ -1,4 +1,3 @@ -/* eslint-disable no-throw-literal --- TK */ import { Verifier } from '@ucanto/principal' import { capability, @@ -43,19 +42,13 @@ export const serve = capability({ * The Space which contains the content. This Space will be charged egress * fees if content is actually retrieved by way of this invocation. */ - with: DID.match({ method: 'key' }), + with: DID, nb: Schema.struct({ /** The authorization token, if any, used for this request. */ token: nullable(string()) }) }) -/** - * @param {string} space - * @returns {space is Ucanto.DIDKey} - */ -const isDIDKey = (space) => space.startsWith('did:key:') - /** * Attempts to locate the {@link IpfsUrlContext.dataCid}. If it's able to, * attempts to authorize the request to access the data. @@ -119,21 +112,18 @@ export function withAuthorizedSpace (handler) { } /** - * @param {string} space + * @param {Ucanto.DID} space * @param {AuthTokenContext & DelegationsStorageContext} ctx - * @returns {Promise>} + * @returns {Promise>} */ const authorize = async (space, ctx) => { - if (!space) throw 'TK' - if (!isDIDKey(space)) throw 'TK' - - const relevantDelegations = await ctx.delegationsStorage.find({ + const relevantDelegationsResult = await ctx.delegationsStorage.find({ audience: ctx.gatewayIdentity.did(), can: 'space/content/serve', with: space }) - if (relevantDelegations.error) throw 'TK' + if (relevantDelegationsResult.error) return relevantDelegationsResult const invocation = await serve .invoke({ @@ -143,7 +133,7 @@ const authorize = async (space, ctx) => { nb: { token: ctx.authToken }, - proofs: relevantDelegations.ok + proofs: relevantDelegationsResult.ok }) .delegate() diff --git a/test/unit/middleware/withAuthorizedSpace.spec.js b/test/unit/middleware/withAuthorizedSpace.spec.js index 6ce65e7..8039152 100644 --- a/test/unit/middleware/withAuthorizedSpace.spec.js +++ b/test/unit/middleware/withAuthorizedSpace.spec.js @@ -26,7 +26,7 @@ import { createTestCID } from './util/createTestCID.js' * Environment as MiddlewareEnvironment, * IpfsUrlContext * } from '@web3-storage/gateway-lib' - * @import { DelegationsStorage, SpaceContext } from '../../../src/middleware/withAuthorizedSpace.types.js' + * @import { DelegationsStorage, DelegationsStorageContext, SpaceContext } from '../../../src/middleware/withAuthorizedSpace.types.js' * @import { AuthTokenContext } from '../../../src/middleware/withAuthToken.types.js' */ @@ -478,4 +478,45 @@ describe('withAuthorizedSpace', async () => { url: 'http://example.com/blob' }) }) + + it('should throw errors encountered by `delegationsStorage`', async () => { + const cid = createTestCID(0) + const space = await ed25519.Signer.generate() + + const ctx = { + ...context, + dataCid: cid, + locator: createLocator(cid.multihash, { + ok: { + digest: cid.multihash, + site: [ + { + location: [new URL('http://example.com/1/blob')], + range: { offset: 0, length: 100 }, + space: space.did() + } + ] + }, + error: undefined + }), + delegationsStorage: { + find: async () => ({ + error: { name: 'Weirdness', message: 'Something weird happened.' } + }) + }, + gatewayIdentity + } + + const error = await rejection( + withAuthorizedSpace(sinon.fake(innerHandler))( + request, + {}, + { ...ctx, authToken: 'a1b2c3' } + ) + ) + + expect(sinon.fake(innerHandler).notCalled).to.be.true + expectToBeInstanceOf(error, AggregateError) + expect(error.errors.map((e) => e.name)).to.deep.equal(['Weirdness']) + }) }) From ddf51d8ab10f8ac300918ae9b260517a4ddfe47f Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Tue, 29 Oct 2024 10:25:33 -0400 Subject: [PATCH 05/12] Add comments and documentation --- src/middleware/withAuthorizedSpace.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/middleware/withAuthorizedSpace.js b/src/middleware/withAuthorizedSpace.js index c56c9d6..b9f57d6 100644 --- a/src/middleware/withAuthorizedSpace.js +++ b/src/middleware/withAuthorizedSpace.js @@ -75,6 +75,10 @@ export function withAuthorizedSpace (handler) { throw new Error(`failed to locate: ${dataCid}`, { cause: locRes.error }) } + // Legacy behavior: Site results which have no Space attached are from + // before we started authorizing serving content explicitly. For these, we + // always serve the content, but only if the request has no authorization + // token. const shouldServeLegacy = locRes.ok.site.some((site) => site.space === undefined) && ctx.authToken === null @@ -83,6 +87,7 @@ export function withAuthorizedSpace (handler) { return handler(request, env, { ...ctx, space: null }) } + // These Spaces all have the content we're to serve, if we're allowed to. const spaces = locRes.ok.site .map((site) => site.space) .filter((s) => s !== undefined) @@ -98,7 +103,7 @@ export function withAuthorizedSpace (handler) { ) return handler(request, env, { ...ctx, space }) } catch (error) { - // If all spaces failed to authorize, throw the first error. + // If all Spaces failed to authorize, throw the first error. if ( error instanceof AggregateError && error.errors.every((e) => e instanceof Unauthorized) @@ -112,11 +117,16 @@ export function withAuthorizedSpace (handler) { } /** + * Authorizes the request to serve content from the given Space. Looks for + * authorizing delegations in the + * {@link DelegationsStorageContext.delegationsStorage}. + * * @param {Ucanto.DID} space * @param {AuthTokenContext & DelegationsStorageContext} ctx * @returns {Promise>} */ const authorize = async (space, ctx) => { + // Look up delegations that might authorize us to serve the content. const relevantDelegationsResult = await ctx.delegationsStorage.find({ audience: ctx.gatewayIdentity.did(), can: 'space/content/serve', @@ -125,6 +135,7 @@ const authorize = async (space, ctx) => { if (relevantDelegationsResult.error) return relevantDelegationsResult + // Create an invocation of the serve capability. const invocation = await serve .invoke({ issuer: ctx.gatewayIdentity, @@ -137,6 +148,7 @@ const authorize = async (space, ctx) => { }) .delegate() + // Validate the invocation. const accessResult = await access(invocation, { capability: serve, authority: ctx.gatewayIdentity, From 08b06a27e99bb6c9fc2cb5e4d7abaf9cb7c99e36 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Wed, 30 Oct 2024 12:41:58 -0400 Subject: [PATCH 06/12] =?UTF-8?q?Use=20mock=20properly=20=F0=9F=A4=A6?= =?UTF-8?q?=E2=80=8D=E2=99=80=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../middleware/withAuthorizedSpace.spec.js | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/test/unit/middleware/withAuthorizedSpace.spec.js b/test/unit/middleware/withAuthorizedSpace.spec.js index 8039152..dc9a3fb 100644 --- a/test/unit/middleware/withAuthorizedSpace.spec.js +++ b/test/unit/middleware/withAuthorizedSpace.spec.js @@ -278,15 +278,16 @@ describe('withAuthorizedSpace', async () => { `Served ${cid} from space ${space1.did()} with token space1-token` ) + const ih = sinon.fake(innerHandler) const error = await rejection( - withAuthorizedSpace(sinon.fake(innerHandler))( + withAuthorizedSpace(ih)( request, {}, { ...ctx, authToken: 'space2-token' } ) ) - expect(sinon.fake(innerHandler).notCalled).to.be.true + expect(ih.notCalled).to.be.true expectToBeInstanceOf(error, HttpError) expect(error.status).to.equal(404) expect(error.message).to.equal('Not Found') @@ -335,15 +336,12 @@ describe('withAuthorizedSpace', async () => { `Served ${cid} from no space with no token` ) + const ih = sinon.fake(innerHandler) const errorWithToken = await rejection( - withAuthorizedSpace(sinon.fake(innerHandler))( - request, - {}, - { ...ctx, authToken: 'a1b2c3' } - ) + withAuthorizedSpace(ih)(request, {}, { ...ctx, authToken: 'a1b2c3' }) ) - expect(sinon.fake(innerHandler).notCalled).to.be.true + expect(ih.notCalled).to.be.true expectToBeInstanceOf(errorWithToken, HttpError) expect(errorWithToken.status).to.equal(404) expect(errorWithToken.message).to.equal('Not Found') @@ -507,15 +505,12 @@ describe('withAuthorizedSpace', async () => { gatewayIdentity } + const ih = sinon.fake(innerHandler) const error = await rejection( - withAuthorizedSpace(sinon.fake(innerHandler))( - request, - {}, - { ...ctx, authToken: 'a1b2c3' } - ) + withAuthorizedSpace(ih)(request, {}, { ...ctx, authToken: 'a1b2c3' }) ) - expect(sinon.fake(innerHandler).notCalled).to.be.true + expect(ih.notCalled).to.be.true expectToBeInstanceOf(error, AggregateError) expect(error.errors.map((e) => e.name)).to.deep.equal(['Weirdness']) }) From fd16fae315b9c015ba2b3a9200c9ca02eaf9e6a0 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Wed, 30 Oct 2024 16:37:38 -0400 Subject: [PATCH 07/12] `withAuthorizedSpace` scopes the `locator` --- src/middleware/withAuthorizedSpace.js | 30 ++++++- .../middleware/withAuthorizedSpace.spec.js | 88 ++++++++++++------- 2 files changed, 87 insertions(+), 31 deletions(-) diff --git a/src/middleware/withAuthorizedSpace.js b/src/middleware/withAuthorizedSpace.js index b9f57d6..957c927 100644 --- a/src/middleware/withAuthorizedSpace.js +++ b/src/middleware/withAuthorizedSpace.js @@ -13,6 +13,7 @@ import { HttpError } from '@web3-storage/gateway-lib/util' /** * @import * as Ucanto from '@ucanto/interface' + * @import { Locator } from '@web3-storage/blob-fetcher' * @import { IpfsUrlContext, Middleware } from '@web3-storage/gateway-lib' * @import { LocatorContext } from './withLocator.types.js' * @import { AuthTokenContext } from './withAuthToken.types.js' @@ -101,7 +102,11 @@ export function withAuthorizedSpace (handler) { return space }) ) - return handler(request, env, { ...ctx, space }) + return handler(request, env, { + ...ctx, + space, + locator: spaceScopedLocator(locator, space) + }) } catch (error) { // If all Spaces failed to authorize, throw the first error. if ( @@ -162,3 +167,26 @@ const authorize = async (space, ctx) => { return { ok: {} } } + +/** + * Wraps a {@link Locator} and locates content only from a specific Space. + * + * @param {Locator} locator + * @param {Ucanto.DID} space + * @returns {Locator} + */ +const spaceScopedLocator = (locator, space) => ({ + locate: async (digest) => { + const locateResult = await locator.locate(digest) + if (locateResult.error) { + return locateResult + } else { + return { + ok: { + ...locateResult.ok, + site: locateResult.ok.site.filter((site) => site.space === space) + } + } + } + } +}) diff --git a/test/unit/middleware/withAuthorizedSpace.spec.js b/test/unit/middleware/withAuthorizedSpace.spec.js index dc9a3fb..80043aa 100644 --- a/test/unit/middleware/withAuthorizedSpace.spec.js +++ b/test/unit/middleware/withAuthorizedSpace.spec.js @@ -26,17 +26,31 @@ import { createTestCID } from './util/createTestCID.js' * Environment as MiddlewareEnvironment, * IpfsUrlContext * } from '@web3-storage/gateway-lib' - * @import { DelegationsStorage, DelegationsStorageContext, SpaceContext } from '../../../src/middleware/withAuthorizedSpace.types.js' + * @import { DelegationsStorage, SpaceContext } from '../../../src/middleware/withAuthorizedSpace.types.js' + * @import { LocatorContext } from '../../../src/middleware/withLocator.types.js' * @import { AuthTokenContext } from '../../../src/middleware/withAuthToken.types.js' */ -/** @type {Handler} */ -const innerHandler = async (_req, _env, ctx) => - new Response( - `Served ${ctx.dataCid.toString()} from ${ - ctx.space ? `space ${ctx.space}` : 'no space' - } with ${ctx.authToken ? `token ${ctx.authToken}` : 'no token'}` +/** @type {Handler} */ +const innerHandler = async (_req, _env, ctx) => { + const locateResult = await ctx.locator.locate(ctx.dataCid.multihash) + if (locateResult.error) { + throw new Error(`Failed to locate: ${ctx.dataCid}`, { + cause: locateResult.error + }) + } + + const blobLocations = locateResult.ok.site.flatMap((site) => site.location) + + return new Response( + JSON.stringify({ + CID: ctx.dataCid.toString(), + Space: ctx.space, + Token: ctx.authToken, + URLs: blobLocations + }) ) +} const request = new Request('http://example.com/') @@ -127,9 +141,12 @@ describe('withAuthorizedSpace', async () => { } ) - expect(await response.text()).to.equal( - `Served ${cid} from space ${space.did()} with token a1b2c3` - ) + expect(await response.json()).to.deep.equal({ + CID: cid.toString(), + Space: space.did(), + Token: 'a1b2c3', + URLs: ['http://example.com/blob'] + }) }) it('should serve a found CID from a Space authorized using no token', async () => { @@ -168,9 +185,12 @@ describe('withAuthorizedSpace', async () => { } ) - expect(await response.text()).to.equal( - `Served ${cid} from space ${space.did()} with no token` - ) + expect(await response.json()).to.deep.equal({ + CID: cid.toString(), + Space: space.did(), + Token: null, + URLs: ['http://example.com/blob'] + }) }) it('should not serve a found CID using a token authorizing no Space', async () => { @@ -274,23 +294,25 @@ describe('withAuthorizedSpace', async () => { { ...ctx, authToken: 'space1-token' } ) - expect(await response1.text()).to.equal( - `Served ${cid} from space ${space1.did()} with token space1-token` - ) + expect(await response1.json()).to.deep.equal({ + CID: cid.toString(), + Space: space1.did(), + Token: 'space1-token', + URLs: ['http://example.com/1/blob'] + }) - const ih = sinon.fake(innerHandler) - const error = await rejection( - withAuthorizedSpace(ih)( + const error2 = await rejection( + withAuthorizedSpace(sinon.fake(innerHandler))( request, {}, { ...ctx, authToken: 'space2-token' } ) ) - expect(ih.notCalled).to.be.true - expectToBeInstanceOf(error, HttpError) - expect(error.status).to.equal(404) - expect(error.message).to.equal('Not Found') + expect(sinon.fake(innerHandler).notCalled).to.be.true + expectToBeInstanceOf(error2, HttpError) + expect(error2.status).to.equal(404) + expect(error2.message).to.equal('Not Found') const response3 = await withAuthorizedSpace(innerHandler)( request, @@ -298,9 +320,12 @@ describe('withAuthorizedSpace', async () => { { ...ctx, authToken: 'space3-token' } ) - expect(await response3.text()).to.equal( - `Served ${cid} from space ${space3.did()} with token space3-token` - ) + expect(await response3.json()).to.deep.equal({ + CID: cid.toString(), + Space: space3.did(), + Token: 'space3-token', + URLs: ['http://example.com/3/blob'] + }) }) it('should serve a found legacy CID only using no token', async () => { @@ -314,7 +339,7 @@ describe('withAuthorizedSpace', async () => { digest: cid.multihash, site: [ { - location: [new URL('http://example.com/1/blob')], + location: [new URL('http://example.com/blob')], range: { offset: 0, length: 100 } // No `space` value means it's legacy } @@ -332,9 +357,12 @@ describe('withAuthorizedSpace', async () => { { ...ctx, authToken: null } ) - expect(await responseWithoutToken.text()).to.equal( - `Served ${cid} from no space with no token` - ) + expect(await responseWithoutToken.json()).to.deep.equal({ + CID: cid.toString(), + Space: null, + Token: null, + URLs: ['http://example.com/blob'] + }) const ih = sinon.fake(innerHandler) const errorWithToken = await rejection( From 721c2e198a2d42b4d5163dfb7b3b06ff481be7e1 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Mon, 4 Nov 2024 12:08:38 -0500 Subject: [PATCH 08/12] Add query param stubs for delegations --- scripts/delegate-serve.js | 41 ++++++++++++++ src/index.js | 4 +- src/middleware/index.js | 1 + src/middleware/withDelegationStubs.js | 80 +++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 scripts/delegate-serve.js create mode 100644 src/middleware/withDelegationStubs.js diff --git a/scripts/delegate-serve.js b/scripts/delegate-serve.js new file mode 100644 index 0000000..7da68fe --- /dev/null +++ b/scripts/delegate-serve.js @@ -0,0 +1,41 @@ +import sade from 'sade' +import { getClient } from '@web3-storage/w3cli/lib.js' +import { serve } from '../src/middleware/withAuthorizedSpace.js' +import * as ed25519 from '@ucanto/principal/ed25519' + +/** @import { Client } from '@web3-storage/w3up-client' */ + +const cli = sade('delegate-serve.js [token]') + +cli + .describe( + `Delegates ${serve.can} to the Gateway for , with an optional token. Outputs a base64url string suitable for the stub_delegation query parameter. Pipe the output to pbcopy or similar for the quickest workflow.` + ) + .action(async (space, token) => { + /** @type {Client} */ + const client = await getClient() + + const gatewayIdentity = (await ed25519.Signer.generate()).withDID( + 'did:web:w3s.link' + ) + + const delegation = await serve.delegate({ + issuer: client.agent.issuer, + audience: gatewayIdentity, + with: space, + nb: { token: token ?? null }, + expiration: Infinity, + proofs: client.proofs([ + { + can: serve.can, + with: space + } + ]) + }) + + const carResult = await delegation.archive() + if (carResult.error) throw carResult.error + process.stdout.write(Buffer.from(carResult.ok).toString('base64url')) + }) + +cli.parse(process.argv) diff --git a/src/index.js b/src/index.js index 85fa13f..7418ef0 100644 --- a/src/index.js +++ b/src/index.js @@ -23,7 +23,8 @@ import { withRateLimit, withEgressTracker withAuthorizedSpace, - withLocator + withLocator, + withDelegationStubs } from './middleware/index.js' import { instrument } from '@microlabs/otel-cf-workers' import { NoopSpanProcessor } from '@opentelemetry/sdk-trace-base' @@ -56,6 +57,7 @@ const handler = { createWithHttpMethod('GET', 'HEAD'), withAuthToken, withLocator, + withDelegationStubs, // Rate-limit requests withRateLimit, diff --git a/src/middleware/index.js b/src/middleware/index.js index cd79d16..78fd617 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -6,3 +6,4 @@ export { withVersionHeader } from './withVersionHeader.js' export { withAuthorizedSpace } from './withAuthorizedSpace.js' export { withLocator } from './withLocator.js' export { withEgressTracker } from './withEgressTracker.js' +export { withDelegationStubs } from './withDelegationStubs.js' diff --git a/src/middleware/withDelegationStubs.js b/src/middleware/withDelegationStubs.js new file mode 100644 index 0000000..6a42295 --- /dev/null +++ b/src/middleware/withDelegationStubs.js @@ -0,0 +1,80 @@ +import * as ed25519 from '@ucanto/principal/ed25519' +import { Delegation } from '@ucanto/core' + +const GATEWAY_DID = 'did:web:w3s.link' + +/** + * @import * as Ucanto from '@ucanto/interface' + * @import { + * Middleware, + * Context as MiddlewareContext + * } from '@web3-storage/gateway-lib' + * @import { DelegationsStorageContext } from './withAuthorizedSpace.types.js' + * @import { LocatorContext } from './withLocator.types.js' + */ + +/** + * Stubs some of the context to make UCAN-authorized requests testable while the + * feature is being built. + * + * NOTE!: This must not persist once the feature is released, without additional + * safeguards. This currently allows anyone to bypass data privacy, which is + * fine while that privacy is not yet a released and used feature, but becomes a + * hole once actual users expect privacy to work. + * + * @type {( + * Middleware< + * MiddlewareContext & LocatorContext & DelegationsStorageContext, + * MiddlewareContext & LocatorContext, + * {} + * > + * )} + */ +export const withDelegationStubs = (handler) => async (request, env, ctx) => { + const stubSpace = new URL(request.url).searchParams.get('stub_space') + const stubDelegations = await Promise.all( + new URL(request.url).searchParams + .getAll('stub_delegation') + .map(async (delegationBase64) => { + const res = await Delegation.extract( + Buffer.from(delegationBase64, 'base64url') + ) + if (res.error) throw res.error + return res.ok + }) + ) + + return handler(request, env, { + ...ctx, + delegationsStorage: { find: async () => ({ ok: stubDelegations }) }, + // NOTE: It doesn't actually matter right now what key the `gatewayIdentity` + // uses, because we don't need anyone else to execute its invocations. + gatewayIdentity: (await ed25519.Signer.generate()).withDID(GATEWAY_DID), + locator: + stubSpace && isDIDKey(stubSpace) + ? { + locate: async (digest, options) => { + const locateResult = await ctx.locator.locate(digest, options) + if (locateResult.error) return locateResult + return { + ok: { + ...locateResult.ok, + site: locateResult.ok.site.map((site) => ({ + ...site, + space: stubSpace + })) + } + } + } + } + : ctx.locator + }) +} + +/** + * True if the given string is a `key:` DID. + * + * @param {string} did + * @returns {did is Ucanto.DIDKey} + */ +const isDIDKey = (did) => did.startsWith('did:key:') From 8e5ccb0b8f1fe6bff8e73ceb2155f9afc68cdb53 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Mon, 4 Nov 2024 12:09:07 -0500 Subject: [PATCH 09/12] Move import to top --- test/unit/middleware/withAuthorizedSpace.spec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/middleware/withAuthorizedSpace.spec.js b/test/unit/middleware/withAuthorizedSpace.spec.js index 80043aa..f194d5a 100644 --- a/test/unit/middleware/withAuthorizedSpace.spec.js +++ b/test/unit/middleware/withAuthorizedSpace.spec.js @@ -20,6 +20,7 @@ import { createTestCID } from './util/createTestCID.js' /** * @import { MultihashDigest } from 'multiformats' + * @import * as Ucanto from '@ucanto/interface' * @import { Locator } from '@web3-storage/blob-fetcher' * @import { * Handler, @@ -79,8 +80,6 @@ const createLocator = (expectedDigest, locateResponse) => ({ } }) -/** @import * as Ucanto from '@ucanto/interface' */ - const gatewayIdentity = (await ed25519.Signer.generate()).withDID( 'did:web:test.w3s.link' ) From 03d89fe4b593afbb8e4120ba4df8db2f5bec1915 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Tue, 5 Nov 2024 15:44:02 -0500 Subject: [PATCH 10/12] Fix syntax (rebase error) --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 7418ef0..5754fbd 100644 --- a/src/index.js +++ b/src/index.js @@ -21,7 +21,7 @@ import { withAuthToken, withCarBlockHandler, withRateLimit, - withEgressTracker + withEgressTracker, withAuthorizedSpace, withLocator, withDelegationStubs From 4e285b458fe67237d50defcd80ecdcfefaa08e01 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Tue, 5 Nov 2024 17:28:56 -0500 Subject: [PATCH 11/12] Use `atob()` instead of `Buffer` `Buffer` is not available in the worker --- src/middleware/withDelegationStubs.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/middleware/withDelegationStubs.js b/src/middleware/withDelegationStubs.js index 6a42295..4683dd5 100644 --- a/src/middleware/withDelegationStubs.js +++ b/src/middleware/withDelegationStubs.js @@ -35,9 +35,14 @@ export const withDelegationStubs = (handler) => async (request, env, ctx) => { const stubDelegations = await Promise.all( new URL(request.url).searchParams .getAll('stub_delegation') - .map(async (delegationBase64) => { + .map(async (delegationBase64url) => { + // atob() only supports base64, not base64url. Buffer supports + // base64url, but isn't available in the worker. + const delegationBase64 = delegationBase64url + .replaceAll('-', '+') + .replaceAll('_', '/') const res = await Delegation.extract( - Buffer.from(delegationBase64, 'base64url') + Uint8Array.from(atob(delegationBase64), (c) => c.charCodeAt(0)) ) if (res.error) throw res.error return res.ok From 4af930901c0ac0ff78bcafdbde54816d00482456 Mon Sep 17 00:00:00 2001 From: Petra Jaros Date: Tue, 5 Nov 2024 17:55:01 -0500 Subject: [PATCH 12/12] Use wildcard capability --- package-lock.json | 2834 ++++++++++++++++- package.json | 1 + scripts/delegate-serve.d.ts | 4 + scripts/delegate-serve.js | 11 +- src/capabilities/serve.js | 51 + src/middleware/withAuthorizedSpace.js | 48 +- .../middleware/withAuthorizedSpace.spec.js | 22 +- tsconfig.json | 4 +- 8 files changed, 2865 insertions(+), 110 deletions(-) create mode 100644 scripts/delegate-serve.d.ts create mode 100644 src/capabilities/serve.js diff --git a/package-lock.json b/package-lock.json index e765221..7c1bee6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "@web3-storage/content-claims": "^5.0.0", "@web3-storage/public-bucket": "^1.1.0", "@web3-storage/upload-client": "^16.1.1", + "@web3-storage/w3cli": "^7.8.2", "carstream": "^2.1.0", "chai": "^5.1.1", "esbuild": "^0.18.20", @@ -899,6 +900,997 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, + "node_modules/@inquirer/checkbox": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-1.5.2.tgz", + "integrity": "sha512-CifrkgQjDkUkWexmgYYNyB5603HhTHI91vLFeQXh6qrTKiCMVASol01Rs1cv6LP/A2WccZSRlJKZhbaBIs/9ZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^6.0.0", + "@inquirer/type": "^1.1.6", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "figures": "^3.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/checkbox/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/checkbox/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/checkbox/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/checkbox/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/checkbox/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/confirm": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-2.0.17.tgz", + "integrity": "sha512-EqzhGryzmGpy2aJf6LxJVhndxYmFs+m8cxXzf8nejb1DE3sabf6mUgBcp4J0jAUEiAcYzqmkqRr7LPFh/WdnXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^6.0.0", + "@inquirer/type": "^1.1.6", + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/confirm/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/confirm/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/confirm/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/confirm/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/confirm/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/core": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-5.1.2.tgz", + "integrity": "sha512-w3PMZH5rahrukn8/I7P9Ihil+twgLTUHDZtJlJyBbUKyPaOSSQjLZkb0PpncVhin1gCaMgOFXy6iNPgcZUoo2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/core/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-1.2.15.tgz", + "integrity": "sha512-gQ77Ls09x5vKLVNMH9q/7xvYPT6sIs5f7URksw+a2iJZ0j48tVS6crLqm2ugG33tgXHIwiEqkytY60Zyh5GkJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^6.0.0", + "@inquirer/type": "^1.1.6", + "chalk": "^4.1.2", + "external-editor": "^3.1.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/editor/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/editor/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/editor/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/editor/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/editor/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/expand": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-1.1.16.tgz", + "integrity": "sha512-TGLU9egcuo+s7PxphKUCnJnpCIVY32/EwPCLLuu+gTvYiD8hZgx8Z2niNQD36sa6xcfpdLY6xXDBiL/+g1r2XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^6.0.0", + "@inquirer/type": "^1.1.6", + "chalk": "^4.1.2", + "figures": "^3.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/expand/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/expand/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/expand/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/expand/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/expand/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/input": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-1.2.16.tgz", + "integrity": "sha512-Ou0LaSWvj1ni+egnyQ+NBtfM1885UwhRCMtsRt2bBO47DoC1dwtCa+ZUNgrxlnCHHF0IXsbQHYtIIjFGAavI4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^6.0.0", + "@inquirer/type": "^1.1.6", + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/input/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/input/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/input/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/input/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/input/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/password": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-1.1.16.tgz", + "integrity": "sha512-aZYZVHLUXZ2gbBot+i+zOJrks1WaiI95lvZCn1sKfcw6MtSSlYC8uDX8sTzQvAsQ8epHoP84UNvAIT0KVGOGqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^6.0.0", + "@inquirer/type": "^1.1.6", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/password/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/password/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/password/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/password/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/password/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/prompts": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-3.3.2.tgz", + "integrity": "sha512-k52mOMRvTUejrqyF1h8Z07chC+sbaoaUYzzr1KrJXyj7yaX7Nrh0a9vktv8TuocRwIJOQMaj5oZEmkspEcJFYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^1.5.2", + "@inquirer/confirm": "^2.0.17", + "@inquirer/core": "^6.0.0", + "@inquirer/editor": "^1.2.15", + "@inquirer/expand": "^1.1.16", + "@inquirer/input": "^1.2.16", + "@inquirer/password": "^1.1.16", + "@inquirer/rawlist": "^1.2.16", + "@inquirer/select": "^1.3.3" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/prompts/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/prompts/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/prompts/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/prompts/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/prompts/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/rawlist": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-1.2.16.tgz", + "integrity": "sha512-pZ6TRg2qMwZAOZAV6TvghCtkr53dGnK29GMNQ3vMZXSNguvGqtOVc4j/h1T8kqGJFagjyfBZhUPGwNS55O5qPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^6.0.0", + "@inquirer/type": "^1.1.6", + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/rawlist/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/rawlist/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/rawlist/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/rawlist/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/rawlist/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/select": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-1.3.3.tgz", + "integrity": "sha512-RzlRISXWqIKEf83FDC9ZtJ3JvuK1l7aGpretf41BCWYrvla2wU8W8MTRNMiPrPJ+1SIqrRC1nZdZ60hD9hRXLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^6.0.0", + "@inquirer/type": "^1.1.6", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "figures": "^3.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/select/node_modules/@inquirer/core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-6.0.0.tgz", + "integrity": "sha512-fKi63Khkisgda3ohnskNf5uZJj+zXOaBvOllHsOkdsXRA/ubQLJQrZchFFi57NKbZzkTunXiBMdvWOv71alonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^1.1.6", + "@types/mute-stream": "^0.0.4", + "@types/node": "^20.10.7", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/select/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/select/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/select/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@inquirer/select/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/type": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.5.tgz", + "integrity": "sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@ipld/car": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@ipld/car/-/car-5.3.1.tgz", @@ -915,9 +1907,10 @@ } }, "node_modules/@ipld/dag-cbor": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-9.2.0.tgz", - "integrity": "sha512-N14oMy0q4gM6OuZkIpisKe0JBSjf1Jb39VI+7jMLiWX9124u1Z3Fdj/Tag1NA0cVxxqWDh0CqsjcVfOKtelPDA==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-9.2.2.tgz", + "integrity": "sha512-uIEOuruCqKTP50OBWwgz4Js2+LhiBQaxc57cnP71f45b1mHEAo1OCR1Zn/TbvSW/mV1x+JqhacIktkKyaYqhCw==", + "license": "Apache-2.0 OR MIT", "dependencies": { "cborg": "^4.0.0", "multiformats": "^13.1.0" @@ -3369,6 +4362,51 @@ "murmurhash3js-revisited": "^3.0.0" } }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -3423,6 +4461,43 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.4.0.tgz", + "integrity": "sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.5.0", + "@scure/base": "~1.1.8" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -3593,6 +4668,13 @@ "@stablelib/wipe": "^1.0.1" } }, + "node_modules/@storacha/one-webcrypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@storacha/one-webcrypto/-/one-webcrypto-1.0.1.tgz", + "integrity": "sha512-bD+vWmcgsEBqU0Dz04BR43SA03bBoLTAY29vaKasY9Oe8cb6XIP0/vkm0OS2UwKC13c8uRgFW4rjJUgDCNLejQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/chai": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.0.tgz", @@ -3631,6 +4713,16 @@ "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==", "dev": true }, + "node_modules/@types/mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "20.14.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.0.tgz", @@ -3679,6 +4771,13 @@ "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", "dev": true }, + "node_modules/@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "dev": true, + "license": "MIT" + }, "node_modules/@ucanto/client": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@ucanto/client/-/client-9.0.1.tgz", @@ -3800,6 +4899,57 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@web3-storage/access": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@web3-storage/access/-/access-20.1.0.tgz", + "integrity": "sha512-IY6ICPRWE8++2jxvy+LzAiFvwAOIHR8cu9eNt+VT5sAFE796o4ma7GSU0eXRCiShmV2n6iSWAwWRT6XD5zIqPA==", + "dev": true, + "license": "(Apache-2.0 OR MIT)", + "dependencies": { + "@ipld/car": "^5.1.1", + "@ipld/dag-ucan": "^3.4.0", + "@scure/bip39": "^1.2.1", + "@storacha/one-webcrypto": "^1.0.1", + "@ucanto/client": "^9.0.1", + "@ucanto/core": "^10.0.1", + "@ucanto/interface": "^10.0.1", + "@ucanto/principal": "^9.0.1", + "@ucanto/transport": "^9.1.1", + "@ucanto/validator": "^9.0.2", + "@web3-storage/capabilities": "^17.3.0", + "@web3-storage/did-mailto": "^2.1.0", + "bigint-mod-arith": "^3.1.2", + "conf": "11.0.2", + "multiformats": "^12.1.2", + "p-defer": "^4.0.0", + "type-fest": "^4.9.0", + "uint8arrays": "^4.0.6" + } + }, + "node_modules/@web3-storage/access/node_modules/multiformats": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.3.tgz", + "integrity": "sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@web3-storage/access/node_modules/type-fest": { + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@web3-storage/blob-fetcher": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/@web3-storage/blob-fetcher/-/blob-fetcher-2.3.1.tgz", @@ -3841,19 +4991,31 @@ } }, "node_modules/@web3-storage/capabilities": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-17.2.0.tgz", - "integrity": "sha512-hnJGIQcCAMBbR8sfgkEwnjBVcpNpNRBnzSEB2E/wKkKIjHKimw3ClsVznu6jjFExCXFaKHd6r1eAU4NcTYsueg==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/@web3-storage/capabilities/-/capabilities-17.4.0.tgz", + "integrity": "sha512-2VNLTTvv9qVewtXiek2Fb6W7WTQgOonq+FcNV9PyXAEgcXsQWsm8dOmbeB83W9bAuiwe9uIOzC1rftDHY3+uYA==", + "license": "(Apache-2.0 OR MIT)", "dependencies": { "@ucanto/core": "^10.0.1", "@ucanto/interface": "^10.0.1", "@ucanto/principal": "^9.0.1", "@ucanto/transport": "^9.1.1", "@ucanto/validator": "^9.0.2", - "@web3-storage/data-segment": "^3.2.0", + "@web3-storage/data-segment": "^5.2.0", "uint8arrays": "^5.0.3" } }, + "node_modules/@web3-storage/capabilities/node_modules/@web3-storage/data-segment": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@web3-storage/data-segment/-/data-segment-5.3.0.tgz", + "integrity": "sha512-zFJ4m+pEKqtKatJNsFrk/2lHeFSbkXZ6KKXjBe7/2ayA9wAar7T/unewnOcZrrZTnCWmaxKsXWqdMFy9bXK9dw==", + "license": "(Apache-2.0 AND MIT)", + "dependencies": { + "@ipld/dag-cbor": "^9.2.1", + "multiformats": "^13.3.0", + "sync-multihash-sha2": "^1.0.0" + } + }, "node_modules/@web3-storage/capabilities/node_modules/uint8arrays": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", @@ -3879,6 +5041,7 @@ "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", @@ -3889,11 +5052,22 @@ "version": "11.0.2", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", + "dev": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" } }, + "node_modules/@web3-storage/did-mailto": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@web3-storage/did-mailto/-/did-mailto-2.1.0.tgz", + "integrity": "sha512-TRmfSXj1IhtX3ESurSNOylZSBKi0z/VJNoMLpof+AVRdovgZjjocpiePQTs2pfHKqHTHfJXc9AboWyK4IKTWMw==", + "dev": true, + "license": "(Apache-2.0 OR MIT)", + "engines": { + "node": ">=16.15" + } + }, "node_modules/@web3-storage/filecoin-client": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/@web3-storage/filecoin-client/-/filecoin-client-3.3.3.tgz", @@ -3932,12 +5106,6 @@ "multiformats": "^13.0.0" } }, - "node_modules/@web3-storage/filecoin-client/node_modules/uint8arrays/node_modules/multiformats": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.1.1.tgz", - "integrity": "sha512-JiptvwMmlxlzIlLLwhCi/srf/nk409UL0eUBr0kioRJq15hqqKyg68iftrBvhCRjR6Rw4fkNnSc4ZJXJDuta/Q==", - "dev": true - }, "node_modules/@web3-storage/gateway-lib": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@web3-storage/gateway-lib/-/gateway-lib-5.1.2.tgz", @@ -4046,18 +5214,119 @@ "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", "dev": true, "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@web3-storage/upload-client/node_modules/multiformats": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.3.tgz", + "integrity": "sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==", + "dev": true, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@web3-storage/w3cli": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/@web3-storage/w3cli/-/w3cli-7.8.2.tgz", + "integrity": "sha512-Ua7qcE0bEL+xKNQN7PSf6IPGIY+IR8oeqkYPyE25m3kY+gwroqz6O+459NsRSPeBBEdQD1lfqnbdxysMpK1GFw==", + "dev": true, + "license": "(Apache-2.0 AND MIT)", + "dependencies": { + "@inquirer/core": "^5.1.1", + "@inquirer/prompts": "^3.3.0", + "@ipld/car": "^5.2.4", + "@ipld/dag-json": "^10.1.5", + "@ipld/dag-ucan": "^3.4.0", + "@ucanto/client": "^9.0.1", + "@ucanto/core": "^10.0.1", + "@ucanto/principal": "^9.0.1", + "@ucanto/transport": "^9.1.1", + "@web3-storage/access": "^20.0.0", + "@web3-storage/capabilities": "^17.2.0", + "@web3-storage/data-segment": "^5.0.0", + "@web3-storage/did-mailto": "^2.1.0", + "@web3-storage/w3up-client": "^14.1.1", + "ansi-escapes": "^6.2.0", + "chalk": "^5.3.0", + "crypto-random-string": "^5.0.0", + "files-from-path": "^1.0.4", + "fr32-sha2-256-trunc254-padded-binary-tree-multihash": "^3.3.0", + "multiformats": "^13.1.3", + "open": "^9.1.0", + "ora": "^7.0.1", + "pretty-tree": "^1.0.0", + "s-ago": "^2.2.0", + "sade": "^1.8.1", + "update-notifier": "^7.0.0" + }, + "bin": { + "w3": "shim.js", + "w3up": "shim.js" + } + }, + "node_modules/@web3-storage/w3cli/node_modules/@web3-storage/data-segment": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@web3-storage/data-segment/-/data-segment-5.3.0.tgz", + "integrity": "sha512-zFJ4m+pEKqtKatJNsFrk/2lHeFSbkXZ6KKXjBe7/2ayA9wAar7T/unewnOcZrrZTnCWmaxKsXWqdMFy9bXK9dw==", + "dev": true, + "license": "(Apache-2.0 AND MIT)", + "dependencies": { + "@ipld/dag-cbor": "^9.2.1", + "multiformats": "^13.3.0", + "sync-multihash-sha2": "^1.0.0" + } + }, + "node_modules/@web3-storage/w3cli/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@web3-storage/w3cli/node_modules/files-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/files-from-path/-/files-from-path-1.0.4.tgz", + "integrity": "sha512-sMNIVdpRh1uCSIaat3qnM3E6aA1C5FVn5/B16z8sN3gIMjZPkxtVCorkEL07xTcCIxVwTXzjU1Ota7Wif6RfQQ==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "dependencies": { + "graceful-fs": "^4.2.10" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@web3-storage/upload-client/node_modules/multiformats": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.3.tgz", - "integrity": "sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==", + "node_modules/@web3-storage/w3up-client": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@web3-storage/w3up-client/-/w3up-client-14.1.1.tgz", + "integrity": "sha512-brBmN1aCJpjtNLwWpz0Jg1OkfsYs7r27m5VMOET9x+j4jy3DCtSqlUkHFIumLYrNhUn5oZrqh0kbWokcaUvrLg==", "dev": true, + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@ipld/dag-ucan": "^3.4.0", + "@ucanto/client": "^9.0.1", + "@ucanto/core": "^10.0.1", + "@ucanto/interface": "^10.0.1", + "@ucanto/principal": "^9.0.1", + "@ucanto/transport": "^9.1.1", + "@web3-storage/access": "^20.0.0", + "@web3-storage/blob-index": "^1.0.3", + "@web3-storage/capabilities": "^17.2.0", + "@web3-storage/did-mailto": "^2.1.0", + "@web3-storage/filecoin-client": "^3.3.3", + "@web3-storage/upload-client": "^16.1.1" + }, "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" + "node": ">=18" } }, "node_modules/abortable-iterator": { @@ -4149,6 +5418,16 @@ } } }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -4158,6 +5437,19 @@ "node": ">=6" } }, + "node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -4458,6 +5750,26 @@ "platform": "^1.3.3" } }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bigint-mod-arith": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/bigint-mod-arith/-/bigint-mod-arith-3.3.1.tgz", + "integrity": "sha512-pX/cYW3dCa87Jrzv6DAr8ivbbJRzEX5yGhdt8IutnX/PCIXfpx+mabWNK/M8qqh+zQ0J3thftUBHW0ByuUlG0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.4.0" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -4470,6 +5782,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/blake3-wasm": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", @@ -4481,6 +5805,153 @@ "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" }, + "node_modules/boxen": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^8.0.0", + "chalk": "^5.3.0", + "cli-boxes": "^3.0.0", + "string-width": "^7.2.0", + "type-fest": "^4.21.0", + "widest-line": "^5.0.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/boxen/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4547,6 +6018,22 @@ "semver": "^7.0.0" } }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/byte-access": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/byte-access/-/byte-access-1.0.1.tgz", @@ -4603,6 +6090,19 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/capnp-ts": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", @@ -4701,6 +6201,58 @@ "fsevents": "~2.3.2" } }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -4746,22 +6298,101 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/conf": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/conf/-/conf-11.0.2.tgz", - "integrity": "sha512-jjyhlQ0ew/iwmtwsS2RaB6s8DBifcE2GYBEaw2SJDUY/slJJbNfY4GlDVzOs/ff8cM/Wua5CikqXgbFl5eu85A==", - "dependencies": { - "ajv": "^8.12.0", - "ajv-formats": "^2.1.1", - "atomically": "^2.0.0", - "debounce-fn": "^5.1.2", - "dot-prop": "^7.2.0", - "env-paths": "^3.0.0", - "json-schema-typed": "^8.0.1", - "semver": "^7.3.8" + "node_modules/conf": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/conf/-/conf-11.0.2.tgz", + "integrity": "sha512-jjyhlQ0ew/iwmtwsS2RaB6s8DBifcE2GYBEaw2SJDUY/slJJbNfY4GlDVzOs/ff8cM/Wua5CikqXgbFl5eu85A==", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^2.1.1", + "atomically": "^2.0.0", + "debounce-fn": "^5.1.2", + "dot-prop": "^7.2.0", + "env-paths": "^3.0.0", + "json-schema-typed": "^8.0.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/configstore": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-7.0.0.tgz", + "integrity": "sha512-yk7/5PN5im4qwz0WFZW3PXnzHgPu9mX29Y8uZ3aefe2lBPC1FYttWZRcaW9fKkT0pBCJyuQ2HfbmPVaODi9jcQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "atomically": "^2.0.3", + "dot-prop": "^9.0.0", + "graceful-fs": "^4.2.11", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/configstore/node_modules/dot-prop": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz", + "integrity": "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^4.18.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/configstore/node_modules/type-fest": { + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/configstore/node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=14.16" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4789,6 +6420,22 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-5.0.0.tgz", + "integrity": "sha512-KWjTXWwxFd6a94m5CdRGW/t82Tr8DoBc9dNnPCAbFI1EBweN6v1tv8y4Y1m7ndkp/nkIBRxUxAzpaBnR2k3bcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^2.12.2" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dagula": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/dagula/-/dagula-8.0.0.tgz", @@ -5060,12 +6707,58 @@ "node": ">=6" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/default-gateway": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-7.2.2.tgz", @@ -5094,6 +6787,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -5184,6 +6890,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-fetch": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/electron-fetch/-/electron-fetch-1.9.1.tgz", @@ -5438,6 +7151,19 @@ "node": ">=6" } }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -6024,6 +7750,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6055,6 +7816,32 @@ "reusify": "^1.0.4" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6206,6 +7993,13 @@ "node": ">= 6" } }, + "node_modules/fr32-sha2-256-trunc254-padded-binary-tree-multihash": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fr32-sha2-256-trunc254-padded-binary-tree-multihash/-/fr32-sha2-256-trunc254-padded-binary-tree-multihash-3.3.0.tgz", + "integrity": "sha512-O11VDxPmPvbQj5eac2BJXyieNacyd+RCMhwOzXQQM/NCI25x3c32YWB4/JwgOWPCpKnNXF6lpK/j0lj7GWOnYQ==", + "dev": true, + "license": "Apache-2.0 OR MIT" + }, "node_modules/freeport-promise": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/freeport-promise/-/freeport-promise-2.0.0.tgz", @@ -6279,6 +8073,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", @@ -6401,6 +8208,22 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -6485,6 +8308,43 @@ "multiformats": "^13.0.0" } }, + "node_modules/has-ansi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz", + "integrity": "sha512-XwLzIec2hoj/LW9F3nCcQpEwZ5fDJ1LOc6SAgc0pz79CGiY9zmZhIkbf7OnK+tC36UhpQBa03HPt13QavGoF6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^1.1.0", + "get-stdin": "^4.0.1" + }, + "bin": { + "has-ansi": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -6684,6 +8544,16 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/interface-datastore": { "version": "8.2.11", "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-8.2.11.tgz", @@ -7012,6 +8882,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-electron": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz", @@ -7073,6 +8959,84 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-ci": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ci/-/is-in-ci-1.0.0.tgz", + "integrity": "sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg==", + "dev": true, + "license": "MIT", + "bin": { + "is-in-ci": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz", + "integrity": "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-directory": "^4.0.1", + "is-path-inside": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally/node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-loopback-addr": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-loopback-addr/-/is-loopback-addr-2.0.2.tgz", @@ -7102,6 +9066,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -7294,6 +9271,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -7721,6 +9727,35 @@ "json-buffer": "3.0.1" } }, + "node_modules/ky": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/ky/-/ky-1.7.2.tgz", + "integrity": "sha512-OzIvbHKKDpi60TnF9t7UUVAF1B4mcqc02z5PIvrm08Wyb+yOcz63GRvEuVxNT18a9E1SrNouhB4W2NNLeD7Ykg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, + "node_modules/latest-version": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-9.0.0.tgz", + "integrity": "sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-json": "^10.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -8439,9 +10474,10 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/multiformats": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.1.1.tgz", - "integrity": "sha512-JiptvwMmlxlzIlLLwhCi/srf/nk409UL0eUBr0kioRJq15hqqKyg68iftrBvhCRjR6Rw4fkNnSc4ZJXJDuta/Q==" + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.3.1.tgz", + "integrity": "sha512-QxowxTNwJ3r5RMctoGA5p13w5RbRT2QDkoM+yFlqfLiioBp78nhDjnRLvmSBI9+KAqN4VdgOVWM9c0CHd86m3g==", + "license": "Apache-2.0 OR MIT" }, "node_modules/multipart-byte-range": { "version": "3.0.1", @@ -8469,6 +10505,16 @@ "mustache": "bin/mustache" } }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -8766,6 +10812,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -8783,6 +10848,137 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", + "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.9.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^1.3.0", + "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", + "string-width": "^6.1.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ora/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/log-symbols": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/string-width": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", + "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^10.2.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-defer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.1.tgz", @@ -8943,6 +11139,25 @@ "node": ">=6" } }, + "node_modules/package-json": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-10.0.1.tgz", + "integrity": "sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ky": "^1.2.0", + "registry-auth-token": "^5.0.2", + "registry-url": "^6.0.1", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -9052,6 +11267,102 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-tree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pretty-tree/-/pretty-tree-1.0.0.tgz", + "integrity": "sha512-BfBHciLsD6KtzG60Lfz6+FRWAjLvBwembXOzJg8lUqYe5eA7ujWB+9wZgrlN4lskhcgUEuIj8OFkIHwxUyh+tQ==", + "dev": true, + "dependencies": { + "archy": "0.0.2", + "chalk": "~1.0.0" + } + }, + "node_modules/pretty-tree/node_modules/ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-tree/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-tree/node_modules/archy": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/archy/-/archy-0.0.2.tgz", + "integrity": "sha512-8mMsetjXv4pCPTrMbPPO2cxy9vzJn2jwbd+ug+mf8fEUZG2E78Vo5erJMjrnGuLTKqOLtS5ulFHJSfg1yaCjxA==", + "dev": true, + "license": "MIT/X11", + "engines": { + "node": "*" + } + }, + "node_modules/pretty-tree/node_modules/chalk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz", + "integrity": "sha512-1TE3hpADga5iWinlcCpyhC7fTl9uQumLD8i2jJoJeVg7UbveY5jj7F6uCq8w0hQpSeLhaPn5QFe8e56toMVP1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.0.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^1.0.3", + "strip-ansi": "^2.0.1", + "supports-color": "^1.3.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-tree/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/pretty-tree/node_modules/strip-ansi": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "integrity": "sha512-2h8q2CP3EeOhDJ+jd932PRMpa3/pOJFGoF22J1U/DNbEK2gSW2DqeF46VjCXsSQXhC+k/l8/gaaRBQKL6hUPfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^1.0.0" + }, + "bin": { + "strip-ansi": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-tree/node_modules/supports-color": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz", + "integrity": "sha512-OHbMkscHFRcNWEcW80fYhCrzAjheSIBwJChpFaBqA6zEz53nxumqi6ukciRb/UA0/v2nDNMk28ce/uBbYRDsng==", + "dev": true, + "license": "MIT", + "bin": { + "supports-color": "cli.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/printable-characters": { "version": "1.0.42", "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", @@ -9103,6 +11414,13 @@ "react-is": "^16.13.1" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, "node_modules/protobufjs": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz", @@ -9161,6 +11479,22 @@ "node": ">=6" } }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9196,11 +11530,44 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/rate-limiter-flexible": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.4.2.tgz", - "integrity": "sha512-rMATGGOdO1suFyf/mI5LYhts71g1sbdhmd6YvdiXO2gJnd42Tt6QS4JUKJKSWVVkMtBacm6l40FR7Trjo6Iruw==" - }, + "node_modules/rate-limiter-flexible": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.4.2.tgz", + "integrity": "sha512-rMATGGOdO1suFyf/mI5LYhts71g1sbdhmd6YvdiXO2gJnd42Tt6QS4JUKJKSWVVkMtBacm6l40FR7Trjo6Iruw==" + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -9310,6 +11677,35 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -9352,6 +11748,49 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/retimer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz", @@ -9421,6 +11860,128 @@ "estree-walker": "^0.6.1" } }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-applescript/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-applescript/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/run-applescript/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -9444,6 +12005,13 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/s-ago": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/s-ago/-/s-ago-2.2.0.tgz", + "integrity": "sha512-t6Q/aFCCJSBf5UUkR/WH0mDHX8EGm2IBQ7nQLobVLsdxOlkryYMbOlwu2D4Cf7jPUp0v1LhfPgvIZNoi9k8lUA==", + "dev": true, + "license": "MIT" + }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -9543,9 +12111,10 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -9881,6 +12450,22 @@ "node": ">=6" } }, + "node_modules/stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stoppable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", @@ -10111,6 +12696,32 @@ "retimer": "^3.0.0" } }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -10389,6 +13000,67 @@ "ufo": "^1.5.4" } }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-7.3.1.tgz", + "integrity": "sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^8.0.1", + "chalk": "^5.3.0", + "configstore": "^7.0.0", + "is-in-ci": "^1.0.0", + "is-installed-globally": "^1.0.0", + "is-npm": "^6.0.0", + "latest-version": "^9.0.0", + "pupa": "^3.1.0", + "semver": "^7.6.3", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -10548,6 +13220,76 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/widest-line": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index 2736f9b..7f7db54 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@web3-storage/content-claims": "^5.0.0", "@web3-storage/public-bucket": "^1.1.0", "@web3-storage/upload-client": "^16.1.1", + "@web3-storage/w3cli": "^7.8.2", "carstream": "^2.1.0", "chai": "^5.1.1", "esbuild": "^0.18.20", diff --git a/scripts/delegate-serve.d.ts b/scripts/delegate-serve.d.ts new file mode 100644 index 0000000..17ca046 --- /dev/null +++ b/scripts/delegate-serve.d.ts @@ -0,0 +1,4 @@ +declare module '@web3-storage/w3cli/lib.js' { + import { Client } from '@web3-storage/w3up-client' + export declare function getClient(): Promise +} diff --git a/scripts/delegate-serve.js b/scripts/delegate-serve.js index 7da68fe..3276a1d 100644 --- a/scripts/delegate-serve.js +++ b/scripts/delegate-serve.js @@ -1,25 +1,22 @@ import sade from 'sade' import { getClient } from '@web3-storage/w3cli/lib.js' -import { serve } from '../src/middleware/withAuthorizedSpace.js' import * as ed25519 from '@ucanto/principal/ed25519' - -/** @import { Client } from '@web3-storage/w3up-client' */ +import * as serve from '../src/capabilities/serve.js' const cli = sade('delegate-serve.js [token]') cli .describe( - `Delegates ${serve.can} to the Gateway for , with an optional token. Outputs a base64url string suitable for the stub_delegation query parameter. Pipe the output to pbcopy or similar for the quickest workflow.` + `Delegates ${serve.star.can} to the Gateway for , with an optional token. Outputs a base64url string suitable for the stub_delegation query parameter. Pipe the output to pbcopy or similar for the quickest workflow.` ) .action(async (space, token) => { - /** @type {Client} */ const client = await getClient() const gatewayIdentity = (await ed25519.Signer.generate()).withDID( 'did:web:w3s.link' ) - const delegation = await serve.delegate({ + const delegation = await serve.star.delegate({ issuer: client.agent.issuer, audience: gatewayIdentity, with: space, @@ -27,7 +24,7 @@ cli expiration: Infinity, proofs: client.proofs([ { - can: serve.can, + can: serve.star.can, with: space } ]) diff --git a/src/capabilities/serve.js b/src/capabilities/serve.js new file mode 100644 index 0000000..4c63e3b --- /dev/null +++ b/src/capabilities/serve.js @@ -0,0 +1,51 @@ +import { capability, Schema, DID, nullable, string } from '@ucanto/validator' + +/** + * "Manage the serving of content owned by the subject Space." + * + * A Principal who may `space/content/serve/*` is permitted to perform all + * operations related to serving content owned by the Space, including actually + * serving it and recording egress charges. + */ +export const star = capability({ + can: 'space/content/serve/*', + /** + * The Space which contains the content. This Space will be charged egress + * fees if content is actually retrieved by way of this invocation. + */ + with: DID, + nb: Schema.struct({ + /** The authorization token, if any, used for this request. */ + token: nullable(string()) + }) +}) + +/** + * "Serve content owned by the subject Space over HTTP." + * + * A Principal who may `space/content/serve/transport/http` is permitted to + * serve any content owned by the Space, in the manner of an [IPFS Gateway]. The + * content may be a Blob stored by a Storage Node, or indexed content stored + * within such Blobs (ie, Shards). + * + * Note that the args do not currently specify *what* content should be served. + * Invoking this command does not currently *serve* the content in any way, but + * merely validates the authority to do so. Currently, the entirety of a Space + * must use the same authorization, thus the content does not need to be + * identified. In the future, this command may refer directly to a piece of + * content by CID. + * + * [IPFS Gateway]: https://specs.ipfs.tech/http-gateways/path-gateway/ + */ +export const transportHttp = capability({ + can: 'space/content/serve/transport/http', + /** + * The Space which contains the content. This Space will be charged egress + * fees if content is actually retrieved by way of this invocation. + */ + with: DID, + nb: Schema.struct({ + /** The authorization token, if any, used for this request. */ + token: nullable(string()) + }) +}) diff --git a/src/middleware/withAuthorizedSpace.js b/src/middleware/withAuthorizedSpace.js index 957c927..7b51c99 100644 --- a/src/middleware/withAuthorizedSpace.js +++ b/src/middleware/withAuthorizedSpace.js @@ -1,15 +1,7 @@ import { Verifier } from '@ucanto/principal' -import { - capability, - Schema, - DID, - nullable, - string, - ok, - access, - Unauthorized -} from '@ucanto/validator' +import { ok, access, Unauthorized } from '@ucanto/validator' import { HttpError } from '@web3-storage/gateway-lib/util' +import * as serve from '../capabilities/serve.js' /** * @import * as Ucanto from '@ucanto/interface' @@ -20,36 +12,6 @@ import { HttpError } from '@web3-storage/gateway-lib/util' * @import { SpaceContext, DelegationsStorageContext } from './withAuthorizedSpace.types.js' */ -/** - * "Serve content owned by the subject Space." - * - * A Principal who may `space/content/serve` is permitted to serve any - * content owned by the Space, in the manner of an [IPFS Gateway]. The - * content may be a Blob stored by a Storage Node, or indexed content stored - * within such Blobs (ie, Shards). - * - * Note that the args do not currently specify *what* content should be - * served. Invoking this command does not currently *serve* the content in - * any way, but merely validates the authority to do so. Currently, the - * entirety of a Space must use the same authorization, thus the content does - * not need to be identified. In the future, this command may refer directly - * to a piece of content by CID. - * - * [IPFS Gateway]: https://specs.ipfs.tech/http-gateways/path-gateway/ - */ -export const serve = capability({ - can: 'space/content/serve', - /** - * The Space which contains the content. This Space will be charged egress - * fees if content is actually retrieved by way of this invocation. - */ - with: DID, - nb: Schema.struct({ - /** The authorization token, if any, used for this request. */ - token: nullable(string()) - }) -}) - /** * Attempts to locate the {@link IpfsUrlContext.dataCid}. If it's able to, * attempts to authorize the request to access the data. @@ -134,14 +96,14 @@ const authorize = async (space, ctx) => { // Look up delegations that might authorize us to serve the content. const relevantDelegationsResult = await ctx.delegationsStorage.find({ audience: ctx.gatewayIdentity.did(), - can: 'space/content/serve', + can: serve.transportHttp.can, with: space }) if (relevantDelegationsResult.error) return relevantDelegationsResult // Create an invocation of the serve capability. - const invocation = await serve + const invocation = await serve.transportHttp .invoke({ issuer: ctx.gatewayIdentity, audience: ctx.gatewayIdentity, @@ -155,7 +117,7 @@ const authorize = async (space, ctx) => { // Validate the invocation. const accessResult = await access(invocation, { - capability: serve, + capability: serve.transportHttp, authority: ctx.gatewayIdentity, principal: Verifier, validateAuthorization: () => ok({}) diff --git a/test/unit/middleware/withAuthorizedSpace.spec.js b/test/unit/middleware/withAuthorizedSpace.spec.js index f194d5a..7c25b73 100644 --- a/test/unit/middleware/withAuthorizedSpace.spec.js +++ b/test/unit/middleware/withAuthorizedSpace.spec.js @@ -7,16 +7,14 @@ import { describe, it } from 'mocha' import { expect } from 'chai' import sinon from 'sinon' import * as ed25519 from '@ucanto/principal/ed25519' -import { - serve, - withAuthorizedSpace -} from '../../../src/middleware/withAuthorizedSpace.js' +import { withAuthorizedSpace } from '../../../src/middleware/withAuthorizedSpace.js' import * as Digest from 'multiformats/hashes/digest' import { base64 } from 'multiformats/bases/base64' import { rejection } from './util/rejection.js' import { expectToBeInstanceOf } from './util/expectToBeInstanceOf.js' import { HttpError } from '@web3-storage/gateway-lib/util' import { createTestCID } from './util/createTestCID.js' +import * as serve from '../../../src/capabilities/serve.js' /** * @import { MultihashDigest } from 'multiformats' @@ -129,7 +127,7 @@ describe('withAuthorizedSpace', async () => { error: undefined }), delegationsStorage: createDelegationStorage([ - await serve.delegate({ + await serve.transportHttp.delegate({ issuer: space, audience: gatewayIdentity, with: space.did(), @@ -173,7 +171,7 @@ describe('withAuthorizedSpace', async () => { error: undefined }), delegationsStorage: createDelegationStorage([ - await serve.delegate({ + await serve.transportHttp.delegate({ issuer: space, audience: gatewayIdentity, with: space.did(), @@ -219,7 +217,7 @@ describe('withAuthorizedSpace', async () => { error: undefined }), delegationsStorage: createDelegationStorage([ - await serve.delegate({ + await serve.transportHttp.delegate({ issuer: space, audience: gatewayIdentity, with: space.did(), @@ -270,14 +268,14 @@ describe('withAuthorizedSpace', async () => { error: undefined }), delegationsStorage: createDelegationStorage([ - await serve.delegate({ + await serve.transportHttp.delegate({ issuer: space1, audience: gatewayIdentity, with: space1.did(), nb: { token: 'space1-token' } }), // No authorization for space2 - await serve.delegate({ + await serve.transportHttp.delegate({ issuer: space3, audience: gatewayIdentity, with: space3.did(), @@ -395,7 +393,7 @@ describe('withAuthorizedSpace', async () => { } }), delegationsStorage: createDelegationStorage([ - await serve.delegate({ + await serve.transportHttp.delegate({ issuer: space, audience: gatewayIdentity, with: space.did(), @@ -439,7 +437,7 @@ describe('withAuthorizedSpace', async () => { } }), delegationsStorage: createDelegationStorage([ - await serve.delegate({ + await serve.transportHttp.delegate({ issuer: space, audience: gatewayIdentity, with: space.did(), @@ -482,7 +480,7 @@ describe('withAuthorizedSpace', async () => { } }), delegationsStorage: createDelegationStorage([ - await serve.delegate({ + await serve.transportHttp.delegate({ issuer: space, audience: gatewayIdentity, with: space.did(), diff --git a/tsconfig.json b/tsconfig.json index e85fbd1..5c8d202 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ - { - "include": ["src", "test"], + "include": ["src", "test", "scripts"], + "exclude": ["scripts/r2-put.js"], "compilerOptions": { "declaration": true, "declarationMap": true,