@bsv/dpp-overlay-topics 0.4.0-beta.1

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.
Files changed (87) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +169 -0
  3. package/dist/anchorStorage.d.ts +58 -0
  4. package/dist/anchorStorage.d.ts.map +1 -0
  5. package/dist/anchorStorage.js +72 -0
  6. package/dist/anchorStorage.js.map +1 -0
  7. package/dist/attestationAnchor.d.ts +10 -0
  8. package/dist/attestationAnchor.d.ts.map +1 -0
  9. package/dist/attestationAnchor.js +10 -0
  10. package/dist/attestationAnchor.js.map +1 -0
  11. package/dist/attestationStorage.d.ts +49 -0
  12. package/dist/attestationStorage.d.ts.map +1 -0
  13. package/dist/attestationStorage.js +78 -0
  14. package/dist/attestationStorage.js.map +1 -0
  15. package/dist/capabilities.d.ts +127 -0
  16. package/dist/capabilities.d.ts.map +1 -0
  17. package/dist/capabilities.js +210 -0
  18. package/dist/capabilities.js.map +1 -0
  19. package/dist/engineStorage.d.ts +106 -0
  20. package/dist/engineStorage.d.ts.map +1 -0
  21. package/dist/engineStorage.js +253 -0
  22. package/dist/engineStorage.js.map +1 -0
  23. package/dist/evidenceExport.d.ts +189 -0
  24. package/dist/evidenceExport.d.ts.map +1 -0
  25. package/dist/evidenceExport.js +517 -0
  26. package/dist/evidenceExport.js.map +1 -0
  27. package/dist/history.d.ts +114 -0
  28. package/dist/history.d.ts.map +1 -0
  29. package/dist/history.js +215 -0
  30. package/dist/history.js.map +1 -0
  31. package/dist/index.d.ts +269 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +1223 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/lib.d.ts +31 -0
  36. package/dist/lib.d.ts.map +1 -0
  37. package/dist/lib.js +31 -0
  38. package/dist/lib.js.map +1 -0
  39. package/dist/limits.d.ts +44 -0
  40. package/dist/limits.d.ts.map +1 -0
  41. package/dist/limits.js +44 -0
  42. package/dist/limits.js.map +1 -0
  43. package/dist/lsAttestation.d.ts +21 -0
  44. package/dist/lsAttestation.d.ts.map +1 -0
  45. package/dist/lsAttestation.js +45 -0
  46. package/dist/lsAttestation.js.map +1 -0
  47. package/dist/lsDpp.d.ts +53 -0
  48. package/dist/lsDpp.d.ts.map +1 -0
  49. package/dist/lsDpp.js +148 -0
  50. package/dist/lsDpp.js.map +1 -0
  51. package/dist/lsUoraDpp.d.ts +55 -0
  52. package/dist/lsUoraDpp.d.ts.map +1 -0
  53. package/dist/lsUoraDpp.js +152 -0
  54. package/dist/lsUoraDpp.js.map +1 -0
  55. package/dist/policyConfig.d.ts +31 -0
  56. package/dist/policyConfig.d.ts.map +1 -0
  57. package/dist/policyConfig.js +112 -0
  58. package/dist/policyConfig.js.map +1 -0
  59. package/dist/retraction.d.ts +41 -0
  60. package/dist/retraction.d.ts.map +1 -0
  61. package/dist/retraction.js +147 -0
  62. package/dist/retraction.js.map +1 -0
  63. package/dist/storage.d.ts +117 -0
  64. package/dist/storage.d.ts.map +1 -0
  65. package/dist/storage.js +158 -0
  66. package/dist/storage.js.map +1 -0
  67. package/dist/sync.d.ts +75 -0
  68. package/dist/sync.d.ts.map +1 -0
  69. package/dist/sync.js +118 -0
  70. package/dist/sync.js.map +1 -0
  71. package/dist/tmAttestation.d.ts +36 -0
  72. package/dist/tmAttestation.d.ts.map +1 -0
  73. package/dist/tmAttestation.js +50 -0
  74. package/dist/tmAttestation.js.map +1 -0
  75. package/dist/tmDpp.d.ts +154 -0
  76. package/dist/tmDpp.d.ts.map +1 -0
  77. package/dist/tmDpp.js +397 -0
  78. package/dist/tmDpp.js.map +1 -0
  79. package/dist/tmUoraDpp.d.ts +73 -0
  80. package/dist/tmUoraDpp.d.ts.map +1 -0
  81. package/dist/tmUoraDpp.js +150 -0
  82. package/dist/tmUoraDpp.js.map +1 -0
  83. package/dist/uoraAnchor.d.ts +209 -0
  84. package/dist/uoraAnchor.d.ts.map +1 -0
  85. package/dist/uoraAnchor.js +433 -0
  86. package/dist/uoraAnchor.js.map +1 -0
  87. package/package.json +51 -0
@@ -0,0 +1,114 @@
1
+ import { type DppRecord, type DppRecordStore, type RecordSelector } from './storage.js';
2
+ export declare const PAGE_VERSION = "1";
3
+ /** One record as a page carries it: what the record store knows, nothing hydrated. */
4
+ export interface HistoryItem {
5
+ txid: string;
6
+ outputIndex: number;
7
+ op: string;
8
+ timestamp: string;
9
+ previousTxid: string;
10
+ spent: boolean;
11
+ spendingTxid: string;
12
+ /** The source's own sequence, the order pages are read in; strictly increasing across the pages of one export. */
13
+ sequence: number;
14
+ }
15
+ export interface HistoryPage {
16
+ pageVersion: typeof PAGE_VERSION;
17
+ items: HistoryItem[];
18
+ nextCursor: string | null;
19
+ snapshotId: string;
20
+ scope: {
21
+ source: string;
22
+ query: {
23
+ passportId: string;
24
+ } | {
25
+ uid: string;
26
+ };
27
+ /**
28
+ * The sequences this page covers within the snapshot: from the position
29
+ * after the previous page to the last item here, or to the snapshot's own
30
+ * sequence on the last page. Consecutive pages tile the snapshot with no
31
+ * gap and no overlap, so a reader detects a missing or a repeated page
32
+ * from the ranges alone.
33
+ */
34
+ sequenceRange: {
35
+ from: number;
36
+ to: number;
37
+ };
38
+ };
39
+ truncated: boolean;
40
+ completeForSnapshot: boolean;
41
+ pageSize: number;
42
+ }
43
+ export type HistoryErrorCode = 'query-invalid' | 'limit-invalid' | 'cursor-invalid' | 'snapshot-expired';
44
+ /** A refusal with the status and the name the wire carries. */
45
+ export declare class HistoryError extends Error {
46
+ readonly status: number;
47
+ readonly code: HistoryErrorCode;
48
+ readonly hint?: string | undefined;
49
+ constructor(status: number, code: HistoryErrorCode, message: string, hint?: string | undefined);
50
+ }
51
+ export interface Snapshot {
52
+ id: string;
53
+ /** Records with a sequence above this are outside the snapshot. */
54
+ sequence: number;
55
+ /** When the snapshot was taken, epoch milliseconds; expiry is measured from here. */
56
+ takenAt: number;
57
+ }
58
+ /**
59
+ * What a cursor resumes: a page of the history or a part of the complete
60
+ * export (`spec/portable-evidence.md` section 2). The kind is inside the
61
+ * signed payload, so a history cursor presented to the export, or the
62
+ * reverse, is refused by name rather than read as a position.
63
+ */
64
+ export type CursorKind = 'history' | 'export';
65
+ /** Where an export resumes: the snapshot, the position and the index of the part to build. */
66
+ export interface ExportResumption {
67
+ snapshot: Snapshot;
68
+ after: number;
69
+ part: number;
70
+ }
71
+ export interface HistoryRequest {
72
+ selector: RecordSelector;
73
+ /** As received on the wire: absent means the default page size. */
74
+ limit?: string | null;
75
+ cursor?: string | null;
76
+ }
77
+ export declare class HistoryPaginator {
78
+ private readonly records;
79
+ private readonly secret;
80
+ private readonly now;
81
+ constructor(records: DppRecordStore, options?: {
82
+ secret?: Buffer;
83
+ now?: () => Date;
84
+ });
85
+ /** Pin the store as it is now. The exporter uses this directly; the paginator does on a first page. */
86
+ takeSnapshot(): Promise<Snapshot>;
87
+ /** At most `limit` records of the selector within the snapshot after `after`, in sequence order: one part's candidates. */
88
+ readFrom(selector: RecordSelector, snapshot: Snapshot, after: number, limit: number): Promise<DppRecord[]>;
89
+ /** Every record of the selector within the snapshot, in sequence order, read page by page. */
90
+ readAll(selector: RecordSelector, snapshot: Snapshot): Promise<DppRecord[]>;
91
+ page(request: HistoryRequest): Promise<HistoryPage>;
92
+ /**
93
+ * The cursor that resumes the complete export after `after`, at part
94
+ * `part`, over the snapshot the first part pinned: the same tag, TTL and
95
+ * query binding as a history cursor, under the export kind.
96
+ */
97
+ mintExportCursor(snapshot: Snapshot, query: {
98
+ passportId: string;
99
+ }, after: number, part: number): string;
100
+ /** Where an export cursor resumes, or the named refusal a history cursor or a stale one earns. */
101
+ openExportCursor(cursor: string, query: {
102
+ passportId: string;
103
+ }): ExportResumption;
104
+ /**
105
+ * Open a cursor for the given query and kind, refusing by name a cursor
106
+ * of the other kind, one issued for another query, and one whose snapshot
107
+ * is older than the TTL.
108
+ */
109
+ private resume;
110
+ private mintCursor;
111
+ private tag;
112
+ private openCursor;
113
+ }
114
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Pages of a snapshot (`spec/portable-evidence.md` section 1,
3
+ * `contracts/paginated-history.schema.json`): the export beside the bounded
4
+ * lookup, which stays exactly what it is.
5
+ *
6
+ * A snapshot is the highest record sequence at the moment the first page is
7
+ * asked for. Every later page of the export reads only records at or below
8
+ * it, ordered by the store's own sequence, so a record admitted while a
9
+ * reader is walking the pages never appears in them and never shifts a page
10
+ * boundary: two readers of one snapshot receive the same pages. The cursor
11
+ * carries the snapshot and the position, base64url over JSON, and an
12
+ * HMAC-SHA256 tag under a secret this process drew at startup, so a cursor
13
+ * from another process, or one edited in transit, is refused by name rather
14
+ * than read as a position. A snapshot older than the TTL is refused by name
15
+ * too, with the instruction to start again without a cursor, because a stale
16
+ * snapshot continued from the middle would be a history that quietly stopped.
17
+ */
18
+ import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
19
+ import { DPP_SERVICE } from './lsDpp.js';
20
+ import { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE, SNAPSHOT_TTL_MS } from './limits.js';
21
+ import { selectorFilter } from './storage.js';
22
+ export const PAGE_VERSION = '1';
23
+ /** A refusal with the status and the name the wire carries. */
24
+ export class HistoryError extends Error {
25
+ status;
26
+ code;
27
+ hint;
28
+ constructor(status, code, message, hint) {
29
+ super(message);
30
+ this.status = status;
31
+ this.code = code;
32
+ this.hint = hint;
33
+ }
34
+ }
35
+ const base64url = (bytes) => bytes.toString('base64url');
36
+ export class HistoryPaginator {
37
+ records;
38
+ secret;
39
+ now;
40
+ constructor(records, options = {}) {
41
+ this.records = records;
42
+ // Per process, never persisted: a cursor is a resumption token for this
43
+ // node's current snapshot, and outliving the process is exactly what it
44
+ // must not do.
45
+ this.secret = options.secret ?? randomBytes(32);
46
+ this.now = options.now ?? (() => new Date());
47
+ }
48
+ /** Pin the store as it is now. The exporter uses this directly; the paginator does on a first page. */
49
+ async takeSnapshot() {
50
+ const sequence = await this.records.highestSequence();
51
+ const takenAt = this.now().getTime();
52
+ return { id: `${sequence}.${takenAt.toString(36)}`, sequence, takenAt };
53
+ }
54
+ /** At most `limit` records of the selector within the snapshot after `after`, in sequence order: one part's candidates. */
55
+ async readFrom(selector, snapshot, after, limit) {
56
+ return await this.records.findPage(selector, { after, upTo: snapshot.sequence }, limit);
57
+ }
58
+ /** Every record of the selector within the snapshot, in sequence order, read page by page. */
59
+ async readAll(selector, snapshot) {
60
+ const all = [];
61
+ let after = 0;
62
+ for (;;) {
63
+ const rows = await this.records.findPage(selector, { after, upTo: snapshot.sequence }, MAX_PAGE_SIZE);
64
+ all.push(...rows);
65
+ if (rows.length < MAX_PAGE_SIZE)
66
+ return all;
67
+ after = rows[rows.length - 1].sequence;
68
+ }
69
+ }
70
+ async page(request) {
71
+ let query;
72
+ try {
73
+ query = selectorFilter(request.selector);
74
+ }
75
+ catch (cause) {
76
+ throw new HistoryError(400, 'query-invalid', cause instanceof Error ? cause.message : 'invalid query');
77
+ }
78
+ const limit = parseLimit(request.limit);
79
+ let snapshot;
80
+ let after;
81
+ if (request.cursor == null || request.cursor === '') {
82
+ snapshot = await this.takeSnapshot();
83
+ after = 0;
84
+ }
85
+ else {
86
+ ;
87
+ ({ snapshot, after } = this.resume(request.cursor, query, 'history'));
88
+ }
89
+ // One row beyond the page tells whether the snapshot continues, without a
90
+ // count query that would race nothing but cost a scan.
91
+ const rows = await this.records.findPage(query, { after, upTo: snapshot.sequence }, limit + 1);
92
+ const more = rows.length > limit;
93
+ const items = rows.slice(0, limit);
94
+ const last = items[items.length - 1];
95
+ const to = more && last != null ? last.sequence : snapshot.sequence;
96
+ const nextCursor = more && last != null
97
+ ? this.mintCursor({ v: 1, kind: 'history', snapshot, query, after: last.sequence })
98
+ : null;
99
+ return {
100
+ pageVersion: PAGE_VERSION,
101
+ items: items.map(toItem),
102
+ nextCursor,
103
+ snapshotId: snapshot.id,
104
+ scope: {
105
+ source: DPP_SERVICE,
106
+ query,
107
+ sequenceRange: { from: Math.min(after + 1, to), to },
108
+ },
109
+ truncated: more,
110
+ // Only on the last page: every record of the selector at or below the
111
+ // snapshot has now been returned across the pages of this export.
112
+ completeForSnapshot: !more,
113
+ pageSize: limit,
114
+ };
115
+ }
116
+ /**
117
+ * The cursor that resumes the complete export after `after`, at part
118
+ * `part`, over the snapshot the first part pinned: the same tag, TTL and
119
+ * query binding as a history cursor, under the export kind.
120
+ */
121
+ mintExportCursor(snapshot, query, after, part) {
122
+ return this.mintCursor({ v: 1, kind: 'export', snapshot, query, after, part });
123
+ }
124
+ /** Where an export cursor resumes, or the named refusal a history cursor or a stale one earns. */
125
+ openExportCursor(cursor, query) {
126
+ const { snapshot, after, part } = this.resume(cursor, query, 'export');
127
+ if (!Number.isSafeInteger(part) || part < 2) {
128
+ throw new HistoryError(400, 'cursor-invalid', 'the cursor is not one this node issued: no part index');
129
+ }
130
+ return { snapshot, after, part: part };
131
+ }
132
+ /**
133
+ * Open a cursor for the given query and kind, refusing by name a cursor
134
+ * of the other kind, one issued for another query, and one whose snapshot
135
+ * is older than the TTL.
136
+ */
137
+ resume(cursor, query, kind) {
138
+ const payload = this.openCursor(cursor);
139
+ if (payload.kind !== kind) {
140
+ throw new HistoryError(400, 'cursor-invalid', `the cursor was issued for the ${payload.kind}, not the ${kind}`);
141
+ }
142
+ if (!sameQuery(payload.query, query)) {
143
+ throw new HistoryError(400, 'cursor-invalid', 'the cursor was issued for a different query');
144
+ }
145
+ if (this.now().getTime() - payload.snapshot.takenAt > SNAPSHOT_TTL_MS) {
146
+ throw new HistoryError(410, 'snapshot-expired', `snapshot ${payload.snapshot.id} is older than ${SNAPSHOT_TTL_MS / 1000} seconds`, `restart the ${kind === 'history' ? 'export' : 'complete export'} without a cursor to read a fresh snapshot from its first ${kind === 'history' ? 'page' : 'part'}`);
147
+ }
148
+ return { snapshot: payload.snapshot, after: payload.after, part: payload.part };
149
+ }
150
+ mintCursor(payload) {
151
+ const body = base64url(Buffer.from(JSON.stringify(payload), 'utf8'));
152
+ return `${body}.${this.tag(body)}`;
153
+ }
154
+ tag(body) {
155
+ return base64url(createHmac('sha256', this.secret).update(body).digest());
156
+ }
157
+ openCursor(cursor) {
158
+ const invalid = (detail) => new HistoryError(400, 'cursor-invalid', `the cursor is not one this node issued: ${detail}`);
159
+ const separator = cursor.lastIndexOf('.');
160
+ if (separator <= 0)
161
+ throw invalid('malformed');
162
+ const body = cursor.slice(0, separator);
163
+ const given = Buffer.from(cursor.slice(separator + 1), 'base64url');
164
+ const expected = Buffer.from(this.tag(body), 'base64url');
165
+ if (given.length !== expected.length || !timingSafeEqual(given, expected))
166
+ throw invalid('bad signature');
167
+ let payload;
168
+ try {
169
+ payload = JSON.parse(Buffer.from(body, 'base64url').toString('utf8'));
170
+ }
171
+ catch {
172
+ throw invalid('unreadable');
173
+ }
174
+ if (payload?.v !== 1 ||
175
+ (payload.kind !== 'history' && payload.kind !== 'export') ||
176
+ typeof payload.snapshot?.id !== 'string' ||
177
+ !Number.isSafeInteger(payload.snapshot.sequence) ||
178
+ !Number.isSafeInteger(payload.snapshot.takenAt) ||
179
+ !Number.isSafeInteger(payload.after) ||
180
+ typeof payload.query !== 'object' ||
181
+ payload.query === null) {
182
+ throw invalid('unexpected shape');
183
+ }
184
+ return payload;
185
+ }
186
+ }
187
+ /** Default 100, maximum 500, anything else refused: a string of digits is the only accepted spelling. */
188
+ function parseLimit(raw) {
189
+ if (raw == null || raw === '')
190
+ return DEFAULT_PAGE_SIZE;
191
+ if (!/^\d+$/.test(raw))
192
+ throw new HistoryError(400, 'limit-invalid', `limit must be an integer from 1 to ${MAX_PAGE_SIZE}`);
193
+ const limit = Number(raw);
194
+ if (limit < 1 || limit > MAX_PAGE_SIZE) {
195
+ throw new HistoryError(400, 'limit-invalid', `limit must be an integer from 1 to ${MAX_PAGE_SIZE}`);
196
+ }
197
+ return limit;
198
+ }
199
+ function sameQuery(a, b) {
200
+ return ('passportId' in a ? a.passportId : undefined) === ('passportId' in b ? b.passportId : undefined) &&
201
+ ('uid' in a ? a.uid : undefined) === ('uid' in b ? b.uid : undefined);
202
+ }
203
+ function toItem(record) {
204
+ return {
205
+ txid: record.txid,
206
+ outputIndex: record.outputIndex,
207
+ op: record.op,
208
+ timestamp: record.timestamp,
209
+ previousTxid: record.previousTxid,
210
+ spent: record.spent,
211
+ spendingTxid: record.spendingTxid,
212
+ sequence: record.sequence,
213
+ };
214
+ }
215
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,269 @@
1
+ /**
2
+ * The DPP overlay node: an HTTP host for two rails, wrapping the
3
+ * `@bsv/overlay` Engine.
4
+ *
5
+ * the passport `tm_dpp` admits states, `ls_dpp` resolves them
6
+ * the anchors `tm_attestation` admits generic anchors, `ls_attestation`
7
+ * looks them up; `tm_uora_dpp` and `ls_uora_dpp` carry the
8
+ * historical UORA anchors
9
+ *
10
+ * The wire contract is the ecosystem's standard one (BRC-22 submit, BRC-24
11
+ * lookup), pinned as OpenAPI in `contracts/overlay.yaml`:
12
+ *
13
+ * POST /submit application/octet-stream body = BEEF bytes
14
+ * X-Topics: ["tm_dpp"] -> STEAK as JSON, plus an
15
+ * X-Admission answer header (topic=admitted|duplicate|none)
16
+ * Authorization: Bearer <token> when SUBMIT_TOKEN is set
17
+ * POST /lookup {"service":"ls_dpp","query":{"passportId"|"uid": "..."}}
18
+ * {"service":"ls_uora_dpp","query":{"issuer":"did:key:z..."}}
19
+ * -> {type:"output-list",
20
+ * outputs:[{beef,outputIndex}]}
21
+ * POST /arc-ingest {"txid","merklePath","blockHeight"}
22
+ * -> the proof, checked and
23
+ * applied to the held state (spec/services.md section 2);
24
+ * X-Callback-Token or bearer when ARC_CALLBACK_TOKEN is set
25
+ * GET /health -> {status:"ok",...}
26
+ *
27
+ * And the extensions this reference deployment serves beside them, each in
28
+ * the shape a contract in `contracts/` fixes:
29
+ *
30
+ * GET /capabilities -> the capability document
31
+ * (contracts/capabilities.schema.json), built from constants
32
+ * and configuration, never typed by hand
33
+ * GET /history?passportId=|uid=&limit=&cursor= -> one page of a stable
34
+ * snapshot (contracts/paginated-history.schema.json), the
35
+ * export beside the bounded lookup
36
+ * GET /evidence-package?passportId= -> dpp-evidence-package@1
37
+ * as {manifest, files} (contracts/evidence-package.schema.json),
38
+ * signed with EXPORT_SIGNING_KEY; 503 when it is unset;
39
+ * bounded to the newest 500 states, the rest declared absent
40
+ * GET /evidence-export?passportId=&cursor= -> one part of the complete
41
+ * export (contracts/evidence-export.schema.json): a package
42
+ * over a contiguous sequence range of one snapshot, oldest
43
+ * first, bounded by states and bytes, resumed by cursor;
44
+ * Authorization: Bearer <token> when EXPORT_TOKEN is set
45
+ * POST /retract {"txid","outputIndex","reason"} -> removes a state the
46
+ * network refused, behind the /submit bearer; 409 when the
47
+ * state is proven, spent or known to the chain tracker
48
+ * POST /requestSyncResponse, POST /requestForeignGASPNode
49
+ * -> the upstream GASP
50
+ * routes a peer synchronises from, exactly as the overlay
51
+ * protocol defines them
52
+ *
53
+ * Everything is environment; an unset variable switches its feature off or
54
+ * falls back, and only a missing identity key (or a policy file that does not
55
+ * verify) fails the boot. See the Configuration table in this package's
56
+ * README.
57
+ *
58
+ * This file is both the entry point and a library: it boots only when node
59
+ * runs it directly, so tests can drive `createRequestHandler` and
60
+ * `startOverlayService` without a container.
61
+ *
62
+ * Deliberately absent: a Broadcaster and an Advertiser. The app's wallet has
63
+ * already broadcast the transaction by the time it announces it here, so a
64
+ * second broadcast would only add a failure mode; and SHIP/SLAP advertising
65
+ * would need this service to hold a funded wallet of its own. Neither is
66
+ * needed for the demo, and both can be added later without changing the wire.
67
+ * Peer synchronisation is present but static: SYNC_PEERS names the operators
68
+ * this node pulls from through the SDK's GASP (sync.ts), and a state a peer
69
+ * offers passes the same topic managers as one a writer announces.
70
+ * Because this host does not broadcast, no broadcaster's callback reaches it
71
+ * on its own: merkle proofs arrive through POST /arc-ingest, pushed by the
72
+ * writer once its wallet has them or by a broadcaster whose callback URL a
73
+ * writer pointed here (spec/writing.md section 7). Re-announcing a mined state
74
+ * would not do it: the engine skips a txid it already holds.
75
+ */
76
+ import { type IncomingMessage, type Server, type ServerResponse } from 'node:http';
77
+ import { type ChainTracker } from '@bsv/sdk';
78
+ import { Engine, type LookupService } from '@bsv/overlay';
79
+ import { type DppRecordStore } from './storage.js';
80
+ import { type RetractableStorage } from './engineStorage.js';
81
+ import { UORA_SERVICE, UORA_TOPIC } from './lsUoraDpp.js';
82
+ import { ATTESTATION_TOPIC } from './tmAttestation.js';
83
+ import { ATTESTATION_SERVICE } from './lsAttestation.js';
84
+ import { type PublisherPolicyConfig } from './policyConfig.js';
85
+ import { type SyncSettings } from './sync.js';
86
+ export declare const TOPIC = "tm_dpp";
87
+ export declare const SERVICE = "ls_dpp";
88
+ export { UORA_SERVICE, UORA_TOPIC };
89
+ export { ATTESTATION_SERVICE, ATTESTATION_TOPIC };
90
+ /** The slice of the Engine the HTTP layer uses, so a test can stand one in. */
91
+ export type OverlayEngine = Pick<Engine, 'submit' | 'lookup' | 'listTopicManagers' | 'listLookupServiceProviders' | 'handleNewMerkleProof' | 'getDocumentationForTopicManager' | 'getDocumentationForLookupServiceProvider' | 'provideForeignSyncResponse' | 'provideForeignGASPNode'>;
92
+ /**
93
+ * The stores, services and policy the extension routes work on, which the
94
+ * Engine does not expose through its own surface. `/history` and
95
+ * `/evidence-package` read the record store and the engine storage;
96
+ * `/retract` removes from both and tells the lookup services; `/capabilities`
97
+ * reports the policy. Without them, the read routes answer 503 by name and the
98
+ * capability document describes a node with no configured policy.
99
+ */
100
+ export interface NodeComponents {
101
+ records: DppRecordStore;
102
+ engineStorage: RetractableStorage;
103
+ lookupServices: Record<string, LookupService>;
104
+ publisherPolicy?: PublisherPolicyConfig;
105
+ serviceIdentityKey?: string;
106
+ anchorServiceKeys?: string[];
107
+ ownerConsent?: boolean | {
108
+ authorities: string[];
109
+ };
110
+ /** CONTROL_AUTHORITIES and ACCEPTANCE_COMMITMENT, the version 2 admission options (`spec/record-model-v2.md` §6, `spec/managed-custody.md`). */
111
+ controlAuthorities?: string[];
112
+ managedAcceptance?: boolean;
113
+ /** SYNC_PEERS and SYNC_INTERVAL_MS, reported by the capability document; the Engine holds the same peers as its syncConfiguration. */
114
+ sync?: Pick<SyncSettings, 'peers' | 'intervalMs'>;
115
+ }
116
+ export interface OverlayHttpOptions {
117
+ /**
118
+ * Shared secret required as `Authorization: Bearer` on POST /submit and
119
+ * POST /retract, the two routes that change what the index holds.
120
+ * `/lookup` and `/health` stay open: browser verification is a stated goal,
121
+ * and a read costs no header quota. Unset leaves both open too, which is only
122
+ * acceptable on a container nobody else can reach.
123
+ */
124
+ submitToken?: string;
125
+ /**
126
+ * Shared secret required on POST /arc-ingest, as `Authorization: Bearer` or
127
+ * as `X-Callback-Token`, the two ways an ARC-compatible broadcaster sends the
128
+ * token it was given at submission. Unset leaves the route open; every proof
129
+ * is still verified against the header source before it is stored, so an
130
+ * open route costs header quota rather than truth.
131
+ */
132
+ proofToken?: string;
133
+ /**
134
+ * The header source a pushed proof is validated against before it is
135
+ * applied, normally the same one the engine verifies submissions with.
136
+ * 'scripts only' or unset applies a proof on its local check alone, which
137
+ * is the local-development setting the engine's own option already is.
138
+ */
139
+ chainTracker?: ChainTracker | 'scripts only';
140
+ /** Reported by /health. */
141
+ network?: string;
142
+ /** Reported by /health. Defaults to the moment the handler was made. */
143
+ startedAt?: string;
144
+ /**
145
+ * The address to bind. Unset binds the wildcard, which is what a container
146
+ * wants and what `main()` leaves it as.
147
+ *
148
+ * **A test must set this, and the reason is not tidiness.** A wildcard bind
149
+ * on an ephemeral port succeeds even when another process already holds that
150
+ * exact port bound to `127.0.0.1` alone: there is no `EADDRINUSE`, and
151
+ * `address().port` reports the port as though it were ours. A request to
152
+ * `127.0.0.1` then goes to the more specific binding, so the caller is
153
+ * answered by the other process and the service it started never sees the
154
+ * request. Found on 2026-08-06 behind an intermittent failure in
155
+ * `test/http.test.ts`: a Logitech daemon holding three ports at the bottom of
156
+ * the ephemeral range answered `501` with an empty body, which surfaces
157
+ * either as a wrong status or as `Unexpected end of JSON input`, roughly once
158
+ * in a hundred server starts. Binding the loopback explicitly makes the
159
+ * socket a caller reaches the socket that was bound.
160
+ */
161
+ host?: string;
162
+ /** What the extension routes work on; see `NodeComponents`. */
163
+ components?: NodeComponents;
164
+ /**
165
+ * EXPORT_SIGNING_KEY: the private key, hex, that signs evidence-package
166
+ * manifests. Unset, GET /evidence-package answers 503 export-unavailable and
167
+ * the capability document lists the export as unsupported. Malformed, the
168
+ * handler refuses to be built, which is the boot.
169
+ */
170
+ exportSigningKey?: string;
171
+ /**
172
+ * EXPORT_TOKEN: shared secret required as `Authorization: Bearer` on GET
173
+ * /evidence-export, the complete export, whose parts are each bounded but
174
+ * whose number is not. Unset leaves it open, as GET /history is; the bounded
175
+ * GET /evidence-package stays open either way, and the capability document
176
+ * says which.
177
+ */
178
+ exportToken?: string;
179
+ /**
180
+ * Whether the network knows a transaction, for POST /retract: asked of the
181
+ * header source's operator before an output is removed. Unset when there is
182
+ * no header source (CHAIN_TRACKER=scripts-only); the retraction then runs on
183
+ * the local merkle-path check alone and its answer says so.
184
+ */
185
+ knownOnChain?: (txid: string) => Promise<boolean>;
186
+ /** The clock: snapshot expiry, export time and the policy's "active now" read it. Injectable for tests. */
187
+ now?: () => Date;
188
+ }
189
+ /**
190
+ * The whole HTTP surface, as a plain node request listener. Separated from the
191
+ * server so a test can exercise the wire contract against a stand-in engine.
192
+ */
193
+ export declare function createRequestHandler(engine: OverlayEngine, options?: OverlayHttpOptions): (request: IncomingMessage, response: ServerResponse) => void;
194
+ export interface RunningService {
195
+ server: Server;
196
+ /** The port actually bound, which matters when the caller asked for 0. */
197
+ port: number;
198
+ close: () => Promise<void>;
199
+ }
200
+ /** Bind the HTTP surface. Resolves once the socket is listening. */
201
+ export declare function startOverlayService(engine: OverlayEngine, options?: OverlayHttpOptions & {
202
+ port?: number;
203
+ }): Promise<RunningService>;
204
+ /**
205
+ * The key `server_signature` is checked against (`spec/record-model.md` §5). Only the
206
+ * public half is needed, so the deployment should set SERVICE_IDENTITY_KEY
207
+ * and this service never holds the treasury secret. SERVER_PRIVATE_KEY is
208
+ * accepted as a fallback because it is what every other component is
209
+ * configured with, but it grants this container more than it needs.
210
+ */
211
+ export declare function serviceIdentityKey(): string;
212
+ /**
213
+ * Identity keys of the anchoring services whose UORA anchors this instance
214
+ * admits, comma-separated in ANCHOR_SERVICE_KEYS.
215
+ *
216
+ * A list rather than one key, because the shared overlay instances this topic
217
+ * is meant for may serve more than one anchoring deployment, and because the
218
+ * resolver already established that this programme has anchored under two
219
+ * treasuries without being able to tell which.
220
+ *
221
+ * Public keys only. Unlike `serviceIdentityKey` there is no private-key
222
+ * fallback: the anchoring treasury is a different custody boundary from this
223
+ * container, and inviting an operator to paste its secret here to save a step
224
+ * is exactly the convenience that should not exist.
225
+ */
226
+ export declare function anchorServiceKeys(): string[];
227
+ /**
228
+ * The owner-signed transfer (`spec/custody.md` §4) is a profile's choice, and
229
+ * a deployment selects it with OWNER_CONSENT=required. TRANSFER_AUTHORITIES
230
+ * then names, comma-separated, the identity keys that may move ownership
231
+ * without proving consent (recovery); public keys only, as for
232
+ * ANCHOR_SERVICE_KEYS, and validated when the topic manager is built. Any
233
+ * other value of OWNER_CONSENT fails the boot rather than being read as a
234
+ * guess, and authorities set without the policy are a misconfiguration worth a
235
+ * warning, because they would silently do nothing.
236
+ */
237
+ export declare function ownerConsentPolicy(): boolean | {
238
+ authorities: string[];
239
+ };
240
+ /**
241
+ * The version 2 admission options (`spec/record-model-v2.md` §6,
242
+ * `spec/managed-custody.md`). ACCEPTANCE_COMMITMENT=required selects the
243
+ * managed-custody profile: a version 2 TRANSFER is admitted only with its
244
+ * acceptance commitment. CONTROL_AUTHORITIES names, comma-separated, the
245
+ * identity keys whose version 2 UPDATE, TRANSFER or RETIRE is admitted without
246
+ * a control proof; absent, the TRANSFER_AUTHORITIES serve both versions.
247
+ * Public keys only, validated when the topic manager is built; any other value
248
+ * of ACCEPTANCE_COMMITMENT fails the boot.
249
+ */
250
+ export declare function versionTwoAdmission(): {
251
+ managedAcceptance: boolean;
252
+ controlAuthorities?: string[];
253
+ };
254
+ /**
255
+ * EXPORT_SIGNING_KEY: the private key that signs evidence-package manifests
256
+ * (`spec/portable-evidence.md` section 2). Optional, because a node that
257
+ * exports nothing needs no key; malformed, it fails the boot, because a key
258
+ * that cannot sign is a promise the capability document would break.
259
+ */
260
+ export declare function exportSigningKey(): string | undefined;
261
+ /**
262
+ * Whether the network knows a transaction, asked of the same explorer the
263
+ * default header source reads, for POST /retract: a transaction it answers is
264
+ * one the network took, and an index does not retract what a block holds. A
265
+ * 404 is the one negative; any other failure is neither and is reported as
266
+ * the source being unavailable.
267
+ */
268
+ export declare function whatsOnChainKnows(network: 'main' | 'test', apiKey?: string): (txid: string) => Promise<boolean>;
269
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}