diff --git a/packages/upload-client/src/index.js b/packages/upload-client/src/index.js index ac714d5d5..a98fde498 100644 --- a/packages/upload-client/src/index.js +++ b/packages/upload-client/src/index.js @@ -8,7 +8,8 @@ import * as Upload from './upload.js' import * as UnixFS from './unixfs.js' import * as CAR from './car.js' import { ShardingStream, defaultFileComparator } from './sharding.js' -import { codec as carCodec } from '@ucanto/transport/car' +// TODO: enable Blob +// import { codec as carCodec } from '@ucanto/transport/car' export { Blob, Store, Upload, UnixFS, CAR } export * from './sharding.js' @@ -132,16 +133,20 @@ async function uploadBlockStream( new TransformStream({ async transform(car, controller) { const bytes = new Uint8Array(await car.arrayBuffer()) - // Invoke blob/add and write bytes to write target - const multihash = await Blob.add(conf, bytes, options) - // Should this be raw instead? - const cid = Link.create(carCodec.code, multihash) + // Invoke blob/add and write bytes to write target + // TODO: enable Blob + // const multihash = await Blob.add(conf, bytes, options) + const cid = await Store.add(conf, bytes, options) + // TODO: enable Blob + // const cid = Link.create(carCodec.code, multihash) let piece if (pieceHasher) { const multihashDigest = await pieceHasher.digest(bytes) /** @type {import('@web3-storage/capabilities/types').PieceLink} */ piece = Link.create(raw.code, multihashDigest) - const content = Link.create(raw.code, multihash) + // TODO: enable Blob + // const content = Link.create(raw.code, multihash) + const content = Link.create(raw.code, cid.multihash) // Invoke filecoin/offer for data const result = await Storefront.filecoinOffer( diff --git a/packages/upload-client/test/index.test.js b/packages/upload-client/test/index.test.js index 77173d4f6..587cf384f 100644 --- a/packages/upload-client/test/index.test.js +++ b/packages/upload-client/test/index.test.js @@ -6,6 +6,7 @@ import * as CAR from '@ucanto/transport/car' import * as Signer from '@ucanto/principal/ed25519' import * as UCAN from '@web3-storage/capabilities/ucan' import * as BlobCapabilities from '@web3-storage/capabilities/blob' +import * as StoreCapabilities from '@web3-storage/capabilities/store' import * as UploadCapabilities from '@web3-storage/capabilities/upload' import * as StorefrontCapabilities from '@web3-storage/capabilities/filecoin/storefront' import { Piece } from '@web3-storage/data-segment' @@ -41,6 +42,12 @@ describe('uploadFile', () => { let carCID const proofs = await Promise.all([ + StoreCapabilities.add.delegate({ + issuer: space, + audience: agent, + with: space.did(), + expiration: Infinity, + }), BlobCapabilities.add.delegate({ issuer: space, audience: agent, @@ -61,6 +68,24 @@ describe('uploadFile', () => { return { ok: { time: Date.now() } } }), }, + store: { + add: provide(StoreCapabilities.add, ({ invocation, capability }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + assert.equal(capability.can, StoreCapabilities.add.can) + assert.equal(capability.with, space.did()) + /** @type {Omit} */ + const res = { + status: 'upload', + headers: { 'x-test': 'true' }, + url: 'http://localhost:9200', + link: expectedCar.cid, + with: space.did(), + } + + return { ok: { ...res, allocated: capability.nb.size } } + }), + }, blob: { add: provide( BlobCapabilities.add, @@ -130,8 +155,11 @@ describe('uploadFile', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 1) + // TODO: Blob Enable + // assert(service.blob.add.called) + // assert.equal(service.blob.add.callCount, 1) + assert(service.store.add.called) + assert.equal(service.store.add.callCount, 1) assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 1) assert(service.upload.add.called) @@ -151,6 +179,12 @@ describe('uploadFile', () => { const carCIDs = [] const proofs = await Promise.all([ + StoreCapabilities.add.delegate({ + issuer: space, + audience: agent, + with: space.did(), + expiration: Infinity, + }), BlobCapabilities.add.delegate({ issuer: space, audience: agent, @@ -165,6 +199,14 @@ describe('uploadFile', () => { }), ]) + /** @type {Omit} */ + const res = { + status: 'upload', + headers: { 'x-test': 'true' }, + url: 'http://localhost:9200', + with: space.did(), + } + const service = mockService({ ucan: { conclude: provide(UCAN.conclude, () => { @@ -180,6 +222,17 @@ describe('uploadFile', () => { ) }), }, + store: { + add: provide(StoreCapabilities.add, ({ capability }) => ({ + ok: { + ...res, + link: /** @type {import('../src/types.js').CARLink} */ ( + capability.nb.link + ), + allocated: capability.nb.size, + }, + })), + }, filecoin: { offer: Server.provideAdvanced({ capability: StorefrontCapabilities.filecoinOffer, @@ -238,6 +291,12 @@ describe('uploadFile', () => { const file = new Blob([bytes]) const proofs = await Promise.all([ + StoreCapabilities.add.delegate({ + issuer: space, + audience: agent, + with: space.did(), + expiration: Infinity, + }), BlobCapabilities.add.delegate({ issuer: space, audience: agent, @@ -271,6 +330,29 @@ describe('uploadFile', () => { ) }), }, + store: { + add: provide( + StoreCapabilities.add, + async ({ invocation, capability }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + assert.equal(capability.can, StoreCapabilities.add.can) + assert.equal(capability.with, space.did()) + + const expectedCar = await toCAR(bytes) + /** @type {Omit} */ + const res = { + status: 'upload', + headers: { 'x-test': 'true' }, + url: 'http://localhost:9200', + link: expectedCar.cid, + with: space.did(), + } + + return { ok: { ...res, allocated: capability.nb.size } } + } + ), + }, filecoin: { offer: Server.provideAdvanced({ capability: StorefrontCapabilities.filecoinOffer, @@ -304,8 +386,11 @@ describe('uploadFile', () => { ) ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 1) + assert(service.store.add.called) + assert.equal(service.store.add.callCount, 1) + // assert(service.blob.add.called) + // assert.equal(service.blob.add.callCount, 1) + assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 1) }) @@ -325,6 +410,12 @@ describe('uploadDirectory', () => { let carCID = null const proofs = await Promise.all([ + StoreCapabilities.add.delegate({ + issuer: space, + audience: agent, + with: space.did(), + expiration: Infinity, + }), BlobCapabilities.add.delegate({ issuer: space, audience: agent, @@ -340,6 +431,33 @@ describe('uploadDirectory', () => { ]) const service = mockService({ + store: { + add: provide(StoreCapabilities.add, ({ capability, invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + const invCap = invocation.capabilities[0] + assert.equal(invCap.can, StoreCapabilities.add.can) + assert.equal(invCap.with, space.did()) + + /** @type {Omit} */ + const res = { + status: 'upload', + headers: { 'x-test': 'true' }, + url: 'http://localhost:9200', + with: space.did(), + } + + return { + ok: { + ...res, + link: /** @type {import('../src/types.js').CARLink} */ ( + capability.nb.link + ), + allocated: capability.nb.size, + }, + } + }), + }, ucan: { conclude: provide(UCAN.conclude, () => { return { ok: { time: Date.now() } } @@ -408,8 +526,10 @@ describe('uploadDirectory', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 1) + // assert(service.blob.add.called) + // assert.equal(service.blob.add.callCount, 1) + assert(service.store.add.called) + assert.equal(service.store.add.callCount, 1) assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 1) assert(service.upload.add.called) @@ -431,6 +551,12 @@ describe('uploadDirectory', () => { const carCIDs = [] const proofs = await Promise.all([ + StoreCapabilities.add.delegate({ + issuer: space, + audience: agent, + with: space.did(), + expiration: Infinity, + }), BlobCapabilities.add.delegate({ issuer: space, audience: agent, @@ -445,6 +571,13 @@ describe('uploadDirectory', () => { }), ]) + /** @type {Omit} */ + const res = { + status: 'upload', + headers: { 'x-test': 'true' }, + url: 'http://localhost:9200', + with: space.did(), + } const service = mockService({ ucan: { conclude: provide(UCAN.conclude, () => { @@ -460,6 +593,17 @@ describe('uploadDirectory', () => { ) }), }, + store: { + add: provide(StoreCapabilities.add, ({ capability }) => ({ + ok: { + ...res, + link: /** @type {import('../src/types.js').CARLink} */ ( + capability.nb.link + ), + allocated: capability.nb.size, + }, + })), + }, filecoin: { offer: Server.provideAdvanced({ capability: StorefrontCapabilities.filecoinOffer, @@ -511,6 +655,12 @@ describe('uploadDirectory', () => { const piece = Piece.fromPayload(someBytes).link const proofs = await Promise.all([ + StoreCapabilities.add.delegate({ + issuer: space, + audience: agent, + with: space.did(), + expiration: Infinity, + }), BlobCapabilities.add.delegate({ issuer: space, audience: agent, @@ -546,6 +696,24 @@ describe('uploadDirectory', () => { ) }), }, + store: { + add: provide(StoreCapabilities.add, ({ invocation, capability }) => { + // @ts-expect-error blob invocation + invocations.push(invocation) + return { + ok: { + status: 'upload', + headers: { 'x-test': 'true' }, + url: 'http://localhost:9200', + with: capability.with, + link: /** @type {import('../src/types.js').CARLink} */ ( + capability.nb.link + ), + allocated: capability.nb.size, + }, + } + }), + }, filecoin: { offer: Server.provideAdvanced({ capability: StorefrontCapabilities.filecoinOffer, @@ -631,6 +799,16 @@ describe('uploadDirectory', () => { : [] ) .map((cid) => cid.toString()) + // const shardsForUnordered = uploadServiceForUnordered.invocations + // .flatMap((i) => + // i.capability.can === 'upload/add' ? i.capability.nb.shards ?? [] : [] + // ) + // .map((cid) => cid.toString()) + // const shardsForOrdered = uploadServiceForOrdered.invocations + // .flatMap((i) => + // i.capability.can === 'upload/add' ? i.capability.nb.shards ?? [] : [] + // ) + // .map((cid) => cid.toString()) assert.deepEqual( shardsForUnordered, shardsForOrdered, @@ -691,6 +869,12 @@ describe('uploadCAR', () => { const carCIDs = [] const proofs = await Promise.all([ + StoreCapabilities.add.delegate({ + issuer: space, + audience: agent, + with: space.did(), + expiration: Infinity, + }), BlobCapabilities.add.delegate({ issuer: space, audience: agent, @@ -705,6 +889,14 @@ describe('uploadCAR', () => { }), ]) + /** @type {Omit} */ + const res = { + status: 'upload', + headers: { 'x-test': 'true' }, + url: 'http://localhost:9200', + with: space.did(), + } + const service = mockService({ ucan: { conclude: provide(UCAN.conclude, () => { @@ -725,6 +917,24 @@ describe('uploadCAR', () => { ) }), }, + store: { + add: provide(StoreCapabilities.add, ({ capability, invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + const invCap = invocation.capabilities[0] + assert.equal(invCap.can, StoreCapabilities.add.can) + assert.equal(invCap.with, space.did()) + return { + ok: { + ...res, + link: /** @type {import('../src/types.js').CARLink} */ ( + capability.nb.link + ), + allocated: capability.nb.size, + }, + } + }), + }, filecoin: { offer: Server.provideAdvanced({ capability: StorefrontCapabilities.filecoinOffer, @@ -778,8 +988,10 @@ describe('uploadCAR', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 2) + // assert(service.blob.add.called) + // assert.equal(service.blob.add.callCount, 2) + assert(service.store.add.called) + assert.equal(service.store.add.callCount, 2) assert(service.filecoin.offer.called) assert.equal(service.filecoin.offer.callCount, 2) assert(service.upload.add.called) @@ -802,6 +1014,12 @@ describe('uploadCAR', () => { const pieceCIDs = [] const proofs = await Promise.all([ + StoreCapabilities.add.delegate({ + issuer: space, + audience: agent, + with: space.did(), + expiration: Infinity, + }), BlobCapabilities.add.delegate({ issuer: space, audience: agent, @@ -835,6 +1053,30 @@ describe('uploadCAR', () => { ) }), }, + store: { + add: provide(StoreCapabilities.add, ({ capability, invocation }) => { + assert.equal(invocation.issuer.did(), agent.did()) + assert.equal(invocation.capabilities.length, 1) + assert.equal(capability.can, StoreCapabilities.add.can) + assert.equal(capability.with, space.did()) + /** @type {Omit} */ + const res = { + status: 'upload', + headers: { 'x-test': 'true' }, + url: 'http://localhost:9200', + with: space.did(), + } + return { + ok: { + ...res, + link: /** @type {import('../src/types.js').CARLink} */ ( + capability.nb.link + ), + allocated: capability.nb.size, + }, + } + }), + }, filecoin: { offer: Server.provideAdvanced({ capability: StorefrontCapabilities.filecoinOffer, @@ -886,8 +1128,10 @@ describe('uploadCAR', () => { } ) - assert(service.blob.add.called) - assert.equal(service.blob.add.callCount, 1) + // assert(service.blob.add.called) + // assert.equal(service.blob.add.callCount, 1) + assert(service.store.add.called) + assert.equal(service.store.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/src/client.js b/packages/w3up-client/src/client.js index 0954dd22e..30743814c 100644 --- a/packages/w3up-client/src/client.js +++ b/packages/w3up-client/src/client.js @@ -156,7 +156,7 @@ export class Client extends Base { /** * Get a receipt for an executed task by its CID. * - * @param {import('multiformats').UnknownLink} taskCid + * @param {import('multiformats').UnknownLink} taskCid - Task CID for receipt. */ async getReceipt(taskCid) { // Fetch receipt from endpoint @@ -353,8 +353,8 @@ export class Client extends Base { cause: error, }) } - /* c8 ignore stop */ } + /* c8 ignore stop */ }) ) } diff --git a/packages/w3up-client/test/client.test.js b/packages/w3up-client/test/client.test.js index fda4a546a..a53945140 100644 --- a/packages/w3up-client/test/client.test.js +++ b/packages/w3up-client/test/client.test.js @@ -12,7 +12,7 @@ export const testClient = { uploadFile: Test.withContext({ 'should upload a file to the service': async ( assert, - { connection, provisionsStorage, uploadTable, allocationsStorage } + { connection, provisionsStorage, uploadTable, storeTable } ) => { const bytes = await randomBytes(128) const file = new Blob([bytes]) @@ -51,15 +51,9 @@ export const testClient = { ok: true, }) - assert.deepEqual( - await allocationsStorage.exists( - space.did(), - expectedCar.cid.multihash.bytes - ), - { - ok: true, - } - ) + assert.deepEqual(await storeTable.exists(space.did(), expectedCar.cid), { + ok: true, + }) assert.equal(carCID?.toString(), expectedCar.cid.toString()) assert.equal(dataCID.toString(), expectedCar.roots[0].toString()) @@ -136,7 +130,7 @@ export const testClient = { uploadCar: Test.withContext({ 'uploads a CAR file to the service': async ( assert, - { connection, provisionsStorage, uploadTable, allocationsStorage } + { connection, provisionsStorage, uploadTable, storeTable } ) => { const car = await randomCAR(32) @@ -176,12 +170,9 @@ export const testClient = { return assert.ok(carCID) } - assert.deepEqual( - await allocationsStorage.exists(space.did(), carCID.multihash.bytes), - { - ok: true, - } - ) + assert.deepEqual(await storeTable.exists(space.did(), carCID), { + ok: true, + }) }, }), getRecipt: Test.withContext({