@metalabel/dfos-web-relay 0.9.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
 
@@ -21,6 +21,12 @@ interface RelayOptions {
21
21
  peers?: PeerConfig[];
22
22
  /** Injected peer client — if omitted, a default HTTP implementation is used */
23
23
  peerClient?: PeerClient;
24
+ /**
25
+ * Max lifetime (exp-iat, seconds) honored on a self-signed auth token.
26
+ * Default 86400 (24h); a value <= 0 disables the ceiling. Applies only to auth
27
+ * tokens, never to DFOS credentials.
28
+ */
29
+ maxAuthTokenTTLSeconds?: number;
24
30
  }
25
31
  interface PeerConfig {
26
32
  url: string;
@@ -84,18 +90,12 @@ interface StoredContentChain {
84
90
  lastCreatedAt: string;
85
91
  state: VerifiedContentChain;
86
92
  }
87
- interface StoredBeacon {
88
- did: string;
89
- jwsToken: string;
90
- beaconCID: string;
91
- state: VerifiedBeacon;
92
- }
93
93
  interface StoredOperation {
94
94
  cid: string;
95
95
  jwsToken: string;
96
96
  /** Which chain type this operation belongs to */
97
- chainType: 'identity' | 'content' | 'artifact' | 'beacon' | 'countersign' | 'revocation' | 'credential';
98
- /** 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 */
99
99
  chainId: string;
100
100
  }
101
101
  /** Key for blob storage — deduplicates across chains sharing the same document */
@@ -111,7 +111,7 @@ interface LogEntry {
111
111
  chainId: string;
112
112
  }
113
113
  /** All operation kinds in the protocol */
114
- type OperationKind = 'identity-op' | 'content-op' | 'beacon' | 'artifact' | 'countersign' | 'revocation' | 'credential';
114
+ type OperationKind = 'identity-op' | 'content-op' | 'artifact' | 'countersign' | 'revocation' | 'credential';
115
115
  interface StoredRevocation {
116
116
  cid: string;
117
117
  issuerDID: string;
@@ -150,8 +150,6 @@ interface RelayStore {
150
150
  putIdentityChain(chain: StoredIdentityChain): Promise<void>;
151
151
  getContentChain(contentId: string): Promise<StoredContentChain | undefined>;
152
152
  putContentChain(chain: StoredContentChain): Promise<void>;
153
- getBeacon(did: string): Promise<StoredBeacon | undefined>;
154
- putBeacon(beacon: StoredBeacon): Promise<void>;
155
153
  getBlob(key: BlobKey): Promise<Uint8Array | undefined>;
156
154
  putBlob(key: BlobKey, data: Uint8Array): Promise<void>;
157
155
  getCountersignatures(operationCID: string): Promise<string[]>;
@@ -236,6 +234,14 @@ interface IngestionResult {
236
234
  kind?: OperationKind;
237
235
  /** Chain identifier if applicable */
238
236
  chainId?: string;
237
+ /**
238
+ * Structured dependency-failure signal. When true, the rejection is due to a
239
+ * missing dependency that may arrive later via sync or gossip, so the
240
+ * sequencer must keep the op pending (retryable) rather than durably reject
241
+ * it. This is the discriminator the sequencer branches on — NOT substring
242
+ * matching of the human-readable `error` string.
243
+ */
244
+ dependencyMissing?: boolean;
239
245
  }
240
246
 
241
247
  /**
@@ -247,6 +253,20 @@ interface IngestionResult {
247
253
  * they are available via the relay's proof plane routes.
248
254
  */
249
255
  declare const bootstrapRelayIdentity: (store: RelayStore) => Promise<RelayIdentity>;
256
+ /**
257
+ * Bootstrap a relay identity from an EXISTING key + key ID, with optional pinned
258
+ * timestamps and profile name. Used for deterministic bootstrap — e.g. the
259
+ * dual-relay parity harness pins one key + one createdAt across both twins so
260
+ * the relay's own genesis + profile log entries are byte-identical, and durable
261
+ * relays that reload their key from storage. Mirrors the Go twin's
262
+ * BootstrapRelayIdentityFromKey.
263
+ */
264
+ declare const bootstrapRelayIdentityFromKey: (store: RelayStore, params: {
265
+ privateKey: Uint8Array;
266
+ keyId: string;
267
+ name?: string;
268
+ createdAt?: string;
269
+ }) => Promise<RelayIdentity>;
250
270
 
251
271
  /**
252
272
  * Create an HTTP-based PeerClient.
@@ -265,6 +285,13 @@ interface CreatedRelay {
265
285
  /** Sync operations from all configured sync peers (call on a schedule) */
266
286
  syncFromPeers: () => Promise<void>;
267
287
  }
288
+ /**
289
+ * Split items into batches of at most `size`, preserving order with no loss.
290
+ * gossip() uses this to stay within the receiver's per-batch cap; exported so
291
+ * the split behavior is directly testable (mirrors Go's maxGossipBatch chunking,
292
+ * whose TestGossipChunksLargeBatches drives the split directly).
293
+ */
294
+ declare const chunkOps: <T>(items: T[], size: number) => T[][];
268
295
  /**
269
296
  * Create a DFOS web relay Hono application
270
297
  *
@@ -285,7 +312,6 @@ declare class MemoryRelayStore implements RelayStore {
285
312
  private operations;
286
313
  private identityChains;
287
314
  private contentChains;
288
- private beacons;
289
315
  private blobs;
290
316
  private countersignatures;
291
317
  private operationLog;
@@ -300,8 +326,6 @@ declare class MemoryRelayStore implements RelayStore {
300
326
  putIdentityChain(chain: StoredIdentityChain): Promise<void>;
301
327
  getContentChain(contentId: string): Promise<StoredContentChain | undefined>;
302
328
  putContentChain(chain: StoredContentChain): Promise<void>;
303
- getBeacon(did: string): Promise<StoredBeacon | undefined>;
304
- putBeacon(beacon: StoredBeacon): Promise<void>;
305
329
  getBlob(key: BlobKey): Promise<Uint8Array | undefined>;
306
330
  putBlob(key: BlobKey, data: Uint8Array): Promise<void>;
307
331
  getCountersignatures(operationCID: string): Promise<string[]>;
@@ -346,6 +370,13 @@ declare class MemoryRelayStore implements RelayStore {
346
370
  resetSequencer(): Promise<void>;
347
371
  }
348
372
 
373
+ /**
374
+ * Derive the operation CID from a JWS token by re-encoding the decoded payload.
375
+ * Returns the empty string for an undecodable token. Used at verify-failure
376
+ * sites so a rejection still carries a CID and can be durably rejected by the
377
+ * sequencer (instead of being skipped forever by `if (!res.cid) continue`).
378
+ */
379
+ declare const computeOpCID: (jwsToken: string) => Promise<string>;
349
380
  /**
350
381
  * Create a key resolver that looks up Ed25519 public keys from identity chains
351
382
  * in the store. Used for chain re-verification during ingestion.
@@ -390,6 +421,11 @@ declare const createHistoricalIdentityResolver: (store: RelayStore) => (did: str
390
421
  }[];
391
422
  did: string;
392
423
  isDeleted: boolean;
424
+ services: {
425
+ [x: string]: unknown;
426
+ id: string;
427
+ type: string;
428
+ }[];
393
429
  } | undefined>;
394
430
  /**
395
431
  * Create a key resolver that only resolves current-state keys.
@@ -403,7 +439,7 @@ declare const createCurrentKeyResolver: (store: RelayStore) => (kid: string) =>
403
439
  * Ingest a batch of JWS operations
404
440
  *
405
441
  * Classifies, dependency-sorts, and processes each token. Identity operations
406
- * are processed first so content chains and beacons can resolve their keys.
442
+ * are processed first so content chains can resolve their keys.
407
443
  * Within each kind, genesis operations are processed before extensions.
408
444
  */
409
445
  declare const ingestOperations: (tokens: string[], store: RelayStore, options?: {
@@ -411,13 +447,13 @@ declare const ingestOperations: (tokens: string[], store: RelayStore, options?:
411
447
  }) => Promise<IngestionResult[]>;
412
448
 
413
449
  /**
414
- * Returns true if the rejection is due to a missing dependency that may
415
- * arrive later via sync or gossip. Only these specific patterns are
416
- * retryable everything else is treated as permanent.
450
+ * Returns true if a rejection is retryable (a missing dependency that may
451
+ * arrive later via sync or gossip). The sequencer branches on the STRUCTURED
452
+ * `dependencyMissing` flag set by the ingest producer — not on substring
453
+ * matching of the human-readable `error` string. Mirrors the Go twin's
454
+ * structured discriminator.
417
455
  */
418
- declare const isDependencyFailure: (error: string) => boolean;
419
- /** Derive the operation CID from a JWS token */
420
- declare const computeOpCID: (jwsToken: string) => Promise<string | undefined>;
456
+ declare const isDependencyFailure: (res: Pick<IngestionResult, "dependencyMissing">) => boolean;
421
457
  /**
422
458
  * Process unsequenced raw ops in a fixed-point loop until no more progress
423
459
  * is made. Returns the JWS tokens of newly sequenced ops and aggregate stats.
@@ -427,4 +463,4 @@ declare const sequenceOps: (store: RelayStore) => Promise<{
427
463
  result: SequenceResult;
428
464
  }>;
429
465
 
430
- 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, 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 };