@web3-storage/capabilities
Advanced tools
Comparing version 13.2.1 to 13.3.0
@@ -10,2 +10,5 @@ import type { TupleToUnion } from 'type-fest'; | ||
import { top } from './top.js'; | ||
import * as BlobCaps from './blob.js'; | ||
import * as W3sBlobCaps from './web3.storage/blob.js'; | ||
import * as HTTPCaps from './http.js'; | ||
import * as StoreCaps from './store.js'; | ||
@@ -28,2 +31,5 @@ import * as UploadCaps from './upload.js'; | ||
export type { Unit, PieceLink }; | ||
export interface UCANAwait<Selector extends string = string, Task = unknown> { | ||
'ucan/await': [Selector, Link<Task>]; | ||
} | ||
/** | ||
@@ -340,2 +346,55 @@ * An IPLD Link that has the CAR codec code. | ||
export type UploadGetFailure = UploadNotFound | Ucanto.Failure; | ||
export type HTTPPut = InferInvokedCapability<typeof HTTPCaps.put>; | ||
export type Blob = InferInvokedCapability<typeof BlobCaps.blob>; | ||
export type BlobAdd = InferInvokedCapability<typeof BlobCaps.add>; | ||
export type ServiceBlob = InferInvokedCapability<typeof W3sBlobCaps.blob>; | ||
export type BlobAllocate = InferInvokedCapability<typeof W3sBlobCaps.allocate>; | ||
export type BlobAccept = InferInvokedCapability<typeof W3sBlobCaps.accept>; | ||
export type BlobMultihash = Uint8Array; | ||
export interface BlobModel { | ||
digest: BlobMultihash; | ||
size: number; | ||
} | ||
export interface BlobAddSuccess { | ||
site: UCANAwait<'.out.ok.site'>; | ||
} | ||
export interface BlobSizeOutsideOfSupportedRange extends Ucanto.Failure { | ||
name: 'BlobSizeOutsideOfSupportedRange'; | ||
} | ||
export interface AwaitError extends Ucanto.Failure { | ||
name: 'AwaitError'; | ||
} | ||
export type BlobAddFailure = BlobSizeOutsideOfSupportedRange | AwaitError | StorageGetError | Ucanto.Failure; | ||
export interface BlobListItem { | ||
blob: BlobModel; | ||
insertedAt: ISO8601Date; | ||
} | ||
export interface BlobAllocateSuccess { | ||
size: number; | ||
address?: BlobAddress; | ||
} | ||
export interface BlobAddress { | ||
url: ToString<URL>; | ||
headers: Record<string, string>; | ||
expiresAt: ISO8601Date; | ||
} | ||
export interface NotEnoughStorageCapacity extends Ucanto.Failure { | ||
name: 'NotEnoughStorageCapacity'; | ||
} | ||
export type BlobAllocateFailure = NotEnoughStorageCapacity | Ucanto.Failure; | ||
export interface BlobAcceptSuccess { | ||
site: Link; | ||
} | ||
export interface AllocatedMemoryHadNotBeenWrittenTo extends Ucanto.Failure { | ||
name: 'AllocatedMemoryHadNotBeenWrittenTo'; | ||
} | ||
export type BlobAcceptFailure = AllocatedMemoryHadNotBeenWrittenTo | Ucanto.Failure; | ||
export type StoragePutError = StorageOperationError; | ||
export type StorageGetError = StorageOperationError | RecordNotFound; | ||
export interface StorageOperationError extends Error { | ||
name: 'StorageOperationFailed'; | ||
} | ||
export interface RecordNotFound extends Error { | ||
name: 'RecordNotFound'; | ||
} | ||
export type Store = InferInvokedCapability<typeof StoreCaps.store>; | ||
@@ -411,2 +470,3 @@ export type StoreAdd = InferInvokedCapability<typeof StoreCaps.add>; | ||
export type UCANAttest = InferInvokedCapability<typeof UCANCaps.attest>; | ||
export type UCANConclude = InferInvokedCapability<typeof UCANCaps.conclude>; | ||
export interface Timestamp { | ||
@@ -419,2 +479,3 @@ /** | ||
export type UCANRevokeSuccess = Timestamp; | ||
export type UCANConcludeSuccess = Timestamp; | ||
/** | ||
@@ -449,2 +510,9 @@ * Error is raised when `UCAN` being revoked is not supplied or it's proof chain | ||
export type UCANRevokeFailure = UCANNotFound | InvalidRevocationScope | UnauthorizedRevocation | RevocationsStoreFailure; | ||
/** | ||
* Error is raised when receipt is received for unknown invocation | ||
*/ | ||
export interface ReferencedInvocationNotFound extends Ucanto.Failure { | ||
name: 'ReferencedInvocationNotFound'; | ||
} | ||
export type UCANConcludeFailure = ReferencedInvocationNotFound | Ucanto.Failure; | ||
export type Admin = InferInvokedCapability<typeof AdminCaps.admin>; | ||
@@ -518,2 +586,3 @@ export type AdminUploadInspect = InferInvokedCapability<typeof AdminCaps.upload.inspect>; | ||
UCANAttest['can'], | ||
UCANConclude['can'], | ||
CustomerGet['can'], | ||
@@ -541,3 +610,9 @@ ConsumerHas['can'], | ||
Usage['can'], | ||
UsageReport['can'] | ||
UsageReport['can'], | ||
Blob['can'], | ||
BlobAdd['can'], | ||
ServiceBlob['can'], | ||
BlobAllocate['can'], | ||
BlobAccept['can'], | ||
HTTPPut['can'] | ||
]; | ||
@@ -544,0 +619,0 @@ /** |
@@ -29,2 +29,15 @@ export const UCANLink: Schema.Schema<API.UCANLink<API.Capabilities, API.MulticodecCode<number, string>, API.SigAlg>, unknown>; | ||
/** | ||
* `ucan/conclude` capability represents a receipt using a special UCAN capability. | ||
* | ||
* The UCAN invocation specification defines receipt record, that is cryptographically | ||
* signed description of the invocation output and requested effects. Receipt | ||
* structure is very similar to UCAN except it has no notion of expiry nor it is | ||
* possible to delegate ability to issue receipt to another principal. | ||
*/ | ||
export const conclude: API.TheCapabilityParser<API.CapabilityMatch<"ucan/conclude", `did:${string}:${string}` & `did:${string}` & API.Phantom<{ | ||
protocol: "did:"; | ||
}>, Schema.InferStruct<{ | ||
receipt: Schema.Schema<API.Link<unknown, number, number, 0 | 1>, any>; | ||
}>>>; | ||
/** | ||
* Issued by trusted authority (usually the one handling invocation) that attest | ||
@@ -31,0 +44,0 @@ * that specific UCAN delegation has been considered authentic. |
@@ -11,3 +11,3 @@ /** | ||
} | { | ||
error: Types.Failure; | ||
error: Schema.Error; | ||
ok?: undefined; | ||
@@ -23,3 +23,3 @@ }; | ||
export function equalWith(child: Types.ParsedCapability, parent: Types.ParsedCapability): { | ||
error: Types.Failure; | ||
error: Schema.Error; | ||
ok?: undefined; | ||
@@ -36,3 +36,3 @@ } | { | ||
export function equal(child: unknown, parent: unknown, constraint: string): { | ||
error: Types.Failure; | ||
error: Schema.Error; | ||
ok?: undefined; | ||
@@ -51,16 +51,34 @@ } | { | ||
export function canDelegateAbility(parent: import('@ucanto/interface').Ability, child: import('@ucanto/interface').Ability): boolean; | ||
export const ProviderDID: import("@ucanto/core/schema").Schema<`did:web:${string}` & `did:${string}` & Types.Phantom<{ | ||
export const ProviderDID: Schema.Schema<`did:web:${string}` & `did:${string}` & Types.Phantom<{ | ||
protocol: "did:"; | ||
}>, any>; | ||
export const SpaceDID: import("@ucanto/core/schema").Schema<`did:key:${string}` & `did:${string}` & Types.Phantom<{ | ||
export const SpaceDID: Schema.Schema<`did:key:${string}` & `did:${string}` & Types.Phantom<{ | ||
protocol: "did:"; | ||
}>, any>; | ||
export const AccountDID: import("@ucanto/core/schema").Schema<`did:mailto:${string}` & `did:${string}` & Types.Phantom<{ | ||
export const AccountDID: Schema.Schema<`did:mailto:${string}` & `did:${string}` & Types.Phantom<{ | ||
protocol: "did:"; | ||
}>, any>; | ||
export const Await: Schema.StructSchema<{ | ||
'ucan/await': Schema.Schema<[string, Types.Link<unknown, number, number, 0 | 1>], any>; | ||
}, unknown>; | ||
export function equalLink<T extends Types.ParsedCapability<"store/add" | "store/get" | "store/remove", Types.URI<"did:">, { | ||
link?: Types.Link<unknown, number, number, 0 | 1> | undefined; | ||
}>>(claimed: T, delegated: T): Types.Result<{}, Types.Failure>; | ||
export function equalBlob<T extends Types.ParsedCapability<"blob/add" | "blob/remove" | "web3.storage/blob/allocate" | "web3.storage/blob/accept", Types.URI<"did:">, { | ||
blob: { | ||
digest: Uint8Array; | ||
size: number; | ||
}; | ||
}>>(claimed: T, delegated: T): Types.Result<{}, Types.Failure>; | ||
export function equalBody<T extends Types.ParsedCapability<"http/put", Types.URI<"did:">, { | ||
body: { | ||
digest: Uint8Array; | ||
size: number; | ||
}; | ||
}>>(claimed: T, delegated: T): Types.Result<{}, Types.Failure>; | ||
export function equalContent<T extends Types.ParsedCapability<"blob/add" | "blob/remove" | "blob/allocate" | "blob/accept" | "http/put", Types.URI<"did:">, { | ||
content: Uint8Array; | ||
}>>(claimed: T, delegated: T): Types.Result<{}, Types.Failure>; | ||
export function checkLink(claimed: Types.UnknownLink, imposed: Types.UnknownLink | undefined, at: string): Types.Result<{}, Types.Failure>; | ||
export function and<T>(result: Types.Result<T, Types.Failure>): { | ||
export function and<T>(result: Schema.Result<T, Schema.Error>): { | ||
error: Types.Failure; | ||
@@ -70,3 +88,4 @@ ok?: undefined; | ||
import * as Types from '@ucanto/interface'; | ||
import { Schema } from '@ucanto/validator'; | ||
import { ok } from '@ucanto/validator'; | ||
//# sourceMappingURL=utils.d.ts.map |
{ | ||
"name": "@web3-storage/capabilities", | ||
"version": "13.2.1", | ||
"version": "13.3.0", | ||
"description": "UCAN Capabilities provided by web3.storage", | ||
@@ -48,2 +48,6 @@ "homepage": "https://web3.storage", | ||
}, | ||
"./web3.storage/blob": { | ||
"types": "./dist/src/web3.storage/blob.d.ts", | ||
"import": "./src/web3.storage/blob.js" | ||
}, | ||
"./types": { | ||
@@ -81,3 +85,4 @@ "types": "./dist/src/types.d.ts", | ||
"@ucanto/validator": "^9.0.2", | ||
"@web3-storage/data-segment": "^3.2.0" | ||
"@web3-storage/data-segment": "^3.2.0", | ||
"uint8arrays": "^5.0.3" | ||
}, | ||
@@ -84,0 +89,0 @@ "devDependencies": { |
@@ -22,2 +22,5 @@ import * as Provider from './provider.js' | ||
import * as Usage from './usage.js' | ||
import * as Blob from './blob.js' | ||
import * as W3sBlob from './web3.storage/blob.js' | ||
import * as HTTP from './http.js' | ||
@@ -67,2 +70,3 @@ export { | ||
UCAN.attest.can, | ||
UCAN.conclude.can, | ||
Customer.get.can, | ||
@@ -91,2 +95,8 @@ Consumer.has.can, | ||
Usage.report.can, | ||
Blob.blob.can, | ||
Blob.add.can, | ||
W3sBlob.blob.can, | ||
W3sBlob.allocate.can, | ||
W3sBlob.accept.can, | ||
HTTP.put.can, | ||
] |
117
src/types.ts
@@ -24,2 +24,5 @@ import type { TupleToUnion } from 'type-fest' | ||
import { top } from './top.js' | ||
import * as BlobCaps from './blob.js' | ||
import * as W3sBlobCaps from './web3.storage/blob.js' | ||
import * as HTTPCaps from './http.js' | ||
import * as StoreCaps from './store.js' | ||
@@ -45,2 +48,6 @@ import * as UploadCaps from './upload.js' | ||
export interface UCANAwait<Selector extends string = string, Task = unknown> { | ||
'ucan/await': [Selector, Link<Task>] | ||
} | ||
/** | ||
@@ -444,2 +451,91 @@ * An IPLD Link that has the CAR codec code. | ||
// HTTP | ||
export type HTTPPut = InferInvokedCapability<typeof HTTPCaps.put> | ||
// Blob | ||
export type Blob = InferInvokedCapability<typeof BlobCaps.blob> | ||
export type BlobAdd = InferInvokedCapability<typeof BlobCaps.add> | ||
export type ServiceBlob = InferInvokedCapability<typeof W3sBlobCaps.blob> | ||
export type BlobAllocate = InferInvokedCapability<typeof W3sBlobCaps.allocate> | ||
export type BlobAccept = InferInvokedCapability<typeof W3sBlobCaps.accept> | ||
export type BlobMultihash = Uint8Array | ||
export interface BlobModel { | ||
digest: BlobMultihash | ||
size: number | ||
} | ||
// Blob add | ||
export interface BlobAddSuccess { | ||
site: UCANAwait<'.out.ok.site'> | ||
} | ||
export interface BlobSizeOutsideOfSupportedRange extends Ucanto.Failure { | ||
name: 'BlobSizeOutsideOfSupportedRange' | ||
} | ||
export interface AwaitError extends Ucanto.Failure { | ||
name: 'AwaitError' | ||
} | ||
// TODO: We need Ucanto.Failure because provideAdvanced can't handle errors without it | ||
export type BlobAddFailure = | ||
| BlobSizeOutsideOfSupportedRange | ||
| AwaitError | ||
| StorageGetError | ||
| Ucanto.Failure | ||
export interface BlobListItem { | ||
blob: BlobModel | ||
insertedAt: ISO8601Date | ||
} | ||
// Blob allocate | ||
export interface BlobAllocateSuccess { | ||
size: number | ||
address?: BlobAddress | ||
} | ||
export interface BlobAddress { | ||
url: ToString<URL> | ||
headers: Record<string, string> | ||
expiresAt: ISO8601Date | ||
} | ||
// If user space has not enough space to allocate the blob. | ||
export interface NotEnoughStorageCapacity extends Ucanto.Failure { | ||
name: 'NotEnoughStorageCapacity' | ||
} | ||
export type BlobAllocateFailure = NotEnoughStorageCapacity | Ucanto.Failure | ||
// Blob accept | ||
export interface BlobAcceptSuccess { | ||
// A Link for a delegation with site commiment for the added blob. | ||
site: Link | ||
} | ||
export interface AllocatedMemoryHadNotBeenWrittenTo extends Ucanto.Failure { | ||
name: 'AllocatedMemoryHadNotBeenWrittenTo' | ||
} | ||
// TODO: We should type the store errors and add them here, instead of Ucanto.Failure | ||
export type BlobAcceptFailure = | ||
| AllocatedMemoryHadNotBeenWrittenTo | ||
| Ucanto.Failure | ||
// Storage errors | ||
export type StoragePutError = StorageOperationError | ||
export type StorageGetError = StorageOperationError | RecordNotFound | ||
// Operation on a storage failed with unexpected error | ||
export interface StorageOperationError extends Error { | ||
name: 'StorageOperationFailed' | ||
} | ||
// Record requested not found in the storage | ||
export interface RecordNotFound extends Error { | ||
name: 'RecordNotFound' | ||
} | ||
// Store | ||
@@ -536,2 +632,3 @@ export type Store = InferInvokedCapability<typeof StoreCaps.store> | ||
export type UCANAttest = InferInvokedCapability<typeof UCANCaps.attest> | ||
export type UCANConclude = InferInvokedCapability<typeof UCANCaps.conclude> | ||
@@ -547,2 +644,4 @@ export interface Timestamp { | ||
export type UCANConcludeSuccess = Timestamp | ||
/** | ||
@@ -586,2 +685,11 @@ * Error is raised when `UCAN` being revoked is not supplied or it's proof chain | ||
/** | ||
* Error is raised when receipt is received for unknown invocation | ||
*/ | ||
export interface ReferencedInvocationNotFound extends Ucanto.Failure { | ||
name: 'ReferencedInvocationNotFound' | ||
} | ||
export type UCANConcludeFailure = ReferencedInvocationNotFound | Ucanto.Failure | ||
// Admin | ||
@@ -695,2 +803,3 @@ export type Admin = InferInvokedCapability<typeof AdminCaps.admin> | ||
UCANAttest['can'], | ||
UCANConclude['can'], | ||
CustomerGet['can'], | ||
@@ -718,3 +827,9 @@ ConsumerHas['can'], | ||
Usage['can'], | ||
UsageReport['can'] | ||
UsageReport['can'], | ||
Blob['can'], | ||
BlobAdd['can'], | ||
ServiceBlob['can'], | ||
BlobAllocate['can'], | ||
BlobAccept['can'], | ||
HTTPPut['can'] | ||
] | ||
@@ -721,0 +836,0 @@ |
@@ -5,3 +5,3 @@ /** | ||
import { capability, Schema } from '@ucanto/validator' | ||
import { capability, Schema, ok } from '@ucanto/validator' | ||
import * as API from '@ucanto/interface' | ||
@@ -79,2 +79,30 @@ import { equalWith, equal, and, checkLink } from './utils.js' | ||
/** | ||
* `ucan/conclude` capability represents a receipt using a special UCAN capability. | ||
* | ||
* The UCAN invocation specification defines receipt record, that is cryptographically | ||
* signed description of the invocation output and requested effects. Receipt | ||
* structure is very similar to UCAN except it has no notion of expiry nor it is | ||
* possible to delegate ability to issue receipt to another principal. | ||
*/ | ||
export const conclude = capability({ | ||
can: 'ucan/conclude', | ||
/** | ||
* DID of the principal representing the Conclusion Authority. | ||
* MUST be the DID of the audience of the ran invocation. | ||
*/ | ||
with: Schema.did(), | ||
nb: Schema.struct({ | ||
/** | ||
* CID of the content with the Receipt. | ||
*/ | ||
receipt: Schema.link(), | ||
}), | ||
derives: (claim, from) => | ||
// With field MUST be the same | ||
and(equalWith(claim, from)) || | ||
and(checkLink(claim.nb.receipt, from.nb.receipt, 'nb.receipt')) || | ||
ok({}), | ||
}) | ||
/** | ||
* Issued by trusted authority (usually the one handling invocation) that attest | ||
@@ -81,0 +109,0 @@ * that specific UCAN delegation has been considered authentic. |
101
src/utils.js
@@ -1,5 +0,7 @@ | ||
import { DID, fail, ok } from '@ucanto/validator' | ||
import { DID, Schema, fail, ok } from '@ucanto/validator' | ||
// eslint-disable-next-line no-unused-vars | ||
import * as Types from '@ucanto/interface' | ||
import { equals } from 'uint8arrays/equals' | ||
// e.g. did:web:web3.storage or did:web:staging.web3.storage | ||
@@ -12,2 +14,6 @@ export const ProviderDID = DID.match({ method: 'web' }) | ||
export const Await = Schema.struct({ | ||
'ucan/await': Schema.tuple([Schema.string(), Schema.link()]), | ||
}) | ||
/** | ||
@@ -90,2 +96,95 @@ * Check URI can be 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 | ||
* @param {T} claimed | ||
* @param {T} delegated | ||
* @returns {Types.Result<{}, Types.Failure>} | ||
*/ | ||
export const equalBlob = (claimed, delegated) => { | ||
if (claimed.with !== delegated.with) { | ||
return fail( | ||
`Expected 'with: "${delegated.with}"' instead got '${claimed.with}'` | ||
) | ||
} else if ( | ||
delegated.nb.blob.digest && | ||
!equals(delegated.nb.blob.digest, claimed.nb.blob.digest) | ||
) { | ||
return fail( | ||
`Link ${ | ||
claimed.nb.blob.digest ? `${claimed.nb.blob.digest}` : '' | ||
} violates imposed ${delegated.nb.blob.digest} constraint.` | ||
) | ||
} else if ( | ||
claimed.nb.blob.size !== undefined && | ||
delegated.nb.blob.size !== undefined | ||
) { | ||
return claimed.nb.blob.size > delegated.nb.blob.size | ||
? fail( | ||
`Size constraint violation: ${claimed.nb.blob.size} > ${delegated.nb.blob.size}` | ||
) | ||
: ok({}) | ||
} else { | ||
return ok({}) | ||
} | ||
} | ||
/** | ||
* @template {Types.ParsedCapability<"http/put", Types.URI<'did:'>, {body: { digest: Uint8Array, size: number }}>} T | ||
* @param {T} claimed | ||
* @param {T} delegated | ||
* @returns {Types.Result<{}, Types.Failure>} | ||
*/ | ||
export const equalBody = (claimed, delegated) => { | ||
if (claimed.with !== delegated.with) { | ||
return fail( | ||
`Expected 'with: "${delegated.with}"' instead got '${claimed.with}'` | ||
) | ||
} else if ( | ||
delegated.nb.body.digest && | ||
!equals(delegated.nb.body.digest, claimed.nb.body.digest) | ||
) { | ||
return fail( | ||
`Link ${ | ||
claimed.nb.body.digest ? `${claimed.nb.body.digest}` : '' | ||
} violates imposed ${delegated.nb.body.digest} constraint.` | ||
) | ||
} else if ( | ||
claimed.nb.body.size !== undefined && | ||
delegated.nb.body.size !== undefined | ||
) { | ||
return claimed.nb.body.size > delegated.nb.body.size | ||
? fail( | ||
`Size constraint violation: ${claimed.nb.body.size} > ${delegated.nb.body.size}` | ||
) | ||
: ok({}) | ||
} else { | ||
return ok({}) | ||
} | ||
} | ||
/** | ||
* @template {Types.ParsedCapability<"blob/add"|"blob/remove"|"blob/allocate"|"blob/accept"|"http/put", Types.URI<'did:'>, {content: Uint8Array}>} T | ||
* @param {T} claimed | ||
* @param {T} delegated | ||
* @returns {Types.Result<{}, Types.Failure>} | ||
*/ | ||
export const equalContent = (claimed, delegated) => { | ||
if (claimed.with !== delegated.with) { | ||
return fail( | ||
`Expected 'with: "${delegated.with}"' instead got '${claimed.with}'` | ||
) | ||
} else if ( | ||
delegated.nb.content && | ||
!equals(delegated.nb.content, claimed.nb.content) | ||
) { | ||
return fail( | ||
`Link ${ | ||
claimed.nb.content ? `${claimed.nb.content}` : '' | ||
} violates imposed ${delegated.nb.content} constraint.` | ||
) | ||
} else { | ||
return ok({}) | ||
} | ||
} | ||
/** | ||
* Checks that `claimed` {@link Types.Link} meets an `imposed` constraint. | ||
@@ -92,0 +191,0 @@ * |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
180556
84
4245
7
+ Addeduint8arrays@^5.0.3
+ Addeduint8arrays@5.1.0(transitive)