diff --git a/packages/capabilities/src/blob.js b/packages/capabilities/src/blob.js index eccadf173..edbc971b7 100644 --- a/packages/capabilities/src/blob.js +++ b/packages/capabilities/src/blob.js @@ -21,11 +21,11 @@ import { equalBlob, equalWith, SpaceDID } from './utils.js' /** * Capability can only be delegated (but not invoked) allowing audience to - * derived any `blob/` prefixed capability for the (memory) space identified + * derived any `space/blob/` prefixed capability for the (memory) space identified * by DID in the `with` field. */ export const blob = capability({ - can: 'blob/*', + can: 'space/blob/*', /** * DID of the (memory) space where Blob is intended to * be stored. @@ -50,13 +50,13 @@ export const content = Schema.struct({ }) /** - * `blob/add` capability allows agent to store a Blob into a (memory) space + * `space/blob/add` capability allows agent to store a Blob into a (memory) space * identified by did:key in the `with` field. Agent should compute blob multihash * and size and provide it under `nb.blob` field, allowing a service to provision * a write location for the agent to PUT desired Blob into. */ export const add = capability({ - can: 'blob/add', + can: 'space/blob/add', /** * DID of the (memory) space where Blob is intended to * be stored. @@ -76,7 +76,7 @@ export const add = capability({ * space identified by `with` field. */ export const remove = capability({ - can: 'blob/remove', + can: 'space/blob/remove', /** * DID of the (memory) space where Blob is stored. */ @@ -111,7 +111,7 @@ export const remove = capability({ * (memory) space identified by `with` field. */ export const list = capability({ - can: 'blob/list', + can: 'space/blob/list', /** * DID of the (memory) space where Blobs to be listed are stored. */ diff --git a/packages/capabilities/src/index/index.js b/packages/capabilities/src/index/index.js index b0541618d..44df4f10b 100644 --- a/packages/capabilities/src/index/index.js +++ b/packages/capabilities/src/index/index.js @@ -18,23 +18,23 @@ import { equalWith, SpaceDID, and, equal } from '../utils.js' /** * Capability can only be delegated (but not invoked) allowing audience to - * derive any `index/` prefixed capability for the space identified by the DID + * derive any `space/index/` prefixed capability for the space identified by the DID * in the `with` field. */ export const index = capability({ - can: 'index/*', + can: 'space/index/*', /** DID of the space where indexed data is stored. */ with: SpaceDID, derives: equalWith, }) /** - * `index/add` capability allows an agent to submit verifiable claims + * `space/index/add` capability allows an agent to submit verifiable claims * about content-addressed data to be published on the InterPlanetary Network * Indexer (IPNI), making it publicly queryable. */ export const add = capability({ - can: 'index/add', + can: 'space/index/add', /** DID of the space where indexed data is stored. */ with: SpaceDID, nb: Schema.struct({ diff --git a/packages/capabilities/src/utils.js b/packages/capabilities/src/utils.js index 0b6a31b64..5360215e7 100644 --- a/packages/capabilities/src/utils.js +++ b/packages/capabilities/src/utils.js @@ -92,7 +92,7 @@ export const equalLink = (claimed, delegated) => { } /** - * @template {Types.ParsedCapability<"blob/add"|"blob/remove"|"web3.storage/blob/allocate"|"web3.storage/blob/accept", Types.URI<'did:'>, {blob: { digest: Uint8Array, size: number }}>} T + * @template {Types.ParsedCapability<"space/blob/add"|"space/blob/remove"|"web3.storage/blob/allocate"|"web3.storage/blob/accept", Types.URI<'did:'>, {blob: { digest: Uint8Array, size: number }}>} T * @param {T} claimed * @param {T} delegated * @returns {Types.Result<{}, Types.Failure>} diff --git a/packages/capabilities/test/capabilities/index.test.js b/packages/capabilities/test/capabilities/index.test.js index 25b1f7d8d..cafd31a64 100644 --- a/packages/capabilities/test/capabilities/index.test.js +++ b/packages/capabilities/test/capabilities/index.test.js @@ -27,7 +27,7 @@ const index = async () => }) describe('index capabilities', function () { - it('index/add can be derived from *', async () => { + it('space/index/add can be derived from *', async () => { const add = Index.add.invoke({ issuer: alice, audience: w3, @@ -50,13 +50,13 @@ describe('index capabilities', function () { } assert.deepEqual(result.ok.audience.did(), w3.did()) - assert.equal(result.ok.capability.can, 'index/add') + assert.equal(result.ok.capability.can, 'space/index/add') assert.deepEqual(result.ok.capability.nb, { index: await createCarCid('test'), }) }) - it('index/add can be derived from index/*', async () => { + it('space/index/add can be derived from index/*', async () => { const add = Index.add.invoke({ issuer: alice, audience: w3, @@ -79,13 +79,13 @@ describe('index capabilities', function () { } assert.deepEqual(result.ok.audience.did(), w3.did()) - assert.equal(result.ok.capability.can, 'index/add') + assert.equal(result.ok.capability.can, 'space/index/add') assert.deepEqual(result.ok.capability.nb, { index: await createCarCid('test'), }) }) - it('index/add can be derived from index/* derived from *', async () => { + it('space/index/add can be derived from index/* derived from *', async () => { const index = await Index.index.delegate({ issuer: alice, audience: bob, @@ -115,13 +115,13 @@ describe('index capabilities', function () { } assert.deepEqual(result.ok.audience.did(), w3.did()) - assert.equal(result.ok.capability.can, 'index/add') + assert.equal(result.ok.capability.can, 'space/index/add') assert.deepEqual(result.ok.capability.nb, { index: await createCarCid('test'), }) }) - it('index/add should fail when escalating index constraint', async () => { + it('space/index/add should fail when escalating index constraint', async () => { const delegation = await Index.add.delegate({ issuer: alice, audience: bob, diff --git a/packages/filecoin-api/src/errors.js b/packages/filecoin-api/src/errors.js index 294ab656a..6744c3dad 100644 --- a/packages/filecoin-api/src/errors.js +++ b/packages/filecoin-api/src/errors.js @@ -109,7 +109,9 @@ export class UnexpectedPiece extends Error { } } -export const UnsupportedCapabilityErrorName = /** @type {const} */ ('UnsupportedCapability') +export const UnsupportedCapabilityErrorName = /** @type {const} */ ( + 'UnsupportedCapability' +) export class UnsupportedCapability extends Server.Failure { /** * @param {object} source diff --git a/packages/filecoin-api/test/context/service.js b/packages/filecoin-api/test/context/service.js index 6572ec2a1..37de7be45 100644 --- a/packages/filecoin-api/test/context/service.js +++ b/packages/filecoin-api/test/context/service.js @@ -203,9 +203,10 @@ export function getMockService() { return Server.ok({ piece: invCap.nb.piece, aggregates: [], - deals: [] + deals: [], }) - }}) + }, + }), }, deal: { info: Server.provideAdvanced({ diff --git a/packages/filecoin-api/test/context/store-implementations.js b/packages/filecoin-api/test/context/store-implementations.js index cce8e556a..3def2032a 100644 --- a/packages/filecoin-api/test/context/store-implementations.js +++ b/packages/filecoin-api/test/context/store-implementations.js @@ -87,12 +87,12 @@ export const getStoreImplementations = ( return undefined } return new ReadableStream({ - start(controller) { - // Push the data into the stream - controller.enqueue(item) - // Close the stream - controller.close() - } + start(controller) { + // Push the data into the stream + controller.enqueue(item) + // Close the stream + controller.close() + }, }) }, }), diff --git a/packages/filecoin-api/test/services/aggregator.js b/packages/filecoin-api/test/services/aggregator.js index 7f29dc44d..df356dffe 100644 --- a/packages/filecoin-api/test/services/aggregator.js +++ b/packages/filecoin-api/test/services/aggregator.js @@ -222,10 +222,7 @@ export const test = { pieceQueue: new FailingQueue(), }) ), - 'piece/accept must be invoked on service did': async ( - assert, - context - ) => { + 'piece/accept must be invoked on service did': async (assert, context) => { const { agent, storefront } = await getServiceContext(context.id) const connection = connect({ id: context.id, diff --git a/packages/filecoin-api/test/services/storefront.js b/packages/filecoin-api/test/services/storefront.js index a162a40c3..2b12e3b92 100644 --- a/packages/filecoin-api/test/services/storefront.js +++ b/packages/filecoin-api/test/services/storefront.js @@ -12,7 +12,7 @@ import { createServer, connect } from '../../src/storefront/service.js' import { QueueOperationErrorName, StoreOperationErrorName, - UnsupportedCapabilityErrorName + UnsupportedCapabilityErrorName, } from '../../src/errors.js' import { randomCargo, randomAggregate } from '../utils.js' import { createInvocationsAndReceiptsForDealDataProofChain } from '../context/receipts.js' @@ -242,30 +242,29 @@ export const test = { pieceStore: getStoreImplementations(FailingStore).storefront.pieceStore, }) ), - 'filecoin/submit must be invoked on service did': - async (assert, context) => { - const { agent } = await getServiceContext(context.id) - const connection = connect({ - id: context.id, - channel: createServer(context), - }) + 'filecoin/submit must be invoked on service did': async (assert, context) => { + const { agent } = await getServiceContext(context.id) + const connection = connect({ + id: context.id, + channel: createServer(context), + }) - // Generate piece for test - const [cargo] = await randomCargo(1, 128) - const filecoinSubmitInv = Filecoin.submit.invoke({ - issuer: agent, - audience: connection.id, - with: agent.did(), - nb: { - piece: cargo.link.link(), - content: cargo.content.link(), - }, - }) + // Generate piece for test + const [cargo] = await randomCargo(1, 128) + const filecoinSubmitInv = Filecoin.submit.invoke({ + issuer: agent, + audience: connection.id, + with: agent.did(), + nb: { + piece: cargo.link.link(), + content: cargo.content.link(), + }, + }) - const response = await filecoinSubmitInv.execute(connection) - assert.ok(response.out.error) - assert.equal(response.out.error?.name, UnsupportedCapabilityErrorName) - }, + const response = await filecoinSubmitInv.execute(connection) + assert.ok(response.out.error) + assert.equal(response.out.error?.name, UnsupportedCapabilityErrorName) + }, 'filecoin/submit inserts piece into piece offer queue and returns effect': async (assert, context) => { const { storefront } = await getServiceContext(context.id) @@ -344,7 +343,9 @@ export const test = { assert, context ) => { - const { storefront, aggregator, dealer } = await getServiceContext(context.id) + const { storefront, aggregator, dealer } = await getServiceContext( + context.id + ) const group = context.id.did() const connection = connect({ id: context.id, @@ -452,30 +453,29 @@ export const test = { BigInt(dealMetadata.dataSource.dealID) ) }, - 'filecoin/accept must be invoked on service did': - async (assert, context) => { - const { agent } = await getServiceContext(context.id) - const connection = connect({ - id: context.id, - channel: createServer(context), - }) + 'filecoin/accept must be invoked on service did': async (assert, context) => { + const { agent } = await getServiceContext(context.id) + const connection = connect({ + id: context.id, + channel: createServer(context), + }) - // Generate piece for test - const [cargo] = await randomCargo(1, 128) - const filecoinSubmitInv = Filecoin.accept.invoke({ - issuer: agent, - audience: connection.id, - with: agent.did(), - nb: { - piece: cargo.link.link(), - content: cargo.content.link(), - }, - }) + // Generate piece for test + const [cargo] = await randomCargo(1, 128) + const filecoinSubmitInv = Filecoin.accept.invoke({ + issuer: agent, + audience: connection.id, + with: agent.did(), + nb: { + piece: cargo.link.link(), + content: cargo.content.link(), + }, + }) - const response = await filecoinSubmitInv.execute(connection) - assert.ok(response.out.error) - assert.equal(response.out.error?.name, UnsupportedCapabilityErrorName) - }, + const response = await filecoinSubmitInv.execute(connection) + assert.ok(response.out.error) + assert.equal(response.out.error?.name, UnsupportedCapabilityErrorName) + }, 'filecoin/accept fails if fails to read from piece store': wichMockableContext( async (assert, context) => { @@ -509,7 +509,8 @@ export const test = { 'filecoin/info gets aggregate where piece was included together with deals and inclusion proof': wichMockableContext( async (assert, context) => { - const { agent, storefront, aggregator, dealer } = await getServiceContext(context.id) + const { agent, storefront, aggregator, dealer } = + await getServiceContext(context.id) const group = context.id.did() const connection = connect({ id: context.id, diff --git a/packages/filecoin-api/test/types.ts b/packages/filecoin-api/test/types.ts index cb2e6fbb3..cfedddf66 100644 --- a/packages/filecoin-api/test/types.ts +++ b/packages/filecoin-api/test/types.ts @@ -1,9 +1,4 @@ -import type { - Signer, - Result, - Unit, - UnknownLink -} from '@ucanto/interface' +import type { Signer, Result, Unit, UnknownLink } from '@ucanto/interface' import * as AggregatorInterface from '../src/aggregator/api.js' import * as DealerInterface from '../src/dealer/api.js' import * as StorefrontInterface from '../src/storefront/api.js' @@ -61,9 +56,10 @@ export interface StorefrontTestEventsContext }> } -export interface TestContentStore extends StorefrontInterface.ContentStore { +export interface TestContentStore + extends StorefrontInterface.ContentStore { /** * Puts a record in the store. */ put: (record: Rec) => Promise> -} \ No newline at end of file +} diff --git a/packages/upload-api/src/lib.js b/packages/upload-api/src/lib.js index 14d90884e..1d866b6ab 100644 --- a/packages/upload-api/src/lib.js +++ b/packages/upload-api/src/lib.js @@ -6,7 +6,6 @@ import * as Types from './types.js' import * as Legacy from '@ucanto/transport/legacy' import * as CAR from '@ucanto/transport/car' import { create as createRevocationChecker } from './utils/revocation.js' -import { createService as createBlobService } from './blob.js' import { createService as createStoreService } from './store.js' import { createService as createUploadService } from './upload.js' import { createService as createConsoleService } from './console.js' @@ -14,7 +13,6 @@ import { createService as createAccessService } from './access.js' import { createService as createConsumerService } from './consumer.js' import { createService as createCustomerService } from './customer.js' import { createService as createSpaceService } from './space.js' -import { createService as createIndexService } from './index.js' import { createService as createProviderService } from './provider.js' import { createService as createSubscriptionService } from './subscription.js' import { createService as createAdminService } from './admin.js' @@ -177,11 +175,9 @@ export const run = async (agent, invocation) => { */ export const createService = (context) => ({ access: createAccessService(context), - blob: createBlobService(context), console: createConsoleService(context), consumer: createConsumerService(context), customer: createCustomerService(context), - index: createIndexService(context), provider: createProviderService(context), 'rate-limit': createRateLimitService(context), admin: createAdminService(context), diff --git a/packages/upload-api/src/space.js b/packages/upload-api/src/space.js index 3faf937f6..a4a030a36 100644 --- a/packages/upload-api/src/space.js +++ b/packages/upload-api/src/space.js @@ -1,52 +1,16 @@ import { Space } from '@web3-storage/capabilities' -import { DID } from '@ucanto/validator' import * as Provider from '@ucanto/server' import * as API from './types.js' -/** - * @param {API.Input} input - * @param {API.SpaceServiceContext} ctx - * @returns {Promise>} - */ -export const info = async ({ capability }, ctx) => { - const { provisionsStorage: provisions } = ctx - - const spaceDid = capability.with - if (!DID.match({ method: 'key' }).is(spaceDid)) { - /** @type {API.SpaceUnknown} */ - const unexpectedSpaceDidFailure = { - name: 'SpaceUnknown', - message: `can only get info for did:key spaces`, - } - return { - error: unexpectedSpaceDidFailure, - } - } - - const result = await provisions.getStorageProviders(spaceDid) - const providers = result.ok - if (providers && providers.length > 0) { - return { - ok: { - did: spaceDid, - providers, - }, - } - } - - /** @type {import('@web3-storage/access/types').SpaceUnknown} */ - const spaceUnknownFailure = { - name: 'SpaceUnknown', - message: `Space not found.`, - } - return { - error: spaceUnknownFailure, - } -} +import { info } from './space/info.js' +import { createService as createBlobService } from './blob.js' +import { createService as createIndexService } from './index.js' /** - * @param {API.SpaceServiceContext} ctx + * @param {API.SpaceServiceContext & API.BlobServiceContext & API.IndexServiceContext} ctx */ export const createService = (ctx) => ({ info: Provider.provide(Space.info, (input) => info(input, ctx)), + blob: createBlobService(ctx), + index: createIndexService(ctx), }) diff --git a/packages/upload-api/src/space/info.js b/packages/upload-api/src/space/info.js new file mode 100644 index 000000000..bbec2eb15 --- /dev/null +++ b/packages/upload-api/src/space/info.js @@ -0,0 +1,44 @@ +import { Space } from '@web3-storage/capabilities' +import { DID } from '@ucanto/validator' +import * as API from '../types.js' + +/** + * @param {API.Input} input + * @param {API.SpaceServiceContext} ctx + * @returns {Promise>} + */ +export const info = async ({ capability }, ctx) => { + const { provisionsStorage: provisions } = ctx + + const spaceDid = capability.with + if (!DID.match({ method: 'key' }).is(spaceDid)) { + /** @type {API.SpaceUnknown} */ + const unexpectedSpaceDidFailure = { + name: 'SpaceUnknown', + message: `can only get info for did:key spaces`, + } + return { + error: unexpectedSpaceDidFailure, + } + } + + const result = await provisions.getStorageProviders(spaceDid) + const providers = result.ok + if (providers && providers.length > 0) { + return { + ok: { + did: spaceDid, + providers, + }, + } + } + + /** @type {import('@web3-storage/access/types').SpaceUnknown} */ + const spaceUnknownFailure = { + name: 'SpaceUnknown', + message: `Space not found.`, + } + return { + error: spaceUnknownFailure, + } +} diff --git a/packages/upload-api/src/types.ts b/packages/upload-api/src/types.ts index 8f4e0e288..9395ebc7e 100644 --- a/packages/upload-api/src/types.ts +++ b/packages/upload-api/src/types.ts @@ -210,11 +210,6 @@ export type { } from './types/index.js' export interface Service extends StorefrontService, W3sService { - blob: { - add: ServiceMethod - remove: ServiceMethod - list: ServiceMethod - } store: { add: ServiceMethod get: ServiceMethod @@ -320,6 +315,14 @@ export interface Service extends StorefrontService, W3sService { } space: { info: ServiceMethod + index: { + add: ServiceMethod + } + blob: { + add: ServiceMethod + remove: ServiceMethod + list: ServiceMethod + } } plan: { get: ServiceMethod @@ -333,9 +336,6 @@ export interface Service extends StorefrontService, W3sService { usage: { report: ServiceMethod } - index: { - add: ServiceMethod - } } export interface W3sService { diff --git a/packages/upload-api/test/handlers/web3.storage.js b/packages/upload-api/test/handlers/web3.storage.js index e0b758bec..ca885ce8b 100644 --- a/packages/upload-api/test/handlers/web3.storage.js +++ b/packages/upload-api/test/handlers/web3.storage.js @@ -684,7 +684,9 @@ export const test = { const locations = delegation.capabilities[0].nb.location assert.equal(locations.length, 1) - const loc = Result.unwrap(await context.blobsStorage.createDownloadUrl(digest)) + const loc = Result.unwrap( + await context.blobsStorage.createDownloadUrl(digest) + ) assert.ok(locations.includes(loc)) }, 'web3.storage/blob/accept fails to provide site delegation when blob was not stored': diff --git a/packages/upload-api/test/storage/blobs-storage-tests.js b/packages/upload-api/test/storage/blobs-storage-tests.js index a7bd2d3fe..9ca49d2ef 100644 --- a/packages/upload-api/test/storage/blobs-storage-tests.js +++ b/packages/upload-api/test/storage/blobs-storage-tests.js @@ -45,28 +45,30 @@ export const test = { assert.ok(hasBlob.ok) }, - 'should create valid download URL for blobs that can be used to read': - async (assert, { blobsStorage }) => { - const data = new Uint8Array([11, 22, 34, 44, 55]) - const digest = await sha256.digest(data) - const expires = 60 * 60 * 24 // 1 day + 'should create valid download URL for blobs that can be used to read': async ( + assert, + { blobsStorage } + ) => { + const data = new Uint8Array([11, 22, 34, 44, 55]) + const digest = await sha256.digest(data) + const expires = 60 * 60 * 24 // 1 day - const upload = Result.unwrap( - await blobsStorage.createUploadUrl(digest.bytes, data.length, expires) - ) + const upload = Result.unwrap( + await blobsStorage.createUploadUrl(digest.bytes, data.length, expires) + ) - await fetch(upload.url, { - method: 'PUT', - mode: 'cors', - body: data, - headers: upload.headers, - }) - - const downloadUrl = Result.unwrap( - await blobsStorage.createDownloadUrl(digest.bytes) - ) + await fetch(upload.url, { + method: 'PUT', + mode: 'cors', + body: data, + headers: upload.headers, + }) + + const downloadUrl = Result.unwrap( + await blobsStorage.createDownloadUrl(digest.bytes) + ) - const res = await fetch(downloadUrl) - assert.ok(equals(new Uint8Array(await res.arrayBuffer()), data)) - } + const res = await fetch(downloadUrl) + assert.ok(equals(new Uint8Array(await res.arrayBuffer()), data)) + }, } diff --git a/packages/upload-api/test/storage/blobs-storage.js b/packages/upload-api/test/storage/blobs-storage.js index 575a609a9..745b1d521 100644 --- a/packages/upload-api/test/storage/blobs-storage.js +++ b/packages/upload-api/test/storage/blobs-storage.js @@ -212,7 +212,7 @@ export class BlobsStorage { } /** @param {Uint8Array} multihash */ - async createDownloadUrl (multihash) { + async createDownloadUrl(multihash) { const digest = digestDecode(multihash) const url = new URL(this.#bucketPath(digest), this.baseURL) return ok(/** @type {Types.URI} */ (url.toString())) diff --git a/packages/upload-client/src/types.ts b/packages/upload-client/src/types.ts index eb96db2b1..bb6d8f809 100644 --- a/packages/upload-client/src/types.ts +++ b/packages/upload-client/src/types.ts @@ -148,13 +148,15 @@ export interface Service extends StorefrontService { UCANConcludeFailure > } - blob: { - add: ServiceMethod - remove: ServiceMethod - list: ServiceMethod - } - index: { - add: ServiceMethod + space: { + blob: { + add: ServiceMethod + remove: ServiceMethod + list: ServiceMethod + } + index: { + add: ServiceMethod + } } store: { add: ServiceMethod diff --git a/packages/upload-client/test/blob.test.js b/packages/upload-client/test/blob.test.js index 8d6316ca5..c9ee70cee 100644 --- a/packages/upload-client/test/blob.test.js +++ b/packages/upload-client/test/blob.test.js @@ -41,20 +41,22 @@ describe('Blob.add', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, async ({ invocation }) => { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - const invCap = invocation.capabilities[0] - assert.equal(invCap.can, BlobCapabilities.add.can) - assert.equal(invCap.with, space.did()) - assert.deepEqual(invCap.nb?.blob.digest, bytesHash.bytes) - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, async ({ invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + const invCap = invocation.capabilities[0] + assert.equal(invCap.can, BlobCapabilities.add.can) + assert.equal(invCap.with, space.did()) + assert.deepEqual(invCap.nb?.blob.digest, bytesHash.bytes) + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, }, }) @@ -85,8 +87,8 @@ describe('Blob.add', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 1) + assert(service.space.blob.add.called) + assert.equal(service.space.blob.add.callCount, 1) assert.equal( progress.reduce((max, { loaded }) => Math.max(max, loaded), 0), 128 @@ -138,14 +140,16 @@ describe('Blob.add', () => { return Server.fail('ouch') }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation }) => { + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, }, }) @@ -168,7 +172,7 @@ describe('Blob.add', () => { { connection } ), { - message: 'failed blob/add invocation', + message: 'failed space/blob/add invocation', } ) }) @@ -193,14 +197,16 @@ describe('Blob.add', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { - return setupBlobAdd4xxResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation }) => { + return setupBlobAdd4xxResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, }, }) @@ -248,14 +254,16 @@ describe('Blob.add', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { - return setupBlobAdd5xxResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation }) => { + return setupBlobAdd5xxResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, }, }) @@ -294,14 +302,16 @@ describe('Blob.add', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation }) => { + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, }, }) @@ -362,10 +372,12 @@ describe('Blob.add', () => { return { ok: { time: Date.now() } } }), }, - blob: { - add: provide(BlobCapabilities.add, () => { - throw new Server.Failure('boom') - }), + space: { + blob: { + add: provide(BlobCapabilities.add, () => { + throw new Server.Failure('boom') + }), + }, }, }) @@ -387,7 +399,7 @@ describe('Blob.add', () => { bytes, { connection } ), - { message: 'failed blob/add invocation' } + { message: 'failed space/blob/add invocation' } ) }) }) @@ -423,15 +435,17 @@ describe('Blob.list', () => { ] const service = mockService({ - blob: { - list: provide(BlobCapabilities.list, ({ invocation }) => { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - const invCap = invocation.capabilities[0] - assert.equal(invCap.can, BlobCapabilities.list.can) - assert.equal(invCap.with, space.did()) - return { ok: res } - }), + space: { + blob: { + list: provide(BlobCapabilities.list, ({ invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + const invCap = invocation.capabilities[0] + assert.equal(invCap.can, BlobCapabilities.list.can) + assert.equal(invCap.with, space.did()) + return { ok: res } + }), + }, }, }) @@ -452,8 +466,8 @@ describe('Blob.list', () => { { connection } ) - assert(service.blob.list.called) - assert.equal(service.blob.list.callCount, 1) + assert(service.space.blob.list.called) + assert.equal(service.space.blob.list.callCount, 1) assert.equal(list.cursor, res.cursor) assert.equal(list.size, res.size) @@ -512,16 +526,18 @@ describe('Blob.list', () => { ] const service = mockService({ - blob: { - list: provide(BlobCapabilities.list, ({ invocation }) => { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - const invCap = invocation.capabilities[0] - assert.equal(invCap.can, BlobCapabilities.list.can) - assert.equal(invCap.with, space.did()) - assert.equal(invCap.nb?.size, 1) - return { ok: invCap.nb?.cursor === cursor ? page1 : page0 } - }), + space: { + blob: { + list: provide(BlobCapabilities.list, ({ invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + const invCap = invocation.capabilities[0] + assert.equal(invCap.can, BlobCapabilities.list.can) + assert.equal(invCap.with, space.did()) + assert.equal(invCap.nb?.size, 1) + return { ok: invCap.nb?.cursor === cursor ? page1 : page0 } + }), + }, }, }) @@ -546,8 +562,8 @@ describe('Blob.list', () => { { size: 1, cursor: results0.cursor, connection } ) - assert(service.blob.list.called) - assert.equal(service.blob.list.callCount, 2) + assert(service.space.blob.list.called) + assert.equal(service.space.blob.list.callCount, 2) assert.equal(results0.cursor, cursor) assert(results0.results) @@ -580,10 +596,12 @@ describe('Blob.list', () => { ] const service = mockService({ - blob: { - list: provide(BlobCapabilities.list, () => { - throw new Server.Failure('boom') - }), + space: { + blob: { + list: provide(BlobCapabilities.list, () => { + throw new Server.Failure('boom') + }), + }, }, }) @@ -605,7 +623,7 @@ describe('Blob.list', () => { { connection } ), { - message: 'failed blob/list invocation', + message: 'failed space/blob/list invocation', } ) }) @@ -628,16 +646,18 @@ describe('Blob.remove', () => { ] const service = mockService({ - blob: { - remove: provide(BlobCapabilities.remove, ({ invocation }) => { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - const invCap = invocation.capabilities[0] - assert.equal(invCap.can, BlobCapabilities.remove.can) - assert.equal(invCap.with, space.did()) - assert.equal(String(invCap.nb?.digest), bytesHash.bytes) - return { ok: { size: bytes.length } } - }), + space: { + blob: { + remove: provide(BlobCapabilities.remove, ({ invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + const invCap = invocation.capabilities[0] + assert.equal(invCap.can, BlobCapabilities.remove.can) + assert.equal(invCap.with, space.did()) + assert.equal(String(invCap.nb?.digest), bytesHash.bytes) + return { ok: { size: bytes.length } } + }), + }, }, }) @@ -659,8 +679,8 @@ describe('Blob.remove', () => { { connection } ) - assert(service.blob.remove.called) - assert.equal(service.blob.remove.callCount, 1) + assert(service.space.blob.remove.called) + assert.equal(service.space.blob.remove.callCount, 1) assert(result.ok) assert.equal(result.ok.size, bytes.length) @@ -682,10 +702,12 @@ describe('Blob.remove', () => { ] const service = mockService({ - blob: { - remove: provide(BlobCapabilities.remove, () => { - throw new Server.Failure('boom') - }), + space: { + blob: { + remove: provide(BlobCapabilities.remove, () => { + throw new Server.Failure('boom') + }), + }, }, }) @@ -707,7 +729,7 @@ describe('Blob.remove', () => { bytesHash, { connection } ), - { message: 'failed blob/remove invocation' } + { message: 'failed space/blob/remove invocation' } ) }) }) diff --git a/packages/upload-client/test/dag-index.test.js b/packages/upload-client/test/dag-index.test.js index 5767c9869..fc62d24b6 100644 --- a/packages/upload-client/test/dag-index.test.js +++ b/packages/upload-client/test/dag-index.test.js @@ -26,14 +26,16 @@ describe('Index.add', () => { ] const service = mockService({ - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async ({ capability }) => { - assert.equal(capability.nb.index.toString(), car.cid.toString()) - return Server.ok({}) - }, - }), + space: { + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async ({ capability }) => { + assert.equal(capability.nb.index.toString(), car.cid.toString()) + return Server.ok({}) + }, + }), + }, }, }) @@ -71,13 +73,15 @@ describe('Index.add', () => { ] const service = mockService({ - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async () => { - throw new Server.Failure('boom') - }, - }), + space: { + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async () => { + throw new Server.Failure('boom') + }, + }), + }, }, }) @@ -99,7 +103,7 @@ describe('Index.add', () => { car.cid, { connection } ), - { message: 'failed index/add invocation' } + { message: 'failed space/index/add invocation' } ) }) }) diff --git a/packages/upload-client/test/helpers/mocks.js b/packages/upload-client/test/helpers/mocks.js index bf863a1b4..21c79e142 100644 --- a/packages/upload-client/test/helpers/mocks.js +++ b/packages/upload-client/test/helpers/mocks.js @@ -7,8 +7,10 @@ const notImplemented = () => { /** * @param {Partial<{ * ucan: Partial - * blob: Partial - * index: Partial + * space: Partial<{ + * blob: Partial + * index: Partial + * }> * store: Partial * upload: Partial * usage: Partial @@ -20,13 +22,15 @@ export function mockService(impl) { ucan: { conclude: withCallCount(impl.ucan?.conclude ?? notImplemented), }, - blob: { - add: withCallCount(impl.blob?.add ?? notImplemented), - list: withCallCount(impl.blob?.list ?? notImplemented), - remove: withCallCount(impl.blob?.remove ?? notImplemented), - }, - index: { - add: withCallCount(impl.index?.add ?? notImplemented), + space: { + blob: { + add: withCallCount(impl.space?.blob?.add ?? notImplemented), + list: withCallCount(impl.space?.blob?.list ?? notImplemented), + remove: withCallCount(impl.space?.blob?.remove ?? notImplemented), + }, + index: { + add: withCallCount(impl.space?.index?.add ?? notImplemented), + }, }, store: { add: withCallCount(impl.store?.add ?? notImplemented), diff --git a/packages/upload-client/test/index.test.js b/packages/upload-client/test/index.test.js index 8808db526..cdb3aa935 100644 --- a/packages/upload-client/test/index.test.js +++ b/packages/upload-client/test/index.test.js @@ -68,30 +68,32 @@ describe('uploadFile', () => { return { ok: { time: Date.now() } } }), }, - blob: { - add: provide( - BlobCapabilities.add, - // @ts-ignore Argument of type - async function ({ invocation, capability }) { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - assert.equal(capability.can, BlobCapabilities.add.can) - assert.equal(capability.with, space.did()) - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - } - ), - }, - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async ({ capability }) => { - assert(capability.nb.index) - return Server.ok({}) - }, - }), + space: { + blob: { + add: provide( + BlobCapabilities.add, + // @ts-ignore Argument of type + async function ({ invocation, capability }) { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + assert.equal(capability.can, BlobCapabilities.add.can) + assert.equal(capability.with, space.did()) + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + } + ), + }, + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async ({ capability }) => { + assert(capability.nb.index) + return Server.ok({}) + }, + }), + }, }, filecoin: { offer: Server.provideAdvanced({ @@ -146,12 +148,12 @@ describe('uploadFile', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 2) + assert(service.space.blob.add.called) + assert.equal(service.space.blob.add.callCount, 2) assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 1) - assert(service.index.add.called) - assert.equal(service.index.add.callCount, 1) + assert(service.space.index.add.called) + assert.equal(service.space.index.add.callCount, 1) assert(service.upload.add.called) assert.equal(service.upload.add.callCount, 1) @@ -195,23 +197,25 @@ describe('uploadFile', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), - }, - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async ({ capability }) => { - assert(capability.nb.index) - return Server.ok({}) - }, - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation }) => { + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async ({ capability }) => { + assert(capability.nb.index) + return Server.ok({}) + }, + }), + }, }, filecoin: { offer: Server.provideAdvanced({ @@ -291,18 +295,20 @@ describe('uploadFile', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation, capability }) => { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - assert.equal(capability.can, BlobCapabilities.add.can) - assert.equal(capability.with, space.did()) - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation, capability }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + assert.equal(capability.can, BlobCapabilities.add.can) + assert.equal(capability.with, space.did()) + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, }, filecoin: { offer: Server.provideAdvanced({ @@ -337,8 +343,8 @@ describe('uploadFile', () => { ) ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 1) + assert(service.space.blob.add.called) + assert.equal(service.space.blob.add.callCount, 1) assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 1) }) @@ -384,28 +390,30 @@ describe('uploadDirectory', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - const invCap = invocation.capabilities[0] - assert.equal(invCap.can, BlobCapabilities.add.can) - assert.equal(invCap.with, space.did()) - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), - }, - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async ({ capability }) => { - assert(capability.nb.index) - return Server.ok({}) - }, - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + const invCap = invocation.capabilities[0] + assert.equal(invCap.can, BlobCapabilities.add.can) + assert.equal(invCap.with, space.did()) + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async ({ capability }) => { + assert(capability.nb.index) + return Server.ok({}) + }, + }), + }, }, filecoin: { offer: Server.provideAdvanced({ @@ -456,10 +464,10 @@ describe('uploadDirectory', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 2) - assert(service.index.add.called) - assert.equal(service.index.add.callCount, 1) + assert(service.space.blob.add.called) + assert.equal(service.space.blob.add.callCount, 2) + assert(service.space.index.add.called) + assert.equal(service.space.index.add.callCount, 1) assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 1) assert(service.upload.add.called) @@ -507,23 +515,25 @@ describe('uploadDirectory', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), - }, - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async ({ capability }) => { - assert(capability.nb.index) - return Server.ok({}) - }, - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation }) => { + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async ({ capability }) => { + assert(capability.nb.index) + return Server.ok({}) + }, + }), + }, }, filecoin: { offer: Server.provideAdvanced({ @@ -606,25 +616,27 @@ describe('uploadDirectory', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { + space: { + blob: { // @ts-ignore Argument of type - invocations.push(invocation) - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), - }, - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async ({ capability }) => { - assert(capability.nb.index) - return Server.ok({}) - }, - }), + add: provide(BlobCapabilities.add, ({ invocation }) => { + // @ts-ignore Argument of type + invocations.push(invocation) + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async ({ capability }) => { + assert(capability.nb.index) + return Server.ok({}) + }, + }), + }, }, filecoin: { offer: Server.provideAdvanced({ @@ -797,28 +809,30 @@ describe('uploadCAR', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ invocation }) => { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - const invCap = invocation.capabilities[0] - assert.equal(invCap.can, BlobCapabilities.add.can) - assert.equal(invCap.with, space.did()) - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), - }, - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async ({ capability }) => { - assert(capability.nb.index) - return Server.ok({}) - }, - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + const invCap = invocation.capabilities[0] + assert.equal(invCap.can, BlobCapabilities.add.can) + assert.equal(invCap.with, space.did()) + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async ({ capability }) => { + assert(capability.nb.index) + return Server.ok({}) + }, + }), + }, }, filecoin: { offer: Server.provideAdvanced({ @@ -873,10 +887,10 @@ describe('uploadCAR', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 3) - assert(service.index.add.called) - assert.equal(service.index.add.callCount, 1) + assert(service.space.blob.add.called) + assert.equal(service.space.blob.add.callCount, 3) + assert(service.space.index.add.called) + assert.equal(service.space.index.add.callCount, 1) assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 2) assert(service.upload.add.called) @@ -925,27 +939,29 @@ describe('uploadCAR', () => { return { ok: { time: Date.now() } } }), }, - blob: { - // @ts-ignore Argument of type - add: provide(BlobCapabilities.add, ({ capability, invocation }) => { - assert.equal(invocation.issuer.did(), agent.did()) - assert.equal(invocation.capabilities.length, 1) - assert.equal(capability.can, BlobCapabilities.add.can) - assert.equal(capability.with, space.did()) - return setupBlobAddSuccessResponse( - { issuer: space, audience: agent, with: space, proofs }, - invocation - ) - }), - }, - index: { - add: Server.provideAdvanced({ - capability: IndexCapabilities.add, - handler: async ({ capability }) => { - assert(capability.nb.index) - return Server.ok({}) - }, - }), + space: { + blob: { + // @ts-ignore Argument of type + add: provide(BlobCapabilities.add, ({ capability, invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + assert.equal(capability.can, BlobCapabilities.add.can) + assert.equal(capability.with, space.did()) + return setupBlobAddSuccessResponse( + { issuer: space, audience: agent, with: space, proofs }, + invocation + ) + }), + }, + index: { + add: Server.provideAdvanced({ + capability: IndexCapabilities.add, + handler: async ({ capability }) => { + assert(capability.nb.index) + return Server.ok({}) + }, + }), + }, }, filecoin: { offer: Server.provideAdvanced({ @@ -998,10 +1014,10 @@ describe('uploadCAR', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 2) - assert(service.index.add.called) - assert.equal(service.index.add.callCount, 1) + assert(service.space.blob.add.called) + assert.equal(service.space.blob.add.callCount, 2) + assert(service.space.index.add.called) + assert.equal(service.space.index.add.callCount, 1) assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 1) assert(service.upload.add.called) diff --git a/packages/w3up-client/test/ability.test.js b/packages/w3up-client/test/ability.test.js index 69de45898..fce89459f 100644 --- a/packages/w3up-client/test/ability.test.js +++ b/packages/w3up-client/test/ability.test.js @@ -8,7 +8,7 @@ export const testAbilities = { 'should return the passed argument if all abilities are valid': async ( assert ) => { - const abilities = ['blob/add', 'upload/add'] + const abilities = ['space/blob/add', 'upload/add'] assert.equal(asAbilities(abilities), abilities) },