footprintjs 4.16.0 → 4.17.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 (188) hide show
  1. package/AGENTS.md +567 -82
  2. package/CLAUDE.md +57 -0
  3. package/README.md +2 -0
  4. package/dist/advanced.js +4 -2
  5. package/dist/detach.js +78 -0
  6. package/dist/esm/advanced.js +2 -1
  7. package/dist/esm/detach.js +57 -0
  8. package/dist/esm/lib/builder/FlowChartBuilder.js +171 -61
  9. package/dist/esm/lib/contract/openapi.js +4 -5
  10. package/dist/esm/lib/contract/schema.js +115 -4
  11. package/dist/esm/lib/decide/decide.js +4 -5
  12. package/dist/esm/lib/decide/evidence.js +3 -2
  13. package/dist/esm/lib/detach/drivers/immediate.js +66 -0
  14. package/dist/esm/lib/detach/drivers/microtaskBatch.js +113 -0
  15. package/dist/esm/lib/detach/drivers/sendBeacon.js +78 -0
  16. package/dist/esm/lib/detach/drivers/setImmediate.js +81 -0
  17. package/dist/esm/lib/detach/drivers/setTimeout.js +69 -0
  18. package/dist/esm/lib/detach/drivers/workerThread.js +117 -0
  19. package/dist/esm/lib/detach/flush.js +91 -0
  20. package/dist/esm/lib/detach/handle.js +134 -0
  21. package/dist/esm/lib/detach/registry.js +97 -0
  22. package/dist/esm/lib/detach/runChild.js +40 -0
  23. package/dist/esm/lib/detach/spawn.js +86 -0
  24. package/dist/esm/lib/detach/types.js +37 -0
  25. package/dist/esm/lib/engine/errors/errorInfo.js +4 -4
  26. package/dist/esm/lib/engine/graph/StageNode.js +2 -2
  27. package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +9 -8
  28. package/dist/esm/lib/engine/handlers/ContinuationResolver.js +12 -9
  29. package/dist/esm/lib/engine/handlers/DeciderHandler.js +7 -8
  30. package/dist/esm/lib/engine/handlers/ExtractorRunner.js +14 -8
  31. package/dist/esm/lib/engine/handlers/NodeResolver.js +5 -3
  32. package/dist/esm/lib/engine/handlers/RuntimeStructureManager.js +11 -14
  33. package/dist/esm/lib/engine/handlers/SelectorHandler.js +9 -9
  34. package/dist/esm/lib/engine/handlers/StageRunner.js +9 -11
  35. package/dist/esm/lib/engine/handlers/SubflowExecutor.js +13 -12
  36. package/dist/esm/lib/engine/handlers/SubflowInputMapper.js +4 -4
  37. package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +85 -96
  38. package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.js +18 -36
  39. package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.js +6 -5
  40. package/dist/esm/lib/engine/narrative/recorders/AdaptiveNarrativeFlowRecorder.js +7 -6
  41. package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.js +10 -10
  42. package/dist/esm/lib/engine/narrative/recorders/MilestoneNarrativeFlowRecorder.js +5 -3
  43. package/dist/esm/lib/engine/narrative/recorders/ProgressiveNarrativeFlowRecorder.js +4 -3
  44. package/dist/esm/lib/engine/narrative/recorders/RLENarrativeFlowRecorder.js +4 -4
  45. package/dist/esm/lib/engine/narrative/recorders/SeparateNarrativeFlowRecorder.js +5 -6
  46. package/dist/esm/lib/engine/narrative/recorders/SilentNarrativeFlowRecorder.js +5 -6
  47. package/dist/esm/lib/engine/narrative/recorders/WindowedNarrativeFlowRecorder.js +5 -3
  48. package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +97 -71
  49. package/dist/esm/lib/memory/DiagnosticCollector.js +6 -8
  50. package/dist/esm/lib/memory/EventLog.js +5 -3
  51. package/dist/esm/lib/memory/SharedMemory.js +3 -2
  52. package/dist/esm/lib/memory/StageContext.js +44 -14
  53. package/dist/esm/lib/memory/TransactionBuffer.js +9 -8
  54. package/dist/esm/lib/memory/backtrack.js +3 -4
  55. package/dist/esm/lib/memory/commitLogUtils.js +2 -2
  56. package/dist/esm/lib/memory/utils.js +2 -3
  57. package/dist/esm/lib/pause/types.js +33 -14
  58. package/dist/esm/lib/reactive/createTypedScope.js +10 -8
  59. package/dist/esm/lib/reactive/types.js +3 -1
  60. package/dist/esm/lib/recorder/BoundaryStateTracker.js +263 -0
  61. package/dist/esm/lib/recorder/CompositeRecorder.js +3 -1
  62. package/dist/esm/lib/recorder/InOutRecorder.js +5 -6
  63. package/dist/esm/lib/recorder/KeyedRecorder.js +2 -4
  64. package/dist/esm/lib/recorder/QualityRecorder.js +15 -14
  65. package/dist/esm/lib/recorder/SequenceRecorder.js +11 -12
  66. package/dist/esm/lib/recorder/TopologyRecorder.js +36 -40
  67. package/dist/esm/lib/recorder/index.js +2 -1
  68. package/dist/esm/lib/recorder/qualityTrace.js +4 -5
  69. package/dist/esm/lib/runner/ExecutionRuntime.js +20 -4
  70. package/dist/esm/lib/runner/FlowChartExecutor.js +99 -55
  71. package/dist/esm/lib/runner/RunContext.js +5 -3
  72. package/dist/esm/lib/runner/RunnableChart.js +7 -9
  73. package/dist/esm/lib/runner/getSubtreeSnapshot.js +4 -5
  74. package/dist/esm/lib/schema/errors.js +4 -3
  75. package/dist/esm/lib/schema/validate.js +4 -5
  76. package/dist/esm/lib/scope/ScopeFacade.js +52 -35
  77. package/dist/esm/lib/scope/providers/baseStateCompatible.js +9 -9
  78. package/dist/esm/lib/scope/providers/guards.js +2 -2
  79. package/dist/esm/lib/scope/recorders/DebugRecorder.js +9 -7
  80. package/dist/esm/lib/scope/recorders/MetricRecorder.js +10 -8
  81. package/dist/esm/lib/scope/state/zod/defineScopeFromZod.js +2 -3
  82. package/dist/esm/lib/scope/state/zod/resolver.js +2 -3
  83. package/dist/esm/lib/scope/state/zod/scopeFactory.js +16 -20
  84. package/dist/esm/lib/scope/state/zod/utils/validateHelper.js +57 -14
  85. package/dist/esm/trace.js +4 -1
  86. package/dist/lib/builder/FlowChartBuilder.js +171 -61
  87. package/dist/lib/contract/openapi.js +4 -5
  88. package/dist/lib/contract/schema.js +115 -4
  89. package/dist/lib/decide/decide.js +4 -5
  90. package/dist/lib/decide/evidence.js +3 -2
  91. package/dist/lib/detach/drivers/immediate.js +70 -0
  92. package/dist/lib/detach/drivers/microtaskBatch.js +117 -0
  93. package/dist/lib/detach/drivers/sendBeacon.js +82 -0
  94. package/dist/lib/detach/drivers/setImmediate.js +85 -0
  95. package/dist/lib/detach/drivers/setTimeout.js +73 -0
  96. package/dist/lib/detach/drivers/workerThread.js +121 -0
  97. package/dist/lib/detach/flush.js +95 -0
  98. package/dist/lib/detach/handle.js +140 -0
  99. package/dist/lib/detach/registry.js +106 -0
  100. package/dist/lib/detach/runChild.js +67 -0
  101. package/dist/lib/detach/spawn.js +92 -0
  102. package/dist/lib/detach/types.js +38 -0
  103. package/dist/lib/engine/errors/errorInfo.js +4 -4
  104. package/dist/lib/engine/graph/StageNode.js +2 -2
  105. package/dist/lib/engine/handlers/ChildrenExecutor.js +9 -8
  106. package/dist/lib/engine/handlers/ContinuationResolver.js +12 -9
  107. package/dist/lib/engine/handlers/DeciderHandler.js +7 -8
  108. package/dist/lib/engine/handlers/ExtractorRunner.js +14 -8
  109. package/dist/lib/engine/handlers/NodeResolver.js +5 -3
  110. package/dist/lib/engine/handlers/RuntimeStructureManager.js +11 -14
  111. package/dist/lib/engine/handlers/SelectorHandler.js +9 -9
  112. package/dist/lib/engine/handlers/StageRunner.js +9 -11
  113. package/dist/lib/engine/handlers/SubflowExecutor.js +13 -12
  114. package/dist/lib/engine/handlers/SubflowInputMapper.js +4 -4
  115. package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +85 -96
  116. package/dist/lib/engine/narrative/FlowRecorderDispatcher.js +18 -36
  117. package/dist/lib/engine/narrative/NarrativeFlowRecorder.js +6 -5
  118. package/dist/lib/engine/narrative/recorders/AdaptiveNarrativeFlowRecorder.js +7 -6
  119. package/dist/lib/engine/narrative/recorders/ManifestFlowRecorder.js +10 -10
  120. package/dist/lib/engine/narrative/recorders/MilestoneNarrativeFlowRecorder.js +5 -3
  121. package/dist/lib/engine/narrative/recorders/ProgressiveNarrativeFlowRecorder.js +4 -3
  122. package/dist/lib/engine/narrative/recorders/RLENarrativeFlowRecorder.js +4 -4
  123. package/dist/lib/engine/narrative/recorders/SeparateNarrativeFlowRecorder.js +5 -6
  124. package/dist/lib/engine/narrative/recorders/SilentNarrativeFlowRecorder.js +5 -6
  125. package/dist/lib/engine/narrative/recorders/WindowedNarrativeFlowRecorder.js +5 -3
  126. package/dist/lib/engine/traversal/FlowchartTraverser.js +97 -71
  127. package/dist/lib/memory/DiagnosticCollector.js +6 -8
  128. package/dist/lib/memory/EventLog.js +5 -3
  129. package/dist/lib/memory/SharedMemory.js +3 -2
  130. package/dist/lib/memory/StageContext.js +44 -14
  131. package/dist/lib/memory/TransactionBuffer.js +9 -8
  132. package/dist/lib/memory/backtrack.js +3 -4
  133. package/dist/lib/memory/commitLogUtils.js +2 -2
  134. package/dist/lib/memory/utils.js +2 -3
  135. package/dist/lib/pause/types.js +33 -14
  136. package/dist/lib/reactive/createTypedScope.js +10 -8
  137. package/dist/lib/reactive/types.js +3 -1
  138. package/dist/lib/recorder/BoundaryStateTracker.js +267 -0
  139. package/dist/lib/recorder/CompositeRecorder.js +3 -1
  140. package/dist/lib/recorder/InOutRecorder.js +5 -6
  141. package/dist/lib/recorder/KeyedRecorder.js +2 -4
  142. package/dist/lib/recorder/QualityRecorder.js +15 -14
  143. package/dist/lib/recorder/SequenceRecorder.js +11 -12
  144. package/dist/lib/recorder/TopologyRecorder.js +36 -40
  145. package/dist/lib/recorder/index.js +4 -2
  146. package/dist/lib/recorder/qualityTrace.js +4 -5
  147. package/dist/lib/runner/ExecutionRuntime.js +20 -4
  148. package/dist/lib/runner/FlowChartExecutor.js +99 -55
  149. package/dist/lib/runner/RunContext.js +5 -3
  150. package/dist/lib/runner/RunnableChart.js +7 -9
  151. package/dist/lib/runner/getSubtreeSnapshot.js +4 -5
  152. package/dist/lib/schema/errors.js +4 -3
  153. package/dist/lib/schema/validate.js +4 -5
  154. package/dist/lib/scope/ScopeFacade.js +52 -35
  155. package/dist/lib/scope/providers/baseStateCompatible.js +9 -9
  156. package/dist/lib/scope/providers/guards.js +2 -2
  157. package/dist/lib/scope/recorders/DebugRecorder.js +9 -7
  158. package/dist/lib/scope/recorders/MetricRecorder.js +10 -8
  159. package/dist/lib/scope/state/zod/defineScopeFromZod.js +2 -3
  160. package/dist/lib/scope/state/zod/resolver.js +2 -3
  161. package/dist/lib/scope/state/zod/scopeFactory.js +16 -20
  162. package/dist/lib/scope/state/zod/utils/validateHelper.js +57 -14
  163. package/dist/trace.js +6 -2
  164. package/dist/types/advanced.d.ts +1 -0
  165. package/dist/types/detach.d.ts +59 -0
  166. package/dist/types/lib/builder/FlowChartBuilder.d.ts +81 -0
  167. package/dist/types/lib/detach/drivers/immediate.d.ts +39 -0
  168. package/dist/types/lib/detach/drivers/microtaskBatch.d.ts +57 -0
  169. package/dist/types/lib/detach/drivers/sendBeacon.d.ts +38 -0
  170. package/dist/types/lib/detach/drivers/setImmediate.d.ts +32 -0
  171. package/dist/types/lib/detach/drivers/setTimeout.d.ts +34 -0
  172. package/dist/types/lib/detach/drivers/workerThread.d.ts +50 -0
  173. package/dist/types/lib/detach/flush.d.ts +62 -0
  174. package/dist/types/lib/detach/handle.d.ts +83 -0
  175. package/dist/types/lib/detach/registry.d.ts +82 -0
  176. package/dist/types/lib/detach/runChild.d.ts +41 -0
  177. package/dist/types/lib/detach/spawn.d.ts +64 -0
  178. package/dist/types/lib/detach/types.d.ts +200 -0
  179. package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +0 -1
  180. package/dist/types/lib/engine/types.d.ts +0 -1
  181. package/dist/types/lib/reactive/types.d.ts +4 -0
  182. package/dist/types/lib/recorder/BoundaryStateTracker.d.ts +215 -0
  183. package/dist/types/lib/recorder/index.d.ts +1 -0
  184. package/dist/types/lib/runner/FlowChartExecutor.d.ts +28 -0
  185. package/dist/types/lib/scope/ScopeFacade.d.ts +4 -0
  186. package/dist/types/lib/scope/state/zod/utils/validateHelper.d.ts +13 -1
  187. package/dist/types/trace.d.ts +1 -0
  188. package/package.json +6 -1
@@ -0,0 +1,113 @@
1
+ /**
2
+ * detach/drivers/microtaskBatch.ts — Batch detached work into ONE microtask.
3
+ *
4
+ * Pattern: Producer-consumer with batched flush. Same shape as
5
+ * agentfootprint's `EventDispatcher` flush queue and the React
6
+ * reconciler's microtask scheduling — accumulate during the
7
+ * current sync slice, drain at the next microtask boundary.
8
+ * Role: Default driver for in-process detach. Cheapest scheduling
9
+ * primitive on V8/JSC: one `queueMicrotask` per batch
10
+ * regardless of how many work items, so the perf budget
11
+ * amortizes. Suitable for browser AND node AND edge runtimes
12
+ * (queueMicrotask is universal since 2018).
13
+ *
14
+ * Lifecycle:
15
+ *
16
+ * schedule(child, input, refId) ← driver entry
17
+ * └─ create handle (queued)
18
+ * └─ register in detachRegistry
19
+ * └─ push work item onto local queue
20
+ * └─ if no microtask scheduled yet → queueMicrotask(flush)
21
+ * └─ return handle (sync — passive recorder rule)
22
+ *
23
+ * flush() (microtask) ← deferred
24
+ * └─ swap out queue (drain races safely)
25
+ * └─ for each item: _markRunning, await runChild, _markDone/_markFailed
26
+ * └─ unregister handle from detachRegistry
27
+ *
28
+ * Why microtask (and not setImmediate / setTimeout):
29
+ * - Microtasks run BEFORE returning to the event loop — guarantees
30
+ * the work finishes within the current "tick" if the runtime allows
31
+ * - Lowest possible deferral cost (~50ns on modern V8)
32
+ * - Works in EVERY JS runtime (browser, node, deno, bun, edge)
33
+ * - Doesn't require any timer infrastructure → no GC pressure
34
+ *
35
+ * Re-entrancy:
36
+ * - If `runChild` calls `schedule()` for nested detach, the new item
37
+ * lands on the SAME queue. Because `scheduled` flips back to false
38
+ * at the start of `flush`, the new item triggers a fresh microtask.
39
+ * - Worst-case: O(n) microtasks for n nested levels. Acceptable —
40
+ * real-world detach trees are shallow.
41
+ */
42
+ import { asImpl, createHandle } from '../handle.js';
43
+ import { register, unregister } from '../registry.js';
44
+ import { defaultRunChild } from '../runChild.js';
45
+ /**
46
+ * Build a microtask-batch driver wired to a custom child runner. Most
47
+ * consumers want the default singleton `microtaskBatchDriver` instead;
48
+ * this factory exists for tests and for advanced consumers who want to
49
+ * inject their own runner (e.g., a runner that wraps the child in a
50
+ * tracing context).
51
+ */
52
+ export function createMicrotaskBatchDriver(runChild = defaultRunChild) {
53
+ // Per-driver-instance queue and flush guard. Closed over by `schedule`
54
+ // and `flush` so each call to `createMicrotaskBatchDriver` gets its
55
+ // own isolated batch (test isolation, multi-tenant scenarios).
56
+ const queue = [];
57
+ let scheduled = false;
58
+ function flush() {
59
+ // Reset BEFORE draining so re-entrant schedule()s during runChild
60
+ // queue a fresh microtask instead of joining the in-flight drain.
61
+ scheduled = false;
62
+ const items = queue.splice(0);
63
+ for (const item of items) {
64
+ // Each item runs concurrently — no awaits here, so the outer
65
+ // for-loop completes within this microtask. Errors inside
66
+ // `executeOne` are routed to the handle, not thrown. The promise
67
+ // is intentionally not awaited; ignore-promise-returned via the
68
+ // explicit no-op .then() pattern that the project's lint config
69
+ // accepts (vs `void`, which `no-void` rejects).
70
+ executeOne(item, runChild).then(undefined, undefined);
71
+ }
72
+ }
73
+ return {
74
+ name: 'microtask-batch',
75
+ capabilities: { browserSafe: true, nodeSafe: true, edgeSafe: true },
76
+ schedule(child, input, refId) {
77
+ const handle = createHandle(refId);
78
+ register(handle);
79
+ queue.push({ child, input, handle });
80
+ if (!scheduled) {
81
+ scheduled = true;
82
+ queueMicrotask(flush);
83
+ }
84
+ return handle;
85
+ },
86
+ };
87
+ }
88
+ /**
89
+ * Per-item execution. Marks the handle running, awaits the runner,
90
+ * routes outcome to the handle, cleans up the registry entry. Never
91
+ * throws — errors land on the handle (passive recorder rule).
92
+ */
93
+ async function executeOne(item, runChild) {
94
+ const impl = asImpl(item.handle);
95
+ impl._markRunning();
96
+ try {
97
+ const result = await runChild(item.child, item.input);
98
+ impl._markDone(result);
99
+ }
100
+ catch (err) {
101
+ impl._markFailed(err instanceof Error ? err : new Error(String(err)));
102
+ }
103
+ finally {
104
+ unregister(impl.id);
105
+ }
106
+ }
107
+ /**
108
+ * Default singleton. Most consumers import this and pass it to
109
+ * `executor.detachAndJoinLater(child, input, { driver: microtaskBatchDriver })`
110
+ * (or rely on it being the executor's default driver, set in T5b).
111
+ */
112
+ export const microtaskBatchDriver = createMicrotaskBatchDriver();
113
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWljcm90YXNrQmF0Y2guanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL2RldGFjaC9kcml2ZXJzL21pY3JvdGFza0JhdGNoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0NHO0FBR0gsT0FBTyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDcEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RCxPQUFPLEVBQW9CLGVBQWUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBU25FOzs7Ozs7R0FNRztBQUNILE1BQU0sVUFBVSwwQkFBMEIsQ0FBQyxXQUF3QixlQUFlO0lBQ2hGLHVFQUF1RTtJQUN2RSxvRUFBb0U7SUFDcEUsK0RBQStEO0lBQy9ELE1BQU0sS0FBSyxHQUFlLEVBQUUsQ0FBQztJQUM3QixJQUFJLFNBQVMsR0FBRyxLQUFLLENBQUM7SUFFdEIsU0FBUyxLQUFLO1FBQ1osa0VBQWtFO1FBQ2xFLGtFQUFrRTtRQUNsRSxTQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ2xCLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDOUIsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUN6Qiw2REFBNkQ7WUFDN0QsMERBQTBEO1lBQzFELGlFQUFpRTtZQUNqRSxnRUFBZ0U7WUFDaEUsZ0VBQWdFO1lBQ2hFLGdEQUFnRDtZQUNoRCxVQUFVLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDeEQsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPO1FBQ0wsSUFBSSxFQUFFLGlCQUFpQjtRQUN2QixZQUFZLEVBQUUsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRTtRQUNuRSxRQUFRLENBQUMsS0FBZ0IsRUFBRSxLQUFjLEVBQUUsS0FBYTtZQUN0RCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDbkMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2pCLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFDckMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNmLFNBQVMsR0FBRyxJQUFJLENBQUM7Z0JBQ2pCLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUN4QixDQUFDO1lBQ0QsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILEtBQUssVUFBVSxVQUFVLENBQUMsSUFBYyxFQUFFLFFBQXFCO0lBQzdELE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDakMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3BCLElBQUksQ0FBQztRQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3RELElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4RSxDQUFDO1lBQVMsQ0FBQztRQUNULFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdEIsQ0FBQztBQUNILENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQWlCLDBCQUEwQixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGRldGFjaC9kcml2ZXJzL21pY3JvdGFza0JhdGNoLnRzIOKAlCBCYXRjaCBkZXRhY2hlZCB3b3JrIGludG8gT05FIG1pY3JvdGFzay5cbiAqXG4gKiBQYXR0ZXJuOiAgUHJvZHVjZXItY29uc3VtZXIgd2l0aCBiYXRjaGVkIGZsdXNoLiBTYW1lIHNoYXBlIGFzXG4gKiAgICAgICAgICAgYWdlbnRmb290cHJpbnQncyBgRXZlbnREaXNwYXRjaGVyYCBmbHVzaCBxdWV1ZSBhbmQgdGhlIFJlYWN0XG4gKiAgICAgICAgICAgcmVjb25jaWxlcidzIG1pY3JvdGFzayBzY2hlZHVsaW5nIOKAlCBhY2N1bXVsYXRlIGR1cmluZyB0aGVcbiAqICAgICAgICAgICBjdXJyZW50IHN5bmMgc2xpY2UsIGRyYWluIGF0IHRoZSBuZXh0IG1pY3JvdGFzayBib3VuZGFyeS5cbiAqIFJvbGU6ICAgICBEZWZhdWx0IGRyaXZlciBmb3IgaW4tcHJvY2VzcyBkZXRhY2guIENoZWFwZXN0IHNjaGVkdWxpbmdcbiAqICAgICAgICAgICBwcmltaXRpdmUgb24gVjgvSlNDOiBvbmUgYHF1ZXVlTWljcm90YXNrYCBwZXIgYmF0Y2hcbiAqICAgICAgICAgICByZWdhcmRsZXNzIG9mIGhvdyBtYW55IHdvcmsgaXRlbXMsIHNvIHRoZSBwZXJmIGJ1ZGdldFxuICogICAgICAgICAgIGFtb3J0aXplcy4gU3VpdGFibGUgZm9yIGJyb3dzZXIgQU5EIG5vZGUgQU5EIGVkZ2UgcnVudGltZXNcbiAqICAgICAgICAgICAocXVldWVNaWNyb3Rhc2sgaXMgdW5pdmVyc2FsIHNpbmNlIDIwMTgpLlxuICpcbiAqIExpZmVjeWNsZTpcbiAqXG4gKiAgIHNjaGVkdWxlKGNoaWxkLCBpbnB1dCwgcmVmSWQpICAgICAgICAgICAg4oaQIGRyaXZlciBlbnRyeVxuICogICAgIOKUlOKUgCBjcmVhdGUgaGFuZGxlIChxdWV1ZWQpXG4gKiAgICAg4pSU4pSAIHJlZ2lzdGVyIGluIGRldGFjaFJlZ2lzdHJ5XG4gKiAgICAg4pSU4pSAIHB1c2ggd29yayBpdGVtIG9udG8gbG9jYWwgcXVldWVcbiAqICAgICDilJTilIAgaWYgbm8gbWljcm90YXNrIHNjaGVkdWxlZCB5ZXQg4oaSIHF1ZXVlTWljcm90YXNrKGZsdXNoKVxuICogICAgIOKUlOKUgCByZXR1cm4gaGFuZGxlIChzeW5jIOKAlCBwYXNzaXZlIHJlY29yZGVyIHJ1bGUpXG4gKlxuICogICBmbHVzaCgpIChtaWNyb3Rhc2spICAgICAgICAgICAgICAgICAgICAgICDihpAgZGVmZXJyZWRcbiAqICAgICDilJTilIAgc3dhcCBvdXQgcXVldWUgKGRyYWluIHJhY2VzIHNhZmVseSlcbiAqICAgICDilJTilIAgZm9yIGVhY2ggaXRlbTogX21hcmtSdW5uaW5nLCBhd2FpdCBydW5DaGlsZCwgX21hcmtEb25lL19tYXJrRmFpbGVkXG4gKiAgICAg4pSU4pSAIHVucmVnaXN0ZXIgaGFuZGxlIGZyb20gZGV0YWNoUmVnaXN0cnlcbiAqXG4gKiBXaHkgbWljcm90YXNrIChhbmQgbm90IHNldEltbWVkaWF0ZSAvIHNldFRpbWVvdXQpOlxuICogICAtIE1pY3JvdGFza3MgcnVuIEJFRk9SRSByZXR1cm5pbmcgdG8gdGhlIGV2ZW50IGxvb3Ag4oCUIGd1YXJhbnRlZXNcbiAqICAgICB0aGUgd29yayBmaW5pc2hlcyB3aXRoaW4gdGhlIGN1cnJlbnQgXCJ0aWNrXCIgaWYgdGhlIHJ1bnRpbWUgYWxsb3dzXG4gKiAgIC0gTG93ZXN0IHBvc3NpYmxlIGRlZmVycmFsIGNvc3QgKH41MG5zIG9uIG1vZGVybiBWOClcbiAqICAgLSBXb3JrcyBpbiBFVkVSWSBKUyBydW50aW1lIChicm93c2VyLCBub2RlLCBkZW5vLCBidW4sIGVkZ2UpXG4gKiAgIC0gRG9lc24ndCByZXF1aXJlIGFueSB0aW1lciBpbmZyYXN0cnVjdHVyZSDihpIgbm8gR0MgcHJlc3N1cmVcbiAqXG4gKiBSZS1lbnRyYW5jeTpcbiAqICAgLSBJZiBgcnVuQ2hpbGRgIGNhbGxzIGBzY2hlZHVsZSgpYCBmb3IgbmVzdGVkIGRldGFjaCwgdGhlIG5ldyBpdGVtXG4gKiAgICAgbGFuZHMgb24gdGhlIFNBTUUgcXVldWUuIEJlY2F1c2UgYHNjaGVkdWxlZGAgZmxpcHMgYmFjayB0byBmYWxzZVxuICogICAgIGF0IHRoZSBzdGFydCBvZiBgZmx1c2hgLCB0aGUgbmV3IGl0ZW0gdHJpZ2dlcnMgYSBmcmVzaCBtaWNyb3Rhc2suXG4gKiAgIC0gV29yc3QtY2FzZTogTyhuKSBtaWNyb3Rhc2tzIGZvciBuIG5lc3RlZCBsZXZlbHMuIEFjY2VwdGFibGUg4oCUXG4gKiAgICAgcmVhbC13b3JsZCBkZXRhY2ggdHJlZXMgYXJlIHNoYWxsb3cuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBGbG93Q2hhcnQgfSBmcm9tICcuLi8uLi9idWlsZGVyL3R5cGVzLmpzJztcbmltcG9ydCB7IGFzSW1wbCwgY3JlYXRlSGFuZGxlIH0gZnJvbSAnLi4vaGFuZGxlLmpzJztcbmltcG9ydCB7IHJlZ2lzdGVyLCB1bnJlZ2lzdGVyIH0gZnJvbSAnLi4vcmVnaXN0cnkuanMnO1xuaW1wb3J0IHsgdHlwZSBDaGlsZFJ1bm5lciwgZGVmYXVsdFJ1bkNoaWxkIH0gZnJvbSAnLi4vcnVuQ2hpbGQuanMnO1xuaW1wb3J0IHR5cGUgeyBEZXRhY2hEcml2ZXIsIERldGFjaEhhbmRsZSB9IGZyb20gJy4uL3R5cGVzLmpzJztcblxuaW50ZXJmYWNlIFdvcmtJdGVtIHtcbiAgcmVhZG9ubHkgY2hpbGQ6IEZsb3dDaGFydDtcbiAgcmVhZG9ubHkgaW5wdXQ6IHVua25vd247XG4gIHJlYWRvbmx5IGhhbmRsZTogRGV0YWNoSGFuZGxlO1xufVxuXG4vKipcbiAqIEJ1aWxkIGEgbWljcm90YXNrLWJhdGNoIGRyaXZlciB3aXJlZCB0byBhIGN1c3RvbSBjaGlsZCBydW5uZXIuIE1vc3RcbiAqIGNvbnN1bWVycyB3YW50IHRoZSBkZWZhdWx0IHNpbmdsZXRvbiBgbWljcm90YXNrQmF0Y2hEcml2ZXJgIGluc3RlYWQ7XG4gKiB0aGlzIGZhY3RvcnkgZXhpc3RzIGZvciB0ZXN0cyBhbmQgZm9yIGFkdmFuY2VkIGNvbnN1bWVycyB3aG8gd2FudCB0b1xuICogaW5qZWN0IHRoZWlyIG93biBydW5uZXIgKGUuZy4sIGEgcnVubmVyIHRoYXQgd3JhcHMgdGhlIGNoaWxkIGluIGFcbiAqIHRyYWNpbmcgY29udGV4dCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNaWNyb3Rhc2tCYXRjaERyaXZlcihydW5DaGlsZDogQ2hpbGRSdW5uZXIgPSBkZWZhdWx0UnVuQ2hpbGQpOiBEZXRhY2hEcml2ZXIge1xuICAvLyBQZXItZHJpdmVyLWluc3RhbmNlIHF1ZXVlIGFuZCBmbHVzaCBndWFyZC4gQ2xvc2VkIG92ZXIgYnkgYHNjaGVkdWxlYFxuICAvLyBhbmQgYGZsdXNoYCBzbyBlYWNoIGNhbGwgdG8gYGNyZWF0ZU1pY3JvdGFza0JhdGNoRHJpdmVyYCBnZXRzIGl0c1xuICAvLyBvd24gaXNvbGF0ZWQgYmF0Y2ggKHRlc3QgaXNvbGF0aW9uLCBtdWx0aS10ZW5hbnQgc2NlbmFyaW9zKS5cbiAgY29uc3QgcXVldWU6IFdvcmtJdGVtW10gPSBbXTtcbiAgbGV0IHNjaGVkdWxlZCA9IGZhbHNlO1xuXG4gIGZ1bmN0aW9uIGZsdXNoKCk6IHZvaWQge1xuICAgIC8vIFJlc2V0IEJFRk9SRSBkcmFpbmluZyBzbyByZS1lbnRyYW50IHNjaGVkdWxlKClzIGR1cmluZyBydW5DaGlsZFxuICAgIC8vIHF1ZXVlIGEgZnJlc2ggbWljcm90YXNrIGluc3RlYWQgb2Ygam9pbmluZyB0aGUgaW4tZmxpZ2h0IGRyYWluLlxuICAgIHNjaGVkdWxlZCA9IGZhbHNlO1xuICAgIGNvbnN0IGl0ZW1zID0gcXVldWUuc3BsaWNlKDApO1xuICAgIGZvciAoY29uc3QgaXRlbSBvZiBpdGVtcykge1xuICAgICAgLy8gRWFjaCBpdGVtIHJ1bnMgY29uY3VycmVudGx5IOKAlCBubyBhd2FpdHMgaGVyZSwgc28gdGhlIG91dGVyXG4gICAgICAvLyBmb3ItbG9vcCBjb21wbGV0ZXMgd2l0aGluIHRoaXMgbWljcm90YXNrLiBFcnJvcnMgaW5zaWRlXG4gICAgICAvLyBgZXhlY3V0ZU9uZWAgYXJlIHJvdXRlZCB0byB0aGUgaGFuZGxlLCBub3QgdGhyb3duLiBUaGUgcHJvbWlzZVxuICAgICAgLy8gaXMgaW50ZW50aW9uYWxseSBub3QgYXdhaXRlZDsgaWdub3JlLXByb21pc2UtcmV0dXJuZWQgdmlhIHRoZVxuICAgICAgLy8gZXhwbGljaXQgbm8tb3AgLnRoZW4oKSBwYXR0ZXJuIHRoYXQgdGhlIHByb2plY3QncyBsaW50IGNvbmZpZ1xuICAgICAgLy8gYWNjZXB0cyAodnMgYHZvaWRgLCB3aGljaCBgbm8tdm9pZGAgcmVqZWN0cykuXG4gICAgICBleGVjdXRlT25lKGl0ZW0sIHJ1bkNoaWxkKS50aGVuKHVuZGVmaW5lZCwgdW5kZWZpbmVkKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG5hbWU6ICdtaWNyb3Rhc2stYmF0Y2gnLFxuICAgIGNhcGFiaWxpdGllczogeyBicm93c2VyU2FmZTogdHJ1ZSwgbm9kZVNhZmU6IHRydWUsIGVkZ2VTYWZlOiB0cnVlIH0sXG4gICAgc2NoZWR1bGUoY2hpbGQ6IEZsb3dDaGFydCwgaW5wdXQ6IHVua25vd24sIHJlZklkOiBzdHJpbmcpOiBEZXRhY2hIYW5kbGUge1xuICAgICAgY29uc3QgaGFuZGxlID0gY3JlYXRlSGFuZGxlKHJlZklkKTtcbiAgICAgIHJlZ2lzdGVyKGhhbmRsZSk7XG4gICAgICBxdWV1ZS5wdXNoKHsgY2hpbGQsIGlucHV0LCBoYW5kbGUgfSk7XG4gICAgICBpZiAoIXNjaGVkdWxlZCkge1xuICAgICAgICBzY2hlZHVsZWQgPSB0cnVlO1xuICAgICAgICBxdWV1ZU1pY3JvdGFzayhmbHVzaCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gaGFuZGxlO1xuICAgIH0sXG4gIH07XG59XG5cbi8qKlxuICogUGVyLWl0ZW0gZXhlY3V0aW9uLiBNYXJrcyB0aGUgaGFuZGxlIHJ1bm5pbmcsIGF3YWl0cyB0aGUgcnVubmVyLFxuICogcm91dGVzIG91dGNvbWUgdG8gdGhlIGhhbmRsZSwgY2xlYW5zIHVwIHRoZSByZWdpc3RyeSBlbnRyeS4gTmV2ZXJcbiAqIHRocm93cyDigJQgZXJyb3JzIGxhbmQgb24gdGhlIGhhbmRsZSAocGFzc2l2ZSByZWNvcmRlciBydWxlKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZXhlY3V0ZU9uZShpdGVtOiBXb3JrSXRlbSwgcnVuQ2hpbGQ6IENoaWxkUnVubmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGltcGwgPSBhc0ltcGwoaXRlbS5oYW5kbGUpO1xuICBpbXBsLl9tYXJrUnVubmluZygpO1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJ1bkNoaWxkKGl0ZW0uY2hpbGQsIGl0ZW0uaW5wdXQpO1xuICAgIGltcGwuX21hcmtEb25lKHJlc3VsdCk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGltcGwuX21hcmtGYWlsZWQoZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIgOiBuZXcgRXJyb3IoU3RyaW5nKGVycikpKTtcbiAgfSBmaW5hbGx5IHtcbiAgICB1bnJlZ2lzdGVyKGltcGwuaWQpO1xuICB9XG59XG5cbi8qKlxuICogRGVmYXVsdCBzaW5nbGV0b24uIE1vc3QgY29uc3VtZXJzIGltcG9ydCB0aGlzIGFuZCBwYXNzIGl0IHRvXG4gKiBgZXhlY3V0b3IuZGV0YWNoQW5kSm9pbkxhdGVyKGNoaWxkLCBpbnB1dCwgeyBkcml2ZXI6IG1pY3JvdGFza0JhdGNoRHJpdmVyIH0pYFxuICogKG9yIHJlbHkgb24gaXQgYmVpbmcgdGhlIGV4ZWN1dG9yJ3MgZGVmYXVsdCBkcml2ZXIsIHNldCBpbiBUNWIpLlxuICovXG5leHBvcnQgY29uc3QgbWljcm90YXNrQmF0Y2hEcml2ZXI6IERldGFjaERyaXZlciA9IGNyZWF0ZU1pY3JvdGFza0JhdGNoRHJpdmVyKCk7XG4iXX0=
@@ -0,0 +1,78 @@
1
+ /**
2
+ * detach/drivers/sendBeacon.ts — Browser-only driver that ships work
3
+ * via `navigator.sendBeacon` so it
4
+ * survives page-unload.
5
+ *
6
+ * Pattern: Strategy / Adapter — translates the consumer's child
7
+ * flowchart into a sendBeacon POST. The "child" is expected
8
+ * to produce a JSON-serializable payload via its
9
+ * `inputMapper`; the URL endpoint is set at driver creation.
10
+ * Role: The narrow but high-value driver for analytics / error
11
+ * reporting / page-leave telemetry — the one case where
12
+ * "fire-and-forget" must really mean "ships even if the
13
+ * user closes the tab right after."
14
+ *
15
+ * `navigator.sendBeacon` semantics:
16
+ * - Browser queues the POST in the OS network stack BEFORE returning
17
+ * control. Survives page-unload, navigation, refresh.
18
+ * - Limited to ~64 KB per call (per HTML5 spec).
19
+ * - Fire-and-forget — no response observable.
20
+ *
21
+ * Caveats:
22
+ * - Browser-only (`browserSafe: true, survivesUnload: true`).
23
+ * `validate()` throws helpfully if `navigator.sendBeacon` isn't a
24
+ * function (e.g., when imported in Node).
25
+ * - The driver does NOT run the child flowchart through a
26
+ * `FlowChartExecutor` — it serializes the input and POSTs. This
27
+ * is an intentional simplification: sendBeacon's semantics
28
+ * wouldn't survive an executor's async stages anyway.
29
+ */
30
+ import { asImpl, createHandle } from '../handle.js';
31
+ import { register, unregister } from '../registry.js';
32
+ export function createSendBeaconDriver(opts) {
33
+ if (!opts.url) {
34
+ throw new TypeError('[detach] createSendBeaconDriver requires a `url` option.');
35
+ }
36
+ function serialize(input) {
37
+ if (opts.serialize)
38
+ return opts.serialize(input);
39
+ return new Blob([JSON.stringify(input ?? null)], { type: 'application/json' });
40
+ }
41
+ return {
42
+ name: 'send-beacon',
43
+ capabilities: {
44
+ browserSafe: true,
45
+ survivesUnload: true,
46
+ },
47
+ validate() {
48
+ if (typeof navigator === 'undefined' || typeof navigator.sendBeacon !== 'function') {
49
+ throw new Error('[detach] sendBeaconDriver requires a browser environment with `navigator.sendBeacon`. ' +
50
+ 'Use `microtaskBatchDriver` for in-process detach, or `setImmediateDriver` for Node.js.');
51
+ }
52
+ },
53
+ schedule(_child, input, refId) {
54
+ const handle = createHandle(refId);
55
+ register(handle);
56
+ const impl = asImpl(handle);
57
+ impl._markRunning();
58
+ try {
59
+ const payload = serialize(input);
60
+ const accepted = navigator.sendBeacon(opts.url, payload);
61
+ if (accepted) {
62
+ impl._markDone({ accepted: true, url: opts.url });
63
+ }
64
+ else {
65
+ impl._markFailed(new Error('[detach] navigator.sendBeacon refused the payload (likely over the ~64 KB limit).'));
66
+ }
67
+ }
68
+ catch (err) {
69
+ impl._markFailed(err instanceof Error ? err : new Error(String(err)));
70
+ }
71
+ finally {
72
+ unregister(impl.id);
73
+ }
74
+ return handle;
75
+ },
76
+ };
77
+ }
78
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZEJlYWNvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvZGV0YWNoL2RyaXZlcnMvc2VuZEJlYWNvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTRCRztBQUdILE9BQU8sRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3BELE9BQU8sRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFXdEQsTUFBTSxVQUFVLHNCQUFzQixDQUFDLElBQTZCO0lBQ2xFLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDZCxNQUFNLElBQUksU0FBUyxDQUFDLDBEQUEwRCxDQUFDLENBQUM7SUFDbEYsQ0FBQztJQUVELFNBQVMsU0FBUyxDQUFDLEtBQWM7UUFDL0IsSUFBSSxJQUFJLENBQUMsU0FBUztZQUFFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNqRCxPQUFPLElBQUksSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7SUFDakYsQ0FBQztJQUVELE9BQU87UUFDTCxJQUFJLEVBQUUsYUFBYTtRQUNuQixZQUFZLEVBQUU7WUFDWixXQUFXLEVBQUUsSUFBSTtZQUNqQixjQUFjLEVBQUUsSUFBSTtTQUNyQjtRQUNELFFBQVE7WUFDTixJQUFJLE9BQU8sU0FBUyxLQUFLLFdBQVcsSUFBSSxPQUFPLFNBQVMsQ0FBQyxVQUFVLEtBQUssVUFBVSxFQUFFLENBQUM7Z0JBQ25GLE1BQU0sSUFBSSxLQUFLLENBQ2Isd0ZBQXdGO29CQUN0Rix3RkFBd0YsQ0FDM0YsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO1FBQ0QsUUFBUSxDQUFDLE1BQWlCLEVBQUUsS0FBYyxFQUFFLEtBQWE7WUFDdkQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ25DLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNqQixNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDNUIsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3BCLElBQUksQ0FBQztnQkFDSCxNQUFNLE9BQU8sR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ2pDLE1BQU0sUUFBUSxHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxPQUFtQixDQUFDLENBQUM7Z0JBQ3JFLElBQUksUUFBUSxFQUFFLENBQUM7b0JBQ2IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO2dCQUNwRCxDQUFDO3FCQUFNLENBQUM7b0JBQ04sSUFBSSxDQUFDLFdBQVcsQ0FDZCxJQUFJLEtBQUssQ0FBQyxtRkFBbUYsQ0FBQyxDQUMvRixDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztnQkFDYixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUN4RSxDQUFDO29CQUFTLENBQUM7Z0JBQ1QsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN0QixDQUFDO1lBQ0QsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBkZXRhY2gvZHJpdmVycy9zZW5kQmVhY29uLnRzIOKAlCBCcm93c2VyLW9ubHkgZHJpdmVyIHRoYXQgc2hpcHMgd29ya1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpYSBgbmF2aWdhdG9yLnNlbmRCZWFjb25gIHNvIGl0XG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vydml2ZXMgcGFnZS11bmxvYWQuXG4gKlxuICogUGF0dGVybjogIFN0cmF0ZWd5IC8gQWRhcHRlciDigJQgdHJhbnNsYXRlcyB0aGUgY29uc3VtZXIncyBjaGlsZFxuICogICAgICAgICAgIGZsb3djaGFydCBpbnRvIGEgc2VuZEJlYWNvbiBQT1NULiBUaGUgXCJjaGlsZFwiIGlzIGV4cGVjdGVkXG4gKiAgICAgICAgICAgdG8gcHJvZHVjZSBhIEpTT04tc2VyaWFsaXphYmxlIHBheWxvYWQgdmlhIGl0c1xuICogICAgICAgICAgIGBpbnB1dE1hcHBlcmA7IHRoZSBVUkwgZW5kcG9pbnQgaXMgc2V0IGF0IGRyaXZlciBjcmVhdGlvbi5cbiAqIFJvbGU6ICAgICBUaGUgbmFycm93IGJ1dCBoaWdoLXZhbHVlIGRyaXZlciBmb3IgYW5hbHl0aWNzIC8gZXJyb3JcbiAqICAgICAgICAgICByZXBvcnRpbmcgLyBwYWdlLWxlYXZlIHRlbGVtZXRyeSDigJQgdGhlIG9uZSBjYXNlIHdoZXJlXG4gKiAgICAgICAgICAgXCJmaXJlLWFuZC1mb3JnZXRcIiBtdXN0IHJlYWxseSBtZWFuIFwic2hpcHMgZXZlbiBpZiB0aGVcbiAqICAgICAgICAgICB1c2VyIGNsb3NlcyB0aGUgdGFiIHJpZ2h0IGFmdGVyLlwiXG4gKlxuICogYG5hdmlnYXRvci5zZW5kQmVhY29uYCBzZW1hbnRpY3M6XG4gKiAgIC0gQnJvd3NlciBxdWV1ZXMgdGhlIFBPU1QgaW4gdGhlIE9TIG5ldHdvcmsgc3RhY2sgQkVGT1JFIHJldHVybmluZ1xuICogICAgIGNvbnRyb2wuIFN1cnZpdmVzIHBhZ2UtdW5sb2FkLCBuYXZpZ2F0aW9uLCByZWZyZXNoLlxuICogICAtIExpbWl0ZWQgdG8gfjY0IEtCIHBlciBjYWxsIChwZXIgSFRNTDUgc3BlYykuXG4gKiAgIC0gRmlyZS1hbmQtZm9yZ2V0IOKAlCBubyByZXNwb25zZSBvYnNlcnZhYmxlLlxuICpcbiAqIENhdmVhdHM6XG4gKiAgIC0gQnJvd3Nlci1vbmx5IChgYnJvd3NlclNhZmU6IHRydWUsIHN1cnZpdmVzVW5sb2FkOiB0cnVlYCkuXG4gKiAgICAgYHZhbGlkYXRlKClgIHRocm93cyBoZWxwZnVsbHkgaWYgYG5hdmlnYXRvci5zZW5kQmVhY29uYCBpc24ndCBhXG4gKiAgICAgZnVuY3Rpb24gKGUuZy4sIHdoZW4gaW1wb3J0ZWQgaW4gTm9kZSkuXG4gKiAgIC0gVGhlIGRyaXZlciBkb2VzIE5PVCBydW4gdGhlIGNoaWxkIGZsb3djaGFydCB0aHJvdWdoIGFcbiAqICAgICBgRmxvd0NoYXJ0RXhlY3V0b3JgIOKAlCBpdCBzZXJpYWxpemVzIHRoZSBpbnB1dCBhbmQgUE9TVHMuIFRoaXNcbiAqICAgICBpcyBhbiBpbnRlbnRpb25hbCBzaW1wbGlmaWNhdGlvbjogc2VuZEJlYWNvbidzIHNlbWFudGljc1xuICogICAgIHdvdWxkbid0IHN1cnZpdmUgYW4gZXhlY3V0b3IncyBhc3luYyBzdGFnZXMgYW55d2F5LlxuICovXG5cbmltcG9ydCB0eXBlIHsgRmxvd0NoYXJ0IH0gZnJvbSAnLi4vLi4vYnVpbGRlci90eXBlcy5qcyc7XG5pbXBvcnQgeyBhc0ltcGwsIGNyZWF0ZUhhbmRsZSB9IGZyb20gJy4uL2hhbmRsZS5qcyc7XG5pbXBvcnQgeyByZWdpc3RlciwgdW5yZWdpc3RlciB9IGZyb20gJy4uL3JlZ2lzdHJ5LmpzJztcbmltcG9ydCB0eXBlIHsgRGV0YWNoRHJpdmVyLCBEZXRhY2hIYW5kbGUgfSBmcm9tICcuLi90eXBlcy5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VuZEJlYWNvbkRyaXZlck9wdGlvbnMge1xuICAvKiogRW5kcG9pbnQgVVJMIOKAlCByZXF1aXJlZC4gZS5nLiwgYCdodHRwczovL3RlbGVtZXRyeS5leGFtcGxlLmNvbS9pbmdlc3QnYC4gKi9cbiAgcmVhZG9ubHkgdXJsOiBzdHJpbmc7XG4gIC8qKiBDdXN0b20gc2VyaWFsaXplci4gRGVmYXVsdHMgdG8gYEpTT04uc3RyaW5naWZ5KGlucHV0KWAgd2l0aFxuICAgKiAgYGFwcGxpY2F0aW9uL2pzb25gIGNvbnRlbnQgdHlwZS4gKi9cbiAgcmVhZG9ubHkgc2VyaWFsaXplPzogKGlucHV0OiB1bmtub3duKSA9PiBCbG9iIHwgc3RyaW5nIHwgRm9ybURhdGE7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTZW5kQmVhY29uRHJpdmVyKG9wdHM6IFNlbmRCZWFjb25Ecml2ZXJPcHRpb25zKTogRGV0YWNoRHJpdmVyIHtcbiAgaWYgKCFvcHRzLnVybCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1tkZXRhY2hdIGNyZWF0ZVNlbmRCZWFjb25Ecml2ZXIgcmVxdWlyZXMgYSBgdXJsYCBvcHRpb24uJyk7XG4gIH1cblxuICBmdW5jdGlvbiBzZXJpYWxpemUoaW5wdXQ6IHVua25vd24pOiBCbG9iIHwgc3RyaW5nIHwgRm9ybURhdGEge1xuICAgIGlmIChvcHRzLnNlcmlhbGl6ZSkgcmV0dXJuIG9wdHMuc2VyaWFsaXplKGlucHV0KTtcbiAgICByZXR1cm4gbmV3IEJsb2IoW0pTT04uc3RyaW5naWZ5KGlucHV0ID8/IG51bGwpXSwgeyB0eXBlOiAnYXBwbGljYXRpb24vanNvbicgfSk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG5hbWU6ICdzZW5kLWJlYWNvbicsXG4gICAgY2FwYWJpbGl0aWVzOiB7XG4gICAgICBicm93c2VyU2FmZTogdHJ1ZSxcbiAgICAgIHN1cnZpdmVzVW5sb2FkOiB0cnVlLFxuICAgIH0sXG4gICAgdmFsaWRhdGUoKTogdm9pZCB7XG4gICAgICBpZiAodHlwZW9mIG5hdmlnYXRvciA9PT0gJ3VuZGVmaW5lZCcgfHwgdHlwZW9mIG5hdmlnYXRvci5zZW5kQmVhY29uICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAnW2RldGFjaF0gc2VuZEJlYWNvbkRyaXZlciByZXF1aXJlcyBhIGJyb3dzZXIgZW52aXJvbm1lbnQgd2l0aCBgbmF2aWdhdG9yLnNlbmRCZWFjb25gLiAnICtcbiAgICAgICAgICAgICdVc2UgYG1pY3JvdGFza0JhdGNoRHJpdmVyYCBmb3IgaW4tcHJvY2VzcyBkZXRhY2gsIG9yIGBzZXRJbW1lZGlhdGVEcml2ZXJgIGZvciBOb2RlLmpzLicsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSxcbiAgICBzY2hlZHVsZShfY2hpbGQ6IEZsb3dDaGFydCwgaW5wdXQ6IHVua25vd24sIHJlZklkOiBzdHJpbmcpOiBEZXRhY2hIYW5kbGUge1xuICAgICAgY29uc3QgaGFuZGxlID0gY3JlYXRlSGFuZGxlKHJlZklkKTtcbiAgICAgIHJlZ2lzdGVyKGhhbmRsZSk7XG4gICAgICBjb25zdCBpbXBsID0gYXNJbXBsKGhhbmRsZSk7XG4gICAgICBpbXBsLl9tYXJrUnVubmluZygpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcGF5bG9hZCA9IHNlcmlhbGl6ZShpbnB1dCk7XG4gICAgICAgIGNvbnN0IGFjY2VwdGVkID0gbmF2aWdhdG9yLnNlbmRCZWFjb24ob3B0cy51cmwsIHBheWxvYWQgYXMgQm9keUluaXQpO1xuICAgICAgICBpZiAoYWNjZXB0ZWQpIHtcbiAgICAgICAgICBpbXBsLl9tYXJrRG9uZSh7IGFjY2VwdGVkOiB0cnVlLCB1cmw6IG9wdHMudXJsIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGltcGwuX21hcmtGYWlsZWQoXG4gICAgICAgICAgICBuZXcgRXJyb3IoJ1tkZXRhY2hdIG5hdmlnYXRvci5zZW5kQmVhY29uIHJlZnVzZWQgdGhlIHBheWxvYWQgKGxpa2VseSBvdmVyIHRoZSB+NjQgS0IgbGltaXQpLicpLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBpbXBsLl9tYXJrRmFpbGVkKGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyIDogbmV3IEVycm9yKFN0cmluZyhlcnIpKSk7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICB1bnJlZ2lzdGVyKGltcGwuaWQpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGhhbmRsZTtcbiAgICB9LFxuICB9O1xufVxuIl19
@@ -0,0 +1,81 @@
1
+ /**
2
+ * detach/drivers/setImmediate.ts — Defer detached work to a Node.js
3
+ * `setImmediate` boundary.
4
+ *
5
+ * Pattern: Same producer-consumer batch flush as `microtaskBatch`,
6
+ * but the deferral is `setImmediate` instead of
7
+ * `queueMicrotask`. Yields control back to the event loop
8
+ * BEFORE running — allows pending I/O callbacks to drain
9
+ * first, which microtasks would block.
10
+ * Role: Node-specific driver for "fire-and-forget after the
11
+ * current I/O tick." Use when the parent stage handles
12
+ * latency-sensitive work and you don't want detached work
13
+ * to compete for the synchronous slice.
14
+ *
15
+ * When to pick this over microtaskBatch:
16
+ * - You're shipping logs / metrics in a hot HTTP path and don't
17
+ * want them blocking the response from being flushed
18
+ * - The detached work itself is CPU-heavy enough that running it on
19
+ * the same microtask cycle would delay other microtasks
20
+ * - You explicitly want "next event-loop tick" semantics — useful
21
+ * when interacting with third-party libraries that expect at
22
+ * least one I/O tick between schedule and execution
23
+ *
24
+ * Capability:
25
+ * - `nodeSafe: true` — relies on Node's `setImmediate`, NOT
26
+ * available in browsers / Deno / Cloudflare Workers (use
27
+ * `setTimeoutDriver` for cross-runtime alternative)
28
+ */
29
+ import { asImpl, createHandle } from '../handle.js';
30
+ import { register, unregister } from '../registry.js';
31
+ import { defaultRunChild } from '../runChild.js';
32
+ export function createSetImmediateDriver(runChild = defaultRunChild) {
33
+ const queue = [];
34
+ let scheduled = false;
35
+ function flush() {
36
+ scheduled = false;
37
+ const items = queue.splice(0);
38
+ for (const item of items) {
39
+ executeOne(item, runChild).then(undefined, undefined);
40
+ }
41
+ }
42
+ return {
43
+ name: 'set-immediate',
44
+ capabilities: { nodeSafe: true },
45
+ validate() {
46
+ if (typeof setImmediate !== 'function') {
47
+ throw new Error('[detach] setImmediateDriver requires Node.js — global `setImmediate` is not defined ' +
48
+ 'in this runtime. Use `microtaskBatchDriver` for cross-runtime use, or `setTimeoutDriver` ' +
49
+ 'for browser/edge environments.');
50
+ }
51
+ },
52
+ schedule(child, input, refId) {
53
+ const handle = createHandle(refId);
54
+ register(handle);
55
+ queue.push({ child, input, handle });
56
+ if (!scheduled) {
57
+ scheduled = true;
58
+ // `setImmediate` is non-undefined here in Node; runtime guard
59
+ // is in `validate()`. The `!` is a deliberate assertion.
60
+ setImmediate(flush);
61
+ }
62
+ return handle;
63
+ },
64
+ };
65
+ }
66
+ async function executeOne(item, runChild) {
67
+ const impl = asImpl(item.handle);
68
+ impl._markRunning();
69
+ try {
70
+ const result = await runChild(item.child, item.input);
71
+ impl._markDone(result);
72
+ }
73
+ catch (err) {
74
+ impl._markFailed(err instanceof Error ? err : new Error(String(err)));
75
+ }
76
+ finally {
77
+ unregister(impl.id);
78
+ }
79
+ }
80
+ export const setImmediateDriver = createSetImmediateDriver();
81
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0SW1tZWRpYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9kZXRhY2gvZHJpdmVycy9zZXRJbW1lZGlhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJCRztBQUdILE9BQU8sRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3BELE9BQU8sRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEQsT0FBTyxFQUFvQixlQUFlLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQWVuRSxNQUFNLFVBQVUsd0JBQXdCLENBQUMsV0FBd0IsZUFBZTtJQUM5RSxNQUFNLEtBQUssR0FBZSxFQUFFLENBQUM7SUFDN0IsSUFBSSxTQUFTLEdBQUcsS0FBSyxDQUFDO0lBRXRCLFNBQVMsS0FBSztRQUNaLFNBQVMsR0FBRyxLQUFLLENBQUM7UUFDbEIsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUM5QixLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3pCLFVBQVUsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUN4RCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxJQUFJLEVBQUUsZUFBZTtRQUNyQixZQUFZLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO1FBQ2hDLFFBQVE7WUFDTixJQUFJLE9BQU8sWUFBWSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUN2QyxNQUFNLElBQUksS0FBSyxDQUNiLHNGQUFzRjtvQkFDcEYsMkZBQTJGO29CQUMzRixnQ0FBZ0MsQ0FDbkMsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO1FBQ0QsUUFBUSxDQUFDLEtBQWdCLEVBQUUsS0FBYyxFQUFFLEtBQWE7WUFDdEQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ25DLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNqQixLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQ3JDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDZixTQUFTLEdBQUcsSUFBSSxDQUFDO2dCQUNqQiw4REFBOEQ7Z0JBQzlELHlEQUF5RDtnQkFDekQsWUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3ZCLENBQUM7WUFDRCxPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUM7QUFFRCxLQUFLLFVBQVUsVUFBVSxDQUFDLElBQWMsRUFBRSxRQUFxQjtJQUM3RCxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2pDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUNwQixJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN0RCxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2IsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEUsQ0FBQztZQUFTLENBQUM7UUFDVCxVQUFVLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3RCLENBQUM7QUFDSCxDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQWlCLHdCQUF3QixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGRldGFjaC9kcml2ZXJzL3NldEltbWVkaWF0ZS50cyDigJQgRGVmZXIgZGV0YWNoZWQgd29yayB0byBhIE5vZGUuanNcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBzZXRJbW1lZGlhdGVgIGJvdW5kYXJ5LlxuICpcbiAqIFBhdHRlcm46ICBTYW1lIHByb2R1Y2VyLWNvbnN1bWVyIGJhdGNoIGZsdXNoIGFzIGBtaWNyb3Rhc2tCYXRjaGAsXG4gKiAgICAgICAgICAgYnV0IHRoZSBkZWZlcnJhbCBpcyBgc2V0SW1tZWRpYXRlYCBpbnN0ZWFkIG9mXG4gKiAgICAgICAgICAgYHF1ZXVlTWljcm90YXNrYC4gWWllbGRzIGNvbnRyb2wgYmFjayB0byB0aGUgZXZlbnQgbG9vcFxuICogICAgICAgICAgIEJFRk9SRSBydW5uaW5nIOKAlCBhbGxvd3MgcGVuZGluZyBJL08gY2FsbGJhY2tzIHRvIGRyYWluXG4gKiAgICAgICAgICAgZmlyc3QsIHdoaWNoIG1pY3JvdGFza3Mgd291bGQgYmxvY2suXG4gKiBSb2xlOiAgICAgTm9kZS1zcGVjaWZpYyBkcml2ZXIgZm9yIFwiZmlyZS1hbmQtZm9yZ2V0IGFmdGVyIHRoZVxuICogICAgICAgICAgIGN1cnJlbnQgSS9PIHRpY2suXCIgVXNlIHdoZW4gdGhlIHBhcmVudCBzdGFnZSBoYW5kbGVzXG4gKiAgICAgICAgICAgbGF0ZW5jeS1zZW5zaXRpdmUgd29yayBhbmQgeW91IGRvbid0IHdhbnQgZGV0YWNoZWQgd29ya1xuICogICAgICAgICAgIHRvIGNvbXBldGUgZm9yIHRoZSBzeW5jaHJvbm91cyBzbGljZS5cbiAqXG4gKiBXaGVuIHRvIHBpY2sgdGhpcyBvdmVyIG1pY3JvdGFza0JhdGNoOlxuICogICAtIFlvdSdyZSBzaGlwcGluZyBsb2dzIC8gbWV0cmljcyBpbiBhIGhvdCBIVFRQIHBhdGggYW5kIGRvbid0XG4gKiAgICAgd2FudCB0aGVtIGJsb2NraW5nIHRoZSByZXNwb25zZSBmcm9tIGJlaW5nIGZsdXNoZWRcbiAqICAgLSBUaGUgZGV0YWNoZWQgd29yayBpdHNlbGYgaXMgQ1BVLWhlYXZ5IGVub3VnaCB0aGF0IHJ1bm5pbmcgaXQgb25cbiAqICAgICB0aGUgc2FtZSBtaWNyb3Rhc2sgY3ljbGUgd291bGQgZGVsYXkgb3RoZXIgbWljcm90YXNrc1xuICogICAtIFlvdSBleHBsaWNpdGx5IHdhbnQgXCJuZXh0IGV2ZW50LWxvb3AgdGlja1wiIHNlbWFudGljcyDigJQgdXNlZnVsXG4gKiAgICAgd2hlbiBpbnRlcmFjdGluZyB3aXRoIHRoaXJkLXBhcnR5IGxpYnJhcmllcyB0aGF0IGV4cGVjdCBhdFxuICogICAgIGxlYXN0IG9uZSBJL08gdGljayBiZXR3ZWVuIHNjaGVkdWxlIGFuZCBleGVjdXRpb25cbiAqXG4gKiBDYXBhYmlsaXR5OlxuICogICAtIGBub2RlU2FmZTogdHJ1ZWAg4oCUIHJlbGllcyBvbiBOb2RlJ3MgYHNldEltbWVkaWF0ZWAsIE5PVFxuICogICAgIGF2YWlsYWJsZSBpbiBicm93c2VycyAvIERlbm8gLyBDbG91ZGZsYXJlIFdvcmtlcnMgKHVzZVxuICogICAgIGBzZXRUaW1lb3V0RHJpdmVyYCBmb3IgY3Jvc3MtcnVudGltZSBhbHRlcm5hdGl2ZSlcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IEZsb3dDaGFydCB9IGZyb20gJy4uLy4uL2J1aWxkZXIvdHlwZXMuanMnO1xuaW1wb3J0IHsgYXNJbXBsLCBjcmVhdGVIYW5kbGUgfSBmcm9tICcuLi9oYW5kbGUuanMnO1xuaW1wb3J0IHsgcmVnaXN0ZXIsIHVucmVnaXN0ZXIgfSBmcm9tICcuLi9yZWdpc3RyeS5qcyc7XG5pbXBvcnQgeyB0eXBlIENoaWxkUnVubmVyLCBkZWZhdWx0UnVuQ2hpbGQgfSBmcm9tICcuLi9ydW5DaGlsZC5qcyc7XG5pbXBvcnQgdHlwZSB7IERldGFjaERyaXZlciwgRGV0YWNoSGFuZGxlIH0gZnJvbSAnLi4vdHlwZXMuanMnO1xuXG4vLyBOb2RlLW9ubHkgZ2xvYmFsLiBXZSBkb24ndCBzaGlwIEB0eXBlcy9ub2RlLCBzbyBkZWNsYXJlIHRoZSBtaW5pbWFsXG4vLyBzaGFwZSBoZXJlLiBgc2V0SW1tZWRpYXRlRHJpdmVyYCBhZHZlcnRpc2VzIGBub2RlU2FmZTogdHJ1ZWAgYW5kXG4vLyBgdmFsaWRhdGUoKWAgdGhyb3dzIGhlbHBmdWxseSBpZiBgc2V0SW1tZWRpYXRlYCBpcyB1bmRlZmluZWQgYXQgdXNlXG4vLyB0aW1lIChlLmcuLCBicm93c2VyIGJ1bmRsZSkuXG5kZWNsYXJlIGNvbnN0IHNldEltbWVkaWF0ZTogKChjYjogKCkgPT4gdm9pZCkgPT4gdW5rbm93bikgfCB1bmRlZmluZWQ7XG5cbmludGVyZmFjZSBXb3JrSXRlbSB7XG4gIHJlYWRvbmx5IGNoaWxkOiBGbG93Q2hhcnQ7XG4gIHJlYWRvbmx5IGlucHV0OiB1bmtub3duO1xuICByZWFkb25seSBoYW5kbGU6IERldGFjaEhhbmRsZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVNldEltbWVkaWF0ZURyaXZlcihydW5DaGlsZDogQ2hpbGRSdW5uZXIgPSBkZWZhdWx0UnVuQ2hpbGQpOiBEZXRhY2hEcml2ZXIge1xuICBjb25zdCBxdWV1ZTogV29ya0l0ZW1bXSA9IFtdO1xuICBsZXQgc2NoZWR1bGVkID0gZmFsc2U7XG5cbiAgZnVuY3Rpb24gZmx1c2goKTogdm9pZCB7XG4gICAgc2NoZWR1bGVkID0gZmFsc2U7XG4gICAgY29uc3QgaXRlbXMgPSBxdWV1ZS5zcGxpY2UoMCk7XG4gICAgZm9yIChjb25zdCBpdGVtIG9mIGl0ZW1zKSB7XG4gICAgICBleGVjdXRlT25lKGl0ZW0sIHJ1bkNoaWxkKS50aGVuKHVuZGVmaW5lZCwgdW5kZWZpbmVkKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG5hbWU6ICdzZXQtaW1tZWRpYXRlJyxcbiAgICBjYXBhYmlsaXRpZXM6IHsgbm9kZVNhZmU6IHRydWUgfSxcbiAgICB2YWxpZGF0ZSgpOiB2b2lkIHtcbiAgICAgIGlmICh0eXBlb2Ygc2V0SW1tZWRpYXRlICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAnW2RldGFjaF0gc2V0SW1tZWRpYXRlRHJpdmVyIHJlcXVpcmVzIE5vZGUuanMg4oCUIGdsb2JhbCBgc2V0SW1tZWRpYXRlYCBpcyBub3QgZGVmaW5lZCAnICtcbiAgICAgICAgICAgICdpbiB0aGlzIHJ1bnRpbWUuIFVzZSBgbWljcm90YXNrQmF0Y2hEcml2ZXJgIGZvciBjcm9zcy1ydW50aW1lIHVzZSwgb3IgYHNldFRpbWVvdXREcml2ZXJgICcgK1xuICAgICAgICAgICAgJ2ZvciBicm93c2VyL2VkZ2UgZW52aXJvbm1lbnRzLicsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSxcbiAgICBzY2hlZHVsZShjaGlsZDogRmxvd0NoYXJ0LCBpbnB1dDogdW5rbm93biwgcmVmSWQ6IHN0cmluZyk6IERldGFjaEhhbmRsZSB7XG4gICAgICBjb25zdCBoYW5kbGUgPSBjcmVhdGVIYW5kbGUocmVmSWQpO1xuICAgICAgcmVnaXN0ZXIoaGFuZGxlKTtcbiAgICAgIHF1ZXVlLnB1c2goeyBjaGlsZCwgaW5wdXQsIGhhbmRsZSB9KTtcbiAgICAgIGlmICghc2NoZWR1bGVkKSB7XG4gICAgICAgIHNjaGVkdWxlZCA9IHRydWU7XG4gICAgICAgIC8vIGBzZXRJbW1lZGlhdGVgIGlzIG5vbi11bmRlZmluZWQgaGVyZSBpbiBOb2RlOyBydW50aW1lIGd1YXJkXG4gICAgICAgIC8vIGlzIGluIGB2YWxpZGF0ZSgpYC4gVGhlIGAhYCBpcyBhIGRlbGliZXJhdGUgYXNzZXJ0aW9uLlxuICAgICAgICBzZXRJbW1lZGlhdGUhKGZsdXNoKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBoYW5kbGU7XG4gICAgfSxcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZXhlY3V0ZU9uZShpdGVtOiBXb3JrSXRlbSwgcnVuQ2hpbGQ6IENoaWxkUnVubmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGltcGwgPSBhc0ltcGwoaXRlbS5oYW5kbGUpO1xuICBpbXBsLl9tYXJrUnVubmluZygpO1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJ1bkNoaWxkKGl0ZW0uY2hpbGQsIGl0ZW0uaW5wdXQpO1xuICAgIGltcGwuX21hcmtEb25lKHJlc3VsdCk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGltcGwuX21hcmtGYWlsZWQoZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIgOiBuZXcgRXJyb3IoU3RyaW5nKGVycikpKTtcbiAgfSBmaW5hbGx5IHtcbiAgICB1bnJlZ2lzdGVyKGltcGwuaWQpO1xuICB9XG59XG5cbmV4cG9ydCBjb25zdCBzZXRJbW1lZGlhdGVEcml2ZXI6IERldGFjaERyaXZlciA9IGNyZWF0ZVNldEltbWVkaWF0ZURyaXZlcigpO1xuIl19
@@ -0,0 +1,69 @@
1
+ /**
2
+ * detach/drivers/setTimeout.ts — Defer detached work via `setTimeout(..., delayMs)`.
3
+ *
4
+ * Pattern: Producer-consumer batch flush; deferral mechanism is
5
+ * `setTimeout` with a configurable delay (default `0`).
6
+ * Role: Cross-runtime "next macrotask" driver. Works in browsers,
7
+ * Node.js, Deno, Cloudflare Workers, Bun, etc.
8
+ *
9
+ * When to pick this:
10
+ * - Consumer wants a SPECIFIC delay (e.g. "ship telemetry in 5
11
+ * seconds, batched") — pass `createSetTimeoutDriver({ delayMs: 5000 })`
12
+ * - Cross-runtime detach where `setImmediate` isn't available
13
+ * - Coalescing high-frequency events into a low-frequency flush
14
+ *
15
+ * Caveats:
16
+ * - Not for low-latency hot paths — minimum delay is ~4ms in
17
+ * browsers per the HTML5 spec, ~1ms in Node. Use
18
+ * `microtaskBatchDriver` for sub-ms scheduling.
19
+ * - Browser tab freezing / throttling can extend the delay
20
+ * significantly. Don't rely on precise timing.
21
+ */
22
+ import { asImpl, createHandle } from '../handle.js';
23
+ import { register, unregister } from '../registry.js';
24
+ import { defaultRunChild } from '../runChild.js';
25
+ export function createSetTimeoutDriver(opts = {}) {
26
+ const delayMs = opts.delayMs ?? 0;
27
+ const runChild = opts.runChild ?? defaultRunChild;
28
+ const queue = [];
29
+ let scheduled = false;
30
+ function flush() {
31
+ scheduled = false;
32
+ const items = queue.splice(0);
33
+ for (const item of items) {
34
+ executeOne(item, runChild).then(undefined, undefined);
35
+ }
36
+ }
37
+ return {
38
+ name: delayMs === 0 ? 'set-timeout' : `set-timeout-${delayMs}ms`,
39
+ capabilities: { browserSafe: true, nodeSafe: true, edgeSafe: true },
40
+ schedule(child, input, refId) {
41
+ const handle = createHandle(refId);
42
+ register(handle);
43
+ queue.push({ child, input, handle });
44
+ if (!scheduled) {
45
+ scheduled = true;
46
+ setTimeout(flush, delayMs);
47
+ }
48
+ return handle;
49
+ },
50
+ };
51
+ }
52
+ async function executeOne(item, runChild) {
53
+ const impl = asImpl(item.handle);
54
+ impl._markRunning();
55
+ try {
56
+ const result = await runChild(item.child, item.input);
57
+ impl._markDone(result);
58
+ }
59
+ catch (err) {
60
+ impl._markFailed(err instanceof Error ? err : new Error(String(err)));
61
+ }
62
+ finally {
63
+ unregister(impl.id);
64
+ }
65
+ }
66
+ /** Default singleton — zero-delay (next macrotask). For configurable
67
+ * delays, use `createSetTimeoutDriver({ delayMs })`. */
68
+ export const setTimeoutDriver = createSetTimeoutDriver();
69
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0VGltZW91dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvZGV0YWNoL2RyaXZlcnMvc2V0VGltZW91dC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFHSCxPQUFPLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNwRCxPQUFPLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3RELE9BQU8sRUFBb0IsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFpQm5FLE1BQU0sVUFBVSxzQkFBc0IsQ0FBQyxPQUFnQyxFQUFFO0lBQ3ZFLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxDQUFDO0lBQ2xDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLElBQUksZUFBZSxDQUFDO0lBQ2xELE1BQU0sS0FBSyxHQUFlLEVBQUUsQ0FBQztJQUM3QixJQUFJLFNBQVMsR0FBRyxLQUFLLENBQUM7SUFFdEIsU0FBUyxLQUFLO1FBQ1osU0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzlCLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7WUFDekIsVUFBVSxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQ3hELENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTztRQUNMLElBQUksRUFBRSxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLGVBQWUsT0FBTyxJQUFJO1FBQ2hFLFlBQVksRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO1FBQ25FLFFBQVEsQ0FBQyxLQUFnQixFQUFFLEtBQWMsRUFBRSxLQUFhO1lBQ3RELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNuQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDakIsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUNyQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ2YsU0FBUyxHQUFHLElBQUksQ0FBQztnQkFDakIsVUFBVSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztZQUM3QixDQUFDO1lBQ0QsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLFVBQVUsQ0FBQyxJQUFjLEVBQUUsUUFBcUI7SUFDN0QsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNqQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDcEIsSUFBSSxDQUFDO1FBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6QixDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7WUFBUyxDQUFDO1FBQ1QsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN0QixDQUFDO0FBQ0gsQ0FBQztBQUVEO3lEQUN5RDtBQUN6RCxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBaUIsc0JBQXNCLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogZGV0YWNoL2RyaXZlcnMvc2V0VGltZW91dC50cyDigJQgRGVmZXIgZGV0YWNoZWQgd29yayB2aWEgYHNldFRpbWVvdXQoLi4uLCBkZWxheU1zKWAuXG4gKlxuICogUGF0dGVybjogIFByb2R1Y2VyLWNvbnN1bWVyIGJhdGNoIGZsdXNoOyBkZWZlcnJhbCBtZWNoYW5pc20gaXNcbiAqICAgICAgICAgICBgc2V0VGltZW91dGAgd2l0aCBhIGNvbmZpZ3VyYWJsZSBkZWxheSAoZGVmYXVsdCBgMGApLlxuICogUm9sZTogICAgIENyb3NzLXJ1bnRpbWUgXCJuZXh0IG1hY3JvdGFza1wiIGRyaXZlci4gV29ya3MgaW4gYnJvd3NlcnMsXG4gKiAgICAgICAgICAgTm9kZS5qcywgRGVubywgQ2xvdWRmbGFyZSBXb3JrZXJzLCBCdW4sIGV0Yy5cbiAqXG4gKiBXaGVuIHRvIHBpY2sgdGhpczpcbiAqICAgLSBDb25zdW1lciB3YW50cyBhIFNQRUNJRklDIGRlbGF5IChlLmcuIFwic2hpcCB0ZWxlbWV0cnkgaW4gNVxuICogICAgIHNlY29uZHMsIGJhdGNoZWRcIikg4oCUIHBhc3MgYGNyZWF0ZVNldFRpbWVvdXREcml2ZXIoeyBkZWxheU1zOiA1MDAwIH0pYFxuICogICAtIENyb3NzLXJ1bnRpbWUgZGV0YWNoIHdoZXJlIGBzZXRJbW1lZGlhdGVgIGlzbid0IGF2YWlsYWJsZVxuICogICAtIENvYWxlc2NpbmcgaGlnaC1mcmVxdWVuY3kgZXZlbnRzIGludG8gYSBsb3ctZnJlcXVlbmN5IGZsdXNoXG4gKlxuICogQ2F2ZWF0czpcbiAqICAgLSBOb3QgZm9yIGxvdy1sYXRlbmN5IGhvdCBwYXRocyDigJQgbWluaW11bSBkZWxheSBpcyB+NG1zIGluXG4gKiAgICAgYnJvd3NlcnMgcGVyIHRoZSBIVE1MNSBzcGVjLCB+MW1zIGluIE5vZGUuIFVzZVxuICogICAgIGBtaWNyb3Rhc2tCYXRjaERyaXZlcmAgZm9yIHN1Yi1tcyBzY2hlZHVsaW5nLlxuICogICAtIEJyb3dzZXIgdGFiIGZyZWV6aW5nIC8gdGhyb3R0bGluZyBjYW4gZXh0ZW5kIHRoZSBkZWxheVxuICogICAgIHNpZ25pZmljYW50bHkuIERvbid0IHJlbHkgb24gcHJlY2lzZSB0aW1pbmcuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBGbG93Q2hhcnQgfSBmcm9tICcuLi8uLi9idWlsZGVyL3R5cGVzLmpzJztcbmltcG9ydCB7IGFzSW1wbCwgY3JlYXRlSGFuZGxlIH0gZnJvbSAnLi4vaGFuZGxlLmpzJztcbmltcG9ydCB7IHJlZ2lzdGVyLCB1bnJlZ2lzdGVyIH0gZnJvbSAnLi4vcmVnaXN0cnkuanMnO1xuaW1wb3J0IHsgdHlwZSBDaGlsZFJ1bm5lciwgZGVmYXVsdFJ1bkNoaWxkIH0gZnJvbSAnLi4vcnVuQ2hpbGQuanMnO1xuaW1wb3J0IHR5cGUgeyBEZXRhY2hEcml2ZXIsIERldGFjaEhhbmRsZSB9IGZyb20gJy4uL3R5cGVzLmpzJztcblxuaW50ZXJmYWNlIFdvcmtJdGVtIHtcbiAgcmVhZG9ubHkgY2hpbGQ6IEZsb3dDaGFydDtcbiAgcmVhZG9ubHkgaW5wdXQ6IHVua25vd247XG4gIHJlYWRvbmx5IGhhbmRsZTogRGV0YWNoSGFuZGxlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNldFRpbWVvdXREcml2ZXJPcHRpb25zIHtcbiAgLyoqIE1pbGxpc2Vjb25kcyB0byB3YWl0IGJlZm9yZSBmbHVzaGluZyB0aGUgYmF0Y2guIERlZmF1bHQgMFxuICAgKiAgKG5leHQgbWFjcm90YXNrKS4gKi9cbiAgcmVhZG9ubHkgZGVsYXlNcz86IG51bWJlcjtcbiAgLyoqIEN1c3RvbSBgcnVuQ2hpbGRgLiBEZWZhdWx0cyB0byBzcGF3bmluZyBhIGBGbG93Q2hhcnRFeGVjdXRvcmAuICovXG4gIHJlYWRvbmx5IHJ1bkNoaWxkPzogQ2hpbGRSdW5uZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTZXRUaW1lb3V0RHJpdmVyKG9wdHM6IFNldFRpbWVvdXREcml2ZXJPcHRpb25zID0ge30pOiBEZXRhY2hEcml2ZXIge1xuICBjb25zdCBkZWxheU1zID0gb3B0cy5kZWxheU1zID8/IDA7XG4gIGNvbnN0IHJ1bkNoaWxkID0gb3B0cy5ydW5DaGlsZCA/PyBkZWZhdWx0UnVuQ2hpbGQ7XG4gIGNvbnN0IHF1ZXVlOiBXb3JrSXRlbVtdID0gW107XG4gIGxldCBzY2hlZHVsZWQgPSBmYWxzZTtcblxuICBmdW5jdGlvbiBmbHVzaCgpOiB2b2lkIHtcbiAgICBzY2hlZHVsZWQgPSBmYWxzZTtcbiAgICBjb25zdCBpdGVtcyA9IHF1ZXVlLnNwbGljZSgwKTtcbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgaXRlbXMpIHtcbiAgICAgIGV4ZWN1dGVPbmUoaXRlbSwgcnVuQ2hpbGQpLnRoZW4odW5kZWZpbmVkLCB1bmRlZmluZWQpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgbmFtZTogZGVsYXlNcyA9PT0gMCA/ICdzZXQtdGltZW91dCcgOiBgc2V0LXRpbWVvdXQtJHtkZWxheU1zfW1zYCxcbiAgICBjYXBhYmlsaXRpZXM6IHsgYnJvd3NlclNhZmU6IHRydWUsIG5vZGVTYWZlOiB0cnVlLCBlZGdlU2FmZTogdHJ1ZSB9LFxuICAgIHNjaGVkdWxlKGNoaWxkOiBGbG93Q2hhcnQsIGlucHV0OiB1bmtub3duLCByZWZJZDogc3RyaW5nKTogRGV0YWNoSGFuZGxlIHtcbiAgICAgIGNvbnN0IGhhbmRsZSA9IGNyZWF0ZUhhbmRsZShyZWZJZCk7XG4gICAgICByZWdpc3RlcihoYW5kbGUpO1xuICAgICAgcXVldWUucHVzaCh7IGNoaWxkLCBpbnB1dCwgaGFuZGxlIH0pO1xuICAgICAgaWYgKCFzY2hlZHVsZWQpIHtcbiAgICAgICAgc2NoZWR1bGVkID0gdHJ1ZTtcbiAgICAgICAgc2V0VGltZW91dChmbHVzaCwgZGVsYXlNcyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gaGFuZGxlO1xuICAgIH0sXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGV4ZWN1dGVPbmUoaXRlbTogV29ya0l0ZW0sIHJ1bkNoaWxkOiBDaGlsZFJ1bm5lcik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBpbXBsID0gYXNJbXBsKGl0ZW0uaGFuZGxlKTtcbiAgaW1wbC5fbWFya1J1bm5pbmcoKTtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBydW5DaGlsZChpdGVtLmNoaWxkLCBpdGVtLmlucHV0KTtcbiAgICBpbXBsLl9tYXJrRG9uZShyZXN1bHQpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBpbXBsLl9tYXJrRmFpbGVkKGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyIDogbmV3IEVycm9yKFN0cmluZyhlcnIpKSk7XG4gIH0gZmluYWxseSB7XG4gICAgdW5yZWdpc3RlcihpbXBsLmlkKTtcbiAgfVxufVxuXG4vKiogRGVmYXVsdCBzaW5nbGV0b24g4oCUIHplcm8tZGVsYXkgKG5leHQgbWFjcm90YXNrKS4gRm9yIGNvbmZpZ3VyYWJsZVxuICogIGRlbGF5cywgdXNlIGBjcmVhdGVTZXRUaW1lb3V0RHJpdmVyKHsgZGVsYXlNcyB9KWAuICovXG5leHBvcnQgY29uc3Qgc2V0VGltZW91dERyaXZlcjogRGV0YWNoRHJpdmVyID0gY3JlYXRlU2V0VGltZW91dERyaXZlcigpO1xuIl19
@@ -0,0 +1,117 @@
1
+ /**
2
+ * detach/drivers/workerThread.ts — Run detached work in a Node.js
3
+ * Worker Thread (or browser Web Worker).
4
+ *
5
+ * Pattern: Adapter — translates the consumer's child flowchart into
6
+ * a worker message + lifecycle handoff. The worker is owned
7
+ * by the driver instance; restarted on crash.
8
+ * Role: CPU-isolation driver — when detached work is genuinely
9
+ * expensive (heavy parsing, hashing, image processing) and
10
+ * you don't want it blocking the main thread's event loop
11
+ * even for a microtask burst.
12
+ *
13
+ * Caveats / IMPORTANT v1 limitations:
14
+ * - The worker entry point is a CONSUMER-PROVIDED file path / URL —
15
+ * this driver does NOT auto-spawn FlowChartExecutor in a worker.
16
+ * Workers can't `import('footprintjs')` portably without setup,
17
+ * and the worker file's lifecycle differs by runtime
18
+ * (Node Worker vs Web Worker vs Bun). Consumer writes the worker
19
+ * code; this driver just hands them a uniform `(input, handle)`
20
+ * API.
21
+ * - The "child flowchart" parameter is IGNORED in v1 (we only ship
22
+ * the input). The chart shape doesn't survive structuredClone +
23
+ * postMessage anyway. v2 may add a serialization protocol.
24
+ *
25
+ * Two ways to consume:
26
+ *
27
+ * 1. Node.js: pass a file path
28
+ * `createWorkerThreadDriver({ workerScript: '/path/to/worker.js' })`
29
+ *
30
+ * 2. Browser: pass a URL or pre-built Worker instance
31
+ * `createWorkerThreadDriver({ worker: new Worker(url) })`
32
+ */
33
+ import { asImpl, createHandle } from '../handle.js';
34
+ import { register, unregister } from '../registry.js';
35
+ let nextMessageId = 0;
36
+ export function createWorkerThreadDriver(opts) {
37
+ let worker;
38
+ const inFlight = new Map();
39
+ // If consumer provided a Worker at construction time, bind its
40
+ // 'message' handler eagerly so replies are routed back to handles.
41
+ // Lazy construction (via `workerScript`) defers binding to first use.
42
+ if (opts.worker) {
43
+ worker = opts.worker;
44
+ bindWorker(worker, inFlight);
45
+ }
46
+ function ensureWorker() {
47
+ if (worker)
48
+ return worker;
49
+ if (!opts.workerScript) {
50
+ throw new Error('[detach] workerThreadDriver: provide either `worker` (a constructed Worker) ' +
51
+ 'or `workerScript` (a path/URL) at driver creation.');
52
+ }
53
+ // Lazy-import Node's worker_threads — keeps browser bundles clean.
54
+ if (typeof require !== 'function') {
55
+ throw new Error('[detach] workerThreadDriver: `workerScript` requires Node.js (CommonJS `require`).');
56
+ }
57
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
58
+ const { Worker } = require('worker_threads');
59
+ worker = new Worker(opts.workerScript);
60
+ bindWorker(worker, inFlight);
61
+ return worker;
62
+ }
63
+ return {
64
+ name: 'worker-thread',
65
+ capabilities: { nodeSafe: true, cpuIsolated: true },
66
+ validate() {
67
+ if (!opts.worker && !opts.workerScript) {
68
+ throw new Error('[detach] workerThreadDriver requires either a pre-built `worker` or a `workerScript` path.');
69
+ }
70
+ },
71
+ schedule(_child, input, refId) {
72
+ const handle = createHandle(refId);
73
+ register(handle);
74
+ const impl = asImpl(handle);
75
+ impl._markRunning();
76
+ const messageId = nextMessageId++;
77
+ inFlight.set(messageId, { handle });
78
+ try {
79
+ const w = ensureWorker();
80
+ w.postMessage({ messageId, refId, input });
81
+ }
82
+ catch (err) {
83
+ impl._markFailed(err instanceof Error ? err : new Error(String(err)));
84
+ unregister(impl.id);
85
+ inFlight.delete(messageId);
86
+ }
87
+ return handle;
88
+ },
89
+ };
90
+ }
91
+ function bindWorker(worker, inFlight) {
92
+ const handler = (msg) => {
93
+ const m = msg;
94
+ if (!m || typeof m.messageId !== 'number')
95
+ return;
96
+ const slot = inFlight.get(m.messageId);
97
+ if (!slot)
98
+ return;
99
+ inFlight.delete(m.messageId);
100
+ const impl = asImpl(slot.handle);
101
+ if (m.ok) {
102
+ impl._markDone(m.result);
103
+ }
104
+ else {
105
+ impl._markFailed(new Error(m.error ?? 'worker reported failure'));
106
+ }
107
+ unregister(impl.id);
108
+ };
109
+ // Node Worker (worker_threads): EventEmitter-shape (`on('message', ...)`).
110
+ if (typeof worker.on === 'function')
111
+ worker.on('message', handler);
112
+ // Browser Worker / Web Worker: EventTarget-shape (`addEventListener`).
113
+ else if (typeof worker.addEventListener === 'function') {
114
+ worker.addEventListener('message', (evt) => handler(evt?.data));
115
+ }
116
+ }
117
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyVGhyZWFkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9kZXRhY2gvZHJpdmVycy93b3JrZXJUaHJlYWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0ErQkc7QUFHSCxPQUFPLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNwRCxPQUFPLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBNkJ0RCxJQUFJLGFBQWEsR0FBRyxDQUFDLENBQUM7QUFFdEIsTUFBTSxVQUFVLHdCQUF3QixDQUFDLElBQStCO0lBQ3RFLElBQUksTUFBOEIsQ0FBQztJQUNuQyxNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBb0IsQ0FBQztJQUU3QywrREFBK0Q7SUFDL0QsbUVBQW1FO0lBQ25FLHNFQUFzRTtJQUN0RSxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNoQixNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUNyQixVQUFVLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRCxTQUFTLFlBQVk7UUFDbkIsSUFBSSxNQUFNO1lBQUUsT0FBTyxNQUFNLENBQUM7UUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN2QixNQUFNLElBQUksS0FBSyxDQUNiLDhFQUE4RTtnQkFDNUUsb0RBQW9ELENBQ3ZELENBQUM7UUFDSixDQUFDO1FBQ0QsbUVBQW1FO1FBQ25FLElBQUksT0FBTyxPQUFPLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDbEMsTUFBTSxJQUFJLEtBQUssQ0FBQyxvRkFBb0YsQ0FBQyxDQUFDO1FBQ3hHLENBQUM7UUFDRCxpRUFBaUU7UUFDakUsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBOEMsQ0FBQztRQUMxRixNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3ZDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDN0IsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELE9BQU87UUFDTCxJQUFJLEVBQUUsZUFBZTtRQUNyQixZQUFZLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUU7UUFDbkQsUUFBUTtZQUNOLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUN2QyxNQUFNLElBQUksS0FBSyxDQUFDLDRGQUE0RixDQUFDLENBQUM7WUFDaEgsQ0FBQztRQUNILENBQUM7UUFDRCxRQUFRLENBQUMsTUFBaUIsRUFBRSxLQUFjLEVBQUUsS0FBYTtZQUN2RCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDbkMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2pCLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUM1QixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFFcEIsTUFBTSxTQUFTLEdBQUcsYUFBYSxFQUFFLENBQUM7WUFDbEMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBRXBDLElBQUksQ0FBQztnQkFDSCxNQUFNLENBQUMsR0FBRyxZQUFZLEVBQUUsQ0FBQztnQkFDekIsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUM3QyxDQUFDO1lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztnQkFDYixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDdEUsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDcEIsUUFBUSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUM3QixDQUFDO1lBRUQsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsTUFBa0IsRUFBRSxRQUErQjtJQUNyRSxNQUFNLE9BQU8sR0FBRyxDQUFDLEdBQVksRUFBUSxFQUFFO1FBQ3JDLE1BQU0sQ0FBQyxHQUFHLEdBQXlGLENBQUM7UUFDcEcsSUFBSSxDQUFDLENBQUMsSUFBSSxPQUFPLENBQUMsQ0FBQyxTQUFTLEtBQUssUUFBUTtZQUFFLE9BQU87UUFDbEQsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLElBQUk7WUFBRSxPQUFPO1FBQ2xCLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRTdCLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDVCxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUMzQixDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBSSx5QkFBeUIsQ0FBQyxDQUFDLENBQUM7UUFDcEUsQ0FBQztRQUNELFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdEIsQ0FBQyxDQUFDO0lBRUYsMkVBQTJFO0lBQzNFLElBQUksT0FBTyxNQUFNLENBQUMsRUFBRSxLQUFLLFVBQVU7UUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNuRSx1RUFBdUU7U0FDbEUsSUFBSSxPQUFPLE1BQU0sQ0FBQyxnQkFBZ0IsS0FBSyxVQUFVLEVBQUUsQ0FBQztRQUN2RCxNQUFNLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLENBQUMsR0FBWSxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUUsR0FBMEIsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ25HLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBkZXRhY2gvZHJpdmVycy93b3JrZXJUaHJlYWQudHMg4oCUIFJ1biBkZXRhY2hlZCB3b3JrIGluIGEgTm9kZS5qc1xuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV29ya2VyIFRocmVhZCAob3IgYnJvd3NlciBXZWIgV29ya2VyKS5cbiAqXG4gKiBQYXR0ZXJuOiAgQWRhcHRlciDigJQgdHJhbnNsYXRlcyB0aGUgY29uc3VtZXIncyBjaGlsZCBmbG93Y2hhcnQgaW50b1xuICogICAgICAgICAgIGEgd29ya2VyIG1lc3NhZ2UgKyBsaWZlY3ljbGUgaGFuZG9mZi4gVGhlIHdvcmtlciBpcyBvd25lZFxuICogICAgICAgICAgIGJ5IHRoZSBkcml2ZXIgaW5zdGFuY2U7IHJlc3RhcnRlZCBvbiBjcmFzaC5cbiAqIFJvbGU6ICAgICBDUFUtaXNvbGF0aW9uIGRyaXZlciDigJQgd2hlbiBkZXRhY2hlZCB3b3JrIGlzIGdlbnVpbmVseVxuICogICAgICAgICAgIGV4cGVuc2l2ZSAoaGVhdnkgcGFyc2luZywgaGFzaGluZywgaW1hZ2UgcHJvY2Vzc2luZykgYW5kXG4gKiAgICAgICAgICAgeW91IGRvbid0IHdhbnQgaXQgYmxvY2tpbmcgdGhlIG1haW4gdGhyZWFkJ3MgZXZlbnQgbG9vcFxuICogICAgICAgICAgIGV2ZW4gZm9yIGEgbWljcm90YXNrIGJ1cnN0LlxuICpcbiAqIENhdmVhdHMgLyBJTVBPUlRBTlQgdjEgbGltaXRhdGlvbnM6XG4gKiAgIC0gVGhlIHdvcmtlciBlbnRyeSBwb2ludCBpcyBhIENPTlNVTUVSLVBST1ZJREVEIGZpbGUgcGF0aCAvIFVSTCDigJRcbiAqICAgICB0aGlzIGRyaXZlciBkb2VzIE5PVCBhdXRvLXNwYXduIEZsb3dDaGFydEV4ZWN1dG9yIGluIGEgd29ya2VyLlxuICogICAgIFdvcmtlcnMgY2FuJ3QgYGltcG9ydCgnZm9vdHByaW50anMnKWAgcG9ydGFibHkgd2l0aG91dCBzZXR1cCxcbiAqICAgICBhbmQgdGhlIHdvcmtlciBmaWxlJ3MgbGlmZWN5Y2xlIGRpZmZlcnMgYnkgcnVudGltZVxuICogICAgIChOb2RlIFdvcmtlciB2cyBXZWIgV29ya2VyIHZzIEJ1bikuIENvbnN1bWVyIHdyaXRlcyB0aGUgd29ya2VyXG4gKiAgICAgY29kZTsgdGhpcyBkcml2ZXIganVzdCBoYW5kcyB0aGVtIGEgdW5pZm9ybSBgKGlucHV0LCBoYW5kbGUpYFxuICogICAgIEFQSS5cbiAqICAgLSBUaGUgXCJjaGlsZCBmbG93Y2hhcnRcIiBwYXJhbWV0ZXIgaXMgSUdOT1JFRCBpbiB2MSAod2Ugb25seSBzaGlwXG4gKiAgICAgdGhlIGlucHV0KS4gVGhlIGNoYXJ0IHNoYXBlIGRvZXNuJ3Qgc3Vydml2ZSBzdHJ1Y3R1cmVkQ2xvbmUgK1xuICogICAgIHBvc3RNZXNzYWdlIGFueXdheS4gdjIgbWF5IGFkZCBhIHNlcmlhbGl6YXRpb24gcHJvdG9jb2wuXG4gKlxuICogVHdvIHdheXMgdG8gY29uc3VtZTpcbiAqXG4gKiAgIDEuIE5vZGUuanM6IHBhc3MgYSBmaWxlIHBhdGhcbiAqICAgICAgYGNyZWF0ZVdvcmtlclRocmVhZERyaXZlcih7IHdvcmtlclNjcmlwdDogJy9wYXRoL3RvL3dvcmtlci5qcycgfSlgXG4gKlxuICogICAyLiBCcm93c2VyOiBwYXNzIGEgVVJMIG9yIHByZS1idWlsdCBXb3JrZXIgaW5zdGFuY2VcbiAqICAgICAgYGNyZWF0ZVdvcmtlclRocmVhZERyaXZlcih7IHdvcmtlcjogbmV3IFdvcmtlcih1cmwpIH0pYFxuICovXG5cbmltcG9ydCB0eXBlIHsgRmxvd0NoYXJ0IH0gZnJvbSAnLi4vLi4vYnVpbGRlci90eXBlcy5qcyc7XG5pbXBvcnQgeyBhc0ltcGwsIGNyZWF0ZUhhbmRsZSB9IGZyb20gJy4uL2hhbmRsZS5qcyc7XG5pbXBvcnQgeyByZWdpc3RlciwgdW5yZWdpc3RlciB9IGZyb20gJy4uL3JlZ2lzdHJ5LmpzJztcbmltcG9ydCB0eXBlIHsgRGV0YWNoRHJpdmVyLCBEZXRhY2hIYW5kbGUgfSBmcm9tICcuLi90eXBlcy5qcyc7XG5cbi8vIE5vZGUtb25seSBDb21tb25KUyBgcmVxdWlyZWAuIFdlIGRvbid0IHNoaXAgQHR5cGVzL25vZGUsIHNvIGRlY2xhcmVcbi8vIHRoZSBtaW5pbWFsIHNoYXBlIGhlcmUuIFVzZWQgb25seSBpbiB0aGUgbGF6eSBgd29ya2VyU2NyaXB0YCBwYXRoO1xuLy8gYnJvd3NlciBjb25zdW1lcnMgcGFzcyBhIHByZS1jb25zdHJ1Y3RlZCBgV29ya2VyYCBhbmQgbmV2ZXIgaGl0IGl0LlxuZGVjbGFyZSBjb25zdCByZXF1aXJlOiAoKG1vZDogc3RyaW5nKSA9PiB1bmtub3duKSB8IHVuZGVmaW5lZDtcblxuaW50ZXJmYWNlIFdvcmtlckxpa2Uge1xuICBwb3N0TWVzc2FnZShtZXNzYWdlOiB1bmtub3duLCB0cmFuc2Zlcj86IFRyYW5zZmVyYWJsZVtdKTogdm9pZDtcbiAgdGVybWluYXRlPygpOiB1bmtub3duO1xuICBvbj8oZXZlbnQ6IHN0cmluZywgbGlzdGVuZXI6IChtc2c6IHVua25vd24pID0+IHZvaWQpOiB2b2lkO1xuICBhZGRFdmVudExpc3RlbmVyPyhldmVudDogc3RyaW5nLCBsaXN0ZW5lcjogKG1zZzogdW5rbm93bikgPT4gdm9pZCk6IHZvaWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV29ya2VyVGhyZWFkRHJpdmVyT3B0aW9ucyB7XG4gIC8qKiBQcmUtY29uc3RydWN0ZWQgV29ya2VyIGluc3RhbmNlLiBQYXNzIGVpdGhlciB0aGlzIE9SXG4gICAqICBgd29ya2VyU2NyaXB0YCDigJQgbm90IGJvdGguICovXG4gIHJlYWRvbmx5IHdvcmtlcj86IFdvcmtlckxpa2U7XG4gIC8qKiBQYXRoIC8gVVJMIHRvIHRoZSB3b3JrZXIgc2NyaXB0LiBVc2VkIG9ubHkgd2hlbiBgd29ya2VyYCBpc1xuICAgKiAgbm90IHByb3ZpZGVkOyB0aGUgZHJpdmVyIGNvbnN0cnVjdHMgYSBXb3JrZXIgZnJvbSB0aGlzIG9uIGRlbWFuZFxuICAgKiAgKE5vZGUgYHdvcmtlcl90aHJlYWRzYCBBUEkpLiAqL1xuICByZWFkb25seSB3b3JrZXJTY3JpcHQ/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBJbkZsaWdodCB7XG4gIHJlYWRvbmx5IGhhbmRsZTogRGV0YWNoSGFuZGxlO1xufVxuXG5sZXQgbmV4dE1lc3NhZ2VJZCA9IDA7XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVXb3JrZXJUaHJlYWREcml2ZXIob3B0czogV29ya2VyVGhyZWFkRHJpdmVyT3B0aW9ucyk6IERldGFjaERyaXZlciB7XG4gIGxldCB3b3JrZXI6IFdvcmtlckxpa2UgfCB1bmRlZmluZWQ7XG4gIGNvbnN0IGluRmxpZ2h0ID0gbmV3IE1hcDxudW1iZXIsIEluRmxpZ2h0PigpO1xuXG4gIC8vIElmIGNvbnN1bWVyIHByb3ZpZGVkIGEgV29ya2VyIGF0IGNvbnN0cnVjdGlvbiB0aW1lLCBiaW5kIGl0c1xuICAvLyAnbWVzc2FnZScgaGFuZGxlciBlYWdlcmx5IHNvIHJlcGxpZXMgYXJlIHJvdXRlZCBiYWNrIHRvIGhhbmRsZXMuXG4gIC8vIExhenkgY29uc3RydWN0aW9uICh2aWEgYHdvcmtlclNjcmlwdGApIGRlZmVycyBiaW5kaW5nIHRvIGZpcnN0IHVzZS5cbiAgaWYgKG9wdHMud29ya2VyKSB7XG4gICAgd29ya2VyID0gb3B0cy53b3JrZXI7XG4gICAgYmluZFdvcmtlcih3b3JrZXIsIGluRmxpZ2h0KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGVuc3VyZVdvcmtlcigpOiBXb3JrZXJMaWtlIHtcbiAgICBpZiAod29ya2VyKSByZXR1cm4gd29ya2VyO1xuICAgIGlmICghb3B0cy53b3JrZXJTY3JpcHQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ1tkZXRhY2hdIHdvcmtlclRocmVhZERyaXZlcjogcHJvdmlkZSBlaXRoZXIgYHdvcmtlcmAgKGEgY29uc3RydWN0ZWQgV29ya2VyKSAnICtcbiAgICAgICAgICAnb3IgYHdvcmtlclNjcmlwdGAgKGEgcGF0aC9VUkwpIGF0IGRyaXZlciBjcmVhdGlvbi4nLFxuICAgICAgKTtcbiAgICB9XG4gICAgLy8gTGF6eS1pbXBvcnQgTm9kZSdzIHdvcmtlcl90aHJlYWRzIOKAlCBrZWVwcyBicm93c2VyIGJ1bmRsZXMgY2xlYW4uXG4gICAgaWYgKHR5cGVvZiByZXF1aXJlICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1tkZXRhY2hdIHdvcmtlclRocmVhZERyaXZlcjogYHdvcmtlclNjcmlwdGAgcmVxdWlyZXMgTm9kZS5qcyAoQ29tbW9uSlMgYHJlcXVpcmVgKS4nKTtcbiAgICB9XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCB7IFdvcmtlciB9ID0gcmVxdWlyZSgnd29ya2VyX3RocmVhZHMnKSBhcyB7IFdvcmtlcjogbmV3IChzOiBzdHJpbmcpID0+IFdvcmtlckxpa2UgfTtcbiAgICB3b3JrZXIgPSBuZXcgV29ya2VyKG9wdHMud29ya2VyU2NyaXB0KTtcbiAgICBiaW5kV29ya2VyKHdvcmtlciwgaW5GbGlnaHQpO1xuICAgIHJldHVybiB3b3JrZXI7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG5hbWU6ICd3b3JrZXItdGhyZWFkJyxcbiAgICBjYXBhYmlsaXRpZXM6IHsgbm9kZVNhZmU6IHRydWUsIGNwdUlzb2xhdGVkOiB0cnVlIH0sXG4gICAgdmFsaWRhdGUoKTogdm9pZCB7XG4gICAgICBpZiAoIW9wdHMud29ya2VyICYmICFvcHRzLndvcmtlclNjcmlwdCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1tkZXRhY2hdIHdvcmtlclRocmVhZERyaXZlciByZXF1aXJlcyBlaXRoZXIgYSBwcmUtYnVpbHQgYHdvcmtlcmAgb3IgYSBgd29ya2VyU2NyaXB0YCBwYXRoLicpO1xuICAgICAgfVxuICAgIH0sXG4gICAgc2NoZWR1bGUoX2NoaWxkOiBGbG93Q2hhcnQsIGlucHV0OiB1bmtub3duLCByZWZJZDogc3RyaW5nKTogRGV0YWNoSGFuZGxlIHtcbiAgICAgIGNvbnN0IGhhbmRsZSA9IGNyZWF0ZUhhbmRsZShyZWZJZCk7XG4gICAgICByZWdpc3RlcihoYW5kbGUpO1xuICAgICAgY29uc3QgaW1wbCA9IGFzSW1wbChoYW5kbGUpO1xuICAgICAgaW1wbC5fbWFya1J1bm5pbmcoKTtcblxuICAgICAgY29uc3QgbWVzc2FnZUlkID0gbmV4dE1lc3NhZ2VJZCsrO1xuICAgICAgaW5GbGlnaHQuc2V0KG1lc3NhZ2VJZCwgeyBoYW5kbGUgfSk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHcgPSBlbnN1cmVXb3JrZXIoKTtcbiAgICAgICAgdy5wb3N0TWVzc2FnZSh7IG1lc3NhZ2VJZCwgcmVmSWQsIGlucHV0IH0pO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGltcGwuX21hcmtGYWlsZWQoZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIgOiBuZXcgRXJyb3IoU3RyaW5nKGVycikpKTtcbiAgICAgICAgdW5yZWdpc3RlcihpbXBsLmlkKTtcbiAgICAgICAgaW5GbGlnaHQuZGVsZXRlKG1lc3NhZ2VJZCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBoYW5kbGU7XG4gICAgfSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gYmluZFdvcmtlcih3b3JrZXI6IFdvcmtlckxpa2UsIGluRmxpZ2h0OiBNYXA8bnVtYmVyLCBJbkZsaWdodD4pOiB2b2lkIHtcbiAgY29uc3QgaGFuZGxlciA9IChtc2c6IHVua25vd24pOiB2b2lkID0+IHtcbiAgICBjb25zdCBtID0gbXNnIGFzIHsgbWVzc2FnZUlkPzogbnVtYmVyOyBvaz86IGJvb2xlYW47IHJlc3VsdD86IHVua25vd247IGVycm9yPzogc3RyaW5nIH0gfCB1bmRlZmluZWQ7XG4gICAgaWYgKCFtIHx8IHR5cGVvZiBtLm1lc3NhZ2VJZCAhPT0gJ251bWJlcicpIHJldHVybjtcbiAgICBjb25zdCBzbG90ID0gaW5GbGlnaHQuZ2V0KG0ubWVzc2FnZUlkKTtcbiAgICBpZiAoIXNsb3QpIHJldHVybjtcbiAgICBpbkZsaWdodC5kZWxldGUobS5tZXNzYWdlSWQpO1xuXG4gICAgY29uc3QgaW1wbCA9IGFzSW1wbChzbG90LmhhbmRsZSk7XG4gICAgaWYgKG0ub2spIHtcbiAgICAgIGltcGwuX21hcmtEb25lKG0ucmVzdWx0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgaW1wbC5fbWFya0ZhaWxlZChuZXcgRXJyb3IobS5lcnJvciA/PyAnd29ya2VyIHJlcG9ydGVkIGZhaWx1cmUnKSk7XG4gICAgfVxuICAgIHVucmVnaXN0ZXIoaW1wbC5pZCk7XG4gIH07XG5cbiAgLy8gTm9kZSBXb3JrZXIgKHdvcmtlcl90aHJlYWRzKTogRXZlbnRFbWl0dGVyLXNoYXBlIChgb24oJ21lc3NhZ2UnLCAuLi4pYCkuXG4gIGlmICh0eXBlb2Ygd29ya2VyLm9uID09PSAnZnVuY3Rpb24nKSB3b3JrZXIub24oJ21lc3NhZ2UnLCBoYW5kbGVyKTtcbiAgLy8gQnJvd3NlciBXb3JrZXIgLyBXZWIgV29ya2VyOiBFdmVudFRhcmdldC1zaGFwZSAoYGFkZEV2ZW50TGlzdGVuZXJgKS5cbiAgZWxzZSBpZiAodHlwZW9mIHdvcmtlci5hZGRFdmVudExpc3RlbmVyID09PSAnZnVuY3Rpb24nKSB7XG4gICAgd29ya2VyLmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCAoZXZ0OiB1bmtub3duKSA9PiBoYW5kbGVyKChldnQgYXMgeyBkYXRhPzogdW5rbm93biB9KT8uZGF0YSkpO1xuICB9XG59XG4iXX0=