diff --git a/.github/workflows/words-to-ignore.txt b/.github/workflows/words-to-ignore.txt index 9a9a40c..efe8b6f 100644 --- a/.github/workflows/words-to-ignore.txt +++ b/.github/workflows/words-to-ignore.txt @@ -186,3 +186,4 @@ Unprocessable satisfiable CORS cURL +lexicographically diff --git a/Readme.md b/Readme.md index 74086d0..949a574 100644 --- a/Readme.md +++ b/Readme.md @@ -2,7 +2,7 @@ This repository contains the specs for the `w3up` protocol and associated subsystems. -The implementations of these specs can be found in +The implementations of these specs can be found in [storacha/upload-service/packages/capabilities](https://github.com/storacha/upload-service/tree/main/packages/capabilities) ## Overview diff --git a/w3-account.md b/w3-account.md index 0c8c4d6..6ea4125 100644 --- a/w3-account.md +++ b/w3-account.md @@ -185,39 +185,188 @@ The attestation signature is denoted by a [Nonstandard `VarSig` signature] with { "/": { "bytes": "gKADAA" } } ``` -## Implementations +## Capabilities -### [`w3 login ` in w3cli](https://github.com/web3-storage/w3cli#w3-login-email) +### `account/usage/*` -- invokes [Account.login](https://github.com/web3-storage/w3cli/blob/fc97ee1b76551bced861f08a4d1e7a31440a6a14/bin.js#L56) which calls `login` on a `@web3-storage/w3up-client` +Capability can only be delegated (not invoked) to allow an audience to derive any `account/usage/*` prefixed capability for the account identified in the `with` field. -### [@web3-storage/w3up-client][] +```ts +type AccountUsage = { + can: 'account/usage/*' + with: AccountDID +} +``` -- login method [returns](https://github.com/web3-storage/w3up/blob/main/packages/w3up-client/src/account.js#L82) an `Account` instance - - [used](https://github.com/web3-storage/w3cli/blob/fc97ee1b76551bced861f08a4d1e7a31440a6a14/account.js#L1) by w3cli +### `account/usage/get` -[@web3-storage/w3up-client]: https://github.com/web3-storage/w3up/tree/main/packages/w3up-client +Capability can be invoked by an agent to retrieve usage data for all, or a specified set, of spaces within an account for a given period. -### [@ucanto/*](https://github.com/web3-storage/ucanto/tree/main) +#### Capability schema -ucanto contains all kinds of tools for building application layer services aligned with the w3-account model. +```ipldsch +type AccountUsageGet struct { + with AccountDID + nb optional AccountUsageGetNB +} -Examples +type AccountUsageGetNB struct { + # Optional list of spaces to filter. If omitted, provider SHOULD aggregate all spaces the account is authorized to include. + spaces optional [SpaceDID] -- [@web3-storage/upload-api](https://github.com/web3-storage/w3up/tree/main/packages/upload-api) - application logic for up.web3.storage - - `createServer` [uses `@ucanto/server`](https://github.com/web3-storage/w3up/blob/main/packages/upload-api/src/lib.js#L29) - - example [invocation handler for `access/delegate`](https://github.com/web3-storage/w3up/blob/main/packages/upload-api/src/access/delegate.js#L17) using `@ucanto/types` -- [@web3-storage/access-client](https://github.com/web3-storage/w3up/tree/main/packages/access-client) - uses `@ucanto/client` to invoke `@web3-storage/upload/api` + # Optional time period (Unix timestamps in seconds). + # If omitted, provider MUST return a current snapshot. + # Semantics: from is inclusive; to is exclusive. + period optional Period +} -### [@web3-storage/did-mailto](https://github.com/web3-storage/w3up/tree/e34eed1fa3d6ef24ce2c01982764f2012dbf30d8/packages/did-mailto) +type Period struct { + from Int # inclusive + to Int # exclusive +} +``` -- `fromEmail` and `toEmail` functions to encoded/decode `did:mailto` from email addresses. -- has `import("@web3-storage/did-mailto/types").DidMailto` typescript type +#### Invocation examples + +> Example: getting the current total usage + +```json +{ + "iss": "did:key:z6MktfnQz8Kcz5nsC65oyXWFXhbbAZQavjg6LYuHOOOagent", + "aud": "did:web:storacha.network", + "att": [ + { + "with": "did:mailto:web.mail:alice", + "can": "account/usage/get" + } + ], + "prf": [ + { "/": "bafyAccountDelegationCid" }, + { "/": "bafySessionAttestationCid" } + ], + "sig": "..." +} +``` -Examples +> Example: filtering a single space and period + +```json +{ + "iss": "did:key:z6MktfnQz8Kcz5nsC65oyXWFXhbbAZQavjg6LYuHOOOagent", + "aud": "did:web:storacha.network", + "att": [ + { + "with": "did:mailto:web.mail:alice", + "can": "account/usage/get", + "nb": { + "spaces": [ + "did:key:z6MkuxVKbEvYzXw89c9ESd3xoZ988MFrCgqT5JF5wtBvuYWe" + ], + "period": { + "from": 1754006400, + "to": 1758111728 + } + } + } + ], + "prf": [ + { "/": "bafyAccountDelegationCid" }, + { "/": "bafySessionAttestationCid" } + ], + "sig": "..." +} +``` -- [@web3-storage/w3cli for account management cli](https://github.com/web3-storage/w3cli/blob/fc97ee1b76551bced861f08a4d1e7a31440a6a14/account.js#L3) -- [@w3up-client](https://github.com/web3-storage/w3up/blob/e34eed1fa3d6ef24ce2c01982764f2012dbf30d8/packages/w3up-client/src/types.ts#L18) +#### Authorization requirements + +The service MUST verify that the Account DID is authorized to access usage data for all requested spaces. If any requested space is not authorized, the entire invocation SHOULD fail with an error message indicating which spaces lack authorization. + +#### Receipt + +```ipldsch +type AccountUsageGetReceipt = { + ran: Link + out: Result +} + +type AccountUsageGetFailure { + message: string +} + +type AccountUsageGetSuccess { + total Int + spaces Record # keys MUST be sorted +} + +type SpaceUsage { + total Int + providers Record # keys MUST be sorted +} + +# UsageData is shared with `usage/report` +type UsageData { + provider ProviderDID + space SpaceDID + period PeriodISO + size SizeDelta + events [UsageEvent] +} + +type SizeDelta { + initial Int + final Int +} + +type UsageEvent { + cause Link + delta Int + receiptAt ISO8601Date +} + +type PeriodISO { + from ISO8601Date + to ISO8601Date +} + +type ISO8601Date = string +type ProviderDID = string +``` + +In all responses, the keys of the `spaces` field in `AccountUsageGetSuccess` and the `providers` field in `SpaceUsage` MUST be sorted lexicographically by their respective key (`SpaceDID`, `ProviderDID`). This ensures that the same query produces the same output each time. + +##### Receipt example (success) + +```json +{ + "total": 5356848797, + "spaces": { + "did:key:z6MkuxVKbEvYzXw89c9ESd3xoZ988MFrCgqT5JF5wtBvuYWe": { + "total": 5356848797, + "providers": { + "did:web:web3.storage": { + "provider": "did:web:web3.storage", + "space": "did:key:z6MkuxVKbEvYzXw89c9ESd3xoZ988MFrCgqT5JF5wtBvuYWe", + "period": { + "from": "2025-07-01T00:00:00.000Z", + "to": "2025-08-12T15:55:11.000Z" + }, + "size": { + "initial": 1035217049, + "final": 5356848797 + }, + "events": [ + { + "cause": { "/": "bafyreiafouslzry3vunc4okazrqpwpuanrq4d3ehb2oatn4vmrhnmj6rzy" }, + "delta": 54394, + "receiptAt": "2025-07-01T14:34:50.947Z" + } + ] + } + } + } + } +} +``` [Protocol Labs]:https://protocol.ai/ [Irakli Gozalishvili]:https://github.com/Gozala