@private.me/xbind 3.0.0 → 3.0.2

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 (217) hide show
  1. package/README.md +55 -7
  2. package/dist-standalone/_deps/mldsa-wasm/dist/mldsa.js +1920 -1
  3. package/dist-standalone/_deps/shared/cjs/errors.js +729 -1
  4. package/dist-standalone/_deps/shared/cjs/index.js +463 -1
  5. package/dist-standalone/_deps/shared/cjs/types.js +315 -1
  6. package/dist-standalone/_deps/shared/errors.js +244 -1
  7. package/dist-standalone/_deps/shared/index.js +72 -1
  8. package/dist-standalone/_deps/shared/types.js +86 -1
  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.js +659 -1
  47. package/dist-standalone/agent-sdk.js +328 -1
  48. package/dist-standalone/agent.js +1800 -1
  49. package/dist-standalone/approval.js +193 -1
  50. package/dist-standalone/async-iterators.js +382 -1
  51. package/dist-standalone/auth.js +219 -1
  52. package/dist-standalone/auto-accept.js +229 -1
  53. package/dist-standalone/backup-config.js +201 -1
  54. package/dist-standalone/backup.js +326 -1
  55. package/dist-standalone/batch-operations.js +388 -1
  56. package/dist-standalone/cancellation.js +477 -1
  57. package/dist-standalone/checkpoint.js +186 -1
  58. package/dist-standalone/circuit-breaker.js +468 -1
  59. package/dist-standalone/cjs/agent-call.js +701 -1
  60. package/dist-standalone/cjs/agent-sdk.js +332 -1
  61. package/dist-standalone/cjs/agent.js +1837 -1
  62. package/dist-standalone/cjs/approval.js +199 -1
  63. package/dist-standalone/cjs/async-iterators.js +392 -1
  64. package/dist-standalone/cjs/auth.js +225 -1
  65. package/dist-standalone/cjs/auto-accept.js +233 -1
  66. package/dist-standalone/cjs/backup-config.js +207 -1
  67. package/dist-standalone/cjs/backup.js +330 -1
  68. package/dist-standalone/cjs/batch-operations.js +397 -1
  69. package/dist-standalone/cjs/cancellation.js +490 -1
  70. package/dist-standalone/cjs/checkpoint.js +193 -1
  71. package/dist-standalone/cjs/circuit-breaker.js +476 -1
  72. package/dist-standalone/cjs/cli/init.js +492 -1
  73. package/dist-standalone/cjs/config-validation.js +522 -1
  74. package/dist-standalone/cjs/connect.js +312 -1
  75. package/dist-standalone/cjs/connection-pool.js +506 -1
  76. package/dist-standalone/cjs/correlation-id.js +339 -1
  77. package/dist-standalone/cjs/crypto-utils.js +176 -1
  78. package/dist-standalone/cjs/debug-mode.js +534 -1
  79. package/dist-standalone/cjs/did-document.js +101 -1
  80. package/dist-standalone/cjs/did-privateme.js +130 -1
  81. package/dist-standalone/cjs/did-web.js +201 -1
  82. package/dist-standalone/cjs/discovery.js +462 -1
  83. package/dist-standalone/cjs/dual-mode.js +251 -1
  84. package/dist-standalone/cjs/email-templates.js +313 -1
  85. package/dist-standalone/cjs/email-transport.js +239 -1
  86. package/dist-standalone/cjs/envelope.js +538 -1
  87. package/dist-standalone/cjs/errors.js +913 -1
  88. package/dist-standalone/cjs/event-emitter.js +461 -1
  89. package/dist-standalone/cjs/gateway-state.js +55 -1
  90. package/dist-standalone/cjs/gateway-transport.js +120 -1
  91. package/dist-standalone/cjs/graceful-degradation.js +403 -1
  92. package/dist-standalone/cjs/guardrails.js +223 -1
  93. package/dist-standalone/cjs/health-check.js +336 -1
  94. package/dist-standalone/cjs/http-compat.js +272 -1
  95. package/dist-standalone/cjs/http-status-map.js +571 -1
  96. package/dist-standalone/cjs/identity.js +645 -1
  97. package/dist-standalone/cjs/index.js +406 -1
  98. package/dist-standalone/cjs/invitation.js +421 -1
  99. package/dist-standalone/cjs/invite.js +328 -1
  100. package/dist-standalone/cjs/key-agreement.js +335 -1
  101. package/dist-standalone/cjs/lazy-init.js +300 -1
  102. package/dist-standalone/cjs/logger.js +291 -1
  103. package/dist-standalone/cjs/mdns-discovery.js +202 -1
  104. package/dist-standalone/cjs/nonce-store.js +80 -1
  105. package/dist-standalone/cjs/pairing-manager.js +223 -1
  106. package/dist-standalone/cjs/plugin-system.js +264 -1
  107. package/dist-standalone/cjs/plugins/logging.js +168 -1
  108. package/dist-standalone/cjs/plugins/metrics.js +181 -1
  109. package/dist-standalone/cjs/plugins/validation.js +302 -1
  110. package/dist-standalone/cjs/policy.js +320 -1
  111. package/dist-standalone/cjs/progress-callbacks.js +583 -1
  112. package/dist-standalone/cjs/redis-nonce-store.js +76 -1
  113. package/dist-standalone/cjs/registry-middleware.js +50 -1
  114. package/dist-standalone/cjs/retry-strategies.js +544 -1
  115. package/dist-standalone/cjs/retry-transport.js +102 -1
  116. package/dist-standalone/cjs/runtime/browser.js +533 -1
  117. package/dist-standalone/cjs/runtime/edge.js +526 -1
  118. package/dist-standalone/cjs/runtime/react-native.js +394 -1
  119. package/dist-standalone/cjs/security-policy.js +245 -1
  120. package/dist-standalone/cjs/serialization.js +1040 -1
  121. package/dist-standalone/cjs/split-channel.js +225 -1
  122. package/dist-standalone/cjs/subscription-proof.js +230 -1
  123. package/dist-standalone/cjs/succession.js +148 -1
  124. package/dist-standalone/cjs/timeouts.js +412 -1
  125. package/dist-standalone/cjs/trace-context.js +424 -1
  126. package/dist-standalone/cjs/trace-spans.js +495 -1
  127. package/dist-standalone/cjs/transport.js +63 -1
  128. package/dist-standalone/cjs/trust-registry.js +991 -1
  129. package/dist-standalone/cjs/types/error-response.js +56 -1
  130. package/dist-standalone/cjs/vault-auth.js +178 -1
  131. package/dist-standalone/cjs/vault-store-loader.js +194 -1
  132. package/dist-standalone/cjs/verify.js +25 -1
  133. package/dist-standalone/cjs/version-info.js +543 -1
  134. package/dist-standalone/cjs/xfetch.js +340 -1
  135. package/dist-standalone/cli/init.js +455 -1
  136. package/dist-standalone/cli/setup.js +514 -1
  137. package/dist-standalone/cli/types.js +27 -1
  138. package/dist-standalone/cli/xbind.js +148 -1
  139. package/dist-standalone/config-validation.js +513 -1
  140. package/dist-standalone/connect.js +274 -1
  141. package/dist-standalone/connection-pool.js +500 -1
  142. package/dist-standalone/correlation-id.js +326 -1
  143. package/dist-standalone/crypto-utils.js +157 -1
  144. package/dist-standalone/debug-mode.js +510 -1
  145. package/dist-standalone/did-document.js +96 -1
  146. package/dist-standalone/did-privateme.js +121 -1
  147. package/dist-standalone/did-web.js +196 -1
  148. package/dist-standalone/discovery.js +458 -1
  149. package/dist-standalone/dual-mode.js +247 -1
  150. package/dist-standalone/email-templates.js +309 -1
  151. package/dist-standalone/email-transport.js +232 -1
  152. package/dist-standalone/envelope.js +525 -1
  153. package/dist-standalone/errors.js +896 -1
  154. package/dist-standalone/event-emitter.js +456 -1
  155. package/dist-standalone/gateway-state.js +51 -1
  156. package/dist-standalone/gateway-transport.js +116 -1
  157. package/dist-standalone/graceful-degradation.js +396 -1
  158. package/dist-standalone/guardrails.js +216 -1
  159. package/dist-standalone/health-check.js +332 -1
  160. package/dist-standalone/http-compat.js +267 -1
  161. package/dist-standalone/http-status-map.js +561 -1
  162. package/dist-standalone/identity.js +619 -1
  163. package/dist-standalone/index.js +78 -1
  164. package/dist-standalone/invitation.js +415 -1
  165. package/dist-standalone/invite.js +324 -1
  166. package/dist-standalone/key-agreement.js +325 -1
  167. package/dist-standalone/lazy-init.js +295 -1
  168. package/dist-standalone/logger.js +285 -1
  169. package/dist-standalone/mdns-discovery.js +195 -1
  170. package/dist-standalone/nonce-store.js +76 -1
  171. package/dist-standalone/pairing-manager.js +219 -1
  172. package/dist-standalone/plugin-system.js +257 -1
  173. package/dist-standalone/plugins/logging.d.ts +84 -0
  174. package/dist-standalone/plugins/logging.js +163 -0
  175. package/dist-standalone/plugins/metrics.d.ts +111 -0
  176. package/dist-standalone/plugins/metrics.js +176 -0
  177. package/dist-standalone/plugins/validation.d.ts +104 -0
  178. package/dist-standalone/plugins/validation.js +297 -0
  179. package/dist-standalone/policy.js +315 -1
  180. package/dist-standalone/progress-callbacks.js +576 -1
  181. package/dist-standalone/redis-nonce-store.js +72 -1
  182. package/dist-standalone/registry-middleware.js +47 -1
  183. package/dist-standalone/retry-strategies.js +534 -1
  184. package/dist-standalone/retry-transport.js +98 -1
  185. package/dist-standalone/runtime/browser.d.ts +311 -0
  186. package/dist-standalone/runtime/browser.js +516 -0
  187. package/dist-standalone/runtime/edge.d.ts +282 -0
  188. package/dist-standalone/runtime/edge.js +511 -0
  189. package/dist-standalone/runtime/react-native.d.ts +157 -0
  190. package/dist-standalone/runtime/react-native.js +383 -0
  191. package/dist-standalone/security-policy.js +239 -1
  192. package/dist-standalone/serialization.js +1031 -1
  193. package/dist-standalone/split-channel.js +219 -1
  194. package/dist-standalone/subscription-proof.js +224 -1
  195. package/dist-standalone/succession.js +142 -1
  196. package/dist-standalone/timeouts.js +398 -1
  197. package/dist-standalone/trace-context.js +414 -1
  198. package/dist-standalone/trace-spans.js +488 -1
  199. package/dist-standalone/transport.js +59 -1
  200. package/dist-standalone/trust-registry.js +950 -1
  201. package/dist-standalone/types/error-response.d.ts +209 -0
  202. package/dist-standalone/types/error-response.js +52 -0
  203. package/dist-standalone/vault-auth.js +174 -1
  204. package/dist-standalone/vault-store-loader.js +187 -1
  205. package/dist-standalone/verify.js +16 -1
  206. package/dist-standalone/version-info.js +530 -1
  207. package/dist-standalone/xfetch.js +335 -1
  208. package/package.json +4 -10
  209. package/share1.dat +0 -0
  210. package/dist-standalone/_deps/mldsa-wasm/LICENSE +0 -24
  211. package/dist-standalone/_deps/mldsa-wasm/package.json +0 -46
  212. package/dist-standalone/_deps/shared/cjs/package.json +0 -1
  213. package/dist-standalone/_deps/ux-helpers/cjs/package.json +0 -1
  214. package/dist-standalone/_deps/xchange/cjs/package.json +0 -1
  215. package/dist-standalone/_deps/xregistry/cjs/package.json +0 -1
  216. package/dist-standalone/cjs/package.json +0 -3
  217. package/dist-standalone/package.json +0 -10
@@ -1 +1,490 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.CancellationError=void 0,exports.createTimeoutSignal=createTimeoutSignal,exports.combineSignals=combineSignals,exports.onCancellation=onCancellation,exports.throwIfAborted=throwIfAborted,exports.withCancellation=withCancellation,exports.delay=delay,exports.withRetry=withRetry,exports.createCancellationController=createCancellationController,exports.isCancellationError=isCancellationError;const shared_1=require("../_deps/shared/index.js");class CancellationError extends Error{reason;context;constructor(e,r,n){super(e),this.reason=r,this.context=n,this.name="CancellationError"}}function createTimeoutSignal(e,r){const n=new AbortController,t=Date.now(),o=setTimeout(()=>{const t=r?.reason||`Operation timed out after ${e}ms`;n.abort(new CancellationError(t,"timeout",r?.context))},e);return{signal:n.signal,clear:()=>{clearTimeout(o)},remaining:()=>{const r=Date.now()-t;return Math.max(0,e-r)}}}function combineSignals(e){const r=e.filter(e=>e&&!e.aborted);if(0===r.length){const r=e.find(e=>e?.aborted);return r||(new AbortController).signal}if(1===r.length)return r[0];if("function"==typeof AbortSignal.any)return AbortSignal.any(r);const n=new AbortController,t=[];for(const e of r){const r=()=>{n.abort(e.reason),t.forEach(e=>e())};e.addEventListener("abort",r,{once:!0}),t.push(()=>{e.removeEventListener("abort",r)})}return n.signal}function onCancellation(e,r){e.aborted?Promise.resolve().then(()=>r()).catch(()=>{}):e.addEventListener("abort",()=>{Promise.resolve().then(()=>r()).catch(()=>{})},{once:!0})}function throwIfAborted(e,r){if(e?.aborted){const n=e.reason instanceof Error?e.reason.message:String(e.reason||"Operation was cancelled");throw new CancellationError(n,"aborted",r)}}async function withCancellation(e,r){if(!r)try{const r=await e;return(0,shared_1.ok)(r)}catch(e){return(0,shared_1.err)(new CancellationError(e instanceof Error?e.message:String(e),"promise_rejected"))}if(r.aborted){const e=r.reason instanceof Error?r.reason.message:String(r.reason||"Operation was cancelled");return(0,shared_1.err)(new CancellationError(e,"aborted"))}return new Promise(n=>{const t=()=>{const e=r.reason instanceof Error?r.reason.message:String(r.reason||"Operation was cancelled");n((0,shared_1.err)(new CancellationError(e,"aborted")))};r.addEventListener("abort",t,{once:!0}),e.then(e=>{r.removeEventListener("abort",t),n((0,shared_1.ok)(e))}).catch(e=>{r.removeEventListener("abort",t),n((0,shared_1.err)(new CancellationError(e instanceof Error?e.message:String(e),"promise_rejected")))})})}function delay(e,r){return new Promise((n,t)=>{if(r?.aborted){const e=r.reason instanceof Error?r.reason.message:String(r.reason||"Delay cancelled");return void t(new CancellationError(e,"aborted"))}const o=setTimeout(()=>{r&&r.removeEventListener("abort",a),n()},e),a=()=>{clearTimeout(o);const e=r.reason instanceof Error?r.reason.message:String(r.reason||"Delay cancelled");t(new CancellationError(e,"aborted"))};r&&r.addEventListener("abort",a,{once:!0})})}async function withRetry(e,r){const n=r?.maxAttempts??3,t=r?.initialDelay??1e3,o=r?.multiplier??2,a=r?.signal,i=r?.shouldRetry??(()=>!0);let s,l=t;for(let r=1;r<=n;r++){if(a?.aborted){const e=a.reason instanceof Error?a.reason.message:String(a.reason||"Operation was cancelled");return(0,shared_1.err)(new CancellationError(e,"aborted",{attempt:r}))}try{const r=await e();return(0,shared_1.ok)(r)}catch(e){if(s=e instanceof Error?e:new Error(String(e)),r>=n||!i(e,r))break;try{await delay(l,a),l*=o}catch(e){if(e instanceof CancellationError)return(0,shared_1.err)(e);throw e}}}return(0,shared_1.err)(s||new Error("Operation failed after retries"))}function createCancellationController(){const e=new AbortController;let r;return{signal:e.signal,get isCancelled(){return e.signal.aborted},get reason(){return r},cancel(n){r=n||"Operation cancelled",e.abort(new CancellationError(r,"manual"))},throwIfCancelled(r){throwIfAborted(e.signal,r)}}}function isCancellationError(e){return e instanceof CancellationError||e instanceof Error&&"AbortError"===e.name||e instanceof Error&&"CancellationError"===e.name}exports.CancellationError=CancellationError;
1
+ "use strict";
2
+ /**
3
+ * @module cancellation
4
+ * Cancellation token support for xBind operations
5
+ *
6
+ * Provides AbortController/AbortSignal integration for enhanced operation control:
7
+ * - Cancellable async operations (fetch, agent.call, transport)
8
+ * - Timeout management with automatic cleanup
9
+ * - Composite signals (multiple cancellation sources)
10
+ * - Resource cleanup on cancellation
11
+ *
12
+ * Architecture:
13
+ * - Uses standard AbortController/AbortSignal (Web API + Node.js)
14
+ * - Timeout wrapper creates time-limited signals
15
+ * - Composite signals combine multiple cancellation sources
16
+ * - Cleanup callbacks ensure proper resource disposal
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // Timeout with cancellation
21
+ * const signal = createTimeoutSignal(5000);
22
+ * await xfetch('https://api.example.com', { signal });
23
+ *
24
+ * // Manual cancellation
25
+ * const controller = new AbortController();
26
+ * setTimeout(() => controller.abort(), 1000);
27
+ * await agent.call('tool:action', params, { signal: controller.signal });
28
+ *
29
+ * // Composite signals
30
+ * const timeout = createTimeoutSignal(10000);
31
+ * const manual = new AbortController();
32
+ * const combined = combineSignals([timeout.signal, manual.signal]);
33
+ * await operation({ signal: combined });
34
+ * ```
35
+ */
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.CancellationError = void 0;
38
+ exports.createTimeoutSignal = createTimeoutSignal;
39
+ exports.combineSignals = combineSignals;
40
+ exports.onCancellation = onCancellation;
41
+ exports.throwIfAborted = throwIfAborted;
42
+ exports.withCancellation = withCancellation;
43
+ exports.delay = delay;
44
+ exports.withRetry = withRetry;
45
+ exports.createCancellationController = createCancellationController;
46
+ exports.isCancellationError = isCancellationError;
47
+ const shared_1 = require("../_deps/shared/index.js");
48
+ /**
49
+ * Cancellation error thrown when operation is aborted
50
+ */
51
+ class CancellationError extends Error {
52
+ reason;
53
+ context;
54
+ constructor(message, reason, context) {
55
+ super(message);
56
+ this.reason = reason;
57
+ this.context = context;
58
+ this.name = 'CancellationError';
59
+ }
60
+ }
61
+ exports.CancellationError = CancellationError;
62
+ /**
63
+ * Create an AbortSignal that triggers after a timeout
64
+ *
65
+ * Automatically aborts the signal after the specified duration.
66
+ * Useful for setting time limits on async operations.
67
+ *
68
+ * @param timeout - Timeout in milliseconds
69
+ * @param options - Optional reason and context
70
+ * @returns TimeoutController with signal and clear function
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const timeout = createTimeoutSignal(5000);
75
+ * try {
76
+ * await fetch('https://api.example.com', { signal: timeout.signal });
77
+ * } catch (error) {
78
+ * if (error.name === 'AbortError') {
79
+ * console.log('Request timed out after 5s');
80
+ * }
81
+ * } finally {
82
+ * timeout.clear(); // Clean up timer
83
+ * }
84
+ * ```
85
+ */
86
+ function createTimeoutSignal(timeout, options) {
87
+ const controller = new AbortController();
88
+ const startTime = Date.now();
89
+ const timeoutId = setTimeout(() => {
90
+ const reason = options?.reason || `Operation timed out after ${timeout}ms`;
91
+ controller.abort(new CancellationError(reason, 'timeout', options?.context));
92
+ }, timeout);
93
+ return {
94
+ signal: controller.signal,
95
+ clear: () => {
96
+ clearTimeout(timeoutId);
97
+ },
98
+ remaining: () => {
99
+ const elapsed = Date.now() - startTime;
100
+ return Math.max(0, timeout - elapsed);
101
+ },
102
+ };
103
+ }
104
+ /**
105
+ * Combine multiple AbortSignals into a single signal
106
+ *
107
+ * The combined signal aborts when ANY of the source signals abort.
108
+ * Useful for operations with multiple cancellation sources (timeout, user action, etc.).
109
+ *
110
+ * @param signals - Array of signals to combine
111
+ * @returns Combined AbortSignal
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * const timeout = createTimeoutSignal(10000);
116
+ * const userCancel = new AbortController();
117
+ * const combined = combineSignals([timeout.signal, userCancel.signal]);
118
+ *
119
+ * // Either timeout OR user cancellation will abort
120
+ * await fetch('https://api.example.com', { signal: combined });
121
+ * ```
122
+ */
123
+ function combineSignals(signals) {
124
+ // Filter out already-aborted signals and undefined
125
+ const activeSignals = signals.filter(s => s && !s.aborted);
126
+ // If all signals are already aborted, return an aborted signal
127
+ if (activeSignals.length === 0) {
128
+ const alreadyAborted = signals.find(s => s?.aborted);
129
+ if (alreadyAborted) {
130
+ // Return already-aborted signal
131
+ return alreadyAborted;
132
+ }
133
+ // No signals provided - return never-aborts signal
134
+ return new AbortController().signal;
135
+ }
136
+ // If only one active signal, return it directly
137
+ if (activeSignals.length === 1) {
138
+ return activeSignals[0];
139
+ }
140
+ // Use AbortSignal.any() if available (Node 20+, modern browsers)
141
+ if (typeof AbortSignal.any === 'function') {
142
+ return AbortSignal.any(activeSignals);
143
+ }
144
+ // Fallback: manually combine signals
145
+ const controller = new AbortController();
146
+ const abortListeners = [];
147
+ for (const signal of activeSignals) {
148
+ const listener = () => {
149
+ controller.abort(signal.reason);
150
+ // Remove all listeners after first abort
151
+ abortListeners.forEach((remove) => remove());
152
+ };
153
+ signal.addEventListener('abort', listener, { once: true });
154
+ // Store cleanup function
155
+ abortListeners.push(() => {
156
+ signal.removeEventListener('abort', listener);
157
+ });
158
+ }
159
+ return controller.signal;
160
+ }
161
+ /**
162
+ * Register cleanup callback to run when signal is aborted
163
+ *
164
+ * Ensures resources are properly disposed when operation is cancelled.
165
+ * Cleanup runs immediately if signal is already aborted.
166
+ *
167
+ * @param signal - AbortSignal to monitor
168
+ * @param cleanup - Cleanup callback
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * const controller = new AbortController();
173
+ * const connection = await openConnection();
174
+ *
175
+ * onCancellation(controller.signal, async () => {
176
+ * console.log('Cleaning up connection...');
177
+ * await connection.close();
178
+ * });
179
+ *
180
+ * // Later...
181
+ * controller.abort(); // Cleanup runs automatically
182
+ * ```
183
+ */
184
+ function onCancellation(signal, cleanup) {
185
+ // If already aborted, run cleanup immediately
186
+ if (signal.aborted) {
187
+ void Promise.resolve().then(() => cleanup()).catch(() => {
188
+ // Cleanup errors are handled silently to avoid unhandled rejections
189
+ });
190
+ return;
191
+ }
192
+ // Register cleanup to run on abort
193
+ signal.addEventListener('abort', () => {
194
+ // Run cleanup and catch errors silently to avoid unhandled rejections
195
+ void Promise.resolve().then(() => cleanup()).catch(() => {
196
+ // Cleanup errors are expected and handled silently
197
+ // (test can spy on this if needed, but we don't log by default)
198
+ });
199
+ }, { once: true });
200
+ }
201
+ /**
202
+ * Check if signal is aborted and throw CancellationError if so
203
+ *
204
+ * Useful for checking cancellation at specific points in long-running operations.
205
+ *
206
+ * @param signal - AbortSignal to check
207
+ * @param context - Optional context for error
208
+ * @throws CancellationError if signal is aborted
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * async function processLargeDataset(data: unknown[], signal?: AbortSignal) {
213
+ * for (const item of data) {
214
+ * throwIfAborted(signal, { item: item.id });
215
+ * await processItem(item);
216
+ * }
217
+ * }
218
+ * ```
219
+ */
220
+ function throwIfAborted(signal, context) {
221
+ if (signal?.aborted) {
222
+ const reason = signal.reason instanceof Error
223
+ ? signal.reason.message
224
+ : String(signal.reason || 'Operation was cancelled');
225
+ throw new CancellationError(reason, 'aborted', context);
226
+ }
227
+ }
228
+ /**
229
+ * Wrap a promise with cancellation support
230
+ *
231
+ * If signal aborts before promise resolves, returns error result.
232
+ * Otherwise returns the promise's result.
233
+ *
234
+ * @param promise - Promise to wrap
235
+ * @param signal - AbortSignal for cancellation
236
+ * @returns Result wrapper around promise
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * const timeout = createTimeoutSignal(5000);
241
+ * const result = await withCancellation(
242
+ * fetch('https://api.example.com'),
243
+ * timeout.signal
244
+ * );
245
+ *
246
+ * if (!result.ok) {
247
+ * console.error('Request cancelled:', result.error.message);
248
+ * }
249
+ * ```
250
+ */
251
+ async function withCancellation(promise, signal) {
252
+ if (!signal) {
253
+ // No signal - just await promise
254
+ try {
255
+ const value = await promise;
256
+ return (0, shared_1.ok)(value);
257
+ }
258
+ catch (error) {
259
+ return (0, shared_1.err)(new CancellationError(error instanceof Error ? error.message : String(error), 'promise_rejected'));
260
+ }
261
+ }
262
+ // If already aborted, return immediately
263
+ if (signal.aborted) {
264
+ const reason = signal.reason instanceof Error
265
+ ? signal.reason.message
266
+ : String(signal.reason || 'Operation was cancelled');
267
+ return (0, shared_1.err)(new CancellationError(reason, 'aborted'));
268
+ }
269
+ // Race promise against abort signal
270
+ return new Promise((resolve) => {
271
+ // Handle abort
272
+ const onAbort = () => {
273
+ const reason = signal.reason instanceof Error
274
+ ? signal.reason.message
275
+ : String(signal.reason || 'Operation was cancelled');
276
+ resolve((0, shared_1.err)(new CancellationError(reason, 'aborted')));
277
+ };
278
+ signal.addEventListener('abort', onAbort, { once: true });
279
+ // Handle promise resolution
280
+ promise
281
+ .then((value) => {
282
+ signal.removeEventListener('abort', onAbort);
283
+ resolve((0, shared_1.ok)(value));
284
+ })
285
+ .catch((error) => {
286
+ signal.removeEventListener('abort', onAbort);
287
+ resolve((0, shared_1.err)(new CancellationError(error instanceof Error ? error.message : String(error), 'promise_rejected')));
288
+ });
289
+ });
290
+ }
291
+ /**
292
+ * Create a cancellable delay
293
+ *
294
+ * Returns a promise that resolves after the specified duration,
295
+ * but can be cancelled early via signal.
296
+ *
297
+ * @param ms - Delay in milliseconds
298
+ * @param signal - Optional AbortSignal for cancellation
299
+ * @returns Promise that resolves after delay or rejects on cancellation
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * const controller = new AbortController();
304
+ *
305
+ * // Start 10s delay
306
+ * const delayPromise = delay(10000, controller.signal);
307
+ *
308
+ * // Cancel after 2s
309
+ * setTimeout(() => controller.abort(), 2000);
310
+ *
311
+ * try {
312
+ * await delayPromise; // Throws CancellationError after 2s
313
+ * } catch (error) {
314
+ * console.log('Delay cancelled');
315
+ * }
316
+ * ```
317
+ */
318
+ function delay(ms, signal) {
319
+ return new Promise((resolve, reject) => {
320
+ // Check if already aborted
321
+ if (signal?.aborted) {
322
+ const reason = signal.reason instanceof Error
323
+ ? signal.reason.message
324
+ : String(signal.reason || 'Delay cancelled');
325
+ reject(new CancellationError(reason, 'aborted'));
326
+ return;
327
+ }
328
+ const timeoutId = setTimeout(() => {
329
+ if (signal) {
330
+ signal.removeEventListener('abort', onAbort);
331
+ }
332
+ resolve();
333
+ }, ms);
334
+ const onAbort = () => {
335
+ clearTimeout(timeoutId);
336
+ const reason = signal.reason instanceof Error
337
+ ? signal.reason.message
338
+ : String(signal.reason || 'Delay cancelled');
339
+ reject(new CancellationError(reason, 'aborted'));
340
+ };
341
+ if (signal) {
342
+ signal.addEventListener('abort', onAbort, { once: true });
343
+ }
344
+ });
345
+ }
346
+ /**
347
+ * Retry an operation with cancellation support
348
+ *
349
+ * Attempts operation multiple times with exponential backoff.
350
+ * Respects cancellation signal between retry attempts.
351
+ *
352
+ * @param operation - Async operation to retry
353
+ * @param options - Retry configuration
354
+ * @returns Result of operation
355
+ *
356
+ * @example
357
+ * ```typescript
358
+ * const timeout = createTimeoutSignal(30000);
359
+ *
360
+ * const result = await withRetry(
361
+ * async () => {
362
+ * const res = await fetch('https://api.example.com');
363
+ * if (!res.ok) throw new Error('Request failed');
364
+ * return res.json();
365
+ * },
366
+ * {
367
+ * maxAttempts: 5,
368
+ * initialDelay: 1000,
369
+ * multiplier: 2,
370
+ * signal: timeout.signal,
371
+ * }
372
+ * );
373
+ * ```
374
+ */
375
+ async function withRetry(operation, options) {
376
+ const maxAttempts = options?.maxAttempts ?? 3;
377
+ const initialDelay = options?.initialDelay ?? 1000;
378
+ const multiplier = options?.multiplier ?? 2;
379
+ const signal = options?.signal;
380
+ const shouldRetry = options?.shouldRetry ?? (() => true);
381
+ let lastError;
382
+ let delayMs = initialDelay;
383
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
384
+ // Check cancellation before attempt
385
+ if (signal?.aborted) {
386
+ const reason = signal.reason instanceof Error
387
+ ? signal.reason.message
388
+ : String(signal.reason || 'Operation was cancelled');
389
+ return (0, shared_1.err)(new CancellationError(reason, 'aborted', { attempt }));
390
+ }
391
+ try {
392
+ const value = await operation();
393
+ return (0, shared_1.ok)(value);
394
+ }
395
+ catch (error) {
396
+ lastError = error instanceof Error ? error : new Error(String(error));
397
+ // On last attempt or if shouldRetry returns false, don't retry
398
+ if (attempt >= maxAttempts || !shouldRetry(error, attempt)) {
399
+ // No more attempts or predicate said no
400
+ break;
401
+ }
402
+ // Wait before retry (with cancellation support)
403
+ try {
404
+ await delay(delayMs, signal);
405
+ delayMs *= multiplier;
406
+ }
407
+ catch (cancelError) {
408
+ // Cancelled during delay
409
+ if (cancelError instanceof CancellationError) {
410
+ return (0, shared_1.err)(cancelError);
411
+ }
412
+ throw cancelError;
413
+ }
414
+ }
415
+ }
416
+ // All attempts failed
417
+ return (0, shared_1.err)(lastError || new Error('Operation failed after retries'));
418
+ }
419
+ /**
420
+ * Create a manual cancellation controller with helper methods
421
+ *
422
+ * Extends AbortController with additional utilities for common patterns.
423
+ *
424
+ * @returns Enhanced controller with helper methods
425
+ *
426
+ * @example
427
+ * ```typescript
428
+ * const controller = createCancellationController();
429
+ *
430
+ * // Start operation
431
+ * const promise = longRunningOperation({ signal: controller.signal });
432
+ *
433
+ * // Cancel with custom reason
434
+ * controller.cancel('User requested cancellation');
435
+ *
436
+ * // Check if cancelled
437
+ * if (controller.isCancelled) {
438
+ * console.log('Operation was cancelled');
439
+ * }
440
+ * ```
441
+ */
442
+ function createCancellationController() {
443
+ const controller = new AbortController();
444
+ let cancelledReason;
445
+ return {
446
+ /** Abort signal for cancellation */
447
+ signal: controller.signal,
448
+ /** True if operation has been cancelled */
449
+ get isCancelled() {
450
+ return controller.signal.aborted;
451
+ },
452
+ /** Reason for cancellation (if any) */
453
+ get reason() {
454
+ return cancelledReason;
455
+ },
456
+ /** Cancel the operation with optional reason */
457
+ cancel(reason) {
458
+ cancelledReason = reason || 'Operation cancelled';
459
+ controller.abort(new CancellationError(cancelledReason, 'manual'));
460
+ },
461
+ /** Throw if cancelled */
462
+ throwIfCancelled(context) {
463
+ throwIfAborted(controller.signal, context);
464
+ },
465
+ };
466
+ }
467
+ /**
468
+ * Check if an error is a cancellation error
469
+ *
470
+ * @param error - Error to check
471
+ * @returns True if error is from cancellation
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * try {
476
+ * await operation({ signal });
477
+ * } catch (error) {
478
+ * if (isCancellationError(error)) {
479
+ * console.log('Operation was cancelled');
480
+ * } else {
481
+ * console.error('Operation failed:', error);
482
+ * }
483
+ * }
484
+ * ```
485
+ */
486
+ function isCancellationError(error) {
487
+ return error instanceof CancellationError ||
488
+ (error instanceof Error && error.name === 'AbortError') ||
489
+ (error instanceof Error && error.name === 'CancellationError');
490
+ }
@@ -1 +1,193 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.createCheckpoint=createCheckpoint,exports.verifyCheckpoint=verifyCheckpoint,exports.isCacheStale=isCacheStale,exports.encodeCheckpoint=encodeCheckpoint,exports.decodeCheckpoint=decodeCheckpoint;const shared_1=require("../_deps/shared/index.js"),identity_js_1=require("./identity.js");async function createCheckpoint(e,r,t,n,i){const o=Date.now(),c=Buffer.from(r).toString("base64"),s=`DIDStateCheckpoint||1.0||${e}||${c}||${t}||${n}||${o}`,a=(new TextEncoder).encode(s),u=await(0,identity_js_1.signMlDsa65)(i,a);return u.ok?(0,shared_1.ok)({type:"DIDStateCheckpoint",version:"1.0",subject:e,current_public_key:c,revoked:t,rotation_sequence:n,timestamp:o,checkpoint_signature_algorithm:"ML-DSA-65",checkpoint_signature:Buffer.from(u.value).toString("base64")}):(0,shared_1.err)("SIGN_FAILED")}async function verifyCheckpoint(e,r){if("DIDStateCheckpoint"!==e.type)return(0,shared_1.err)("INVALID_FORMAT");if("1.0"!==e.version)return(0,shared_1.err)("INVALID_FORMAT");if(!e.subject||!e.current_public_key)return(0,shared_1.err)("INVALID_FORMAT");if("number"!=typeof e.rotation_sequence||e.rotation_sequence<0)return(0,shared_1.err)("INVALID_FORMAT");if("number"!=typeof e.timestamp||e.timestamp<=0)return(0,shared_1.err)("INVALID_TIMESTAMP");if("ML-DSA-65"!==e.checkpoint_signature_algorithm)return(0,shared_1.err)("INVALID_FORMAT");const t=`DIDStateCheckpoint||1.0||${e.subject}||${e.current_public_key}||${e.revoked}||${e.rotation_sequence}||${e.timestamp}`,n=(new TextEncoder).encode(t);let i;try{i=Buffer.from(e.checkpoint_signature,"base64")}catch{return(0,shared_1.err)("INVALID_SIGNATURE")}const o=await(0,identity_js_1.verifyMlDsa65)(r,i,n);return o.ok?(0,shared_1.ok)(o.value):(0,shared_1.err)("VERIFY_FAILED")}function isCacheStale(e,r){if(r.rotation_sequence>e.rotationSequence)return!0;if(r.revoked!==e.revoked)return!0;const t=Buffer.from(r.current_public_key,"base64");return!Buffer.from(e.publicKey).equals(t)}function encodeCheckpoint(e){return JSON.stringify(e)}function decodeCheckpoint(e){try{const r=JSON.parse(e);return"DIDStateCheckpoint"!==r.type||"1.0"!==r.version?(0,shared_1.err)("INVALID_FORMAT"):r.subject&&r.current_public_key&&r.checkpoint_signature?(0,shared_1.ok)(r):(0,shared_1.err)("INVALID_FORMAT")}catch{return(0,shared_1.err)("INVALID_FORMAT")}}
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCheckpoint = createCheckpoint;
4
+ exports.verifyCheckpoint = verifyCheckpoint;
5
+ exports.isCacheStale = isCacheStale;
6
+ exports.encodeCheckpoint = encodeCheckpoint;
7
+ exports.decodeCheckpoint = decodeCheckpoint;
8
+ const shared_1 = require("../_deps/shared/index.js");
9
+ const identity_js_1 = require("./identity.js");
10
+ /* ── Checkpoint Creation (Gateway-side) ── */
11
+ /**
12
+ * Create a signed checkpoint for a DID (gateway-side operation).
13
+ *
14
+ * Gateway signs the DID state snapshot using its ML-DSA-65 private key.
15
+ * Clients verify this signature using the gateway's published public key.
16
+ *
17
+ * @param subject - DID being checkpointed
18
+ * @param publicKey - Current public key bytes
19
+ * @param revoked - Current revocation status
20
+ * @param rotationSequence - Current rotation sequence counter
21
+ * @param gatewayPrivateKey - Gateway's ML-DSA-65 secret key (32-byte seed or 4032-byte expanded)
22
+ * @returns Signed checkpoint or error
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const checkpoint = await createCheckpoint(
27
+ * 'did:key:z6Mk...',
28
+ * publicKeyBytes,
29
+ * false,
30
+ * 5,
31
+ * gatewaySecretKey
32
+ * );
33
+ * if (checkpoint.ok) {
34
+ * // Send checkpoint to client for staleness detection
35
+ * sendToClient(checkpoint.value);
36
+ * }
37
+ * ```
38
+ */
39
+ async function createCheckpoint(subject, publicKey, revoked, rotationSequence, gatewayPrivateKey) {
40
+ const timestamp = Date.now();
41
+ // Construct canonical message to sign
42
+ const publicKeyB64 = Buffer.from(publicKey).toString('base64');
43
+ const message = `DIDStateCheckpoint||1.0||${subject}||${publicKeyB64}||${revoked}||${rotationSequence}||${timestamp}`;
44
+ const messageBytes = new TextEncoder().encode(message);
45
+ // Sign using gateway's ML-DSA-65 key
46
+ const sigResult = await (0, identity_js_1.signMlDsa65)(gatewayPrivateKey, messageBytes);
47
+ if (!sigResult.ok) {
48
+ return (0, shared_1.err)('SIGN_FAILED');
49
+ }
50
+ return (0, shared_1.ok)({
51
+ type: 'DIDStateCheckpoint',
52
+ version: '1.0',
53
+ subject,
54
+ current_public_key: publicKeyB64,
55
+ revoked,
56
+ rotation_sequence: rotationSequence,
57
+ timestamp,
58
+ checkpoint_signature_algorithm: 'ML-DSA-65',
59
+ checkpoint_signature: Buffer.from(sigResult.value).toString('base64')
60
+ });
61
+ }
62
+ /* ── Checkpoint Verification (Client-side) ── */
63
+ /**
64
+ * Verify a checkpoint signature (client-side operation).
65
+ *
66
+ * Clients MUST verify checkpoint signatures before trusting the state.
67
+ * Uses gateway's published ML-DSA-65 public key to verify signature.
68
+ *
69
+ * @param checkpoint - Checkpoint to verify
70
+ * @param gatewayPublicKey - Gateway's ML-DSA-65 public key (1952 bytes)
71
+ * @returns true if signature valid, false if invalid, error if verification fails
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const valid = await verifyCheckpoint(checkpoint, gatewayPubKey);
76
+ * if (valid.ok && valid.value) {
77
+ * // Checkpoint is authentic - safe to use for staleness detection
78
+ * if (isCacheStale(localCache, checkpoint)) {
79
+ * // Refresh local cache
80
+ * }
81
+ * }
82
+ * ```
83
+ */
84
+ async function verifyCheckpoint(checkpoint, gatewayPublicKey) {
85
+ // Validate checkpoint format
86
+ if (checkpoint.type !== 'DIDStateCheckpoint') {
87
+ return (0, shared_1.err)('INVALID_FORMAT');
88
+ }
89
+ if (checkpoint.version !== '1.0') {
90
+ return (0, shared_1.err)('INVALID_FORMAT');
91
+ }
92
+ if (!checkpoint.subject || !checkpoint.current_public_key) {
93
+ return (0, shared_1.err)('INVALID_FORMAT');
94
+ }
95
+ if (typeof checkpoint.rotation_sequence !== 'number' || checkpoint.rotation_sequence < 0) {
96
+ return (0, shared_1.err)('INVALID_FORMAT');
97
+ }
98
+ if (typeof checkpoint.timestamp !== 'number' || checkpoint.timestamp <= 0) {
99
+ return (0, shared_1.err)('INVALID_TIMESTAMP');
100
+ }
101
+ if (checkpoint.checkpoint_signature_algorithm !== 'ML-DSA-65') {
102
+ return (0, shared_1.err)('INVALID_FORMAT');
103
+ }
104
+ // Reconstruct canonical message
105
+ const message = `DIDStateCheckpoint||1.0||${checkpoint.subject}||${checkpoint.current_public_key}||${checkpoint.revoked}||${checkpoint.rotation_sequence}||${checkpoint.timestamp}`;
106
+ const messageBytes = new TextEncoder().encode(message);
107
+ // Decode signature
108
+ let signature;
109
+ try {
110
+ signature = Buffer.from(checkpoint.checkpoint_signature, 'base64');
111
+ }
112
+ catch {
113
+ return (0, shared_1.err)('INVALID_SIGNATURE');
114
+ }
115
+ // Verify signature using gateway public key
116
+ const verifyResult = await (0, identity_js_1.verifyMlDsa65)(gatewayPublicKey, signature, messageBytes);
117
+ if (!verifyResult.ok) {
118
+ return (0, shared_1.err)('VERIFY_FAILED');
119
+ }
120
+ return (0, shared_1.ok)(verifyResult.value);
121
+ }
122
+ /* ── Staleness Detection ── */
123
+ /**
124
+ * Detect if local cache is stale compared to gateway checkpoint.
125
+ *
126
+ * Cache is stale if:
127
+ * 1. Checkpoint rotation_sequence > local rotationSequence (key rotated)
128
+ * 2. Checkpoint revoked !== local revoked (revocation status changed)
129
+ * 3. Checkpoint public key !== local publicKey (state drift)
130
+ *
131
+ * @param localCache - Local cache entry for DID
132
+ * @param checkpoint - Verified checkpoint from gateway
133
+ * @returns true if cache needs refresh, false if cache is current
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * if (isCacheStale(localCache, checkpoint)) {
138
+ * // Local cache is outdated - fetch fresh state from gateway
139
+ * const freshState = await registry.getEntry(did);
140
+ * }
141
+ * ```
142
+ */
143
+ function isCacheStale(localCache, checkpoint) {
144
+ // Sequence number mismatch indicates key rotation
145
+ if (checkpoint.rotation_sequence > localCache.rotationSequence) {
146
+ return true;
147
+ }
148
+ // Revocation status changed
149
+ if (checkpoint.revoked !== localCache.revoked) {
150
+ return true;
151
+ }
152
+ // Public key mismatch indicates state drift
153
+ const checkpointPubKey = Buffer.from(checkpoint.current_public_key, 'base64');
154
+ if (!Buffer.from(localCache.publicKey).equals(checkpointPubKey)) {
155
+ return true;
156
+ }
157
+ return false;
158
+ }
159
+ /* ── Encoding/Decoding ── */
160
+ /**
161
+ * Encode checkpoint to JSON string for wire transport.
162
+ *
163
+ * @param checkpoint - Checkpoint to encode
164
+ * @returns JSON string
165
+ */
166
+ function encodeCheckpoint(checkpoint) {
167
+ return JSON.stringify(checkpoint);
168
+ }
169
+ /**
170
+ * Decode checkpoint from JSON string.
171
+ *
172
+ * @param encoded - JSON string
173
+ * @returns Parsed checkpoint or error
174
+ */
175
+ function decodeCheckpoint(encoded) {
176
+ try {
177
+ const parsed = JSON.parse(encoded);
178
+ // Basic validation
179
+ if (parsed.type !== 'DIDStateCheckpoint') {
180
+ return (0, shared_1.err)('INVALID_FORMAT');
181
+ }
182
+ if (parsed.version !== '1.0') {
183
+ return (0, shared_1.err)('INVALID_FORMAT');
184
+ }
185
+ if (!parsed.subject || !parsed.current_public_key || !parsed.checkpoint_signature) {
186
+ return (0, shared_1.err)('INVALID_FORMAT');
187
+ }
188
+ return (0, shared_1.ok)(parsed);
189
+ }
190
+ catch {
191
+ return (0, shared_1.err)('INVALID_FORMAT');
192
+ }
193
+ }