@private.me/xbind 3.0.2 → 3.0.4

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 (222) hide show
  1. package/README.md +2366 -204
  2. package/dist-standalone/_deps/mldsa-wasm/dist/mldsa.js +1 -1920
  3. package/dist-standalone/_deps/shared/cjs/errors.js +1 -729
  4. package/dist-standalone/_deps/shared/cjs/index.js +1 -463
  5. package/dist-standalone/_deps/shared/cjs/types.js +1 -315
  6. package/dist-standalone/_deps/shared/errors.js +1 -244
  7. package/dist-standalone/_deps/shared/index.js +1 -72
  8. package/dist-standalone/_deps/shared/types.js +1 -86
  9. package/dist-standalone/_deps/ux-helpers/cjs/errors.js +1 -1
  10. package/dist-standalone/_deps/ux-helpers/cjs/index.js +1 -1
  11. package/dist-standalone/_deps/ux-helpers/cjs/pagination.js +1 -1
  12. package/dist-standalone/_deps/ux-helpers/cjs/progress.js +1 -1
  13. package/dist-standalone/_deps/ux-helpers/cjs/search.js +1 -1
  14. package/dist-standalone/_deps/ux-helpers/cjs/types.js +1 -1
  15. package/dist-standalone/_deps/ux-helpers/errors.js +1 -1
  16. package/dist-standalone/_deps/ux-helpers/index.js +1 -1
  17. package/dist-standalone/_deps/ux-helpers/pagination.js +1 -1
  18. package/dist-standalone/_deps/ux-helpers/progress.js +1 -1
  19. package/dist-standalone/_deps/ux-helpers/search.js +1 -1
  20. package/dist-standalone/_deps/xchange/auto-accept.js +1 -1
  21. package/dist-standalone/_deps/xchange/cjs/auto-accept.js +1 -1
  22. package/dist-standalone/_deps/xchange/cjs/errors.js +1 -1
  23. package/dist-standalone/_deps/xchange/cjs/index.js +1 -1
  24. package/dist-standalone/_deps/xchange/cjs/invite-client.js +1 -1
  25. package/dist-standalone/_deps/xchange/cjs/lazy-init.js +1 -1
  26. package/dist-standalone/_deps/xchange/cjs/trust-integration.js +1 -1
  27. package/dist-standalone/_deps/xchange/cjs/xchange.js +1 -1
  28. package/dist-standalone/_deps/xchange/errors.js +1 -1
  29. package/dist-standalone/_deps/xchange/index.js +1 -1
  30. package/dist-standalone/_deps/xchange/invite-client.js +1 -1
  31. package/dist-standalone/_deps/xchange/lazy-init.js +1 -1
  32. package/dist-standalone/_deps/xchange/trust-integration.js +1 -1
  33. package/dist-standalone/_deps/xchange/xchange.js +1 -1
  34. package/dist-standalone/_deps/xregistry/cjs/discovery.js +1 -1
  35. package/dist-standalone/_deps/xregistry/cjs/errors.js +1 -1
  36. package/dist-standalone/_deps/xregistry/cjs/index.js +1 -1
  37. package/dist-standalone/_deps/xregistry/cjs/registry.js +1 -1
  38. package/dist-standalone/_deps/xregistry/cjs/schema.js +1 -1
  39. package/dist-standalone/_deps/xregistry/cjs/types.js +1 -1
  40. package/dist-standalone/_deps/xregistry/discovery.js +1 -1
  41. package/dist-standalone/_deps/xregistry/errors.js +1 -1
  42. package/dist-standalone/_deps/xregistry/index.js +1 -1
  43. package/dist-standalone/_deps/xregistry/registry.js +1 -1
  44. package/dist-standalone/_deps/xregistry/schema.js +1 -1
  45. package/dist-standalone/_deps/xregistry/types.js +1 -1
  46. package/dist-standalone/agent-call.d.ts +2 -2
  47. package/dist-standalone/agent-call.js +1 -659
  48. package/dist-standalone/agent-sdk.js +1 -328
  49. package/dist-standalone/agent.d.ts +2 -0
  50. package/dist-standalone/agent.js +1 -1800
  51. package/dist-standalone/approval.js +1 -193
  52. package/dist-standalone/async-iterators.d.ts +3 -3
  53. package/dist-standalone/async-iterators.js +1 -382
  54. package/dist-standalone/auth.js +1 -219
  55. package/dist-standalone/auto-accept.js +1 -229
  56. package/dist-standalone/backup-config.js +1 -201
  57. package/dist-standalone/backup.js +1 -326
  58. package/dist-standalone/batch-operations.js +1 -388
  59. package/dist-standalone/cancellation.js +1 -477
  60. package/dist-standalone/checkpoint.js +1 -186
  61. package/dist-standalone/circuit-breaker.js +1 -468
  62. package/dist-standalone/cjs/agent-call.js +1 -701
  63. package/dist-standalone/cjs/agent-sdk.js +1 -332
  64. package/dist-standalone/cjs/agent.js +1 -1837
  65. package/dist-standalone/cjs/approval.js +1 -199
  66. package/dist-standalone/cjs/async-iterators.js +1 -392
  67. package/dist-standalone/cjs/auth.js +1 -225
  68. package/dist-standalone/cjs/auto-accept.js +1 -233
  69. package/dist-standalone/cjs/backup-config.js +1 -207
  70. package/dist-standalone/cjs/backup.js +1 -330
  71. package/dist-standalone/cjs/batch-operations.js +1 -397
  72. package/dist-standalone/cjs/cancellation.js +1 -490
  73. package/dist-standalone/cjs/checkpoint.js +1 -193
  74. package/dist-standalone/cjs/circuit-breaker.js +1 -476
  75. package/dist-standalone/cjs/cli/init.js +1 -492
  76. package/dist-standalone/cjs/config-validation.js +1 -522
  77. package/dist-standalone/cjs/connect.js +1 -312
  78. package/dist-standalone/cjs/connection-pool.js +1 -506
  79. package/dist-standalone/cjs/correlation-id.js +1 -339
  80. package/dist-standalone/cjs/crypto-utils.js +1 -176
  81. package/dist-standalone/cjs/debug-mode.js +1 -534
  82. package/dist-standalone/cjs/did-document.js +1 -101
  83. package/dist-standalone/cjs/did-privateme.js +1 -130
  84. package/dist-standalone/cjs/did-web.js +1 -201
  85. package/dist-standalone/cjs/discovery.js +1 -462
  86. package/dist-standalone/cjs/dual-mode.js +1 -251
  87. package/dist-standalone/cjs/email-templates.js +1 -313
  88. package/dist-standalone/cjs/email-transport.js +1 -239
  89. package/dist-standalone/cjs/envelope.js +1 -538
  90. package/dist-standalone/cjs/errors.js +1 -913
  91. package/dist-standalone/cjs/event-emitter.js +1 -461
  92. package/dist-standalone/cjs/gateway-state.js +1 -55
  93. package/dist-standalone/cjs/gateway-transport.js +1 -120
  94. package/dist-standalone/cjs/graceful-degradation.js +1 -403
  95. package/dist-standalone/cjs/guardrails.js +1 -223
  96. package/dist-standalone/cjs/health-check.js +1 -336
  97. package/dist-standalone/cjs/http-compat.js +1 -272
  98. package/dist-standalone/cjs/http-status-map.js +1 -571
  99. package/dist-standalone/cjs/identity.js +1 -645
  100. package/dist-standalone/cjs/index.js +1 -406
  101. package/dist-standalone/cjs/invitation.js +1 -421
  102. package/dist-standalone/cjs/invite.js +1 -328
  103. package/dist-standalone/cjs/key-agreement.js +1 -335
  104. package/dist-standalone/cjs/lazy-init.js +1 -300
  105. package/dist-standalone/cjs/logger.js +1 -291
  106. package/dist-standalone/cjs/loopback-transport.js +1 -0
  107. package/dist-standalone/cjs/mdns-discovery.js +1 -202
  108. package/dist-standalone/cjs/nonce-store.js +1 -80
  109. package/dist-standalone/cjs/pairing-manager.js +1 -223
  110. package/dist-standalone/cjs/plugin-system.js +1 -264
  111. package/dist-standalone/cjs/plugins/logging.js +1 -168
  112. package/dist-standalone/cjs/plugins/metrics.js +1 -181
  113. package/dist-standalone/cjs/plugins/validation.js +1 -302
  114. package/dist-standalone/cjs/policy.js +1 -320
  115. package/dist-standalone/cjs/progress-callbacks.js +1 -583
  116. package/dist-standalone/cjs/redis-nonce-store.js +1 -76
  117. package/dist-standalone/cjs/registry-middleware.js +1 -50
  118. package/dist-standalone/cjs/retry-strategies.js +1 -544
  119. package/dist-standalone/cjs/retry-transport.js +1 -102
  120. package/dist-standalone/cjs/runtime/browser.js +1 -533
  121. package/dist-standalone/cjs/runtime/edge.js +1 -526
  122. package/dist-standalone/cjs/runtime/react-native.js +1 -394
  123. package/dist-standalone/cjs/security-policy.js +1 -245
  124. package/dist-standalone/cjs/serialization.js +1 -1040
  125. package/dist-standalone/cjs/split-channel.js +1 -225
  126. package/dist-standalone/cjs/subscription-proof.js +1 -230
  127. package/dist-standalone/cjs/succession.js +1 -148
  128. package/dist-standalone/cjs/timeouts.js +1 -412
  129. package/dist-standalone/cjs/trace-context.js +1 -424
  130. package/dist-standalone/cjs/trace-spans.js +1 -495
  131. package/dist-standalone/cjs/transport.js +1 -63
  132. package/dist-standalone/cjs/trust-registry.js +1 -991
  133. package/dist-standalone/cjs/types/error-response.js +1 -56
  134. package/dist-standalone/cjs/vault-auth.js +1 -178
  135. package/dist-standalone/cjs/vault-store-loader.js +1 -194
  136. package/dist-standalone/cjs/verify.js +1 -25
  137. package/dist-standalone/cjs/version-info.js +1 -543
  138. package/dist-standalone/cjs/xfetch.js +1 -340
  139. package/dist-standalone/cli/init.js +1 -455
  140. package/dist-standalone/cli/setup.js +1 -514
  141. package/dist-standalone/cli/types.js +1 -27
  142. package/dist-standalone/cli/xbind.js +1 -148
  143. package/dist-standalone/config-validation.js +1 -513
  144. package/dist-standalone/connect.js +1 -274
  145. package/dist-standalone/connection-pool.js +1 -500
  146. package/dist-standalone/correlation-id.js +1 -326
  147. package/dist-standalone/crypto-utils.d.ts +2 -7
  148. package/dist-standalone/crypto-utils.js +1 -157
  149. package/dist-standalone/debug-mode.js +1 -510
  150. package/dist-standalone/did-document.js +1 -96
  151. package/dist-standalone/did-privateme.js +1 -121
  152. package/dist-standalone/did-web.js +1 -196
  153. package/dist-standalone/discovery.js +1 -458
  154. package/dist-standalone/dual-mode.js +1 -247
  155. package/dist-standalone/email-templates.js +1 -309
  156. package/dist-standalone/email-transport.d.ts +2 -2
  157. package/dist-standalone/email-transport.js +1 -232
  158. package/dist-standalone/envelope.js +1 -525
  159. package/dist-standalone/errors.d.ts +13 -3
  160. package/dist-standalone/errors.js +1 -896
  161. package/dist-standalone/event-emitter.js +1 -456
  162. package/dist-standalone/gateway-state.d.ts +1 -1
  163. package/dist-standalone/gateway-state.js +1 -51
  164. package/dist-standalone/gateway-transport.js +1 -116
  165. package/dist-standalone/graceful-degradation.js +1 -396
  166. package/dist-standalone/guardrails.js +1 -216
  167. package/dist-standalone/health-check.d.ts +5 -1
  168. package/dist-standalone/health-check.js +1 -332
  169. package/dist-standalone/http-compat.d.ts +1 -1
  170. package/dist-standalone/http-compat.js +1 -267
  171. package/dist-standalone/http-status-map.js +1 -561
  172. package/dist-standalone/identity.js +1 -619
  173. package/dist-standalone/index.d.ts +15 -4
  174. package/dist-standalone/index.js +1 -78
  175. package/dist-standalone/invitation.js +1 -415
  176. package/dist-standalone/invite.js +1 -324
  177. package/dist-standalone/key-agreement.js +1 -325
  178. package/dist-standalone/lazy-init.d.ts +11 -6
  179. package/dist-standalone/lazy-init.js +1 -295
  180. package/dist-standalone/logger.js +1 -285
  181. package/dist-standalone/loopback-transport.d.ts +87 -0
  182. package/dist-standalone/loopback-transport.js +1 -0
  183. package/dist-standalone/mdns-discovery.js +1 -195
  184. package/dist-standalone/nonce-store.js +1 -76
  185. package/dist-standalone/pairing-manager.js +1 -219
  186. package/dist-standalone/plugin-system.js +1 -257
  187. package/dist-standalone/plugins/logging.js +1 -163
  188. package/dist-standalone/plugins/metrics.d.ts +4 -4
  189. package/dist-standalone/plugins/metrics.js +1 -176
  190. package/dist-standalone/plugins/validation.js +1 -297
  191. package/dist-standalone/policy.js +1 -315
  192. package/dist-standalone/progress-callbacks.js +1 -576
  193. package/dist-standalone/redis-nonce-store.js +1 -72
  194. package/dist-standalone/registry-middleware.js +1 -47
  195. package/dist-standalone/retry-strategies.js +1 -534
  196. package/dist-standalone/retry-transport.js +1 -98
  197. package/dist-standalone/runtime/browser.js +1 -516
  198. package/dist-standalone/runtime/edge.js +1 -511
  199. package/dist-standalone/runtime/react-native.d.ts +1 -1
  200. package/dist-standalone/runtime/react-native.js +1 -383
  201. package/dist-standalone/security-policy.js +1 -239
  202. package/dist-standalone/serialization.js +1 -1031
  203. package/dist-standalone/split-channel.d.ts +1 -1
  204. package/dist-standalone/split-channel.js +1 -219
  205. package/dist-standalone/subscription-proof.js +1 -224
  206. package/dist-standalone/succession.js +1 -142
  207. package/dist-standalone/timeouts.js +1 -398
  208. package/dist-standalone/trace-context.js +1 -414
  209. package/dist-standalone/trace-spans.js +1 -488
  210. package/dist-standalone/transport.d.ts +1 -1
  211. package/dist-standalone/transport.js +1 -59
  212. package/dist-standalone/trust-registry.d.ts +3 -3
  213. package/dist-standalone/trust-registry.js +1 -950
  214. package/dist-standalone/types/error-response.js +1 -52
  215. package/dist-standalone/vault-auth.js +1 -174
  216. package/dist-standalone/vault-store-loader.d.ts +9 -0
  217. package/dist-standalone/vault-store-loader.js +1 -187
  218. package/dist-standalone/verify.js +1 -16
  219. package/dist-standalone/version-info.js +1 -530
  220. package/dist-standalone/xfetch.js +1 -335
  221. package/package.json +1 -1
  222. package/share1.dat +0 -0
@@ -1,991 +1 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.FileTrustRegistry = exports.HttpTrustRegistry = exports.MemoryTrustRegistry = exports.RegistrationRateLimiter = void 0;
37
- exports.createEnterpriseTrustRegistry = createEnterpriseTrustRegistry;
38
- const shared_1 = require("../_deps/shared/index.js");
39
- const fs = __importStar(require("node:fs/promises"));
40
- const path = __importStar(require("node:path"));
41
- /* ── Types ── */
42
- /** Check if a registry entry has expired. */
43
- function isExpired(entry) {
44
- if (!entry.expiresAt)
45
- return false;
46
- return Date.now() > entry.expiresAt;
47
- }
48
- /* ── Rate Limiting ── */
49
- /**
50
- * Rate limiter for DID registration endpoints.
51
- *
52
- * Implements sliding window algorithm with:
53
- * - Per-IP limit: 10 registrations/hour
54
- * - Global limit: 1000 registrations/hour
55
- *
56
- * Prevents DID registration spam attacks (SCALE-1).
57
- */
58
- class RegistrationRateLimiter {
59
- perIPTimestamps = new Map();
60
- globalTimestamps = [];
61
- perIPLimit;
62
- globalLimit;
63
- windowMs;
64
- cleanupInterval = null;
65
- /**
66
- * Create a new registration rate limiter.
67
- *
68
- * @param perIPLimit - Maximum registrations per IP in time window (default: 10)
69
- * @param globalLimit - Maximum global registrations in time window (default: 1000)
70
- * @param windowMs - Time window in milliseconds (default: 3600000 = 1 hour)
71
- */
72
- constructor(perIPLimit = 10, globalLimit = 1000, windowMs = 3600000) {
73
- this.perIPLimit = perIPLimit;
74
- this.globalLimit = globalLimit;
75
- this.windowMs = windowMs;
76
- // Cleanup old timestamps every 5 minutes
77
- this.cleanupInterval = setInterval(() => this.cleanup(), 300000);
78
- }
79
- /**
80
- * Check if registration is allowed for the given IP.
81
- *
82
- * @param ip - Client IP address
83
- * @returns True if allowed, false if rate limited
84
- */
85
- checkLimit(ip) {
86
- const now = Date.now();
87
- const windowStart = now - this.windowMs;
88
- // Check per-IP limit
89
- const ipTimestamps = this.perIPTimestamps.get(ip) || [];
90
- const recentIPRequests = ipTimestamps.filter((t) => t > windowStart);
91
- if (recentIPRequests.length >= this.perIPLimit) {
92
- return false;
93
- }
94
- // Check global limit
95
- const recentGlobalRequests = this.globalTimestamps.filter((t) => t > windowStart);
96
- if (recentGlobalRequests.length >= this.globalLimit) {
97
- return false;
98
- }
99
- return true;
100
- }
101
- /**
102
- * Record a registration attempt.
103
- *
104
- * Call this AFTER successful registration to avoid counting failures.
105
- *
106
- * @param ip - Client IP address
107
- */
108
- recordRegistration(ip) {
109
- const now = Date.now();
110
- // Record per-IP
111
- const ipTimestamps = this.perIPTimestamps.get(ip) || [];
112
- ipTimestamps.push(now);
113
- this.perIPTimestamps.set(ip, ipTimestamps);
114
- // Record global
115
- this.globalTimestamps.push(now);
116
- }
117
- /**
118
- * Get remaining registrations for an IP.
119
- *
120
- * @param ip - Client IP address
121
- * @returns Remaining registrations allowed
122
- */
123
- getRemainingForIP(ip) {
124
- const now = Date.now();
125
- const windowStart = now - this.windowMs;
126
- const ipTimestamps = this.perIPTimestamps.get(ip) || [];
127
- const recentIPRequests = ipTimestamps.filter((t) => t > windowStart);
128
- return Math.max(0, this.perIPLimit - recentIPRequests.length);
129
- }
130
- /**
131
- * Get remaining global registrations.
132
- *
133
- * @returns Remaining global registrations allowed
134
- */
135
- getRemainingGlobal() {
136
- const now = Date.now();
137
- const windowStart = now - this.windowMs;
138
- const recentGlobalRequests = this.globalTimestamps.filter((t) => t > windowStart);
139
- return Math.max(0, this.globalLimit - recentGlobalRequests.length);
140
- }
141
- /**
142
- * Get reset time for an IP's rate limit.
143
- *
144
- * @param ip - Client IP address
145
- * @returns Unix timestamp (ms) when limit resets, or null if not rate limited
146
- */
147
- getResetTimeForIP(ip) {
148
- const ipTimestamps = this.perIPTimestamps.get(ip) || [];
149
- if (ipTimestamps.length === 0)
150
- return null;
151
- const oldestTimestamp = ipTimestamps[0];
152
- if (!oldestTimestamp)
153
- return null;
154
- return oldestTimestamp + this.windowMs;
155
- }
156
- /**
157
- * Cleanup old timestamps to prevent memory leaks.
158
- *
159
- * Removes entries with no requests in the last window period.
160
- */
161
- cleanup() {
162
- const now = Date.now();
163
- const windowStart = now - this.windowMs;
164
- // Cleanup per-IP timestamps
165
- for (const [ip, timestamps] of this.perIPTimestamps.entries()) {
166
- const recentRequests = timestamps.filter((t) => t > windowStart);
167
- if (recentRequests.length === 0) {
168
- this.perIPTimestamps.delete(ip);
169
- }
170
- else {
171
- this.perIPTimestamps.set(ip, recentRequests);
172
- }
173
- }
174
- // Cleanup global timestamps
175
- const recentGlobalRequests = this.globalTimestamps.filter((t) => t > windowStart);
176
- this.globalTimestamps.length = 0;
177
- this.globalTimestamps.push(...recentGlobalRequests);
178
- }
179
- /**
180
- * Stop cleanup interval (for testing or shutdown).
181
- */
182
- destroy() {
183
- if (this.cleanupInterval) {
184
- clearInterval(this.cleanupInterval);
185
- this.cleanupInterval = null;
186
- }
187
- }
188
- /**
189
- * Reset all rate limits (for testing).
190
- */
191
- reset() {
192
- this.perIPTimestamps.clear();
193
- this.globalTimestamps.length = 0;
194
- }
195
- }
196
- exports.RegistrationRateLimiter = RegistrationRateLimiter;
197
- /* ── Memory Implementation ── */
198
- /**
199
- * In-memory trust registry for development and testing.
200
- */
201
- class MemoryTrustRegistry {
202
- entries = new Map();
203
- rateLimiter;
204
- constructor(opts) {
205
- if (opts?.enableRateLimiting) {
206
- this.rateLimiter = opts.rateLimiter || new RegistrationRateLimiter();
207
- }
208
- }
209
- async register(did, publicKey, name, scopes, x25519PublicKey, mlKemPublicKey, mlDsaPublicKey, xchange, receiveScopes, sdkVersion, minEnvelopeVersion, maxEnvelopeVersion, ttlMs, clientIP) {
210
- // Check rate limit if enabled
211
- if (this.rateLimiter && clientIP) {
212
- if (!this.rateLimiter.checkLimit(clientIP)) {
213
- return (0, shared_1.err)('RATE_LIMIT_EXCEEDED');
214
- }
215
- }
216
- if (this.entries.has(did))
217
- return (0, shared_1.err)('ALREADY_REGISTERED');
218
- const expiresAt = ttlMs ? Date.now() + ttlMs : undefined;
219
- this.entries.set(did, {
220
- did,
221
- publicKey,
222
- name,
223
- scopes: new Set(scopes ?? []),
224
- receiveScopes: receiveScopes ? new Set(receiveScopes) : undefined,
225
- revoked: false,
226
- rotation_sequence: 1, // Initial sequence starts at 1
227
- x25519PublicKey,
228
- mlKemPublicKey,
229
- mlDsaPublicKey,
230
- xchange,
231
- sdkVersion,
232
- minEnvelopeVersion,
233
- maxEnvelopeVersion,
234
- expiresAt,
235
- });
236
- // Record registration after success
237
- if (this.rateLimiter && clientIP) {
238
- this.rateLimiter.recordRegistration(clientIP);
239
- }
240
- return (0, shared_1.ok)(undefined);
241
- }
242
- async resolve(did) {
243
- const entry = this.entries.get(did);
244
- if (!entry)
245
- return (0, shared_1.err)('NOT_FOUND');
246
- if (isExpired(entry))
247
- return (0, shared_1.err)('EXPIRED');
248
- if (entry.revoked)
249
- return (0, shared_1.err)('REVOKED');
250
- return (0, shared_1.ok)(entry.publicKey);
251
- }
252
- async hasScope(did, scope) {
253
- const entry = this.entries.get(did);
254
- if (!entry || isExpired(entry) || entry.revoked)
255
- return false;
256
- return entry.scopes.has(scope);
257
- }
258
- async hasReceiveScope(did, scope) {
259
- const entry = this.entries.get(did);
260
- if (!entry || isExpired(entry) || entry.revoked)
261
- return false;
262
- // Undefined = accept all scopes (backward compatibility)
263
- if (!entry.receiveScopes)
264
- return true;
265
- return entry.receiveScopes.has(scope);
266
- }
267
- async revoke(did) {
268
- const entry = this.entries.get(did);
269
- if (!entry)
270
- return (0, shared_1.err)('NOT_FOUND');
271
- this.entries.set(did, { ...entry, revoked: true });
272
- return (0, shared_1.ok)(undefined);
273
- }
274
- async getEntry(did) {
275
- const entry = this.entries.get(did);
276
- if (!entry)
277
- return (0, shared_1.err)('NOT_FOUND');
278
- if (isExpired(entry))
279
- return (0, shared_1.err)('EXPIRED');
280
- return (0, shared_1.ok)(entry);
281
- }
282
- async updateScopes(did, scopes) {
283
- const entry = this.entries.get(did);
284
- if (!entry)
285
- return (0, shared_1.err)('NOT_FOUND');
286
- if (isExpired(entry))
287
- return (0, shared_1.err)('EXPIRED');
288
- if (entry.revoked)
289
- return (0, shared_1.err)('REVOKED');
290
- this.entries.set(did, { ...entry, scopes: new Set(scopes) });
291
- return (0, shared_1.ok)(undefined);
292
- }
293
- /** Remove all expired entries from the registry. */
294
- async cleanup() {
295
- let removed = 0;
296
- const now = Date.now();
297
- for (const [did, entry] of this.entries) {
298
- if (entry.expiresAt && now > entry.expiresAt) {
299
- this.entries.delete(did);
300
- removed++;
301
- }
302
- }
303
- return removed;
304
- }
305
- /** Number of entries (for testing). */
306
- get size() {
307
- return this.entries.size;
308
- }
309
- }
310
- exports.MemoryTrustRegistry = MemoryTrustRegistry;
311
- /**
312
- * HTTP-backed trust registry for production use.
313
- * Delegates to a remote atelier.xail.io service.
314
- */
315
- class HttpTrustRegistry {
316
- baseUrl;
317
- fetchFn;
318
- cacheTtlMs;
319
- cacheFailureMode;
320
- enablePush;
321
- bloomFilterSize;
322
- bloomFilterFpr;
323
- resolveCache = new Map();
324
- entryCache = new Map();
325
- constructor(opts) {
326
- this.baseUrl = opts.baseUrl.replace(/\/$/, '');
327
- this.fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
328
- this.cacheTtlMs = opts.cacheTtlMs ?? 30_000;
329
- this.cacheFailureMode = opts.cacheFailureMode ?? 'fail-secure';
330
- this.enablePush = opts.enablePush ?? false;
331
- this.bloomFilterSize = opts.bloomFilterSize ?? 10_000;
332
- this.bloomFilterFpr = opts.bloomFilterFpr ?? 0.01;
333
- }
334
- /** Clear all cached entries. Call after registration or revocation. */
335
- clearCache() {
336
- this.resolveCache.clear();
337
- this.entryCache.clear();
338
- }
339
- async register(did, publicKey, name, scopes, x25519PublicKey, mlKemPublicKey, mlDsaPublicKey, xchange, receiveScopes, sdkVersion, minEnvelopeVersion, maxEnvelopeVersion, ttlMs, clientIP) {
340
- try {
341
- const res = await this.fetchFn(`${this.baseUrl}/registry/register`, {
342
- method: 'POST',
343
- headers: { 'Content-Type': 'application/json' },
344
- body: JSON.stringify({
345
- did,
346
- publicKey: Array.from(publicKey),
347
- name,
348
- scopes: scopes ?? [],
349
- ...(receiveScopes
350
- ? { receiveScopes }
351
- : {}),
352
- ...(x25519PublicKey
353
- ? { x25519PublicKey: Array.from(x25519PublicKey) }
354
- : {}),
355
- ...(mlKemPublicKey
356
- ? { mlKemPublicKey: Array.from(mlKemPublicKey) }
357
- : {}),
358
- ...(mlDsaPublicKey
359
- ? { mlDsaPublicKey: Array.from(mlDsaPublicKey) }
360
- : {}),
361
- ...(xchange !== undefined
362
- ? { xchange }
363
- : {}),
364
- ...(sdkVersion !== undefined
365
- ? { sdkVersion }
366
- : {}),
367
- ...(minEnvelopeVersion !== undefined
368
- ? { minEnvelopeVersion }
369
- : {}),
370
- ...(maxEnvelopeVersion !== undefined
371
- ? { maxEnvelopeVersion }
372
- : {}),
373
- ...(ttlMs !== undefined
374
- ? { ttlMs }
375
- : {}),
376
- }),
377
- });
378
- if (res.status === 409)
379
- return (0, shared_1.err)('ALREADY_REGISTERED');
380
- if (res.status === 429)
381
- return (0, shared_1.err)('RATE_LIMIT_EXCEEDED');
382
- if (!res.ok)
383
- return (0, shared_1.err)('NETWORK_ERROR');
384
- return (0, shared_1.ok)(undefined);
385
- }
386
- catch {
387
- return (0, shared_1.err)('NETWORK_ERROR');
388
- }
389
- }
390
- async resolve(did) {
391
- // Check cache first
392
- if (this.cacheTtlMs > 0) {
393
- const cached = this.resolveCache.get(did);
394
- if (cached && cached.expiry > Date.now())
395
- return cached.value;
396
- }
397
- let result;
398
- try {
399
- const res = await this.fetchFn(`${this.baseUrl}/registry/resolve/${encodeURIComponent(did)}`);
400
- if (res.status === 404)
401
- result = (0, shared_1.err)('NOT_FOUND');
402
- else if (res.status === 408)
403
- result = (0, shared_1.err)('EXPIRED');
404
- else if (res.status === 410)
405
- result = (0, shared_1.err)('REVOKED');
406
- else if (!res.ok)
407
- result = (0, shared_1.err)('NETWORK_ERROR');
408
- else {
409
- const data = (await res.json());
410
- result = (0, shared_1.ok)(new Uint8Array(data.publicKey));
411
- }
412
- }
413
- catch {
414
- // Network failure - apply cache failure mode
415
- const staleCache = this.resolveCache.get(did);
416
- if (this.cacheFailureMode === 'fail-secure') {
417
- // Fail-secure: reject on cache refresh failure (default)
418
- result = (0, shared_1.err)('NETWORK_ERROR');
419
- }
420
- else {
421
- // Fail-open: accept stale cache if available
422
- if (staleCache) {
423
- // Return stale cached value
424
- return staleCache.value;
425
- }
426
- result = (0, shared_1.err)('NETWORK_ERROR');
427
- }
428
- }
429
- // Update cache with fresh result (only if cache enabled)
430
- if (this.cacheTtlMs > 0) {
431
- this.resolveCache.set(did, { value: result, expiry: Date.now() + this.cacheTtlMs });
432
- }
433
- return result;
434
- }
435
- async hasScope(did, scope) {
436
- try {
437
- const res = await this.fetchFn(`${this.baseUrl}/registry/scope/${encodeURIComponent(did)}/${encodeURIComponent(scope)}`);
438
- return res.ok;
439
- }
440
- catch {
441
- return false;
442
- }
443
- }
444
- async hasReceiveScope(did, scope) {
445
- try {
446
- const res = await this.fetchFn(`${this.baseUrl}/registry/receive-scope/${encodeURIComponent(did)}/${encodeURIComponent(scope)}`);
447
- return res.ok;
448
- }
449
- catch {
450
- return false;
451
- }
452
- }
453
- async revoke(did) {
454
- try {
455
- const res = await this.fetchFn(`${this.baseUrl}/registry/revoke/${encodeURIComponent(did)}`, { method: 'POST' });
456
- if (res.status === 404)
457
- return (0, shared_1.err)('NOT_FOUND');
458
- if (!res.ok)
459
- return (0, shared_1.err)('NETWORK_ERROR');
460
- return (0, shared_1.ok)(undefined);
461
- }
462
- catch {
463
- return (0, shared_1.err)('NETWORK_ERROR');
464
- }
465
- }
466
- async getEntry(did) {
467
- if (this.cacheTtlMs > 0) {
468
- const cached = this.entryCache.get(did);
469
- if (cached && cached.expiry > Date.now())
470
- return cached.value;
471
- }
472
- let result;
473
- try {
474
- const res = await this.fetchFn(`${this.baseUrl}/registry/entry/${encodeURIComponent(did)}`);
475
- if (res.status === 404)
476
- result = (0, shared_1.err)('NOT_FOUND');
477
- else if (res.status === 408)
478
- result = (0, shared_1.err)('EXPIRED');
479
- else if (!res.ok)
480
- result = (0, shared_1.err)('NETWORK_ERROR');
481
- else {
482
- const data = (await res.json());
483
- result = (0, shared_1.ok)({
484
- did: data.did,
485
- publicKey: new Uint8Array(data.publicKey),
486
- name: data.name,
487
- scopes: new Set(data.scopes),
488
- receiveScopes: data.receiveScopes ? new Set(data.receiveScopes) : undefined,
489
- revoked: data.revoked,
490
- rotation_sequence: data.rotation_sequence ?? 1,
491
- x25519PublicKey: data.x25519PublicKey
492
- ? new Uint8Array(data.x25519PublicKey)
493
- : undefined,
494
- mlKemPublicKey: data.mlKemPublicKey
495
- ? new Uint8Array(data.mlKemPublicKey)
496
- : undefined,
497
- mlDsaPublicKey: data.mlDsaPublicKey
498
- ? new Uint8Array(data.mlDsaPublicKey)
499
- : undefined,
500
- xchange: data.xchange,
501
- sdkVersion: data.sdkVersion,
502
- minEnvelopeVersion: data.minEnvelopeVersion,
503
- maxEnvelopeVersion: data.maxEnvelopeVersion,
504
- expiresAt: data.expiresAt,
505
- });
506
- }
507
- }
508
- catch {
509
- result = (0, shared_1.err)('NETWORK_ERROR');
510
- }
511
- if (this.cacheTtlMs > 0) {
512
- this.entryCache.set(did, { value: result, expiry: Date.now() + this.cacheTtlMs });
513
- }
514
- return result;
515
- }
516
- /**
517
- * Rotate a DID to a new public key with cryptographic proof.
518
- *
519
- * Sends rotation request to gateway and invalidates local cache.
520
- *
521
- * @param did - DID being rotated (old key)
522
- * @param newPublicKey - New public key bytes
523
- * @param proof - Succession announcement (dual signatures from old and new keys)
524
- * @param rotationSequence - Monotonically increasing sequence number (prevents rollback)
525
- */
526
- async rotate(did, newPublicKey, proof, rotationSequence) {
527
- const res = await this.fetchFn(`${this.baseUrl}/registry/rotate`, {
528
- method: 'POST',
529
- headers: { 'Content-Type': 'application/json' },
530
- body: JSON.stringify({
531
- did,
532
- newPublicKey: Array.from(newPublicKey),
533
- proof: Array.from(proof),
534
- rotationSequence,
535
- }),
536
- });
537
- if (!res.ok) {
538
- throw new Error(`Key rotation failed: ${res.status} ${res.statusText}`);
539
- }
540
- // Invalidate cache for this DID
541
- this.resolveCache.delete(did);
542
- this.entryCache.delete(did);
543
- }
544
- /**
545
- * Subscribe to real-time trust events (revocation, key rotation).
546
- *
547
- * Creates a bloom filter from DIDs and connects WebSocket to gateway.
548
- * Events matching subscribed DIDs trigger the callback and invalidate cache.
549
- *
550
- * @param dids - Array of DIDs to monitor
551
- * @param callback - Function called when trust events occur
552
- * @returns Unsubscribe function to stop watching
553
- *
554
- * @throws Error if push notifications not enabled (enablePush: true)
555
- */
556
- async subscribe(dids, callback) {
557
- if (!this.enablePush) {
558
- throw new Error('Push notifications not enabled (set enablePush: true in HttpTrustRegistryOptions)');
559
- }
560
- // Simple bloom filter: hash each DID to track subscriptions
561
- // Production implementation would use full bloom filter library
562
- const bloomSet = new Set(dids.map(did => this.hashDid(did)));
563
- // Convert HTTP URL to WebSocket URL
564
- const wsUrl = this.baseUrl.replace(/^http/, 'ws') + '/trust/events';
565
- // SAFETY: WebSocket is a standard browser/Node.js API
566
- const ws = new globalThis.WebSocket(wsUrl);
567
- ws.addEventListener('open', () => {
568
- // Send subscription with bloom filter
569
- ws.send(JSON.stringify({
570
- type: 'subscribe',
571
- dids: dids, // Simple implementation sends full DID list
572
- bloomSize: this.bloomFilterSize,
573
- bloomFpr: this.bloomFilterFpr,
574
- }));
575
- });
576
- ws.addEventListener('message', (event) => {
577
- try {
578
- const trustEvent = JSON.parse(event.data);
579
- // Check if event DID matches our subscription
580
- const eventHash = this.hashDid(trustEvent.did);
581
- if (bloomSet.has(eventHash)) {
582
- // Invalidate cache for this DID
583
- if (trustEvent.type === 'revocation' || trustEvent.type === 'succession') {
584
- this.resolveCache.delete(trustEvent.did);
585
- this.entryCache.delete(trustEvent.did);
586
- }
587
- // Notify callback
588
- callback(trustEvent);
589
- }
590
- }
591
- catch (error) {
592
- // Ignore malformed events
593
- console.warn('Failed to parse trust event:', error);
594
- }
595
- });
596
- ws.addEventListener('error', (error) => {
597
- console.error('WebSocket error:', error);
598
- });
599
- // Return unsubscribe function
600
- return () => {
601
- if (ws.readyState === globalThis.WebSocket.OPEN) {
602
- ws.close();
603
- }
604
- };
605
- }
606
- /**
607
- * Simple hash function for bloom filter (DID → number).
608
- * Production implementation would use proper bloom filter hashing.
609
- */
610
- hashDid(did) {
611
- let hash = 0;
612
- for (let i = 0; i < did.length; i++) {
613
- hash = ((hash << 5) - hash) + did.charCodeAt(i);
614
- hash = hash & hash; // Convert to 32-bit integer
615
- }
616
- return hash;
617
- }
618
- /**
619
- * Resume subscriptions on this gateway using proofs from another gateway.
620
- *
621
- * Allows clients to migrate between gateways without re-subscribing.
622
- * Validates proofs and restores subscription state.
623
- *
624
- * @param proofs - Array of subscription proofs from previous gateway.
625
- * @returns Success or error.
626
- *
627
- * @example
628
- * ```typescript
629
- * const registry = new HttpTrustRegistry({ baseUrl: 'https://atelier2.xail.io' });
630
- * const result = await registry.resumeSubscriptions([proof1, proof2]);
631
- * ```
632
- */
633
- async resumeSubscriptions(proofs) {
634
- try {
635
- const res = await this.fetchFn(`${this.baseUrl}/trust/resume-batch`, {
636
- method: 'POST',
637
- headers: { 'Content-Type': 'application/json' },
638
- body: JSON.stringify({ proofs }),
639
- });
640
- if (!res.ok)
641
- return (0, shared_1.err)('NETWORK_ERROR');
642
- return (0, shared_1.ok)(undefined);
643
- }
644
- catch {
645
- return (0, shared_1.err)('NETWORK_ERROR');
646
- }
647
- }
648
- /**
649
- * Fetch signed checkpoint for a DID (freshness primitive).
650
- *
651
- * Checkpoints provide cryptographic proof of DID state at a specific timestamp.
652
- * Clients verify checkpoint signature and compare rotation_sequence to detect staleness.
653
- *
654
- * @param did - DID to fetch checkpoint for
655
- * @returns Signed checkpoint or error
656
- *
657
- * @example
658
- * ```typescript
659
- * const checkpoint = await registry.fetchCheckpoint('did:key:z6Mk...');
660
- * if (checkpoint.ok) {
661
- * const verified = await verifyCheckpoint(checkpoint.value, gatewayPubKey);
662
- * if (verified.ok && verified.value) {
663
- * // Use checkpoint for staleness detection
664
- * if (isCacheStale(localCache, checkpoint.value)) {
665
- * // Refresh cache
666
- * }
667
- * }
668
- * }
669
- * ```
670
- */
671
- async fetchCheckpoint(did) {
672
- try {
673
- const res = await this.fetchFn(`${this.baseUrl}/registry/checkpoint/${encodeURIComponent(did)}`);
674
- if (res.status === 404)
675
- return (0, shared_1.err)('NOT_FOUND');
676
- if (!res.ok)
677
- return (0, shared_1.err)('NETWORK_ERROR');
678
- const checkpoint = (await res.json());
679
- return (0, shared_1.ok)(checkpoint);
680
- }
681
- catch {
682
- return (0, shared_1.err)('NETWORK_ERROR');
683
- }
684
- }
685
- async updateScopes(did, scopes) {
686
- try {
687
- const res = await this.fetchFn(`${this.baseUrl}/registry/${encodeURIComponent(did)}/scopes`, {
688
- method: 'POST',
689
- headers: { 'Content-Type': 'application/json' },
690
- body: JSON.stringify({ scopes }),
691
- });
692
- if (res.status === 404)
693
- return (0, shared_1.err)('NOT_FOUND');
694
- if (res.status === 410)
695
- return (0, shared_1.err)('REVOKED');
696
- if (!res.ok)
697
- return (0, shared_1.err)('NETWORK_ERROR');
698
- // Clear cache for this DID
699
- this.resolveCache.delete(did);
700
- this.entryCache.delete(did);
701
- return (0, shared_1.ok)(undefined);
702
- }
703
- catch {
704
- return (0, shared_1.err)('NETWORK_ERROR');
705
- }
706
- }
707
- }
708
- exports.HttpTrustRegistry = HttpTrustRegistry;
709
- /**
710
- * File-based trust registry using JSONL append-only log.
711
- * Replays all entries on initialization, keeps in-memory Map for fast access.
712
- * Suitable for production deployments with local persistence.
713
- */
714
- class FileTrustRegistry {
715
- path;
716
- entries = new Map();
717
- initialized = false;
718
- constructor(opts) {
719
- this.path = opts.path;
720
- }
721
- /** Initialize by replaying JSONL log. Called automatically on first operation. */
722
- async init() {
723
- if (this.initialized)
724
- return;
725
- try {
726
- // Ensure directory exists
727
- await fs.mkdir(path.dirname(this.path), { recursive: true });
728
- // Read and replay JSONL file
729
- const content = await fs.readFile(this.path, 'utf-8').catch(() => '');
730
- const lines = content.split('\n').filter((line) => line.trim());
731
- for (const line of lines) {
732
- const record = JSON.parse(line);
733
- if (record.type === 'register' && record.publicKey && record.name) {
734
- this.entries.set(record.did, {
735
- did: record.did,
736
- publicKey: new Uint8Array(record.publicKey),
737
- name: record.name,
738
- scopes: new Set(record.scopes ?? []),
739
- receiveScopes: record.receiveScopes ? new Set(record.receiveScopes) : undefined,
740
- revoked: false,
741
- rotation_sequence: record.rotation_sequence ?? 1,
742
- x25519PublicKey: record.x25519PublicKey
743
- ? new Uint8Array(record.x25519PublicKey)
744
- : undefined,
745
- mlKemPublicKey: record.mlKemPublicKey
746
- ? new Uint8Array(record.mlKemPublicKey)
747
- : undefined,
748
- mlDsaPublicKey: record.mlDsaPublicKey
749
- ? new Uint8Array(record.mlDsaPublicKey)
750
- : undefined,
751
- xchange: record.xchange,
752
- sdkVersion: record.sdkVersion,
753
- minEnvelopeVersion: record.minEnvelopeVersion,
754
- maxEnvelopeVersion: record.maxEnvelopeVersion,
755
- expiresAt: record.expiresAt,
756
- });
757
- }
758
- else if (record.type === 'revoke') {
759
- const entry = this.entries.get(record.did);
760
- if (entry) {
761
- this.entries.set(record.did, { ...entry, revoked: true });
762
- }
763
- }
764
- else if (record.type === 'update-scopes') {
765
- const entry = this.entries.get(record.did);
766
- if (entry) {
767
- this.entries.set(record.did, { ...entry, scopes: new Set(record.scopes ?? []) });
768
- }
769
- }
770
- else if (record.type === 'rotate' && record.publicKey && record.rotation_sequence) {
771
- const entry = this.entries.get(record.did);
772
- if (entry) {
773
- // Only apply rotation if sequence is greater (prevents replaying stale rotations)
774
- if (record.rotation_sequence > entry.rotation_sequence) {
775
- this.entries.set(record.did, {
776
- ...entry,
777
- publicKey: new Uint8Array(record.publicKey),
778
- rotation_sequence: record.rotation_sequence,
779
- });
780
- }
781
- }
782
- }
783
- }
784
- }
785
- catch (error) {
786
- // If file doesn't exist yet, that's OK - it will be created on first write
787
- }
788
- this.initialized = true;
789
- }
790
- /** Append record to JSONL file. */
791
- async append(record) {
792
- await fs.appendFile(this.path, JSON.stringify(record) + '\n', 'utf-8');
793
- }
794
- async register(did, publicKey, name, scopes, x25519PublicKey, mlKemPublicKey, mlDsaPublicKey, xchange, receiveScopes, sdkVersion, minEnvelopeVersion, maxEnvelopeVersion, ttlMs, clientIP) {
795
- await this.init();
796
- if (this.entries.has(did))
797
- return (0, shared_1.err)('ALREADY_REGISTERED');
798
- const expiresAt = ttlMs ? Date.now() + ttlMs : undefined;
799
- const entry = {
800
- did,
801
- publicKey,
802
- name,
803
- scopes: new Set(scopes ?? []),
804
- receiveScopes: receiveScopes ? new Set(receiveScopes) : undefined,
805
- revoked: false,
806
- rotation_sequence: 1, // Initial sequence starts at 1
807
- x25519PublicKey,
808
- mlKemPublicKey,
809
- mlDsaPublicKey,
810
- xchange,
811
- sdkVersion,
812
- minEnvelopeVersion,
813
- maxEnvelopeVersion,
814
- expiresAt,
815
- };
816
- this.entries.set(did, entry);
817
- // Append to JSONL
818
- await this.append({
819
- type: 'register',
820
- did,
821
- publicKey: Array.from(publicKey),
822
- name,
823
- scopes: scopes ?? [],
824
- rotation_sequence: 1,
825
- ...(receiveScopes ? { receiveScopes } : {}),
826
- ...(x25519PublicKey ? { x25519PublicKey: Array.from(x25519PublicKey) } : {}),
827
- ...(mlKemPublicKey ? { mlKemPublicKey: Array.from(mlKemPublicKey) } : {}),
828
- ...(mlDsaPublicKey ? { mlDsaPublicKey: Array.from(mlDsaPublicKey) } : {}),
829
- ...(xchange !== undefined ? { xchange } : {}),
830
- ...(sdkVersion !== undefined ? { sdkVersion } : {}),
831
- ...(minEnvelopeVersion !== undefined ? { minEnvelopeVersion } : {}),
832
- ...(maxEnvelopeVersion !== undefined ? { maxEnvelopeVersion } : {}),
833
- ...(expiresAt !== undefined ? { expiresAt } : {}),
834
- });
835
- return (0, shared_1.ok)(undefined);
836
- }
837
- async resolve(did) {
838
- await this.init();
839
- const entry = this.entries.get(did);
840
- if (!entry)
841
- return (0, shared_1.err)('NOT_FOUND');
842
- if (isExpired(entry))
843
- return (0, shared_1.err)('EXPIRED');
844
- if (entry.revoked)
845
- return (0, shared_1.err)('REVOKED');
846
- return (0, shared_1.ok)(entry.publicKey);
847
- }
848
- async hasScope(did, scope) {
849
- await this.init();
850
- const entry = this.entries.get(did);
851
- if (!entry || isExpired(entry) || entry.revoked)
852
- return false;
853
- return entry.scopes.has(scope);
854
- }
855
- async hasReceiveScope(did, scope) {
856
- await this.init();
857
- const entry = this.entries.get(did);
858
- if (!entry || isExpired(entry) || entry.revoked)
859
- return false;
860
- // Undefined = accept all scopes (backward compatibility)
861
- if (!entry.receiveScopes)
862
- return true;
863
- return entry.receiveScopes.has(scope);
864
- }
865
- async revoke(did) {
866
- await this.init();
867
- const entry = this.entries.get(did);
868
- if (!entry)
869
- return (0, shared_1.err)('NOT_FOUND');
870
- this.entries.set(did, { ...entry, revoked: true });
871
- await this.append({ type: 'revoke', did });
872
- return (0, shared_1.ok)(undefined);
873
- }
874
- async getEntry(did) {
875
- await this.init();
876
- const entry = this.entries.get(did);
877
- if (!entry)
878
- return (0, shared_1.err)('NOT_FOUND');
879
- if (isExpired(entry))
880
- return (0, shared_1.err)('EXPIRED');
881
- return (0, shared_1.ok)(entry);
882
- }
883
- async updateScopes(did, scopes) {
884
- await this.init();
885
- const entry = this.entries.get(did);
886
- if (!entry)
887
- return (0, shared_1.err)('NOT_FOUND');
888
- if (isExpired(entry))
889
- return (0, shared_1.err)('EXPIRED');
890
- if (entry.revoked)
891
- return (0, shared_1.err)('REVOKED');
892
- this.entries.set(did, { ...entry, scopes: new Set(scopes) });
893
- await this.append({ type: 'update-scopes', did, scopes });
894
- return (0, shared_1.ok)(undefined);
895
- }
896
- /** Remove all expired entries from the registry. */
897
- async cleanup() {
898
- await this.init();
899
- let removed = 0;
900
- const now = Date.now();
901
- for (const [did, entry] of this.entries) {
902
- if (entry.expiresAt && now > entry.expiresAt) {
903
- this.entries.delete(did);
904
- removed++;
905
- }
906
- }
907
- return removed;
908
- }
909
- /**
910
- * Rotate a DID to a new public key with rollback protection.
911
- *
912
- * Validates that rotationSequence is greater than current sequence to prevent
913
- * rollback attacks. Appends rotation event to JSONL and updates in-memory state.
914
- *
915
- * @param did - DID being rotated
916
- * @param newPublicKey - New public key bytes
917
- * @param proof - Cryptographic proof (e.g., signature from old key)
918
- * @param rotationSequence - Monotonically increasing sequence number
919
- * @throws Error if DID not found or sequence validation fails
920
- */
921
- async rotate(did, newPublicKey, proof, rotationSequence) {
922
- await this.init();
923
- const entry = this.entries.get(did);
924
- if (!entry) {
925
- throw new Error(`DID not found: ${did}`);
926
- }
927
- // Rollback protection: new sequence must be greater than current
928
- if (rotationSequence <= entry.rotation_sequence) {
929
- throw new Error(`Rotation sequence ${rotationSequence} must be > current ${entry.rotation_sequence} (rollback attack prevented)`);
930
- }
931
- // Append rotation event to JSONL
932
- await this.append({
933
- type: 'rotate',
934
- did,
935
- publicKey: Array.from(newPublicKey),
936
- proof: Array.from(proof),
937
- rotation_sequence: rotationSequence,
938
- timestamp: Date.now(),
939
- });
940
- // Update in-memory entry
941
- this.entries.set(did, {
942
- ...entry,
943
- publicKey: newPublicKey,
944
- rotation_sequence: rotationSequence,
945
- });
946
- }
947
- /** Number of entries (for testing). */
948
- get size() {
949
- return this.entries.size;
950
- }
951
- }
952
- exports.FileTrustRegistry = FileTrustRegistry;
953
- /* ── Enterprise Factory ── */
954
- /**
955
- * Create an enterprise trust registry with optional pre-population.
956
- * Suitable for corporate deployments with centralized trust management.
957
- *
958
- * @example
959
- * ```typescript
960
- * const registry = await TrustRegistry.enterprise({
961
- * storage: 'file',
962
- * path: '/opt/corp/trust.jsonl',
963
- * preload: [
964
- * { did: 'did:web:corp.example.com', publicKey: ..., name: 'Corporate Gateway' }
965
- * ]
966
- * });
967
- * ```
968
- */
969
- async function createEnterpriseTrustRegistry(opts) {
970
- let registry;
971
- if (opts.storage === 'file') {
972
- if (!opts.path)
973
- throw new Error('FileTrustRegistry requires path option');
974
- registry = new FileTrustRegistry({ path: opts.path });
975
- }
976
- else if (opts.storage === 'http') {
977
- if (!opts.baseUrl)
978
- throw new Error('HttpTrustRegistry requires baseUrl option');
979
- registry = new HttpTrustRegistry({ baseUrl: opts.baseUrl });
980
- }
981
- else {
982
- registry = new MemoryTrustRegistry();
983
- }
984
- // Pre-populate if requested
985
- if (opts.preload) {
986
- for (const entry of opts.preload) {
987
- await registry.register(entry.did, entry.publicKey, entry.name, entry.scopes, entry.x25519PublicKey, entry.mlKemPublicKey, entry.mlDsaPublicKey, entry.xchange, entry.receiveScopes, entry.sdkVersion, entry.minEnvelopeVersion, entry.maxEnvelopeVersion);
988
- }
989
- }
990
- return registry;
991
- }
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,r,s){void 0===s&&(s=r);var i=Object.getOwnPropertyDescriptor(t,r);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,s,i)}:function(e,t,r,s){void 0===s&&(s=r),e[s]=t[r]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),__importStar=this&&this.__importStar||function(){var e=function(t){return e=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r);return t},e(t)};return function(t){if(t&&t.__esModule)return t;var r={};if(null!=t)for(var s=e(t),i=0;i<s.length;i++)"default"!==s[i]&&__createBinding(r,t,s[i]);return __setModuleDefault(r,t),r}}();Object.defineProperty(exports,"__esModule",{value:!0}),exports.FileTrustRegistry=exports.HttpTrustRegistry=exports.MemoryTrustRegistry=exports.RegistrationRateLimiter=void 0,exports.createEnterpriseTrustRegistry=createEnterpriseTrustRegistry;const shared_1=require("../_deps/shared/index.js"),fs=__importStar(require("node:fs/promises")),path=__importStar(require("node:path"));function isExpired(e){return!!e.expiresAt&&Date.now()>e.expiresAt}class RegistrationRateLimiter{perIPTimestamps=new Map;globalTimestamps=[];perIPLimit;globalLimit;windowMs;cleanupInterval=null;constructor(e=10,t=1e3,r=36e5){this.perIPLimit=e,this.globalLimit=t,this.windowMs=r,this.cleanupInterval=setInterval(()=>this.cleanup(),3e5)}checkLimit(e){const t=Date.now()-this.windowMs;if((this.perIPTimestamps.get(e)||[]).filter(e=>e>t).length>=this.perIPLimit)return!1;return!(this.globalTimestamps.filter(e=>e>t).length>=this.globalLimit)}recordRegistration(e){const t=Date.now(),r=this.perIPTimestamps.get(e)||[];r.push(t),this.perIPTimestamps.set(e,r),this.globalTimestamps.push(t)}getRemainingForIP(e){const t=Date.now()-this.windowMs,r=(this.perIPTimestamps.get(e)||[]).filter(e=>e>t);return Math.max(0,this.perIPLimit-r.length)}getRemainingGlobal(){const e=Date.now()-this.windowMs,t=this.globalTimestamps.filter(t=>t>e);return Math.max(0,this.globalLimit-t.length)}getResetTimeForIP(e){const t=this.perIPTimestamps.get(e)||[];if(0===t.length)return null;const r=t[0];return r?r+this.windowMs:null}cleanup(){const e=Date.now()-this.windowMs;for(const[t,r]of this.perIPTimestamps.entries()){const s=r.filter(t=>t>e);0===s.length?this.perIPTimestamps.delete(t):this.perIPTimestamps.set(t,s)}const t=this.globalTimestamps.filter(t=>t>e);this.globalTimestamps.length=0,this.globalTimestamps.push(...t)}destroy(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null)}reset(){this.perIPTimestamps.clear(),this.globalTimestamps.length=0}}exports.RegistrationRateLimiter=RegistrationRateLimiter;class MemoryTrustRegistry{entries=new Map;rateLimiter;constructor(e){e?.enableRateLimiting&&(this.rateLimiter=e.rateLimiter||new RegistrationRateLimiter)}async register(e,t,r,s,i,n,a,o,c,h,l,d,p,u){if(this.rateLimiter&&u&&!this.rateLimiter.checkLimit(u))return(0,shared_1.err)("RATE_LIMIT_EXCEEDED");if(this.entries.has(e))return(0,shared_1.err)("ALREADY_REGISTERED");const y=p?Date.now()+p:void 0;return this.entries.set(e,{did:e,publicKey:t,name:r,scopes:new Set(s??[]),receiveScopes:c?new Set(c):void 0,revoked:!1,rotation_sequence:1,x25519PublicKey:i,mlKemPublicKey:n,mlDsaPublicKey:a,xchange:o,sdkVersion:h,minEnvelopeVersion:l,maxEnvelopeVersion:d,expiresAt:y}),this.rateLimiter&&u&&this.rateLimiter.recordRegistration(u),(0,shared_1.ok)(void 0)}async resolve(e){const t=this.entries.get(e);return t?isExpired(t)?(0,shared_1.err)("EXPIRED"):t.revoked?(0,shared_1.err)("REVOKED"):(0,shared_1.ok)(t.publicKey):(0,shared_1.err)("NOT_FOUND")}async hasScope(e,t){const r=this.entries.get(e);return!(!r||isExpired(r)||r.revoked)&&r.scopes.has(t)}async hasReceiveScope(e,t){const r=this.entries.get(e);return!(!r||isExpired(r)||r.revoked)&&(!r.receiveScopes||r.receiveScopes.has(t))}async revoke(e){const t=this.entries.get(e);return t?(this.entries.set(e,{...t,revoked:!0}),(0,shared_1.ok)(void 0)):(0,shared_1.err)("NOT_FOUND")}async getEntry(e){const t=this.entries.get(e);return t?isExpired(t)?(0,shared_1.err)("EXPIRED"):(0,shared_1.ok)(t):(0,shared_1.err)("NOT_FOUND")}async updateScopes(e,t){const r=this.entries.get(e);return r?isExpired(r)?(0,shared_1.err)("EXPIRED"):r.revoked?(0,shared_1.err)("REVOKED"):(this.entries.set(e,{...r,scopes:new Set(t)}),(0,shared_1.ok)(void 0)):(0,shared_1.err)("NOT_FOUND")}async cleanup(){let e=0;const t=Date.now();for(const[r,s]of this.entries)s.expiresAt&&t>s.expiresAt&&(this.entries.delete(r),e++);return e}get size(){return this.entries.size}}exports.MemoryTrustRegistry=MemoryTrustRegistry;class HttpTrustRegistry{baseUrl;fetchFn;cacheTtlMs;cacheFailureMode;enablePush;bloomFilterSize;bloomFilterFpr;resolveCache=new Map;entryCache=new Map;constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.fetchFn=e.fetch??globalThis.fetch.bind(globalThis),this.cacheTtlMs=e.cacheTtlMs??3e4,this.cacheFailureMode=e.cacheFailureMode??"fail-secure",this.enablePush=e.enablePush??!1,this.bloomFilterSize=e.bloomFilterSize??1e4,this.bloomFilterFpr=e.bloomFilterFpr??.01}clearCache(){this.resolveCache.clear(),this.entryCache.clear()}async register(e,t,r,s,i,n,a,o,c,h,l,d,p,u){try{const u=await this.fetchFn(`${this.baseUrl}/registry/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({did:e,publicKey:Array.from(t),name:r,scopes:s??[],...c?{receiveScopes:c}:{},...i?{x25519PublicKey:Array.from(i)}:{},...n?{mlKemPublicKey:Array.from(n)}:{},...a?{mlDsaPublicKey:Array.from(a)}:{},...void 0!==o?{xchange:o}:{},...void 0!==h?{sdkVersion:h}:{},...void 0!==l?{minEnvelopeVersion:l}:{},...void 0!==d?{maxEnvelopeVersion:d}:{},...void 0!==p?{ttlMs:p}:{}})});return 409===u.status?(0,shared_1.err)("ALREADY_REGISTERED"):429===u.status?(0,shared_1.err)("RATE_LIMIT_EXCEEDED"):u.ok?(0,shared_1.ok)(void 0):(0,shared_1.err)("NETWORK_ERROR")}catch{return(0,shared_1.err)("NETWORK_ERROR")}}async resolve(e){if(this.cacheTtlMs>0){const t=this.resolveCache.get(e);if(t&&t.expiry>Date.now())return t.value}let t;try{const r=await this.fetchFn(`${this.baseUrl}/registry/resolve/${encodeURIComponent(e)}`);if(404===r.status)t=(0,shared_1.err)("NOT_FOUND");else if(408===r.status)t=(0,shared_1.err)("EXPIRED");else if(410===r.status)t=(0,shared_1.err)("REVOKED");else if(r.ok){const e=await r.json();t=(0,shared_1.ok)(new Uint8Array(e.publicKey))}else t=(0,shared_1.err)("NETWORK_ERROR")}catch{const r=this.resolveCache.get(e);if("fail-secure"===this.cacheFailureMode)t=(0,shared_1.err)("NETWORK_ERROR");else{if(r)return r.value;t=(0,shared_1.err)("NETWORK_ERROR")}}return this.cacheTtlMs>0&&this.resolveCache.set(e,{value:t,expiry:Date.now()+this.cacheTtlMs}),t}async hasScope(e,t){try{return(await this.fetchFn(`${this.baseUrl}/registry/scope/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).ok}catch{return!1}}async hasReceiveScope(e,t){try{return(await this.fetchFn(`${this.baseUrl}/registry/receive-scope/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).ok}catch{return!1}}async revoke(e){try{const t=await this.fetchFn(`${this.baseUrl}/registry/revoke/${encodeURIComponent(e)}`,{method:"POST"});return 404===t.status?(0,shared_1.err)("NOT_FOUND"):t.ok?(0,shared_1.ok)(void 0):(0,shared_1.err)("NETWORK_ERROR")}catch{return(0,shared_1.err)("NETWORK_ERROR")}}async getEntry(e){if(this.cacheTtlMs>0){const t=this.entryCache.get(e);if(t&&t.expiry>Date.now())return t.value}let t;try{const r=await this.fetchFn(`${this.baseUrl}/registry/entry/${encodeURIComponent(e)}`);if(404===r.status)t=(0,shared_1.err)("NOT_FOUND");else if(408===r.status)t=(0,shared_1.err)("EXPIRED");else if(r.ok){const e=await r.json();t=(0,shared_1.ok)({did:e.did,publicKey:new Uint8Array(e.publicKey),name:e.name,scopes:new Set(e.scopes),receiveScopes:e.receiveScopes?new Set(e.receiveScopes):void 0,revoked:e.revoked,rotation_sequence:e.rotation_sequence??1,x25519PublicKey:e.x25519PublicKey?new Uint8Array(e.x25519PublicKey):void 0,mlKemPublicKey:e.mlKemPublicKey?new Uint8Array(e.mlKemPublicKey):void 0,mlDsaPublicKey:e.mlDsaPublicKey?new Uint8Array(e.mlDsaPublicKey):void 0,xchange:e.xchange,sdkVersion:e.sdkVersion,minEnvelopeVersion:e.minEnvelopeVersion,maxEnvelopeVersion:e.maxEnvelopeVersion,expiresAt:e.expiresAt})}else t=(0,shared_1.err)("NETWORK_ERROR")}catch{t=(0,shared_1.err)("NETWORK_ERROR")}return this.cacheTtlMs>0&&this.entryCache.set(e,{value:t,expiry:Date.now()+this.cacheTtlMs}),t}async rotate(e,t,r,s){const i=await this.fetchFn(`${this.baseUrl}/registry/rotate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({did:e,newPublicKey:Array.from(t),proof:Array.from(r),rotationSequence:s})});if(!i.ok)throw new Error(`Key rotation failed: ${i.status} ${i.statusText}`);this.resolveCache.delete(e),this.entryCache.delete(e)}async subscribe(e,t){if(!this.enablePush)throw new Error("Push notifications not enabled (set enablePush: true in HttpTrustRegistryOptions)");const r=new Set(e.map(e=>this.hashDid(e))),s=this.baseUrl.replace(/^http/,"ws")+"/trust/events",i=new globalThis.WebSocket(s);return i.addEventListener("open",()=>{i.send(JSON.stringify({type:"subscribe",dids:e,bloomSize:this.bloomFilterSize,bloomFpr:this.bloomFilterFpr}))}),i.addEventListener("message",e=>{try{const s=JSON.parse(e.data),i=this.hashDid(s.did);r.has(i)&&("revocation"!==s.type&&"succession"!==s.type||(this.resolveCache.delete(s.did),this.entryCache.delete(s.did)),t(s))}catch(e){console.warn("Failed to parse trust event:",e)}}),i.addEventListener("error",e=>{console.error("WebSocket error:",e)}),()=>{i.readyState===globalThis.WebSocket.OPEN&&i.close()}}hashDid(e){let t=0;for(let r=0;r<e.length;r++)t=(t<<5)-t+e.charCodeAt(r),t&=t;return t}async resumeSubscriptions(e){try{return(await this.fetchFn(`${this.baseUrl}/trust/resume-batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({proofs:e})})).ok?(0,shared_1.ok)(void 0):(0,shared_1.err)("NETWORK_ERROR")}catch{return(0,shared_1.err)("NETWORK_ERROR")}}async fetchCheckpoint(e){try{const t=await this.fetchFn(`${this.baseUrl}/registry/checkpoint/${encodeURIComponent(e)}`);if(404===t.status)return(0,shared_1.err)("NOT_FOUND");if(!t.ok)return(0,shared_1.err)("NETWORK_ERROR");const r=await t.json();return(0,shared_1.ok)(r)}catch{return(0,shared_1.err)("NETWORK_ERROR")}}async updateScopes(e,t){try{const r=await this.fetchFn(`${this.baseUrl}/registry/${encodeURIComponent(e)}/scopes`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({scopes:t})});return 404===r.status?(0,shared_1.err)("NOT_FOUND"):410===r.status?(0,shared_1.err)("REVOKED"):r.ok?(this.resolveCache.delete(e),this.entryCache.delete(e),(0,shared_1.ok)(void 0)):(0,shared_1.err)("NETWORK_ERROR")}catch{return(0,shared_1.err)("NETWORK_ERROR")}}}exports.HttpTrustRegistry=HttpTrustRegistry;class FileTrustRegistry{path;entries=new Map;initialized=!1;constructor(e){this.path=e.path}async init(){if(!this.initialized){try{await fs.mkdir(path.dirname(this.path),{recursive:!0});const e=(await fs.readFile(this.path,"utf-8").catch(()=>"")).split("\n").filter(e=>e.trim());for(const t of e){const e=JSON.parse(t);if("register"===e.type&&e.publicKey&&e.name)this.entries.set(e.did,{did:e.did,publicKey:new Uint8Array(e.publicKey),name:e.name,scopes:new Set(e.scopes??[]),receiveScopes:e.receiveScopes?new Set(e.receiveScopes):void 0,revoked:!1,rotation_sequence:e.rotation_sequence??1,x25519PublicKey:e.x25519PublicKey?new Uint8Array(e.x25519PublicKey):void 0,mlKemPublicKey:e.mlKemPublicKey?new Uint8Array(e.mlKemPublicKey):void 0,mlDsaPublicKey:e.mlDsaPublicKey?new Uint8Array(e.mlDsaPublicKey):void 0,xchange:e.xchange,sdkVersion:e.sdkVersion,minEnvelopeVersion:e.minEnvelopeVersion,maxEnvelopeVersion:e.maxEnvelopeVersion,expiresAt:e.expiresAt});else if("revoke"===e.type){const t=this.entries.get(e.did);t&&this.entries.set(e.did,{...t,revoked:!0})}else if("update-scopes"===e.type){const t=this.entries.get(e.did);t&&this.entries.set(e.did,{...t,scopes:new Set(e.scopes??[])})}else if("rotate"===e.type&&e.publicKey&&e.rotation_sequence){const t=this.entries.get(e.did);t&&e.rotation_sequence>t.rotation_sequence&&this.entries.set(e.did,{...t,publicKey:new Uint8Array(e.publicKey),rotation_sequence:e.rotation_sequence})}}}catch{}this.initialized=!0}}async append(e){await fs.appendFile(this.path,JSON.stringify(e)+"\n","utf-8")}async register(e,t,r,s,i,n,a,o,c,h,l,d,p,u){if(await this.init(),this.entries.has(e))return(0,shared_1.err)("ALREADY_REGISTERED");const y=p?Date.now()+p:void 0,m={did:e,publicKey:t,name:r,scopes:new Set(s??[]),receiveScopes:c?new Set(c):void 0,revoked:!1,rotation_sequence:1,x25519PublicKey:i,mlKemPublicKey:n,mlDsaPublicKey:a,xchange:o,sdkVersion:h,minEnvelopeVersion:l,maxEnvelopeVersion:d,expiresAt:y};return this.entries.set(e,m),await this.append({type:"register",did:e,publicKey:Array.from(t),name:r,scopes:s??[],rotation_sequence:1,...c?{receiveScopes:c}:{},...i?{x25519PublicKey:Array.from(i)}:{},...n?{mlKemPublicKey:Array.from(n)}:{},...a?{mlDsaPublicKey:Array.from(a)}:{},...void 0!==o?{xchange:o}:{},...void 0!==h?{sdkVersion:h}:{},...void 0!==l?{minEnvelopeVersion:l}:{},...void 0!==d?{maxEnvelopeVersion:d}:{},...void 0!==y?{expiresAt:y}:{}}),(0,shared_1.ok)(void 0)}async resolve(e){await this.init();const t=this.entries.get(e);return t?isExpired(t)?(0,shared_1.err)("EXPIRED"):t.revoked?(0,shared_1.err)("REVOKED"):(0,shared_1.ok)(t.publicKey):(0,shared_1.err)("NOT_FOUND")}async hasScope(e,t){await this.init();const r=this.entries.get(e);return!(!r||isExpired(r)||r.revoked)&&r.scopes.has(t)}async hasReceiveScope(e,t){await this.init();const r=this.entries.get(e);return!(!r||isExpired(r)||r.revoked)&&(!r.receiveScopes||r.receiveScopes.has(t))}async revoke(e){await this.init();const t=this.entries.get(e);return t?(this.entries.set(e,{...t,revoked:!0}),await this.append({type:"revoke",did:e}),(0,shared_1.ok)(void 0)):(0,shared_1.err)("NOT_FOUND")}async getEntry(e){await this.init();const t=this.entries.get(e);return t?isExpired(t)?(0,shared_1.err)("EXPIRED"):(0,shared_1.ok)(t):(0,shared_1.err)("NOT_FOUND")}async updateScopes(e,t){await this.init();const r=this.entries.get(e);return r?isExpired(r)?(0,shared_1.err)("EXPIRED"):r.revoked?(0,shared_1.err)("REVOKED"):(this.entries.set(e,{...r,scopes:new Set(t)}),await this.append({type:"update-scopes",did:e,scopes:t}),(0,shared_1.ok)(void 0)):(0,shared_1.err)("NOT_FOUND")}async cleanup(){await this.init();let e=0;const t=Date.now();for(const[r,s]of this.entries)s.expiresAt&&t>s.expiresAt&&(this.entries.delete(r),e++);return e}async rotate(e,t,r,s){await this.init();const i=this.entries.get(e);if(!i)throw new Error(`DID not found: ${e}`);if(s<=i.rotation_sequence)throw new Error(`Rotation sequence ${s} must be > current ${i.rotation_sequence} (rollback attack prevented)`);await this.append({type:"rotate",did:e,publicKey:Array.from(t),proof:Array.from(r),rotation_sequence:s,timestamp:Date.now()}),this.entries.set(e,{...i,publicKey:t,rotation_sequence:s})}get size(){return this.entries.size}}async function createEnterpriseTrustRegistry(e){let t;if("file"===e.storage){if(!e.path)throw new Error("FileTrustRegistry requires path option");t=new FileTrustRegistry({path:e.path})}else if("http"===e.storage){if(!e.baseUrl)throw new Error("HttpTrustRegistry requires baseUrl option");t=new HttpTrustRegistry({baseUrl:e.baseUrl})}else t=new MemoryTrustRegistry;if(e.preload)for(const r of e.preload)await t.register(r.did,r.publicKey,r.name,r.scopes,r.x25519PublicKey,r.mlKemPublicKey,r.mlDsaPublicKey,r.xchange,r.receiveScopes,r.sdkVersion,r.minEnvelopeVersion,r.maxEnvelopeVersion);return t}exports.FileTrustRegistry=FileTrustRegistry;