@storacha/client
Version:
Client for the storacha.network w3up api
418 lines • 20.6 kB
JavaScript
import { AgentData } from '@storacha/access/agent';
import { Client } from '../../src/client.js';
import * as Test from '../test.js';
import { Space } from '@storacha/capabilities';
import { gatewaySigner } from '@storacha/upload-api/test/utils';
import { randomCAR } from '../helpers/random.js';
export const SpaceClient = Test.withContext({
info: {
'should retrieve space info': async (assert, { connection, provisionsStorage }) => {
const alice = new Client(await AgentData.create(), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
const space = await alice.createSpace('test', {
skipGatewayAuthorization: true,
});
const auth = await space.createAuthorization(alice, {
access: { 'space/info': {} },
expiration: Infinity,
});
await alice.addSpace(auth);
await alice.setCurrentSpace(space.did());
// Then we setup a billing for this account
await provisionsStorage.put({
// @ts-expect-error
provider: connection.id.did(),
account: alice.agent.did(),
consumer: space.did(),
});
const info = await alice.capability.space.info(space.did());
assert.equal(info.did, space.did());
assert.deepEqual(info.providers, [connection.id.did()]);
},
},
record: {
'should record egress if the capability is derived from *': async (assert, { id: w3, connection, provisionsStorage }) => {
const expiration = Date.now() + 1000 * 60 * 60 * 24; // 1 day from now
// 1. Setup test space and allow Alice Agent to access it
const alice = new Client(await AgentData.create(), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
const space = await alice.createSpace('test', {
skipGatewayAuthorization: true,
});
const auth = await alice.addSpace(await space.createAuthorization(alice));
assert.ok(auth);
await alice.setCurrentSpace(space.did());
await provisionsStorage.put({
// @ts-expect-error
provider: w3.did(),
account: alice.did(),
consumer: space.did(),
});
// 2. Creates a new agent using freewaySigner as the principal
const freewayService = new Client(await AgentData.create({
principal: gatewaySigner,
}), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
// 3. Alice delegates to the Gateway the ability to record egress
const egressRecordGatewayDelegation = await Space.egressRecord.delegate({
issuer: alice.agent.issuer,
audience: freewayService,
with: space.did(),
expiration: expiration,
proofs: await alice.proofs(),
});
const resultDelegation2 = await alice.capability.access.delegate({
delegations: [egressRecordGatewayDelegation],
});
assert.ok(resultDelegation2.ok);
// 4. freewayService claims the delegation
const freewayDelegations = await freewayService.capability.access.claim();
assert.ok(freewayDelegations.length > 0);
assert.ok(freewayDelegations.some((d) => d.issuer.did() === alice.did() &&
d.audience.did() === freewayService.did() &&
d.capabilities.some((c) => c.can === Space.egressRecord.can && c.with === space.did())));
// 5. Create a random resource to record egress
const car = await randomCAR(128);
const resource = car.cid;
assert.ok(resource);
// 6. freewayService invokes egress/record
try {
const egressData = {
space: space.did(),
resource: resource.link(),
bytes: car.size,
servedAt: new Date().toISOString(),
};
const egressRecord = await freewayService.capability.space.egressRecord(egressData, {
proofs: await freewayService.proofs(),
});
assert.ok(egressRecord, 'egressRecord should be returned');
assert.equal(egressRecord.space, space.did(), 'space should be the same');
assert.equal(egressRecord.resource.toString(), resource.toString(), 'resource should be the same');
assert.equal(egressRecord.bytes, car.size, 'bytes should be the same');
assert.equal(new Date(egressRecord.servedAt).getTime(), Math.floor(new Date(egressData.servedAt).getTime() / 1000), 'servedAt should be the same');
assert.ok(egressRecord.cause.toString(), 'cause should be a link');
}
catch (error) {
// @ts-ignore
assert.fail(error.cause ? error.cause.message : error);
}
},
'should record egress if the capability is derived from space/*': async (assert, { id: w3, connection, provisionsStorage }) => {
const expiration = Date.now() + 1000 * 60 * 60 * 24; // 1 day from now
// 1. Setup test space and allow Alice Agent to access it
const alice = new Client(await AgentData.create(), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
const space = await alice.createSpace('test', {
skipGatewayAuthorization: true,
});
const auth = await alice.addSpace(await space.createAuthorization(alice));
assert.ok(auth);
await alice.setCurrentSpace(space.did());
await provisionsStorage.put({
// @ts-expect-error
provider: w3.did(),
account: alice.did(),
consumer: space.did(),
});
// 2. Creates a new agent using freewaySigner as the principal
const freewayService = new Client(await AgentData.create({
principal: gatewaySigner,
}), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
// 3. Alice delegates to the Gateway the ability to record egress
const spaceAccessGatewayDelegation = await Space.top.delegate({
issuer: alice.agent.issuer,
audience: freewayService,
with: space.did(),
expiration: expiration,
proofs: await alice.proofs(),
});
const resultDelegation2 = await alice.capability.access.delegate({
delegations: [spaceAccessGatewayDelegation],
});
assert.ok(resultDelegation2.ok);
// 4. freewayService claims the delegation
const freewayDelegations = await freewayService.capability.access.claim();
assert.ok(freewayDelegations.length > 0);
assert.ok(freewayDelegations.some((d) => d.issuer.did() === alice.did() &&
d.audience.did() === freewayService.did() &&
d.capabilities.some((c) => c.can === Space.top.can && c.with === space.did())));
// 5. Create a random resource to record egress
const car = await randomCAR(128);
const resource = car.cid;
assert.ok(resource);
// 6. freewayService invokes egress/record
try {
const egressData = {
space: space.did(),
resource: resource.link(),
bytes: car.size,
servedAt: new Date().toISOString(),
};
const egressRecord = await freewayService.capability.space.egressRecord(egressData, {
proofs: await freewayService.proofs(),
});
assert.ok(egressRecord, 'egressRecord should be returned');
assert.equal(egressRecord.space, space.did(), 'space should be the same');
assert.equal(egressRecord.resource.toString(), resource.toString(), 'resource should be the same');
assert.equal(egressRecord.bytes, car.size, 'bytes should be the same');
assert.equal(new Date(egressRecord.servedAt).getTime(), Math.floor(new Date(egressData.servedAt).getTime() / 1000), 'servedAt should be the same');
assert.ok(egressRecord.cause.toString(), 'cause should be a link');
}
catch (error) {
// @ts-ignore
assert.fail(error.cause ? error.cause.message : error);
}
},
'should record egress if the capability is derived from space/content/serve/*': async (assert, { id: w3, connection, provisionsStorage }) => {
const expiration = Date.now() + 1000 * 60 * 60 * 24; // 1 day from now
// 1. Setup test space and allow Alice Agent to access it
const alice = new Client(await AgentData.create(), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
const space = await alice.createSpace('test', {
skipGatewayAuthorization: true,
});
const auth = await alice.addSpace(await space.createAuthorization(alice));
assert.ok(auth);
await alice.setCurrentSpace(space.did());
await provisionsStorage.put({
// @ts-expect-error
provider: w3.did(),
account: alice.did(),
consumer: space.did(),
});
// 2. Creates a new agent using freewaySigner as the principal
const freewayService = new Client(await AgentData.create({
principal: gatewaySigner,
}), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
// 3. Alice delegates to the Gateway the ability to serve content
const contentServeGatewayDelegation = await Space.contentServe.delegate({
issuer: alice.agent.issuer,
audience: freewayService,
with: space.did(),
expiration: expiration,
proofs: await alice.proofs(),
});
const resultDelegation2 = await alice.capability.access.delegate({
delegations: [contentServeGatewayDelegation],
});
assert.ok(resultDelegation2.ok);
// 4. freewayService claims the delegation
const freewayDelegations = await freewayService.capability.access.claim();
assert.ok(freewayDelegations.length > 0);
assert.ok(freewayDelegations.some((d) => d.issuer.did() === alice.did() &&
d.audience.did() === freewayService.did() &&
d.capabilities.some((c) => c.can === Space.contentServe.can && c.with === space.did())));
// 5. Create a random resource to record egress
const car = await randomCAR(128);
const resource = car.cid;
assert.ok(resource);
// 6. freewayService invokes egress/record
try {
const egressData = {
space: space.did(),
resource: resource.link(),
bytes: car.size,
servedAt: new Date().toISOString(),
};
const egressRecord = await freewayService.capability.space.egressRecord(egressData, {
proofs: await freewayService.proofs(),
});
assert.ok(egressRecord, 'egressRecord should be returned');
assert.equal(egressRecord.space, space.did(), 'space should be the same');
assert.equal(egressRecord.resource.toString(), resource.toString(), 'resource should be the same');
assert.equal(egressRecord.bytes, car.size, 'bytes should be the same');
assert.equal(new Date(egressRecord.servedAt).getTime(), Math.floor(new Date(egressData.servedAt).getTime() / 1000), 'servedAt should be the same');
assert.ok(egressRecord.cause.toString(), 'cause should be a link');
}
catch (error) {
// @ts-ignore
assert.fail(error.cause ? error.cause.message : error);
}
},
'should record egress if the capability space/content/serve/egress/record is delegated': async (assert, { id: w3, connection, provisionsStorage }) => {
const expiration = Date.now() + 1000 * 60 * 60 * 24; // 1 day from now
// 1. Setup test space and allow Alice Agent to access it
const alice = new Client(await AgentData.create(), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
const space = await alice.createSpace('test', {
skipGatewayAuthorization: true,
});
const auth = await alice.addSpace(await space.createAuthorization(alice));
assert.ok(auth);
await alice.setCurrentSpace(space.did());
await provisionsStorage.put({
// @ts-expect-error
provider: w3.did(),
account: alice.did(),
consumer: space.did(),
});
// 2. Creates a new agent using freewaySigner as the principal
const freewayService = new Client(await AgentData.create({
principal: gatewaySigner,
}), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
// 3. Alice delegates to the Gateway the ability to record egress
const egressRecordGatewayDelegation = await Space.egressRecord.delegate({
issuer: alice.agent.issuer,
audience: freewayService,
with: space.did(),
expiration: expiration,
proofs: await alice.proofs(),
});
const resultDelegation2 = await alice.capability.access.delegate({
delegations: [egressRecordGatewayDelegation],
});
assert.ok(resultDelegation2.ok);
// 4. freewayService claims the delegation
const freewayDelegations = await freewayService.capability.access.claim();
assert.ok(freewayDelegations.length > 0);
assert.ok(freewayDelegations.some((d) => d.issuer.did() === alice.did() &&
d.audience.did() === freewayService.did() &&
d.capabilities.some((c) => c.can === Space.egressRecord.can && c.with === space.did())));
// 5. Create a random resource to record egress
const car = await randomCAR(128);
const resource = car.cid;
assert.ok(resource);
// 6. freewayService invokes egress/record
try {
const egressData = {
space: space.did(),
resource: resource.link(),
bytes: car.size,
servedAt: new Date().toISOString(),
};
const egressRecord = await freewayService.capability.space.egressRecord(egressData, {
proofs: await freewayService.proofs(),
});
assert.ok(egressRecord, 'egressRecord should be returned');
assert.equal(egressRecord.space, space.did(), 'space should be the same');
assert.equal(egressRecord.resource.toString(), resource.toString(), 'resource should be the same');
assert.equal(egressRecord.bytes, car.size, 'bytes should be the same');
assert.equal(new Date(egressRecord.servedAt).getTime(), Math.floor(new Date(egressData.servedAt).getTime() / 1000), 'servedAt should be the same');
assert.ok(egressRecord.cause.toString(), 'cause should be a link');
}
catch (error) {
// @ts-ignore
assert.fail(error.cause ? error.cause.message : error);
}
},
'should fail to record egress if the capability was not delegated': async (assert, { id: w3, connection, provisionsStorage }) => {
const expiration = Date.now() + 1000 * 60 * 60 * 24; // 1 day from now
// 1. Setup test space and allow Alice Agent to access it
const alice = new Client(await AgentData.create(), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
const space = await alice.createSpace('test', {
skipGatewayAuthorization: true,
});
const auth = await alice.addSpace(await space.createAuthorization(alice));
assert.ok(auth);
await alice.setCurrentSpace(space.did());
await provisionsStorage.put({
// @ts-expect-error
provider: w3.did(),
account: alice.did(),
consumer: space.did(),
});
// 2. Creates a new agent using freewaySigner as the principal
const freewayService = new Client(await AgentData.create({
principal: gatewaySigner,
}), {
// @ts-ignore
serviceConf: {
access: connection,
upload: connection,
},
});
// 3. Alice delegates to the Gateway the ability to record egress but without proofs
const egressRecordGatewayDelegation = await Space.egressRecord.delegate({
issuer: alice.agent.issuer,
audience: freewayService,
with: space.did(),
expiration: expiration,
proofs: [], // No proofs to test the error
});
const resultDelegation2 = await alice.capability.access.delegate({
delegations: [egressRecordGatewayDelegation],
});
assert.ok(resultDelegation2.ok);
// 4. freewayService claims the delegation
const freewayDelegations = await freewayService.capability.access.claim();
assert.ok(freewayDelegations.length > 0);
assert.ok(freewayDelegations.some((d) => d.issuer.did() === alice.did() &&
d.audience.did() === freewayService.did() &&
d.capabilities.some((c) => c.can === Space.egressRecord.can && c.with === space.did())));
// 5. Create a random resource to record egress
const car = await randomCAR(128);
// 6. FreewayService attempts to invoke egress/record without having the delegation
try {
await freewayService.capability.space.egressRecord({
space: space.did(),
resource: car.cid.link(),
bytes: car.size,
servedAt: new Date().toISOString(),
}, { proofs: [] });
assert.fail('Expected an error due to missing delegation');
}
catch (error) {
assert.equal(
// @ts-ignore
error.message, `failed ${Space.egressRecord.can} invocation`, 'error message should be the same');
}
},
},
});
Test.test({ SpaceClient });
//# sourceMappingURL=space.test.js.map