@metalabel/dfos-protocol 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/PROTOCOL.md CHANGED
@@ -20,15 +20,16 @@ The protocol is not coupled to the DFOS platform. Any system implementing the sa
20
20
 
21
21
  ## Protocol Overview
22
22
 
23
- The DFOS protocol has five components:
23
+ The DFOS protocol has six components:
24
24
 
25
- | Component | Concern |
26
- | --------------------- | ---------------------------------------------------------------------------- |
27
- | **Crypto core** | Identity chains + content chains — Ed25519 signatures, JWS tokens, CID links |
28
- | **Credentials** | Auth tokens (DID-signed JWT) and VC-JWT credentials for authorization |
29
- | **Beacons** | Signed merkle root announcements — periodic commitment over content sets |
30
- | **Countersignatures** | Witness attestationthird-party signatures over existing chain operations |
31
- | **Merkle trees** | SHA-256 binary trees over content IDs inclusion proofs for beacon roots |
25
+ | Component | Concern |
26
+ | --------------------- | ------------------------------------------------------------------------------- |
27
+ | **Crypto core** | Identity chains + content chains — Ed25519 signatures, JWS tokens, CID links |
28
+ | **Credentials** | Auth tokens (DID-signed JWT) and VC-JWT credentials for authorization |
29
+ | **Beacons** | Signed merkle root announcements — periodic commitment over content sets |
30
+ | **Artifacts** | Standalone signed inline documents immutable, CID-addressable structured data |
31
+ | **Countersignatures** | Standalone witness attestation signed references to any CID-addressable op |
32
+ | **Merkle trees** | SHA-256 binary trees over content IDs — inclusion proofs for beacon roots |
32
33
 
33
34
  The crypto core is the trust boundary — everything below it is cryptographically verified. Documents are flat content objects, content-addressed directly: `documentCID = CID(dagCborCanonicalEncode(contentObject))`. What goes inside the content object is application-defined — see the [DFOS Content Model](https://protocol.dfos.com/content-model) for the standard schema library.
34
35
 
@@ -126,6 +127,8 @@ The JWS `typ` header uses protocol-specific values (not IANA media types):
126
127
  | `did:dfos:identity-op` | Identity chain operations |
127
128
  | `did:dfos:content-op` | Content chain operations |
128
129
  | `did:dfos:beacon` | Beacon announcements |
130
+ | `did:dfos:artifact` | Standalone signed inline documents |
131
+ | `did:dfos:countersign` | Standalone witness attestations |
129
132
  | `JWT` | Auth tokens (DID-signed relay authentication) |
130
133
  | `vc+jwt` | VC-JWT credentials (W3C VC Data Model v2) |
131
134
 
@@ -584,15 +587,9 @@ typ: did:dfos:beacon
584
587
  cid: bafyreihholuui7s7ns74iem6ahfxsb472hwogbqd32yrrp5fztc3kxa5qu
585
588
  ```
586
589
 
587
- **Witness countersignature** (key 2 signs the same payload — same CID, different kid):
590
+ **Witness countersignature** (a separate identity countersigns the beacon by CID):
588
591
 
589
- ```
590
- kid: did:dfos:e3vvtck42d4eacdnzvtrn6#key_ez9a874tckr3dv933d3ckd
591
- typ: did:dfos:beacon
592
- cid: bafyreihholuui7s7ns74iem6ahfxsb472hwogbqd32yrrp5fztc3kxa5qu
593
- ```
594
-
595
- Both JWS tokens commit to identical bytes (same CID). The controller/witness distinction is determined at verification time by comparing the `kid` DID to the payload `did`.
592
+ A countersignature is a standalone operation with its own CID and `typ: did:dfos:countersign`. See the [Countersignatures](#countersignatures) section below.
596
593
 
597
594
  Full JWS tokens are in [`examples/beacon.json`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/examples/beacon.json).
598
595
 
@@ -700,22 +697,78 @@ Proof path (from [`examples/merkle-tree.json`](https://github.com/metalabel/dfos
700
697
 
701
698
  ---
702
699
 
700
+ ## Artifacts
701
+
702
+ Artifacts are standalone signed inline documents — immutable, CID-addressable proof plane primitives. Unlike chain operations which extend a sequence, an artifact is a single signed statement with no predecessor or successor.
703
+
704
+ ### Payload
705
+
706
+ ```json
707
+ {
708
+ "version": 1,
709
+ "type": "artifact",
710
+ "did": "did:dfos:...",
711
+ "content": {
712
+ "$schema": "https://schemas.dfos.com/profile/v1",
713
+ "name": "Example"
714
+ },
715
+ "createdAt": "2026-03-25T00:00:00.000Z"
716
+ }
717
+ ```
718
+
719
+ The `content` object MUST include a `$schema` string that identifies the artifact's schema. The schema acts as a discriminator — consumers use it to determine how to interpret the artifact's content. Schema names are free-form strings (no protocol-level registry).
720
+
721
+ ### Constraints
722
+
723
+ - **JWS `typ` header**: `did:dfos:artifact`
724
+ - **Max payload size**: 16384 bytes CBOR-encoded. Protocol constant — not configurable
725
+ - **Immutability**: Once published, an artifact is never updated or replaced
726
+ - **CID-addressable**: Each artifact is addressed by the CID of its CBOR-encoded payload
727
+
728
+ ### Verification
729
+
730
+ 1. JWS signature verification against the signing DID's current key state
731
+ 2. CID integrity — `header.cid` matches the CID computed from dag-cbor canonical encoding the raw payload
732
+ 3. Payload schema validation — `version`, `type: "artifact"`, `did`, `content` with `$schema`, `createdAt`
733
+ 4. Size limit — CBOR-encoded payload does not exceed 16384 bytes
734
+
735
+ ---
736
+
703
737
  ## Countersignatures
704
738
 
705
- A countersignature is a witness attestation — a third-party identity signing the same CID-committed bytes as an existing chain operation. Countersignatures use the same JWS format and `typ` (`did:dfos:content-op`) as the original operation.
739
+ A countersignature is a standalone witness attestation — a signed statement that references a target operation by CID. Each countersignature has its own `typ` header (`did:dfos:countersign`), its own payload, and its own CID distinct from the target.
740
+
741
+ ### Payload
742
+
743
+ ```json
744
+ {
745
+ "version": 1,
746
+ "type": "countersign",
747
+ "did": "did:dfos:witness...",
748
+ "targetCID": "bafy...",
749
+ "createdAt": "2026-03-25T00:00:00.000Z"
750
+ }
751
+ ```
706
752
 
707
- ### Discrimination Rule
753
+ The `did` field is the witness identity — the DID signing the attestation. The `targetCID` references the operation being attested to.
708
754
 
709
- The protocol distinguishes author operations from countersignatures by comparing the `kid` DID in the JWS header to the `did` field in the operation payload:
755
+ ### Properties
710
756
 
711
- - **`kid` DID === payload `did`** → author operation (chain operation)
712
- - **`kid` DID !== payload `did`** witness countersignature
757
+ - **JWS `typ` header**: `did:dfos:countersign`
758
+ - **Own CID**: Each countersignature has its own CID derived from its own payload, distinct from the target. This avoids the ambiguity of multiple JWS tokens sharing the same CID
759
+ - **Stateless verification**: Signature + CID integrity + payload schema. No chain state required to verify the cryptographic validity of a countersignature
760
+ - **Composable**: The `targetCID` can reference any CID-addressable operation — content ops, beacons, artifacts, identity ops, even other countersignatures
761
+ - **Immutable**: Once published, a countersignature is permanent
713
762
 
714
- ### Semantics
763
+ ### Verification
715
764
 
716
- A countersignature proves that a witness identity has seen and attested to a specific operation. The witness signs the exact same payload (same CID), but with their own key. The countersignature's JWS header will contain the witness's `kid` (their DID URL), while the payload's `did` field remains the original author's DID.
765
+ 1. Decode JWS, verify `typ` is `did:dfos:countersign`
766
+ 2. Parse and validate countersign payload (`version`, `type: "countersign"`, `did`, `targetCID`, `createdAt`)
767
+ 3. Verify the `kid` DID matches the payload `did` (the witness must sign with their own key)
768
+ 4. CID integrity — `header.cid` matches the CID computed from dag-cbor canonical encoding the raw payload
769
+ 5. Verify EdDSA JWS signature against the witness's public key
717
770
 
718
- Countersignatures are not part of the chain they do not have `previousOperationCID` links and do not affect chain state. They are auxiliary attestations stored alongside chain operations.
771
+ Relay-level semantic checks (target exists, witness author, deduplication) are enforcement concerns, not protocol verification.
719
772
 
720
773
  ---
721
774
 
@@ -741,7 +794,7 @@ Countersignatures are not part of the chain — they do not have `previousOperat
741
794
  2. First op must be `type: "create"` — the signer is the chain creator
742
795
  3. For each subsequent op: verify `previousOperationCID` matches, verify `createdAt` increasing
743
796
  4. Derive the operation CID via dag-cbor canonical encoding. Verify `header.cid` matches the derived CID.
744
- 5. Verify the `kid` DID matches the payload `did` field (mismatches indicate a countersignature, not a chain operation)
797
+ 5. Verify the `kid` DID matches the payload `did` field
745
798
  6. Resolve `kid` via external key resolver (caller provides)
746
799
  7. Verify EdDSA JWS signature
747
800
  8. If `enforceAuthorization` is enabled and the signer DID differs from the chain creator: verify the `authorization` field contains a valid `DFOSContentWrite` VC-JWT issued by the creator DID, with `sub` matching the signer, not expired at `op.createdAt`, and `contentId` (if present) matching this chain
@@ -1077,7 +1130,7 @@ Given the artifacts above, verify:
1077
1130
 
1078
1131
  ## Source and Verification
1079
1132
 
1080
- All source lives in [`packages/dfos-protocol/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol) — self-contained, zero monorepo dependencies. 293 checks across 5 languages.
1133
+ All source lives in [`packages/dfos-protocol/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol) — self-contained, zero monorepo dependencies. 266 checks across 5 languages.
1081
1134
 
1082
1135
  - [`crypto/ed25519`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/crypto/ed25519.ts) — `createNewEd25519Keypair`, `importEd25519Keypair`, `signPayloadEd25519`, `isValidEd25519Signature`
1083
1136
  - [`crypto/jws`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/crypto/jws.ts) — `createJws`, `verifyJws`, `decodeJwsUnsafe`
@@ -1086,11 +1139,12 @@ All source lives in [`packages/dfos-protocol/`](https://github.com/metalabel/dfo
1086
1139
  - [`crypto/multiformats`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/crypto/multiformats.ts) — `dagCborCanonicalEncode`, `dagCborCanonicalEqual`
1087
1140
  - [`crypto/id`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/crypto/id.ts) — `generateId`, `generateIdNoPrefix`, `isValidId`
1088
1141
  - [`chain/multikey`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/multikey.ts) — `encodeEd25519Multikey`, `decodeMultikey`
1089
- - [`chain/schemas`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/schemas.ts) — `IdentityOperation`, `ContentOperation`, `MultikeyPublicKey`, `VerifiedIdentity`
1090
- - [`chain/identity-chain`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/identity-chain.ts) — `signIdentityOperation`, `verifyIdentityChain`
1091
- - [`chain/content-chain`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/content-chain.ts) — `signContentOperation`, `verifyContentChain`
1142
+ - [`chain/schemas`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/schemas.ts) — `IdentityOperation`, `ContentOperation`, `ArtifactPayload`, `CountersignPayload`, `MultikeyPublicKey`, `VerifiedIdentity`
1143
+ - [`chain/identity-chain`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/identity-chain.ts) — `signIdentityOperation`, `verifyIdentityChain`, `verifyIdentityExtensionFromTrustedState`
1144
+ - [`chain/content-chain`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/content-chain.ts) — `signContentOperation`, `verifyContentChain`, `verifyContentExtensionFromTrustedState`
1092
1145
  - [`chain/derivation`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/derivation.ts) — `deriveChainIdentifier`, `deriveContentId`
1093
1146
  - [`chain/beacon`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/beacon.ts) — `signBeacon`, `verifyBeacon`
1147
+ - [`chain/artifact`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/artifact.ts) — `signArtifact`, `verifyArtifact`
1094
1148
  - [`chain/countersign`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/chain/countersign.ts) — `signCountersignature`, `verifyCountersignature`
1095
1149
  - [`credentials/auth-token`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/credentials/auth-token.ts) — `createAuthToken`, `verifyAuthToken`
1096
1150
  - [`credentials/credential`](https://github.com/metalabel/dfos/blob/main/packages/dfos-protocol/src/credentials/credential.ts) — `createCredential`, `verifyCredential`, `decodeCredentialUnsafe`
@@ -1102,16 +1156,17 @@ All source lives in [`packages/dfos-protocol/`](https://github.com/metalabel/dfo
1102
1156
 
1103
1157
  - [DID Method: `did:dfos`](https://protocol.dfos.com/did-method) — W3C DID method specification for identity chains
1104
1158
  - [Content Model](https://protocol.dfos.com/content-model) — Standard content schemas (post, profile) for document content objects
1159
+ - [Web Relay](https://protocol.dfos.com/web-relay) — HTTP relay specification for ingestion, state, and content plane
1105
1160
 
1106
1161
  ### Cross-Language Verification
1107
1162
 
1108
1163
  | Language | Tests | Source |
1109
1164
  | ---------- | ----- | ---------------------------------------------------------------------------------------------------- |
1110
- | TypeScript | 190 | [`tests/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/tests) |
1111
- | Python | 59 | [`verify/python/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/python) |
1112
- | Go | 15 | [`verify/go/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/go) |
1113
- | Rust | 15 | [`verify/rust/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/rust) |
1114
- | Swift | 14 | [`verify/swift/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/swift) |
1165
+ | TypeScript | 224 | [`tests/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/tests) |
1166
+ | Go | 18 | [`verify/go/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/go) |
1167
+ | Rust | 18 | [`verify/rust/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/rust) |
1168
+ | Python | 3 | [`verify/python/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/python) |
1169
+ | Swift | 3 | [`verify/swift/`](https://github.com/metalabel/dfos/tree/main/packages/dfos-protocol/verify/swift) |
1115
1170
 
1116
1171
  ---
1117
1172
 
package/README.md CHANGED
@@ -53,6 +53,19 @@ The `examples/` directory contains deterministic reference fixtures that can be
53
53
  - `merkle-tree.json` — 5 content IDs → sorted tree → root, with inclusion proof
54
54
  - `beacon.json` — signed merkle root announcement with witness countersignature
55
55
 
56
+ ## Cross-Language Verification
57
+
58
+ The `verify/` directory contains independent verification suites that re-derive CIDs and verify signatures from the reference fixtures — proving protocol correctness across implementations:
59
+
60
+ | Language | Path | Status |
61
+ | -------- | ---------------- | ------- |
62
+ | Go | `verify/go/` | Passing |
63
+ | Python | `verify/python/` | Passing |
64
+ | Rust | `verify/rust/` | Passing |
65
+ | Swift | `verify/swift/` | Passing |
66
+
67
+ Each suite uses only its language's native Ed25519, dag-cbor, and multihash implementations — no shared code with the TypeScript reference.
68
+
56
69
  ## License
57
70
 
58
71
  MIT
@@ -113,6 +113,28 @@ declare const BeaconPayload: z.ZodObject<{
113
113
  createdAt: z.ZodISODateTime;
114
114
  }, z.core.$strict>;
115
115
  type BeaconPayload = z.infer<typeof BeaconPayload>;
116
+ /** Max CBOR-encoded payload size for artifacts (bytes) — protocol constant */
117
+ declare const MAX_ARTIFACT_PAYLOAD_SIZE = 16384;
118
+ /** Artifact: standalone signed inline document, immutable, CID-addressable */
119
+ declare const ArtifactPayload: z.ZodObject<{
120
+ version: z.ZodLiteral<1>;
121
+ type: z.ZodLiteral<"artifact">;
122
+ did: z.ZodString;
123
+ content: z.ZodObject<{
124
+ $schema: z.ZodString;
125
+ }, z.core.$catchall<z.ZodUnknown>>;
126
+ createdAt: z.ZodISODateTime;
127
+ }, z.core.$strict>;
128
+ type ArtifactPayload = z.infer<typeof ArtifactPayload>;
129
+ /** Countersign: standalone witness attestation referencing a target operation by CID */
130
+ declare const CountersignPayload: z.ZodObject<{
131
+ version: z.ZodLiteral<1>;
132
+ type: z.ZodLiteral<"countersign">;
133
+ did: z.ZodString;
134
+ targetCID: z.ZodString;
135
+ createdAt: z.ZodISODateTime;
136
+ }, z.core.$strict>;
137
+ type CountersignPayload = z.infer<typeof CountersignPayload>;
116
138
 
117
139
  /** Ed25519 public key multicodec value */
118
140
  declare const ED25519_PUB_MULTICODEC = 237;
@@ -172,6 +194,33 @@ declare const verifyIdentityChain: (input: {
172
194
  didPrefix: string;
173
195
  log: string[];
174
196
  }) => Promise<VerifiedIdentity>;
197
+ /**
198
+ * Verify a single new operation against already-verified identity state
199
+ *
200
+ * The caller guarantees that `currentState` was produced by a correct prior
201
+ * verification (full chain replay or a chain of trusted extensions from a
202
+ * verified genesis). This function performs one signature verification and one
203
+ * state transition — constant time regardless of chain length.
204
+ *
205
+ * Note: key-ID consistency across the full chain history is NOT checked here.
206
+ * That invariant is established during genesis verification and maintained by
207
+ * the protocol's key consistency rules. Periodic full re-verification can
208
+ * audit this property.
209
+ */
210
+ declare const verifyIdentityExtensionFromTrustedState: (input: {
211
+ /** Previously verified identity state */
212
+ currentState: VerifiedIdentity;
213
+ /** CID of the most recent operation in the chain */
214
+ headCID: string;
215
+ /** createdAt timestamp of the most recent operation */
216
+ lastCreatedAt: string;
217
+ /** The new JWS operation to verify */
218
+ newOp: string;
219
+ }) => Promise<{
220
+ state: VerifiedIdentity;
221
+ operationCID: string;
222
+ createdAt: string;
223
+ }>;
175
224
 
176
225
  interface VerifiedContentChain {
177
226
  /** Content identifier — bare 22-char hash derived from genesis CID */
@@ -227,6 +276,29 @@ declare const verifyContentChain: (input: {
227
276
  */
228
277
  enforceAuthorization?: boolean;
229
278
  }) => Promise<VerifiedContentChain>;
279
+ /**
280
+ * Verify a single new content operation against already-verified chain state
281
+ *
282
+ * Same trust model as verifyIdentityExtensionFromTrustedState — the caller
283
+ * guarantees `currentState` was correctly verified. One signature verification,
284
+ * one key resolution, one state transition.
285
+ */
286
+ declare const verifyContentExtensionFromTrustedState: (input: {
287
+ /** Previously verified content chain state */
288
+ currentState: VerifiedContentChain;
289
+ /** createdAt timestamp of the most recent operation */
290
+ lastCreatedAt: string;
291
+ /** The new JWS operation to verify */
292
+ newOp: string;
293
+ /** Resolve a kid (DID URL) to the raw Ed25519 public key bytes */
294
+ resolveKey: (kid: string) => Promise<Uint8Array>;
295
+ /** Enforce creator-sovereignty authorization (see verifyContentChain) */
296
+ enforceAuthorization?: boolean;
297
+ }) => Promise<{
298
+ state: VerifiedContentChain;
299
+ operationCID: string;
300
+ createdAt: string;
301
+ }>;
230
302
 
231
303
  /**
232
304
  * Sign a beacon announcement as a JWS
@@ -253,57 +325,60 @@ declare const verifyBeacon: (input: {
253
325
  now?: number;
254
326
  }) => Promise<VerifiedBeacon>;
255
327
 
328
+ interface VerifiedCountersignature {
329
+ /** CID of this countersign operation (distinct from the target) */
330
+ countersignCID: string;
331
+ /** The witness DID (payload.did — the DID that signed this attestation) */
332
+ witnessDID: string;
333
+ /** The CID being attested to */
334
+ targetCID: string;
335
+ }
256
336
  /**
257
- * Sign an existing content operation as a countersignature (witness JWS)
258
- *
259
- * The witness signs the same payload as the author, producing a different
260
- * JWS token with their own kid. The CID is identical because the payload
261
- * is identical.
337
+ * Sign a countersignature attesting to a target operation by CID
262
338
  */
263
339
  declare const signCountersignature: (input: {
264
- /** The original operation payload (must include did of the author) */
265
- operationPayload: ContentOperation;
266
- /** Witness signer */
340
+ payload: CountersignPayload;
267
341
  signer: Signer;
268
- /** Witness kid — DID URL of the witness (must differ from payload.did) */
269
342
  kid: string;
270
343
  }) => Promise<{
271
344
  jwsToken: string;
272
- operationCID: string;
345
+ countersignCID: string;
273
346
  }>;
274
- interface VerifiedCountersignature {
275
- operationCID: string;
276
- /** The DID that authored the operation (payload.did) */
277
- authorDID: string;
278
- /** The DID that witnessed the operation (kid DID) */
279
- witnessDID: string;
280
- }
281
347
  /**
282
- * Verify a countersignature JWS against an expected operation CID
348
+ * Verify a countersignature JWS stateless verification
283
349
  *
284
- * Checks: valid signature, CID matches, kid DID differs from payload did
350
+ * Checks: valid signature, CID integrity, payload schema. Does NOT check
351
+ * whether the target exists or whether the witness differs from the target
352
+ * author — those are relay-level semantic checks.
285
353
  */
286
354
  declare const verifyCountersignature: (input: {
287
355
  jwsToken: string;
288
- expectedCID: string;
289
356
  resolveKey: (kid: string) => Promise<Uint8Array>;
290
357
  }) => Promise<VerifiedCountersignature>;
291
- interface VerifiedBeaconCountersignature {
292
- beaconCID: string;
293
- /** The DID that controls the beacon (payload.did) */
294
- controllerDID: string;
295
- /** The DID that witnessed the beacon (kid DID) */
296
- witnessDID: string;
358
+
359
+ interface VerifiedArtifact {
360
+ payload: ArtifactPayload;
361
+ artifactCID: string;
297
362
  }
298
363
  /**
299
- * Verify a beacon countersignature JWS against an expected beacon CID
364
+ * Sign an artifact as a JWS
300
365
  *
301
- * Checks: valid signature, CID matches, kid DID differs from payload did
366
+ * Enforces the protocol size limit on the CBOR-encoded payload.
367
+ */
368
+ declare const signArtifact: (input: {
369
+ payload: ArtifactPayload;
370
+ signer: Signer;
371
+ kid: string;
372
+ }) => Promise<{
373
+ jwsToken: string;
374
+ artifactCID: string;
375
+ }>;
376
+ /**
377
+ * Verify an artifact JWS — signature, CID, payload schema, size limit
302
378
  */
303
- declare const verifyBeaconCountersignature: (input: {
379
+ declare const verifyArtifact: (input: {
304
380
  jwsToken: string;
305
- expectedCID: string;
306
381
  resolveKey: (kid: string) => Promise<Uint8Array>;
307
- }) => Promise<VerifiedBeaconCountersignature>;
382
+ }) => Promise<VerifiedArtifact>;
308
383
 
309
- export { BeaconPayload, ContentOperation, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, MultikeyPublicKey, type Signer, type VerifiedBeacon, type VerifiedBeaconCountersignature, type VerifiedContentChain, type VerifiedCountersignature, VerifiedIdentity, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, signBeacon, signContentOperation, signCountersignature, signIdentityOperation, verifyBeacon, verifyBeaconCountersignature, verifyContentChain, verifyCountersignature, verifyIdentityChain };
384
+ export { ArtifactPayload, BeaconPayload, ContentOperation, CountersignPayload, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, MAX_ARTIFACT_PAYLOAD_SIZE, MultikeyPublicKey, type Signer, type VerifiedArtifact, type VerifiedBeacon, type VerifiedContentChain, type VerifiedCountersignature, VerifiedIdentity, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, signArtifact, signBeacon, signContentOperation, signCountersignature, signIdentityOperation, verifyArtifact, verifyBeacon, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyIdentityChain, verifyIdentityExtensionFromTrustedState };
@@ -1,46 +1,58 @@
1
1
  import {
2
+ ArtifactPayload,
2
3
  BeaconPayload,
3
4
  ContentOperation,
5
+ CountersignPayload,
4
6
  ED25519_PRIV_MULTICODEC,
5
7
  ED25519_PUB_MULTICODEC,
6
8
  IdentityOperation,
9
+ MAX_ARTIFACT_PAYLOAD_SIZE,
7
10
  MultikeyPublicKey,
8
11
  VerifiedIdentity,
9
12
  decodeMultikey,
10
13
  deriveChainIdentifier,
11
14
  deriveContentId,
12
15
  encodeEd25519Multikey,
16
+ signArtifact,
13
17
  signBeacon,
14
18
  signContentOperation,
15
19
  signCountersignature,
16
20
  signIdentityOperation,
21
+ verifyArtifact,
17
22
  verifyBeacon,
18
- verifyBeaconCountersignature,
19
23
  verifyContentChain,
24
+ verifyContentExtensionFromTrustedState,
20
25
  verifyCountersignature,
21
- verifyIdentityChain
22
- } from "../chunk-GEVJ3SEV.js";
26
+ verifyIdentityChain,
27
+ verifyIdentityExtensionFromTrustedState
28
+ } from "../chunk-QKHP7UVL.js";
23
29
  import "../chunk-CZSEEZLL.js";
24
30
  import "../chunk-ZXXP5W5N.js";
25
31
  export {
32
+ ArtifactPayload,
26
33
  BeaconPayload,
27
34
  ContentOperation,
35
+ CountersignPayload,
28
36
  ED25519_PRIV_MULTICODEC,
29
37
  ED25519_PUB_MULTICODEC,
30
38
  IdentityOperation,
39
+ MAX_ARTIFACT_PAYLOAD_SIZE,
31
40
  MultikeyPublicKey,
32
41
  VerifiedIdentity,
33
42
  decodeMultikey,
34
43
  deriveChainIdentifier,
35
44
  deriveContentId,
36
45
  encodeEd25519Multikey,
46
+ signArtifact,
37
47
  signBeacon,
38
48
  signContentOperation,
39
49
  signCountersignature,
40
50
  signIdentityOperation,
51
+ verifyArtifact,
41
52
  verifyBeacon,
42
- verifyBeaconCountersignature,
43
53
  verifyContentChain,
54
+ verifyContentExtensionFromTrustedState,
44
55
  verifyCountersignature,
45
- verifyIdentityChain
56
+ verifyIdentityChain,
57
+ verifyIdentityExtensionFromTrustedState
46
58
  };
@@ -104,6 +104,23 @@ var BeaconPayload = z.strictObject({
104
104
  merkleRoot: z.string().regex(/^[0-9a-f]{64}$/),
105
105
  createdAt: Iso8601
106
106
  });
107
+ var MAX_SCHEMA = 256;
108
+ var MAX_ARTIFACT_PAYLOAD_SIZE = 16384;
109
+ var ArtifactContent = z.object({ $schema: z.string().max(MAX_SCHEMA) }).catchall(z.unknown());
110
+ var ArtifactPayload = z.strictObject({
111
+ version: z.literal(1),
112
+ type: z.literal("artifact"),
113
+ did: z.string().max(MAX_DID),
114
+ content: ArtifactContent,
115
+ createdAt: Iso8601
116
+ });
117
+ var CountersignPayload = z.strictObject({
118
+ version: z.literal(1),
119
+ type: z.literal("countersign"),
120
+ did: z.string().max(MAX_DID),
121
+ targetCID: CIDString,
122
+ createdAt: Iso8601
123
+ });
107
124
 
108
125
  // src/chain/multikey.ts
109
126
  import { base58btc } from "multiformats/bases/base58";
@@ -299,6 +316,78 @@ var verifyIdentityChain = async (input) => {
299
316
  controllerKeys: state.controllerKeys
300
317
  };
301
318
  };
319
+ var verifyIdentityExtensionFromTrustedState = async (input) => {
320
+ const { currentState, headCID, lastCreatedAt, newOp } = input;
321
+ if (currentState.isDeleted) {
322
+ throw new Error("cannot extend a deleted identity");
323
+ }
324
+ const decoded = decodeJwsUnsafe(newOp);
325
+ if (!decoded) throw new Error("failed to decode JWS");
326
+ const result = IdentityOperation.safeParse(decoded.payload);
327
+ if (!result.success) {
328
+ const messages = result.error.issues.map((e) => e.message).join(", ");
329
+ throw new Error(messages);
330
+ }
331
+ const op = result.data;
332
+ if (decoded.header.typ !== "did:dfos:identity-op") {
333
+ throw new Error(`invalid typ: ${decoded.header.typ}`);
334
+ }
335
+ if (op.type === "create") {
336
+ throw new Error("extension cannot be a create operation");
337
+ }
338
+ if (op.previousOperationCID !== headCID) {
339
+ throw new Error("previousCID is incorrect");
340
+ }
341
+ if (op.createdAt <= lastCreatedAt) {
342
+ throw new Error("createdAt must be after last op");
343
+ }
344
+ const encoded = await dagCborCanonicalEncode(op);
345
+ const operationCID = encoded.cid.toString();
346
+ if (!decoded.header.cid) throw new Error("missing cid in protected header");
347
+ if (decoded.header.cid !== operationCID) throw new Error("cid mismatch in protected header");
348
+ const kid = decoded.header.kid;
349
+ if (!kid.includes("#")) {
350
+ throw new Error("non-genesis op kid must be DID URL, got bare key ID");
351
+ }
352
+ const hashIdx = kid.indexOf("#");
353
+ const signingKeyId = kid.substring(hashIdx + 1);
354
+ const kidDid = kid.substring(0, hashIdx);
355
+ if (kidDid !== currentState.did) {
356
+ throw new Error("kid DID does not match identity DID");
357
+ }
358
+ const signingKey = currentState.controllerKeys.find((k) => k.id === signingKeyId);
359
+ if (!signingKey) {
360
+ throw new Error(`kid references unknown key: ${signingKeyId}`);
361
+ }
362
+ const { keyBytes } = decodeMultikey(signingKey.publicKeyMultibase);
363
+ try {
364
+ verifyJws({ token: newOp, publicKey: keyBytes });
365
+ } catch {
366
+ throw new Error("invalid signature");
367
+ }
368
+ if (op.type === "update") {
369
+ [op.authKeys, op.assertKeys, op.controllerKeys].forEach((keys) => {
370
+ const set = new Set(keys.map((k) => k.id));
371
+ if (set.size !== keys.length) {
372
+ throw new Error("cannot repeat key ids in same usage");
373
+ }
374
+ });
375
+ }
376
+ const newState = op.type === "update" ? {
377
+ did: currentState.did,
378
+ isDeleted: false,
379
+ authKeys: op.authKeys,
380
+ assertKeys: op.assertKeys,
381
+ controllerKeys: op.controllerKeys
382
+ } : {
383
+ did: currentState.did,
384
+ isDeleted: true,
385
+ authKeys: currentState.authKeys,
386
+ assertKeys: currentState.assertKeys,
387
+ controllerKeys: currentState.controllerKeys
388
+ };
389
+ return { state: newState, operationCID, createdAt: op.createdAt };
390
+ };
302
391
 
303
392
  // src/chain/content-chain.ts
304
393
  var signContentOperation = async (input) => {
@@ -447,6 +536,98 @@ var verifyContentChain = async (input) => {
447
536
  creatorDID: state.creatorDID
448
537
  };
449
538
  };
539
+ var verifyContentExtensionFromTrustedState = async (input) => {
540
+ const { currentState, lastCreatedAt, newOp, resolveKey } = input;
541
+ if (currentState.isDeleted) {
542
+ throw new Error("cannot extend a deleted chain");
543
+ }
544
+ const decoded = decodeJwsUnsafe(newOp);
545
+ if (!decoded) throw new Error("failed to decode JWS");
546
+ const result = ContentOperation.safeParse(decoded.payload);
547
+ if (!result.success) {
548
+ const messages = result.error.issues.map((e) => e.message).join(", ");
549
+ throw new Error(messages);
550
+ }
551
+ const op = result.data;
552
+ if (decoded.header.typ !== "did:dfos:content-op") {
553
+ throw new Error(`invalid typ: ${decoded.header.typ}`);
554
+ }
555
+ if (op.type === "create") {
556
+ throw new Error("extension cannot be a create operation");
557
+ }
558
+ if (op.previousOperationCID !== currentState.headCID) {
559
+ throw new Error("previousOperationCID is incorrect");
560
+ }
561
+ if (op.createdAt <= lastCreatedAt) {
562
+ throw new Error("createdAt must be after last op");
563
+ }
564
+ const kid = decoded.header.kid;
565
+ const hashIdx = kid.indexOf("#");
566
+ if (hashIdx < 0) throw new Error("kid must be a DID URL");
567
+ const kidDid = kid.substring(0, hashIdx);
568
+ if (kidDid !== op.did) {
569
+ throw new Error("kid DID does not match operation did");
570
+ }
571
+ const publicKey = await resolveKey(kid);
572
+ try {
573
+ verifyJws({ token: newOp, publicKey });
574
+ } catch {
575
+ throw new Error("invalid signature");
576
+ }
577
+ if (op.did !== currentState.creatorDID && input.enforceAuthorization) {
578
+ const authorization = op.authorization;
579
+ if (!authorization) {
580
+ throw new Error(`signer ${op.did} is not the chain creator \u2014 authorization VC required`);
581
+ }
582
+ const vcDecoded = decodeCredentialUnsafe(authorization);
583
+ if (!vcDecoded) throw new Error("failed to decode authorization VC");
584
+ const vcKid = vcDecoded.header.kid;
585
+ if (!vcKid || !vcKid.includes("#")) {
586
+ throw new Error("authorization VC kid must be a DID URL");
587
+ }
588
+ let creatorPublicKey;
589
+ try {
590
+ creatorPublicKey = await resolveKey(vcKid);
591
+ } catch {
592
+ throw new Error("cannot resolve creator key for authorization verification");
593
+ }
594
+ const opCreatedAtUnix = Math.floor(new Date(op.createdAt).getTime() / 1e3);
595
+ try {
596
+ const credential = verifyCredential({
597
+ token: authorization,
598
+ publicKey: creatorPublicKey,
599
+ subject: op.did,
600
+ expectedType: VC_TYPE_CONTENT_WRITE,
601
+ currentTime: opCreatedAtUnix
602
+ });
603
+ if (credential.iss !== currentState.creatorDID) {
604
+ throw new Error("VC issuer is not the chain creator");
605
+ }
606
+ if (credential.contentId && credential.contentId !== currentState.contentId) {
607
+ throw new Error(
608
+ `VC contentId ${credential.contentId} does not match chain ${currentState.contentId}`
609
+ );
610
+ }
611
+ } catch (err) {
612
+ const message = err instanceof Error ? err.message : "unknown error";
613
+ throw new Error(`authorization verification failed: ${message}`);
614
+ }
615
+ }
616
+ const encoded = await dagCborCanonicalEncode(op);
617
+ const operationCID = encoded.cid.toString();
618
+ if (!decoded.header.cid) throw new Error("missing cid in protected header");
619
+ if (decoded.header.cid !== operationCID) throw new Error("cid mismatch in protected header");
620
+ const newState = {
621
+ contentId: currentState.contentId,
622
+ genesisCID: currentState.genesisCID,
623
+ headCID: operationCID,
624
+ isDeleted: op.type === "delete",
625
+ currentDocumentCID: op.type === "update" ? op.documentCID : null,
626
+ length: currentState.length + 1,
627
+ creatorDID: currentState.creatorDID
628
+ };
629
+ return { state: newState, operationCID, createdAt: op.createdAt };
630
+ };
450
631
 
451
632
  // src/chain/beacon.ts
452
633
  var signBeacon = async (input) => {
@@ -499,92 +680,102 @@ var verifyBeacon = async (input) => {
499
680
 
500
681
  // src/chain/countersign.ts
501
682
  var signCountersignature = async (input) => {
502
- const encoded = await dagCborCanonicalEncode(input.operationPayload);
503
- const operationCID = encoded.cid.toString();
683
+ const encoded = await dagCborCanonicalEncode(input.payload);
684
+ const countersignCID = encoded.cid.toString();
504
685
  const jwsToken = await createJws({
505
- header: { alg: "EdDSA", typ: "did:dfos:content-op", kid: input.kid, cid: operationCID },
506
- payload: input.operationPayload,
686
+ header: { alg: "EdDSA", typ: "did:dfos:countersign", kid: input.kid, cid: countersignCID },
687
+ payload: input.payload,
507
688
  sign: input.signer
508
689
  });
509
- return { jwsToken, operationCID };
690
+ return { jwsToken, countersignCID };
510
691
  };
511
692
  var verifyCountersignature = async (input) => {
512
693
  const decoded = decodeJwsUnsafe(input.jwsToken);
513
694
  if (!decoded) throw new Error("failed to decode countersignature JWS");
514
- if (decoded.header.typ !== "did:dfos:content-op") {
695
+ if (decoded.header.typ !== "did:dfos:countersign") {
515
696
  throw new Error(`invalid countersignature typ: ${decoded.header.typ}`);
516
697
  }
517
- const result = ContentOperation.safeParse(decoded.payload);
698
+ const result = CountersignPayload.safeParse(decoded.payload);
518
699
  if (!result.success) {
519
700
  const messages = result.error.issues.map((e) => e.message).join(", ");
520
- throw new Error(`invalid operation payload: ${messages}`);
521
- }
522
- const op = result.data;
523
- const encoded = await dagCborCanonicalEncode(op);
524
- const operationCID = encoded.cid.toString();
525
- if (operationCID !== input.expectedCID) {
526
- throw new Error("countersignature CID does not match expected CID");
527
- }
528
- if (decoded.header.cid !== operationCID) {
529
- throw new Error("countersignature header cid mismatch");
701
+ throw new Error(`invalid countersignature payload: ${messages}`);
530
702
  }
703
+ const payload = result.data;
531
704
  const kid = decoded.header.kid;
705
+ const hashIdx = kid.indexOf("#");
706
+ if (hashIdx < 0) throw new Error("countersignature kid must be a DID URL");
707
+ const kidDid = kid.substring(0, hashIdx);
708
+ if (kidDid !== payload.did) {
709
+ throw new Error("countersignature kid DID does not match payload did");
710
+ }
532
711
  const publicKey = await input.resolveKey(kid);
533
712
  try {
534
713
  verifyJws({ token: input.jwsToken, publicKey });
535
714
  } catch {
536
- throw new Error("invalid countersignature");
537
- }
538
- const hashIdx = kid.indexOf("#");
539
- if (hashIdx < 0) throw new Error("countersignature kid must be a DID URL");
540
- const witnessDID = kid.substring(0, hashIdx);
541
- if (witnessDID === op.did) {
542
- throw new Error("countersignature kid DID must differ from operation did (not a witness)");
715
+ throw new Error("invalid countersignature signature");
543
716
  }
717
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
718
+ const countersignCID = encoded.cid.toString();
719
+ if (!decoded.header.cid) throw new Error("missing cid in countersignature header");
720
+ if (decoded.header.cid !== countersignCID) throw new Error("countersignature cid mismatch");
544
721
  return {
545
- operationCID,
546
- authorDID: op.did,
547
- witnessDID
722
+ countersignCID,
723
+ witnessDID: payload.did,
724
+ targetCID: payload.targetCID
548
725
  };
549
726
  };
550
- var verifyBeaconCountersignature = async (input) => {
551
- const decoded = decodeJwsUnsafe(input.jwsToken);
552
- if (!decoded) throw new Error("failed to decode beacon countersignature JWS");
553
- if (decoded.header.typ !== "did:dfos:beacon") {
554
- throw new Error(`invalid beacon countersignature typ: ${decoded.header.typ}`);
727
+
728
+ // src/chain/artifact.ts
729
+ var signArtifact = async (input) => {
730
+ const encoded = await dagCborCanonicalEncode(input.payload);
731
+ const artifactCID = encoded.cid.toString();
732
+ if (encoded.bytes.length > MAX_ARTIFACT_PAYLOAD_SIZE) {
733
+ throw new Error(
734
+ `artifact payload exceeds max size: ${encoded.bytes.length} > ${MAX_ARTIFACT_PAYLOAD_SIZE}`
735
+ );
555
736
  }
556
- const result = BeaconPayload.safeParse(decoded.payload);
737
+ const jwsToken = await createJws({
738
+ header: { alg: "EdDSA", typ: "did:dfos:artifact", kid: input.kid, cid: artifactCID },
739
+ payload: input.payload,
740
+ sign: input.signer
741
+ });
742
+ return { jwsToken, artifactCID };
743
+ };
744
+ var verifyArtifact = async (input) => {
745
+ const decoded = decodeJwsUnsafe(input.jwsToken);
746
+ if (!decoded) throw new Error("failed to decode artifact JWS");
747
+ const result = ArtifactPayload.safeParse(decoded.payload);
557
748
  if (!result.success) {
558
749
  const messages = result.error.issues.map((e) => e.message).join(", ");
559
- throw new Error(`invalid beacon payload: ${messages}`);
750
+ throw new Error(`invalid artifact payload: ${messages}`);
560
751
  }
561
- const beacon = result.data;
562
- const encoded = await dagCborCanonicalEncode(beacon);
563
- const beaconCID = encoded.cid.toString();
564
- if (beaconCID !== input.expectedCID) {
565
- throw new Error("beacon countersignature CID does not match expected CID");
566
- }
567
- if (decoded.header.cid !== beaconCID) {
568
- throw new Error("beacon countersignature header cid mismatch");
752
+ const payload = result.data;
753
+ if (decoded.header.typ !== "did:dfos:artifact") {
754
+ throw new Error(`invalid artifact typ: ${decoded.header.typ}`);
569
755
  }
570
756
  const kid = decoded.header.kid;
757
+ const hashIdx = kid.indexOf("#");
758
+ if (hashIdx < 0) throw new Error("artifact kid must be a DID URL");
759
+ const kidDid = kid.substring(0, hashIdx);
760
+ if (kidDid !== payload.did) {
761
+ throw new Error("artifact kid DID does not match payload did");
762
+ }
571
763
  const publicKey = await input.resolveKey(kid);
572
764
  try {
573
765
  verifyJws({ token: input.jwsToken, publicKey });
574
766
  } catch {
575
- throw new Error("invalid beacon countersignature");
767
+ throw new Error("invalid artifact signature");
576
768
  }
577
- const hashIdx = kid.indexOf("#");
578
- if (hashIdx < 0) throw new Error("beacon countersignature kid must be a DID URL");
579
- const witnessDID = kid.substring(0, hashIdx);
580
- if (witnessDID === beacon.did) {
581
- throw new Error("beacon countersignature kid DID must differ from beacon did (not a witness)");
769
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
770
+ const artifactCID = encoded.cid.toString();
771
+ if (!decoded.header.cid) throw new Error("missing cid in artifact header");
772
+ if (decoded.header.cid !== artifactCID) throw new Error("artifact cid mismatch");
773
+ if (encoded.bytes.length > MAX_ARTIFACT_PAYLOAD_SIZE) {
774
+ throw new Error(
775
+ `artifact payload exceeds max size: ${encoded.bytes.length} > ${MAX_ARTIFACT_PAYLOAD_SIZE}`
776
+ );
582
777
  }
583
- return {
584
- beaconCID,
585
- controllerDID: beacon.did,
586
- witnessDID
587
- };
778
+ return { payload, artifactCID };
588
779
  };
589
780
 
590
781
  export {
@@ -593,6 +784,9 @@ export {
593
784
  VerifiedIdentity,
594
785
  ContentOperation,
595
786
  BeaconPayload,
787
+ MAX_ARTIFACT_PAYLOAD_SIZE,
788
+ ArtifactPayload,
789
+ CountersignPayload,
596
790
  ED25519_PUB_MULTICODEC,
597
791
  ED25519_PRIV_MULTICODEC,
598
792
  encodeEd25519Multikey,
@@ -601,11 +795,14 @@ export {
601
795
  deriveContentId,
602
796
  signIdentityOperation,
603
797
  verifyIdentityChain,
798
+ verifyIdentityExtensionFromTrustedState,
604
799
  signContentOperation,
605
800
  verifyContentChain,
801
+ verifyContentExtensionFromTrustedState,
606
802
  signBeacon,
607
803
  verifyBeacon,
608
804
  signCountersignature,
609
805
  verifyCountersignature,
610
- verifyBeaconCountersignature
806
+ signArtifact,
807
+ verifyArtifact
611
808
  };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { JwsHeader, JwsVerificationError, JwtClaims, JwtCreateOptions, JwtHeader, JwtVerificationError, JwtVerifyOptions, PrefixedID, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, signPayloadEd25519, verifyJws, verifyJwt } from './crypto/index.js';
2
- export { BeaconPayload, ContentOperation, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, MultikeyPublicKey, Signer, VerifiedBeacon, VerifiedBeaconCountersignature, VerifiedContentChain, VerifiedCountersignature, VerifiedIdentity, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, signBeacon, signContentOperation, signCountersignature, signIdentityOperation, verifyBeacon, verifyBeaconCountersignature, verifyContentChain, verifyCountersignature, verifyIdentityChain } from './chain/index.js';
2
+ export { ArtifactPayload, BeaconPayload, ContentOperation, CountersignPayload, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, MAX_ARTIFACT_PAYLOAD_SIZE, MultikeyPublicKey, Signer, VerifiedArtifact, VerifiedBeacon, VerifiedContentChain, VerifiedCountersignature, VerifiedIdentity, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, signArtifact, signBeacon, signContentOperation, signCountersignature, signIdentityOperation, verifyArtifact, verifyBeacon, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyIdentityChain, verifyIdentityExtensionFromTrustedState } from './chain/index.js';
3
3
  export { MerkleProof, buildMerkleTree, generateMerkleProof, hashLeaf, hexToBytes, verifyMerkleProof } from './merkle/index.js';
4
4
  export { AuthTokenClaims, AuthTokenCreateOptions, AuthTokenVerificationError, AuthTokenVerifyOptions, ContentReadSubject, ContentWriteSubject, CredentialClaims, CredentialCreateOptions, CredentialVerificationError, CredentialVerifyOptions, DFOSCredentialType, VCClaim, VC_TYPE_CONTENT_READ, VC_TYPE_CONTENT_WRITE, VerifiedAuthToken, VerifiedCredential, createAuthToken, createCredential, decodeCredentialUnsafe, verifyAuthToken, verifyCredential } from './credentials/index.js';
5
5
  import 'multiformats';
package/dist/index.js CHANGED
@@ -1,25 +1,31 @@
1
1
  import {
2
+ ArtifactPayload,
2
3
  BeaconPayload,
3
4
  ContentOperation,
5
+ CountersignPayload,
4
6
  ED25519_PRIV_MULTICODEC,
5
7
  ED25519_PUB_MULTICODEC,
6
8
  IdentityOperation,
9
+ MAX_ARTIFACT_PAYLOAD_SIZE,
7
10
  MultikeyPublicKey,
8
11
  VerifiedIdentity,
9
12
  decodeMultikey,
10
13
  deriveChainIdentifier,
11
14
  deriveContentId,
12
15
  encodeEd25519Multikey,
16
+ signArtifact,
13
17
  signBeacon,
14
18
  signContentOperation,
15
19
  signCountersignature,
16
20
  signIdentityOperation,
21
+ verifyArtifact,
17
22
  verifyBeacon,
18
- verifyBeaconCountersignature,
19
23
  verifyContentChain,
24
+ verifyContentExtensionFromTrustedState,
20
25
  verifyCountersignature,
21
- verifyIdentityChain
22
- } from "./chunk-GEVJ3SEV.js";
26
+ verifyIdentityChain,
27
+ verifyIdentityExtensionFromTrustedState
28
+ } from "./chunk-QKHP7UVL.js";
23
29
  import {
24
30
  buildMerkleTree,
25
31
  generateMerkleProof,
@@ -68,12 +74,14 @@ import {
68
74
  verifyJwt
69
75
  } from "./chunk-ZXXP5W5N.js";
70
76
  export {
77
+ ArtifactPayload,
71
78
  AuthTokenClaims,
72
79
  AuthTokenVerificationError,
73
80
  BeaconPayload,
74
81
  ContentOperation,
75
82
  ContentReadSubject,
76
83
  ContentWriteSubject,
84
+ CountersignPayload,
77
85
  CredentialClaims,
78
86
  CredentialVerificationError,
79
87
  DFOSCredentialType,
@@ -82,6 +90,7 @@ export {
82
90
  IdentityOperation,
83
91
  JwsVerificationError,
84
92
  JwtVerificationError,
93
+ MAX_ARTIFACT_PAYLOAD_SIZE,
85
94
  MultikeyPublicKey,
86
95
  VCClaim,
87
96
  VC_TYPE_CONTENT_READ,
@@ -114,18 +123,21 @@ export {
114
123
  isValidId,
115
124
  normalizedId,
116
125
  parseDagCborCID,
126
+ signArtifact,
117
127
  signBeacon,
118
128
  signContentOperation,
119
129
  signCountersignature,
120
130
  signIdentityOperation,
121
131
  signPayloadEd25519,
132
+ verifyArtifact,
122
133
  verifyAuthToken,
123
134
  verifyBeacon,
124
- verifyBeaconCountersignature,
125
135
  verifyContentChain,
136
+ verifyContentExtensionFromTrustedState,
126
137
  verifyCountersignature,
127
138
  verifyCredential,
128
139
  verifyIdentityChain,
140
+ verifyIdentityExtensionFromTrustedState,
129
141
  verifyJws,
130
142
  verifyJwt,
131
143
  verifyMerkleProof
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metalabel/dfos-protocol",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "DFOS Protocol — Ed25519 signed chain primitives, beacons, merkle trees, and verification",
6
6
  "license": "MIT",
@@ -69,7 +69,7 @@
69
69
  "ajv-formats": "^3.0.1",
70
70
  "tsup": "^8.5.1",
71
71
  "tsx": "^4.21.0",
72
- "vitest": "^4.0.18"
72
+ "vitest": "^4.1.0"
73
73
  },
74
74
  "scripts": {
75
75
  "build": "tsup",