diff --git a/packages/capabilities/package.json b/packages/capabilities/package.json index 901631f9e..6f69ce774 100644 --- a/packages/capabilities/package.json +++ b/packages/capabilities/package.json @@ -39,6 +39,10 @@ "types": "./dist/test/helpers/*.d.ts", "import": "./test/helpers/*.js" }, + "./assert": { + "types": "./dist/assert.d.ts", + "import": "./dist/assert.js" + }, "./blob": { "types": "./dist/blob/index.d.ts", "import": "./dist/blob/index.js" @@ -95,7 +99,7 @@ "@ucanto/transport": "catalog:", "@ucanto/validator": "catalog:", "@web3-storage/data-segment": "^5.2.0", - "uint8arrays": "^5.0.3" + "multiformats": "catalog:" }, "devDependencies": { "@arethetypeswrong/cli": "catalog:", diff --git a/packages/capabilities/src/assert.js b/packages/capabilities/src/assert.js new file mode 100644 index 000000000..0ddb08961 --- /dev/null +++ b/packages/capabilities/src/assert.js @@ -0,0 +1,138 @@ +import { capability, URI, Schema, ok } from '@ucanto/validator' +import { and, equal, equalLinkOrDigestContent, equalWith } from './utils.js' + +const linkOrDigest = () => + Schema.link().or(Schema.struct({ digest: Schema.bytes() })) + +export const assert = capability({ + can: 'assert/*', + with: URI.match({ protocol: 'did:' }), +}) + +/** + * Claims that a CID is available at a URL. + */ +export const location = capability({ + can: 'assert/location', + with: URI.match({ protocol: 'did:' }), + nb: Schema.struct({ + /** Blob CID or multihash */ + content: linkOrDigest(), + location: Schema.array(URI), + range: Schema.struct({ + offset: Schema.integer(), + length: Schema.integer().optional(), + }).optional(), + space: Schema.principal().optional(), + }), + derives: (claimed, delegated) => + and(equalWith(claimed, delegated)) || + and(equalLinkOrDigestContent(claimed, delegated)) || + and(equal(claimed.nb.location, delegated.nb.location, 'location')) || + and( + equal(claimed.nb.range?.offset, delegated.nb.range?.offset, 'offset') + ) || + and( + equal(claimed.nb.range?.length, delegated.nb.range?.length, 'length') + ) || + and(equal(claimed.nb.space, delegated.nb.space, 'space')) || + ok({}), +}) + +/** + * Claims that a CID includes the contents claimed in another CID. + */ +export const inclusion = capability({ + can: 'assert/inclusion', + with: URI.match({ protocol: 'did:' }), + nb: Schema.struct({ + /** CAR CID */ + content: linkOrDigest(), + /** CARv2 index CID */ + includes: Schema.link({ version: 1 }), + proof: Schema.link({ version: 1 }).optional(), + }), +}) + +/** + * Claims that a content graph can be found in blob(s) that are identified and + * indexed in the given index CID. + */ +export const index = capability({ + can: 'assert/index', + with: URI.match({ protocol: 'did:' }), + nb: Schema.struct({ + /** DAG root CID */ + content: linkOrDigest(), + /** + * Link to a Content Archive that contains the index. + * e.g. `index/sharded/dag@0.1` + * + * @see https://github.com/storacha/specs/blob/main/w3-index.md + */ + index: Schema.link({ version: 1 }), + }), + derives: (claimed, delegated) => + and(equalWith(claimed, delegated)) || + and(equal(claimed.nb.content, delegated.nb.content, 'content')) || + and(equal(claimed.nb.index, delegated.nb.index, 'index')) || + ok({}), +}) + +/** + * Claims that a CID's graph can be read from the blocks found in parts. + */ +export const partition = capability({ + can: 'assert/partition', + with: URI.match({ protocol: 'did:' }), + nb: Schema.struct({ + /** Content root CID */ + content: linkOrDigest(), + /** CIDs CID */ + blocks: Schema.link({ version: 1 }).optional(), + parts: Schema.array(Schema.link({ version: 1 })), + }), +}) + +/** + * Claims that a CID links to other CIDs. + */ +export const relation = capability({ + can: 'assert/relation', + with: URI.match({ protocol: 'did:' }), + nb: Schema.struct({ + content: linkOrDigest(), + /** CIDs this content links to directly. */ + children: Schema.array(Schema.link()), + /** Parts this content and it's children can be read from. */ + parts: Schema.array( + Schema.struct({ + content: Schema.link({ version: 1 }), + /** CID of contents (CARv2 index) included in this part. */ + includes: Schema.struct({ + content: Schema.link({ version: 1 }), + /** CIDs of parts this index may be found in. */ + parts: Schema.array(Schema.link({ version: 1 })).optional(), + }).optional(), + }) + ), + }), +}) + +/** + * Claim data is referred to by another CID and/or multihash. + * e.g CAR CID & CommP CID + */ +export const equals = capability({ + can: 'assert/equals', + with: URI.match({ protocol: 'did:' }), + nb: Schema.struct({ + content: linkOrDigest(), + equals: Schema.link(), + }), + derives: (claimed, delegated) => + and(equalWith(claimed, delegated)) || + and(equalLinkOrDigestContent(claimed, delegated)) || + and(equal(claimed.nb.equals, delegated.nb.equals, 'equals')) || + ok({}), +}) diff --git a/packages/capabilities/src/index.js b/packages/capabilities/src/index.js index dbbe77296..b2d36a3ae 100644 --- a/packages/capabilities/src/index.js +++ b/packages/capabilities/src/index.js @@ -1,3 +1,4 @@ +import * as Assert from './assert.js' import * as Provider from './provider.js' import * as Space from './space.js' import * as Top from './top.js' @@ -27,6 +28,7 @@ import * as HTTP from './http.js' export { Access, + Assert, Provider, Space, Top, @@ -57,6 +59,13 @@ export { /** @type {import('./types.js').ServiceAbility[]} */ export const abilitiesAsStrings = [ Top.top.can, + Assert.assert.can, + Assert.equals.can, + Assert.inclusion.can, + Assert.index.can, + Assert.location.can, + Assert.partition.can, + Assert.relation.can, Provider.add.can, Space.space.can, Space.info.can, diff --git a/packages/capabilities/src/space/blob.js b/packages/capabilities/src/space/blob.js index 24ba98a56..cda518468 100644 --- a/packages/capabilities/src/space/blob.js +++ b/packages/capabilities/src/space/blob.js @@ -11,7 +11,7 @@ * * @module */ -import { equals as SpaceBlobCapabilities } from 'uint8arrays/equals' +import { equals } from 'multiformats/bytes' import { capability, Schema, fail, ok } from '@ucanto/validator' import { equalBlob, @@ -101,7 +101,7 @@ export const remove = capability({ ) } else if ( delegated.nb.digest && - !SpaceBlobCapabilities(delegated.nb.digest, claimed.nb.digest) + !equals(delegated.nb.digest, claimed.nb.digest) ) { return fail( `Link ${ @@ -167,7 +167,7 @@ export const get = capability({ ) } else if ( delegated.nb.digest && - !SpaceBlobCapabilities(delegated.nb.digest, claimed.nb.digest) + !equals(delegated.nb.digest, claimed.nb.digest) ) { return fail( `Link ${ diff --git a/packages/capabilities/src/types.ts b/packages/capabilities/src/types.ts index 01be04f3e..b0f29b254 100644 --- a/packages/capabilities/src/types.ts +++ b/packages/capabilities/src/types.ts @@ -18,6 +18,7 @@ import { ProofData, uint64, } from '@web3-storage/data-segment' +import * as AssertCaps from './assert.js' import * as SpaceCaps from './space.js' import * as provider from './provider.js' import { top } from './top.js' @@ -126,6 +127,20 @@ export interface DelegationNotFound extends Ucanto.Failure { export type AccessConfirm = InferInvokedCapability +// Assert + +export type Assert = InferInvokedCapability +export type AssertEquals = InferInvokedCapability +export type AssertInclusion = InferInvokedCapability< + typeof AssertCaps.inclusion +> +export type AssertIndex = InferInvokedCapability +export type AssertLocation = InferInvokedCapability +export type AssertPartition = InferInvokedCapability< + typeof AssertCaps.partition +> +export type AssertRelation = InferInvokedCapability + // Usage export type Usage = InferInvokedCapability @@ -985,6 +1000,13 @@ export type ServiceAbility = TupleToUnion export type ServiceAbilityArray = [ Top['can'], + Assert['can'], + AssertEquals['can'], + AssertInclusion['can'], + AssertIndex['can'], + AssertLocation['can'], + AssertPartition['can'], + AssertRelation['can'], ProviderAdd['can'], Space['can'], SpaceInfo['can'], diff --git a/packages/capabilities/src/utils.js b/packages/capabilities/src/utils.js index 76a1b7aef..796fb22e3 100644 --- a/packages/capabilities/src/utils.js +++ b/packages/capabilities/src/utils.js @@ -1,6 +1,7 @@ import * as API from '@ucanto/interface' import { DID, Schema, fail, ok } from '@ucanto/validator' -import { equals } from 'uint8arrays/equals' +import { equals } from 'multiformats/bytes' +import { base58btc } from 'multiformats/bases/base58' // e.g. did:web:storacha.network or did:web:staging.storacha.network export const ProviderDID = DID.match({ method: 'web' }) @@ -59,7 +60,7 @@ export function equal(child, parent, constraint) { return ok({}) } else { return fail( - `Constrain violation: ${child} violates imposed ${constraint} constraint ${parent}` + `Constraint violation: ${child} violates imposed ${constraint} constraint ${parent}` ) } } @@ -89,6 +90,42 @@ export const equalLink = (claimed, delegated) => { } } +/** @param {API.UnknownLink | { digest: Uint8Array }} linkOrDigest */ +const toDigestBytes = (linkOrDigest) => + 'multihash' in linkOrDigest + ? linkOrDigest.multihash.bytes + : linkOrDigest.digest + +/** + * @template {API.ParsedCapability} T + * @param {T} claimed + * @param {T} delegated + * @returns {API.Result<{}, API.Failure>} + */ +export const equalLinkOrDigestContent = (claimed, delegated) => { + if (delegated.nb.content) { + const delegatedBytes = toDigestBytes(delegated.nb.content) + if (!claimed.nb.content) { + return fail( + `Constraint violation: undefined violates imposed content constraint ${base58btc.encode( + delegatedBytes + )}` + ) + } + const claimedBytes = toDigestBytes(claimed.nb.content) + if (!equals(claimedBytes, delegatedBytes)) { + return fail( + `Constraint violation: ${base58btc.encode( + claimedBytes + )} violates imposed content constraint ${base58btc.encode( + delegatedBytes + )}` + ) + } + } + return ok({}) +} + /** * @template {API.ParsedCapability, {blob: { digest: Uint8Array, size: number }}>} T * @param {T} claimed diff --git a/packages/capabilities/test/capabilities/assert.test.js b/packages/capabilities/test/capabilities/assert.test.js new file mode 100644 index 000000000..8b6c08802 --- /dev/null +++ b/packages/capabilities/test/capabilities/assert.test.js @@ -0,0 +1,611 @@ +import assert from 'assert' +import { access } from '@ucanto/validator' +import { Verifier } from '@ucanto/principal' +import * as Assert from '../../src/assert.js' +import * as Top from '../../src/top.js' +import { + alice, + service as w3, + mallory as account, + bob, +} from '../helpers/fixtures.js' +import { + createCborCid, + createCarCid, + validateAuthorization, +} from '../helpers/utils.js' + +const top = async () => + Top.top.delegate({ + issuer: account, + audience: alice, + with: account.did(), + }) + +const assertTop = async () => + Assert.assert.delegate({ + issuer: account, + audience: alice, + with: account.did(), + proofs: [await top()], + }) + +describe('assert capabilities', function () { + it('assert/equals can be derived from *', async () => { + const equals = Assert.equals.invoke({ + issuer: alice, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + equals: await createCarCid('equivalent'), + }, + proofs: [await top()], + }) + + const result = await access(await equals.delegate(), { + capability: Assert.equals, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/equals') + assert.deepEqual(result.ok.capability.nb, { + content: await createCarCid('test'), + equals: await createCarCid('equivalent'), + }) + }) + + it('assert/equals can be derived from assert/*', async () => { + const equals = Assert.equals.invoke({ + issuer: alice, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + equals: await createCarCid('equivalent'), + }, + proofs: [await assertTop()], + }) + + const result = await access(await equals.delegate(), { + capability: Assert.equals, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/equals') + assert.deepEqual(result.ok.capability.nb, { + content: await createCarCid('test'), + equals: await createCarCid('equivalent'), + }) + }) + + it('assert/equals can be derived from assert/* derived from *', async () => { + const assertTop = await Assert.assert.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + proofs: [await top()], + }) + + const equals = Assert.equals.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + equals: await createCarCid('equivalent'), + }, + proofs: [assertTop], + }) + + const result = await access(await equals.delegate(), { + capability: Assert.equals, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/equals') + assert.deepEqual(result.ok.capability.nb, { + content: await createCarCid('test'), + equals: await createCarCid('equivalent'), + }) + }) + + it('assert/equals should fail when escalating content constraint', async () => { + const delegation = await Assert.equals.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + nb: { + content: await createCarCid('test'), + equals: await createCarCid('equivalent'), + }, + proofs: [await top()], + }) + + const equals = Assert.equals.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test2'), + equals: await createCarCid('equivalent'), + }, + proofs: [delegation], + }) + + const result = await access(await equals.delegate(), { + capability: Assert.equals, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + assert.ok(result.error) + assert(result.error.message.includes('violates imposed content constraint')) + }) + + it('assert/equals should fail when escalating equals constraint', async () => { + const delegation = await Assert.equals.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + nb: { + content: await createCarCid('test'), + equals: await createCarCid('equivalent'), + }, + proofs: [await top()], + }) + + const equals = Assert.equals.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + equals: await createCarCid('equivalent2'), + }, + proofs: [delegation], + }) + + const result = await access(await equals.delegate(), { + capability: Assert.equals, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + assert.ok(result.error) + assert(result.error.message.includes('violates imposed equals constraint')) + }) + + it('assert/location can be derived from *', async () => { + const site = Assert.location.invoke({ + issuer: alice, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + }, + proofs: [await top()], + }) + + const result = await access(await site.delegate(), { + capability: Assert.location, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/location') + assert.deepEqual(result.ok.capability.nb, { + content: await createCarCid('test'), + location: ['http://localhost/'], + }) + }) + + it('assert/location can be derived from assert/*', async () => { + const site = Assert.location.invoke({ + issuer: alice, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + }, + proofs: [await assertTop()], + }) + + const result = await access(await site.delegate(), { + capability: Assert.location, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/location') + assert.deepEqual(result.ok.capability.nb, { + content: await createCarCid('test'), + location: ['http://localhost/'], + }) + }) + + it('assert/location can be derived from assert/* derived from *', async () => { + const assertTop = await Assert.assert.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + proofs: [await top()], + }) + + const site = Assert.location.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + }, + proofs: [assertTop], + }) + + const result = await access(await site.delegate(), { + capability: Assert.location, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/location') + assert.deepEqual(result.ok.capability.nb, { + content: await createCarCid('test'), + location: ['http://localhost/'], + }) + }) + + it('assert/location should fail when escalating content constraint', async () => { + const delegation = await Assert.location.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + }, + proofs: [await top()], + }) + + const site = Assert.location.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test2'), + location: ['http://localhost/'], + }, + proofs: [delegation], + }) + + const result = await access(await site.delegate(), { + capability: Assert.location, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + assert.ok(result.error) + assert(result.error.message.includes('violates imposed content constraint')) + }) + + it('assert/location should fail when escalating location constraint', async () => { + const delegation = await Assert.location.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + }, + proofs: [await top()], + }) + + const site = Assert.location.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost:3000/'], + }, + proofs: [delegation], + }) + + const result = await access(await site.delegate(), { + capability: Assert.location, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + assert.ok(result.error) + assert( + result.error.message.includes('violates imposed location constraint') + ) + }) + + it('assert/location should fail when escalating range offset constraint', async () => { + const delegation = await Assert.location.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + range: { offset: 123, length: 456 }, + }, + proofs: [await top()], + }) + + const site = Assert.location.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + range: { offset: 120, length: 456 }, + }, + proofs: [delegation], + }) + + const result = await access(await site.delegate(), { + capability: Assert.location, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + assert.ok(result.error) + assert(result.error.message.includes('violates imposed offset constraint')) + }) + + it('assert/location should fail when escalating range length constraint', async () => { + const delegation = await Assert.location.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + range: { offset: 123, length: 456 }, + }, + proofs: [await top()], + }) + + const site = Assert.location.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCarCid('test'), + location: ['http://localhost/'], + range: { offset: 123, length: 457 }, + }, + proofs: [delegation], + }) + + const result = await access(await site.delegate(), { + capability: Assert.location, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + assert.ok(result.error) + assert(result.error.message.includes('violates imposed length constraint')) + }) + + it('assert/index can be derived from *', async () => { + const index = Assert.index.invoke({ + issuer: alice, + audience: w3, + with: account.did(), + nb: { + content: await createCborCid('test'), + index: await createCarCid('index'), + }, + proofs: [await top()], + }) + + const result = await access(await index.delegate(), { + capability: Assert.index, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/index') + assert.deepEqual(result.ok.capability.nb, { + content: await createCborCid('test'), + index: await createCarCid('index'), + }) + }) + + it('assert/index can be derived from assert/*', async () => { + const index = Assert.index.invoke({ + issuer: alice, + audience: w3, + with: account.did(), + nb: { + content: await createCborCid('test'), + index: await createCarCid('index'), + }, + proofs: [await assertTop()], + }) + + const result = await access(await index.delegate(), { + capability: Assert.index, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/index') + assert.deepEqual(result.ok.capability.nb, { + content: await createCborCid('test'), + index: await createCarCid('index'), + }) + }) + + it('assert/index can be derived from assert/* derived from *', async () => { + const assertTop = await Assert.assert.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + proofs: [await top()], + }) + + const index = Assert.index.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCborCid('test'), + index: await createCarCid('index'), + }, + proofs: [assertTop], + }) + + const result = await access(await index.delegate(), { + capability: Assert.index, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + if (result.error) { + assert.fail(result.error.message) + } + + assert.deepEqual(result.ok.audience.did(), w3.did()) + assert.equal(result.ok.capability.can, 'assert/index') + assert.deepEqual(result.ok.capability.nb, { + content: await createCborCid('test'), + index: await createCarCid('index'), + }) + }) + + it('assert/index should fail when escalating content constraint', async () => { + const delegation = await Assert.index.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + nb: { + content: await createCborCid('test'), + index: await createCarCid('index'), + }, + proofs: [await top()], + }) + + const index = Assert.index.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCborCid('test2'), + index: await createCarCid('index'), + }, + proofs: [delegation], + }) + + const result = await access(await index.delegate(), { + capability: Assert.index, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + assert.ok(result.error) + assert(result.error.message.includes('violates imposed content constraint')) + }) + + it('assert/index should fail when escalating index constraint', async () => { + const delegation = await Assert.index.delegate({ + issuer: alice, + audience: bob, + with: account.did(), + nb: { + content: await createCborCid('test'), + index: await createCarCid('index'), + }, + proofs: [await top()], + }) + + const index = Assert.index.invoke({ + issuer: bob, + audience: w3, + with: account.did(), + nb: { + content: await createCborCid('test'), + index: await createCarCid('index2'), + }, + proofs: [delegation], + }) + + const result = await access(await index.delegate(), { + capability: Assert.index, + principal: Verifier, + authority: w3, + validateAuthorization, + }) + + assert.ok(result.error) + assert(result.error.message.includes('violates imposed index constraint')) + }) +}) diff --git a/packages/capabilities/test/capabilities/provider.test.js b/packages/capabilities/test/capabilities/provider.test.js index 7b50fd8a8..69ef9d17d 100644 --- a/packages/capabilities/test/capabilities/provider.test.js +++ b/packages/capabilities/test/capabilities/provider.test.js @@ -326,7 +326,7 @@ describe('provider/add', function () { validateAuthorization, }) - assert.equal(result.error?.message.includes('Constrain violation'), true) + assert.equal(result.error?.message.includes('Constraint violation'), true) }) it('can not change delegated provider', async () => { diff --git a/packages/upload-api/src/test/handlers/ucan.js b/packages/upload-api/src/test/handlers/ucan.js index 8c2b5a96d..da30fe73f 100644 --- a/packages/upload-api/src/test/handlers/ucan.js +++ b/packages/upload-api/src/test/handlers/ucan.js @@ -358,7 +358,7 @@ export const test = { }) .execute(context.connection) - assert.ok(String(revoke.out.error?.message).match(/Constrain violation/)) + assert.ok(String(revoke.out.error?.message).match(/Constraint violation/)) }, 'ucan/conclude writes a receipt for unknown tasks': async ( assert, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f154fa03..715d43729 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -535,9 +535,9 @@ importers: '@web3-storage/data-segment': specifier: ^5.2.0 version: 5.3.0 - uint8arrays: - specifier: ^5.0.3 - version: 5.1.0 + multiformats: + specifier: 'catalog:' + version: 13.3.3 devDependencies: '@arethetypeswrong/cli': specifier: 'catalog:' @@ -2629,21 +2629,12 @@ packages: resolution: {integrity: sha512-hUMFbDQ/nZN+1TLMi6iMO1QFz9RSV8yGG8S42WFPFma1d7VSNE0eMdJUmwjmtav22/iQkzHMmu6oTSfAvRGS8g==} engines: {node: '>=16'} - '@emnapi/core@1.3.1': - resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==} - '@emnapi/core@1.4.3': resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} - '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} - '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} - '@emnapi/wasi-threads@1.0.1': - resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==} - '@emnapi/wasi-threads@1.0.2': resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} @@ -5977,6 +5968,7 @@ packages: '@walletconnect/ethereum-provider@2.9.2': resolution: {integrity: sha512-eO1dkhZffV1g7vpG19XUJTw09M/bwGUwwhy1mJ3AOPbOSbMPvwiCuRz2Kbtm1g9B0Jv15Dl+TvJ9vTgYF8zoZg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' peerDependencies: '@walletconnect/modal': '>=2' peerDependenciesMeta: @@ -6032,7 +6024,7 @@ packages: '@walletconnect/sign-client@2.9.2': resolution: {integrity: sha512-anRwnXKlR08lYllFMEarS01hp1gr6Q9XUgvacr749hoaC/AwGVlxYFdM8+MyYr3ozlA+2i599kjbK/mAebqdXg==} - deprecated: Reliability and performance greatly improved - please see https://github.com/WalletConnect/walletconnect-monorepo/releases + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/time@1.0.2': resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} @@ -8499,14 +8491,6 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fdir@6.4.4: resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} peerDependencies: @@ -12603,10 +12587,6 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.12: - resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} - engines: {node: '>=12.0.0'} - tinyglobby@0.2.13: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} @@ -14536,34 +14516,18 @@ snapshots: dependencies: '@edge-runtime/primitives': 4.0.5 - '@emnapi/core@1.3.1': - dependencies: - '@emnapi/wasi-threads': 1.0.1 - tslib: 2.8.1 - '@emnapi/core@1.4.3': dependencies: '@emnapi/wasi-threads': 1.0.2 tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.3.1': - dependencies: - tslib: 2.8.1 '@emnapi/runtime@1.4.3': dependencies: tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.0.1': - dependencies: - tslib: 2.8.1 '@emnapi/wasi-threads@1.0.2': dependencies: tslib: 2.8.1 - optional: true '@es-joy/jsdoccomment@0.36.1': dependencies: @@ -15458,7 +15422,7 @@ snapshots: '@img/sharp-wasm32@0.33.5': dependencies: - '@emnapi/runtime': 1.3.1 + '@emnapi/runtime': 1.4.3 optional: true '@img/sharp-win32-ia32@0.33.5': @@ -16247,7 +16211,7 @@ snapshots: nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 - semver: 7.6.3 + semver: 7.7.1 tar: 6.2.1 transitivePeerDependencies: - encoding @@ -16620,8 +16584,8 @@ snapshots: '@napi-rs/wasm-runtime@0.2.4': dependencies: - '@emnapi/core': 1.3.1 - '@emnapi/runtime': 1.3.1 + '@emnapi/core': 1.4.3 + '@emnapi/runtime': 1.4.3 '@tybys/wasm-util': 0.9.0 '@napi-rs/wasm-runtime@0.2.9': @@ -16706,7 +16670,7 @@ snapshots: '@npmcli/fs@4.0.0': dependencies: - semver: 7.6.3 + semver: 7.7.1 '@npmcli/redact@3.1.1': {} @@ -16769,9 +16733,9 @@ snapshots: npm-package-arg: 11.0.1 npm-run-path: 4.0.1 ora: 5.3.0 - semver: 7.6.3 + semver: 7.7.1 source-map-support: 0.5.19 - tinyglobby: 0.2.12 + tinyglobby: 0.2.13 ts-node: 10.9.1(@swc/core@1.11.11(@swc/helpers@0.5.15))(@types/node@22.13.10)(typescript@5.6.3) tsconfig-paths: 4.2.0 tslib: 2.8.1 @@ -16812,9 +16776,9 @@ snapshots: npm-package-arg: 11.0.1 npm-run-path: 4.0.1 ora: 5.3.0 - semver: 7.6.3 + semver: 7.7.1 source-map-support: 0.5.19 - tinyglobby: 0.2.12 + tinyglobby: 0.2.13 ts-node: 10.9.1(@swc/core@1.11.11(@swc/helpers@0.5.15))(@types/node@22.13.10)(typescript@5.8.3) tsconfig-paths: 4.2.0 tslib: 2.8.1 @@ -17348,7 +17312,7 @@ snapshots: '@opentelemetry/core': 1.26.0(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.53.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.27.0 - semver: 7.6.3 + semver: 7.7.1 transitivePeerDependencies: - supports-color @@ -17464,7 +17428,7 @@ snapshots: '@types/shimmer': 1.2.0 import-in-the-middle: 1.13.1 require-in-the-middle: 7.5.2 - semver: 7.6.3 + semver: 7.7.1 shimmer: 1.2.1 transitivePeerDependencies: - supports-color @@ -17476,7 +17440,7 @@ snapshots: '@types/shimmer': 1.2.0 import-in-the-middle: 1.13.1 require-in-the-middle: 7.5.2 - semver: 7.6.3 + semver: 7.7.1 shimmer: 1.2.1 transitivePeerDependencies: - supports-color @@ -18776,7 +18740,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.3 + semver: 7.7.1 tsutils: 3.21.0(typescript@4.9.5) optionalDependencies: typescript: 4.9.5 @@ -18791,7 +18755,7 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.6.3 + semver: 7.7.1 ts-api-utils: 1.4.3(typescript@5.8.3) optionalDependencies: typescript: 5.8.3 @@ -18806,7 +18770,7 @@ snapshots: fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.3 + semver: 7.7.1 ts-api-utils: 2.0.1(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: @@ -18820,7 +18784,7 @@ snapshots: fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.3 + semver: 7.7.1 ts-api-utils: 2.0.1(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: @@ -18836,7 +18800,7 @@ snapshots: '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) eslint: 8.57.1 eslint-scope: 5.1.1 - semver: 7.6.3 + semver: 7.7.1 transitivePeerDependencies: - supports-color - typescript @@ -20487,7 +20451,7 @@ snapshots: builtins@5.1.0: dependencies: - semver: 7.6.3 + semver: 7.7.1 bundle-name@3.0.0: dependencies: @@ -21092,7 +21056,7 @@ snapshots: postcss-modules-scope: 3.2.1(postcss@8.5.1) postcss-modules-values: 4.0.0(postcss@8.5.1) postcss-value-parser: 4.2.0 - semver: 7.6.3 + semver: 7.7.1 optionalDependencies: '@rspack/core': 1.3.6(@swc/helpers@0.5.15) webpack: 5.99.6(@swc/core@1.11.11(@swc/helpers@0.5.15)) @@ -21366,7 +21330,7 @@ snapshots: require-package-name: 2.0.1 resolve: 1.22.10 resolve-from: 5.0.0 - semver: 7.6.3 + semver: 7.7.1 yargs: 16.2.0 transitivePeerDependencies: - supports-color @@ -22025,7 +21989,7 @@ snapshots: eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) @@ -22096,7 +22060,7 @@ snapshots: tinyglobby: 0.2.13 unrs-resolver: 1.7.0 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -22140,7 +22104,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -22206,7 +22170,7 @@ snapshots: escape-string-regexp: 4.0.0 eslint: 8.57.1 esquery: 1.6.0 - semver: 7.6.3 + semver: 7.7.1 spdx-expression-parse: 3.0.1 transitivePeerDependencies: - supports-color @@ -22257,7 +22221,7 @@ snapshots: is-core-module: 2.16.1 minimatch: 3.1.2 resolve: 1.22.10 - semver: 7.6.3 + semver: 7.7.1 eslint-plugin-next-on-pages@1.6.3(eslint@8.57.1): dependencies: @@ -22318,7 +22282,7 @@ snapshots: regexp-tree: 0.1.27 regjsparser: 0.9.1 safe-regex: 2.1.1 - semver: 7.6.3 + semver: 7.7.1 strip-indent: 3.0.0 eslint-scope@5.1.1: @@ -22634,10 +22598,6 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.4.3(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - fdir@6.4.4(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 @@ -22768,7 +22728,7 @@ snapshots: minimatch: 3.1.2 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.6.3 + semver: 7.7.1 tapable: 2.2.1 typescript: 5.8.3 webpack: 5.99.6(@swc/core@1.11.11(@swc/helpers@0.5.15)) @@ -24562,7 +24522,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.6.3 + semver: 7.7.1 make-error@1.3.6: {} @@ -25104,7 +25064,7 @@ snapshots: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.16.1 - semver: 7.6.3 + semver: 7.7.1 validate-npm-package-license: 3.0.4 normalize-path@3.0.0: {} @@ -25115,7 +25075,7 @@ snapshots: dependencies: hosted-git-info: 7.0.2 proc-log: 3.0.0 - semver: 7.6.3 + semver: 7.7.1 validate-npm-package-name: 5.0.1 npm-package-arg@12.0.2: @@ -25196,7 +25156,7 @@ snapshots: open: 8.4.2 ora: 5.3.0 resolve.exports: 2.0.3 - semver: 7.6.3 + semver: 7.7.1 string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.3 @@ -25473,7 +25433,7 @@ snapshots: ky: 1.7.4 registry-auth-token: 5.0.3 registry-url: 6.0.1 - semver: 7.6.3 + semver: 7.7.1 package-manager-manager@0.2.0: dependencies: @@ -25804,7 +25764,7 @@ snapshots: cosmiconfig: 7.1.0 klona: 2.0.6 postcss: 8.5.1 - semver: 7.6.3 + semver: 7.7.1 webpack: 5.99.6(@swc/core@1.11.11(@swc/helpers@0.5.15)) postcss-merge-longhand@6.0.5(postcss@8.5.1): @@ -26686,7 +26646,7 @@ snapshots: dependencies: color: 4.2.3 detect-libc: 2.0.4 - semver: 7.6.3 + semver: 7.7.1 optionalDependencies: '@img/sharp-darwin-arm64': 0.33.5 '@img/sharp-darwin-x64': 0.33.5 @@ -27423,11 +27383,6 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.12: - dependencies: - fdir: 6.4.3(picomatch@4.0.2) - picomatch: 4.0.2 - tinyglobby@0.2.13: dependencies: fdir: 6.4.4(picomatch@4.0.2) @@ -27507,7 +27462,7 @@ snapshots: chalk: 4.1.2 enhanced-resolve: 5.18.1 micromatch: 4.0.8 - semver: 7.6.3 + semver: 7.7.1 source-map: 0.7.4 typescript: 5.8.3 webpack: 5.99.6(@swc/core@1.11.11(@swc/helpers@0.5.15))