@metalabel/dfos-web-relay 0.10.0 → 0.11.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/README.md CHANGED
@@ -38,19 +38,18 @@ serve({ port: 4444 });
38
38
 
39
39
  ## Routes
40
40
 
41
- | Method | Path | Description |
42
- | ------ | ---------------------------------------- | ---------------------------------------------------------------- |
43
- | `GET` | `/.well-known/dfos-relay` | Relay metadata (DID, protocol version) |
44
- | `POST` | `/operations` | Submit signed operations (identity, content, beacon, countersig) |
45
- | `GET` | `/identities/:did` | Get identity chain state and operation log |
46
- | `GET` | `/content/:contentId` | Get content chain state and operation log |
47
- | `GET` | `/operations/:cid` | Get a single operation by CID |
48
- | `GET` | `/beacons/:did` | Get beacon for an identity |
49
- | `GET` | `/countersignatures/:cid` | Get countersignatures for an operation |
50
- | `GET` | `/operations/:cid/countersignatures` | Same as above (alias) |
51
- | `PUT` | `/content/:contentId/blob/:operationCID` | Upload blob (auth required) |
52
- | `GET` | `/content/:contentId/blob` | Download blob at head (standing auth, or auth + credential) |
53
- | `GET` | `/content/:contentId/blob/:ref` | Download blob at specific operation ref |
41
+ | Method | Path | Description |
42
+ | ------ | ---------------------------------------- | ----------------------------------------------------------- |
43
+ | `GET` | `/.well-known/dfos-relay` | Relay metadata (DID, protocol version) |
44
+ | `POST` | `/operations` | Submit signed operations (identity, content, countersig) |
45
+ | `GET` | `/identities/:did` | Get identity chain state and operation log |
46
+ | `GET` | `/content/:contentId` | Get content chain state and operation log |
47
+ | `GET` | `/operations/:cid` | Get a single operation by CID |
48
+ | `GET` | `/countersignatures/:cid` | Get countersignatures for an operation |
49
+ | `GET` | `/operations/:cid/countersignatures` | Same as above (alias) |
50
+ | `PUT` | `/content/:contentId/blob/:operationCID` | Upload blob (auth required) |
51
+ | `GET` | `/content/:contentId/blob` | Download blob at head (standing auth, or auth + credential) |
52
+ | `GET` | `/content/:contentId/blob/:ref` | Download blob at specific operation ref |
54
53
 
55
54
  ## Blob Authorization
56
55
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { VerifiedIdentity, VerifiedContentChain, VerifiedBeacon } from '@metalabel/dfos-protocol/chain';
1
+ import { VerifiedIdentity, VerifiedContentChain } from '@metalabel/dfos-protocol/chain';
2
2
  import { Attenuation } from '@metalabel/dfos-protocol/credentials';
3
3
  import { Hono } from 'hono';
4
4
 
@@ -90,18 +90,12 @@ interface StoredContentChain {
90
90
  lastCreatedAt: string;
91
91
  state: VerifiedContentChain;
92
92
  }
93
- interface StoredBeacon {
94
- did: string;
95
- jwsToken: string;
96
- beaconCID: string;
97
- state: VerifiedBeacon;
98
- }
99
93
  interface StoredOperation {
100
94
  cid: string;
101
95
  jwsToken: string;
102
96
  /** Which chain type this operation belongs to */
103
- chainType: 'identity' | 'content' | 'artifact' | 'beacon' | 'countersign' | 'revocation' | 'credential';
104
- /** The chain identifier — DID for identity/beacon/artifact, contentId for content, targetCID for countersign */
97
+ chainType: 'identity' | 'content' | 'artifact' | 'countersign' | 'revocation' | 'credential';
98
+ /** The chain identifier — DID for identity/artifact, contentId for content, targetCID for countersign */
105
99
  chainId: string;
106
100
  }
107
101
  /** Key for blob storage — deduplicates across chains sharing the same document */
@@ -117,7 +111,7 @@ interface LogEntry {
117
111
  chainId: string;
118
112
  }
119
113
  /** All operation kinds in the protocol */
120
- type OperationKind = 'identity-op' | 'content-op' | 'beacon' | 'artifact' | 'countersign' | 'revocation' | 'credential';
114
+ type OperationKind = 'identity-op' | 'content-op' | 'artifact' | 'countersign' | 'revocation' | 'credential';
121
115
  interface StoredRevocation {
122
116
  cid: string;
123
117
  issuerDID: string;
@@ -156,8 +150,6 @@ interface RelayStore {
156
150
  putIdentityChain(chain: StoredIdentityChain): Promise<void>;
157
151
  getContentChain(contentId: string): Promise<StoredContentChain | undefined>;
158
152
  putContentChain(chain: StoredContentChain): Promise<void>;
159
- getBeacon(did: string): Promise<StoredBeacon | undefined>;
160
- putBeacon(beacon: StoredBeacon): Promise<void>;
161
153
  getBlob(key: BlobKey): Promise<Uint8Array | undefined>;
162
154
  putBlob(key: BlobKey, data: Uint8Array): Promise<void>;
163
155
  getCountersignatures(operationCID: string): Promise<string[]>;
@@ -320,7 +312,6 @@ declare class MemoryRelayStore implements RelayStore {
320
312
  private operations;
321
313
  private identityChains;
322
314
  private contentChains;
323
- private beacons;
324
315
  private blobs;
325
316
  private countersignatures;
326
317
  private operationLog;
@@ -335,8 +326,6 @@ declare class MemoryRelayStore implements RelayStore {
335
326
  putIdentityChain(chain: StoredIdentityChain): Promise<void>;
336
327
  getContentChain(contentId: string): Promise<StoredContentChain | undefined>;
337
328
  putContentChain(chain: StoredContentChain): Promise<void>;
338
- getBeacon(did: string): Promise<StoredBeacon | undefined>;
339
- putBeacon(beacon: StoredBeacon): Promise<void>;
340
329
  getBlob(key: BlobKey): Promise<Uint8Array | undefined>;
341
330
  putBlob(key: BlobKey, data: Uint8Array): Promise<void>;
342
331
  getCountersignatures(operationCID: string): Promise<string[]>;
@@ -432,6 +421,11 @@ declare const createHistoricalIdentityResolver: (store: RelayStore) => (did: str
432
421
  }[];
433
422
  did: string;
434
423
  isDeleted: boolean;
424
+ services: {
425
+ [x: string]: unknown;
426
+ id: string;
427
+ type: string;
428
+ }[];
435
429
  } | undefined>;
436
430
  /**
437
431
  * Create a key resolver that only resolves current-state keys.
@@ -445,7 +439,7 @@ declare const createCurrentKeyResolver: (store: RelayStore) => (kid: string) =>
445
439
  * Ingest a batch of JWS operations
446
440
  *
447
441
  * Classifies, dependency-sorts, and processes each token. Identity operations
448
- * are processed first so content chains and beacons can resolve their keys.
442
+ * are processed first so content chains can resolve their keys.
449
443
  * Within each kind, genesis operations are processed before extensions.
450
444
  */
451
445
  declare const ingestOperations: (tokens: string[], store: RelayStore, options?: {
@@ -469,4 +463,4 @@ declare const sequenceOps: (store: RelayStore) => Promise<{
469
463
  result: SequenceResult;
470
464
  }>;
471
465
 
472
- export { type BlobKey, type CreatedRelay, type IngestionResult, type LogEntry, MemoryRelayStore, type OperationKind, type PeerClient, type PeerConfig, type PeerLogEntry, type RelayIdentity, type RelayOptions, type RelayStore, type SequenceResult, type StoredBeacon, type StoredContentChain, type StoredIdentityChain, type StoredOperation, bootstrapRelayIdentity, bootstrapRelayIdentityFromKey, chunkOps, computeOpCID, createCurrentKeyResolver, createHistoricalIdentityResolver, createHttpPeerClient, createKeyResolver, createRelay, ingestOperations, isDependencyFailure, sequenceOps };
466
+ export { type BlobKey, type CreatedRelay, type IngestionResult, type LogEntry, MemoryRelayStore, type OperationKind, type PeerClient, type PeerConfig, type PeerLogEntry, type RelayIdentity, type RelayOptions, type RelayStore, type SequenceResult, type StoredContentChain, type StoredIdentityChain, type StoredOperation, bootstrapRelayIdentity, bootstrapRelayIdentityFromKey, chunkOps, computeOpCID, createCurrentKeyResolver, createHistoricalIdentityResolver, createHttpPeerClient, createKeyResolver, createRelay, ingestOperations, isDependencyFailure, sequenceOps };
package/dist/index.js CHANGED
@@ -15,7 +15,6 @@ import {
15
15
  import {
16
16
  decodeMultikey,
17
17
  verifyArtifact,
18
- verifyBeacon,
19
18
  verifyContentChain,
20
19
  verifyContentExtensionFromTrustedState,
21
20
  verifyCountersignature,
@@ -71,17 +70,6 @@ var classify = (jwsToken) => {
71
70
  const opDID = typeof payload["did"] === "string" ? payload["did"] : null;
72
71
  return { ...base, kind: "content-op", referencedDID: null, signerDID: opDID, priority: 2 };
73
72
  }
74
- if (typ === "did:dfos:beacon") {
75
- const beaconDID = typeof payload["did"] === "string" ? payload["did"] : null;
76
- return {
77
- ...base,
78
- kind: "beacon",
79
- referencedDID: beaconDID,
80
- signerDID: null,
81
- priority: 1,
82
- previousCID: null
83
- };
84
- }
85
73
  if (typ === "did:dfos:countersign") {
86
74
  const witnessDID = typeof payload["did"] === "string" ? payload["did"] : null;
87
75
  return {
@@ -102,7 +90,7 @@ var classify = (jwsToken) => {
102
90
  referencedDID: artifactDID,
103
91
  signerDID: null,
104
92
  priority: 1,
105
- // same as beacons — needs identity keys resolved first
93
+ // needs identity keys resolved first
106
94
  previousCID: null
107
95
  };
108
96
  }
@@ -114,7 +102,7 @@ var classify = (jwsToken) => {
114
102
  referencedDID: revocationDID,
115
103
  signerDID: null,
116
104
  priority: 1,
117
- // same as beacons — needs identity keys to verify
105
+ // needs identity keys to verify
118
106
  previousCID: null
119
107
  };
120
108
  }
@@ -548,41 +536,6 @@ var ingestContentOp = async (jwsToken, store, logEnabled) => {
548
536
  }
549
537
  return { cid, status: "new", kind: "content-op", chainId: chain.contentId };
550
538
  };
551
- var ingestBeacon = async (jwsToken, store, logEnabled) => {
552
- const resolveKey = createCurrentKeyResolver(store);
553
- let verified;
554
- try {
555
- verified = await verifyBeacon({ jwsToken, resolveKey });
556
- } catch (err) {
557
- const message = err instanceof Error ? err.message : "verification failed";
558
- return {
559
- cid: await computeOpCID(jwsToken),
560
- status: "rejected",
561
- error: message,
562
- dependencyMissing: isKeyResolutionFailure(message)
563
- };
564
- }
565
- const did = verified.did;
566
- const cid = verified.beaconCID;
567
- const identity = await store.getIdentityChain(did);
568
- if (identity?.state.isDeleted) {
569
- return { cid, status: "rejected", error: "identity is deleted" };
570
- }
571
- const existing = await store.getBeacon(did);
572
- if (existing) {
573
- const existingTime = new Date(existing.state.createdAt).getTime();
574
- const newTime = new Date(verified.createdAt).getTime();
575
- if (newTime < existingTime || newTime === existingTime && cid <= existing.beaconCID) {
576
- return { cid, status: "duplicate", kind: "beacon", chainId: did };
577
- }
578
- }
579
- await store.putBeacon({ did, jwsToken, beaconCID: cid, state: verified });
580
- await store.putOperation({ cid, jwsToken, chainType: "beacon", chainId: did });
581
- if (logEnabled) {
582
- await store.appendToLog({ cid, jwsToken, kind: "beacon", chainId: did });
583
- }
584
- return { cid, status: "new", kind: "beacon", chainId: did };
585
- };
586
539
  var ingestCountersign = async (jwsToken, store, logEnabled) => {
587
540
  const resolveKey = createKeyResolver(store);
588
541
  let verified;
@@ -880,9 +833,6 @@ var ingestOperations = async (tokens, store, options) => {
880
833
  case "content-op":
881
834
  result = await ingestContentOp(op.jwsToken, store, logEnabled);
882
835
  break;
883
- case "beacon":
884
- result = await ingestBeacon(op.jwsToken, store, logEnabled);
885
- break;
886
836
  case "countersign":
887
837
  result = await ingestCountersign(op.jwsToken, store, logEnabled);
888
838
  break;
@@ -1466,18 +1416,6 @@ var createRelay = async (options) => {
1466
1416
  const countersigs = await store.getCountersignatures(cid);
1467
1417
  return c.json({ operationCID: cid, countersignatures: countersigs });
1468
1418
  });
1469
- app.get("/beacons/:did{.+}", async (c) => {
1470
- const did = c.req.param("did");
1471
- const beacon = await store.getBeacon(did);
1472
- if (!beacon) return c.json({ error: "not found" }, 404);
1473
- return c.json({
1474
- did: beacon.did,
1475
- jwsToken: beacon.jwsToken,
1476
- beaconCID: beacon.beaconCID,
1477
- manifestContentId: beacon.state.manifestContentId,
1478
- createdAt: beacon.state.createdAt
1479
- });
1480
- });
1481
1419
  app.get("/log", async (c) => {
1482
1420
  if (!logEnabled) return c.json({ error: "global log not available" }, 501);
1483
1421
  const afterParam = c.req.query("after");
@@ -1643,7 +1581,6 @@ var MemoryRelayStore = class {
1643
1581
  operations = /* @__PURE__ */ new Map();
1644
1582
  identityChains = /* @__PURE__ */ new Map();
1645
1583
  contentChains = /* @__PURE__ */ new Map();
1646
- beacons = /* @__PURE__ */ new Map();
1647
1584
  blobs = /* @__PURE__ */ new Map();
1648
1585
  countersignatures = /* @__PURE__ */ new Map();
1649
1586
  operationLog = [];
@@ -1670,12 +1607,6 @@ var MemoryRelayStore = class {
1670
1607
  async putContentChain(chain) {
1671
1608
  this.contentChains.set(chain.contentId, chain);
1672
1609
  }
1673
- async getBeacon(did) {
1674
- return this.beacons.get(did);
1675
- }
1676
- async putBeacon(beacon) {
1677
- this.beacons.set(beacon.did, beacon);
1678
- }
1679
1610
  async getBlob(key) {
1680
1611
  return this.blobs.get(blobKeyString(key));
1681
1612
  }
package/openapi.yaml CHANGED
@@ -4,10 +4,10 @@ info:
4
4
  version: 0.9.0
5
5
  description: |
6
6
  HTTP relay for the DFOS protocol. Receives, verifies, stores, and serves
7
- identity chains, content chains, beacons, countersignatures, and content blobs.
7
+ identity chains, content chains, countersignatures, and content blobs.
8
8
 
9
9
  Two data planes:
10
- - **Proof plane** (public): signed chain operations, beacons, countersignatures
10
+ - **Proof plane** (public): signed chain operations, countersignatures
11
11
  - **Content plane** (authenticated): raw content blobs gated by DID auth tokens and DFOS credentials
12
12
 
13
13
  servers:
@@ -66,7 +66,7 @@ paths:
66
66
  summary: Submit operations for ingestion
67
67
  description: |
68
68
  Accept a batch of JWS tokens — identity operations, content operations,
69
- beacons, and countersignatures. The relay classifies, dependency-sorts,
69
+ and countersignatures. The relay classifies, dependency-sorts,
70
70
  verifies, and stores each token.
71
71
  tags: [Proof Plane]
72
72
  requestBody:
@@ -422,7 +422,7 @@ paths:
422
422
  summary: Paginated global log of all accepted operations
423
423
  description: |
424
424
  Returns every operation the relay has accepted — across all identity and
425
- content chains, plus beacons and countersignatures — in acceptance order.
425
+ content chains, plus countersignatures — in acceptance order.
426
426
  Cursor-based pagination. Used by peer relays to background-sync. Available
427
427
  only when the relay advertises the `log` capability; otherwise returns 501.
428
428
  tags: [Proof Plane]
@@ -462,15 +462,7 @@ paths:
462
462
  kind:
463
463
  type: string
464
464
  enum:
465
- [
466
- identity-op,
467
- content-op,
468
- beacon,
469
- artifact,
470
- countersign,
471
- revocation,
472
- credential,
473
- ]
465
+ [identity-op, content-op, artifact, countersign, revocation, credential]
474
466
  chainId:
475
467
  type: string
476
468
  description: Chain identifier (DID or contentId)
@@ -589,7 +581,7 @@ paths:
589
581
  /countersignatures/{cid}:
590
582
  get:
591
583
  operationId: getCountersignaturesByCID
592
- summary: Get countersignatures for any CID (operation or beacon)
584
+ summary: Get countersignatures for an operation CID
593
585
  tags: [Proof Plane]
594
586
  parameters:
595
587
  - name: cid
@@ -597,7 +589,7 @@ paths:
597
589
  required: true
598
590
  schema:
599
591
  type: string
600
- description: CIDv1 of the operation or beacon
592
+ description: CIDv1 of the operation
601
593
  responses:
602
594
  '200':
603
595
  description: Countersignatures
@@ -617,27 +609,6 @@ paths:
617
609
  '404':
618
610
  $ref: '#/components/responses/NotFound'
619
611
 
620
- /beacons/{did}:
621
- get:
622
- operationId: getBeacon
623
- summary: Get the latest beacon for a DID
624
- tags: [Proof Plane]
625
- parameters:
626
- - name: did
627
- in: path
628
- required: true
629
- schema:
630
- type: string
631
- responses:
632
- '200':
633
- description: Latest beacon
634
- content:
635
- application/json:
636
- schema:
637
- $ref: '#/components/schemas/BeaconResponse'
638
- '404':
639
- $ref: '#/components/responses/NotFound'
640
-
641
612
  components:
642
613
  securitySchemes:
643
614
  BearerAuth:
@@ -661,7 +632,7 @@ components:
661
632
  description: Error message if rejected
662
633
  kind:
663
634
  type: string
664
- enum: [identity-op, content-op, beacon, artifact, countersign, revocation, credential]
635
+ enum: [identity-op, content-op, artifact, countersign, revocation, credential]
665
636
  chainId:
666
637
  type: string
667
638
  description: Chain identifier (DID or contentId)
@@ -676,7 +647,7 @@ components:
676
647
  type: string
677
648
  chainType:
678
649
  type: string
679
- enum: [identity, content, artifact, beacon, countersign, revocation, credential]
650
+ enum: [identity, content, artifact, countersign, revocation, credential]
680
651
  chainId:
681
652
  type: string
682
653
 
@@ -691,7 +662,7 @@ components:
691
662
  description: CID of the current head operation
692
663
  state:
693
664
  type: object
694
- required: [did, isDeleted, authKeys, assertKeys, controllerKeys]
665
+ required: [did, isDeleted, authKeys, assertKeys, controllerKeys, services]
695
666
  properties:
696
667
  did:
697
668
  type: string
@@ -709,6 +680,22 @@ components:
709
680
  type: array
710
681
  items:
711
682
  $ref: '#/components/schemas/MultikeyPublicKey'
683
+ services:
684
+ type: array
685
+ description: >-
686
+ Resolved discovery vocabulary (controller-signed). Each entry has
687
+ a common envelope {id, type}; recognized types DfosRelay and
688
+ ContentAnchor carry type-specific fields. The namespace is open —
689
+ unrecognized types are preserved verbatim.
690
+ items:
691
+ type: object
692
+ required: [id, type]
693
+ properties:
694
+ id:
695
+ type: string
696
+ type:
697
+ type: string
698
+ additionalProperties: true
712
699
 
713
700
  ContentChainResponse:
714
701
  type: object
@@ -743,23 +730,6 @@ components:
743
730
  creatorDID:
744
731
  type: string
745
732
 
746
- BeaconResponse:
747
- type: object
748
- required: [did, jwsToken, beaconCID, manifestContentId, createdAt]
749
- properties:
750
- did:
751
- type: string
752
- jwsToken:
753
- type: string
754
- beaconCID:
755
- type: string
756
- manifestContentId:
757
- type: string
758
- description: Content ID of the manifest chain
759
- createdAt:
760
- type: string
761
- format: date-time
762
-
763
733
  MultikeyPublicKey:
764
734
  type: object
765
735
  required: [id, type, publicKeyMultibase]
@@ -809,6 +779,6 @@ tags:
809
779
  - name: Meta
810
780
  description: Relay metadata and discovery
811
781
  - name: Proof Plane
812
- description: Public routes for signed chain operations, beacons, and countersignatures
782
+ description: Public routes for signed chain operations and countersignatures
813
783
  - name: Content Plane
814
784
  description: Authenticated routes for content blob storage and retrieval
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@metalabel/dfos-web-relay",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
- "description": "DFOS Web Relay — verifying HTTP relay for identity chains, content chains, beacons, and content blobs",
5
+ "description": "DFOS Web Relay — verifying HTTP relay for identity chains, content chains, and content blobs",
6
6
  "license": "MIT",
7
7
  "author": "Metalabel <hello@metalabel.com> (https://metalabel.com)",
8
8
  "repository": {
@@ -45,14 +45,14 @@
45
45
  "zod": "^4.4.3"
46
46
  },
47
47
  "peerDependencies": {
48
- "@metalabel/dfos-protocol": "^0.10.0"
48
+ "@metalabel/dfos-protocol": "^0.11.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node": "^24.10.4",
52
52
  "tsup": "^8.5.1",
53
53
  "tsx": "^4.22.4",
54
54
  "vitest": "^4.1.8",
55
- "@metalabel/dfos-protocol": "0.10.0"
55
+ "@metalabel/dfos-protocol": "0.11.0"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsup",