@workflow/core 5.0.0-beta.35 → 5.0.0-beta.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities.d.ts +6 -0
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +13 -1
- package/dist/classify-error.d.ts.map +1 -1
- package/dist/classify-error.js +5 -2
- package/dist/create-hook.d.ts +41 -22
- package/dist/create-hook.d.ts.map +1 -1
- package/dist/create-hook.js +1 -1
- package/dist/describe-error.d.ts.map +1 -1
- package/dist/describe-error.js +12 -1
- package/dist/encryption.d.ts +15 -2
- package/dist/encryption.d.ts.map +1 -1
- package/dist/encryption.js +28 -7
- package/dist/flushable-stream.d.ts +55 -0
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +106 -4
- package/dist/global.d.ts +2 -0
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/log-format.js +3 -3
- package/dist/private.d.ts +82 -50
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +149 -22
- package/dist/replay-payload-cache.d.ts +57 -0
- package/dist/replay-payload-cache.d.ts.map +1 -0
- package/dist/replay-payload-cache.js +143 -0
- package/dist/runtime/constants.d.ts +11 -0
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +26 -1
- package/dist/runtime/count-step-started-events.d.ts +52 -0
- package/dist/runtime/count-step-started-events.d.ts.map +1 -0
- package/dist/runtime/count-step-started-events.js +72 -0
- package/dist/runtime/get-port-lazy.js +4 -4
- package/dist/runtime/helpers.d.ts +47 -16
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +97 -28
- package/dist/runtime/resume-hook.d.ts +6 -3
- package/dist/runtime/resume-hook.d.ts.map +1 -1
- package/dist/runtime/resume-hook.js +180 -58
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +3 -3
- package/dist/runtime/runs.d.ts.map +1 -1
- package/dist/runtime/runs.js +5 -3
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +65 -18
- package/dist/runtime/step-executor.d.ts +48 -8
- package/dist/runtime/step-executor.d.ts.map +1 -1
- package/dist/runtime/step-executor.js +90 -20
- package/dist/runtime/suspension-handler.js +3 -3
- package/dist/runtime/world.d.ts +2 -7
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +3 -10
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +398 -184
- package/dist/sealed-box.d.ts +167 -0
- package/dist/sealed-box.d.ts.map +1 -0
- package/dist/sealed-box.js +571 -0
- package/dist/serialization/client.d.ts +3 -3
- package/dist/serialization/client.d.ts.map +1 -1
- package/dist/serialization/client.js +1 -1
- package/dist/serialization/codec.d.ts +6 -4
- package/dist/serialization/codec.d.ts.map +1 -1
- package/dist/serialization/codec.js +1 -1
- package/dist/serialization/encryption.d.ts +118 -17
- package/dist/serialization/encryption.d.ts.map +1 -1
- package/dist/serialization/encryption.js +131 -15
- package/dist/serialization/step.d.ts +4 -4
- package/dist/serialization/step.d.ts.map +1 -1
- package/dist/serialization/step.js +2 -2
- package/dist/serialization/types.d.ts +20 -0
- package/dist/serialization/types.d.ts.map +1 -1
- package/dist/serialization/types.js +11 -1
- package/dist/serialization-format.d.ts +44 -4
- package/dist/serialization-format.d.ts.map +1 -1
- package/dist/serialization-format.js +66 -9
- package/dist/serialization.d.ts +61 -21
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +556 -200
- package/dist/set-attributes.d.ts +2 -7
- package/dist/set-attributes.d.ts.map +1 -1
- package/dist/set-attributes.js +1 -6
- package/dist/step/context-storage.d.ts +2 -2
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +2 -2
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +14 -3
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +87 -22
- package/dist/symbols.d.ts +26 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +27 -1
- package/dist/telemetry/semantic-conventions.d.ts +4 -4
- package/dist/telemetry/semantic-conventions.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/dist/vm/index.d.ts.map +1 -1
- package/dist/vm/index.js +76 -9
- package/dist/workflow/abort-controller.d.ts +1 -1
- package/dist/workflow/abort-controller.d.ts.map +1 -1
- package/dist/workflow/abort-controller.js +38 -3
- package/dist/workflow/hook.d.ts.map +1 -1
- package/dist/workflow/hook.js +85 -30
- package/dist/workflow/index.d.ts +1 -1
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +2 -2
- package/dist/workflow/set-attributes.d.ts +0 -9
- package/dist/workflow/set-attributes.d.ts.map +1 -1
- package/dist/workflow/set-attributes.js +1 -6
- package/dist/workflow/sleep.d.ts.map +1 -1
- package/dist/workflow/sleep.js +21 -9
- package/dist/workflow.d.ts +14 -11
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +37 -92
- package/docs/api-reference/create-hook.mdx +43 -2
- package/docs/api-reference/define-hook.mdx +26 -24
- package/docs/api-reference/fatal-error.mdx +29 -7
- package/docs/api-reference/fetch.mdx +3 -4
- package/docs/api-reference/set-attributes.mdx +0 -4
- package/docs/api-reference/sleep.mdx +1 -1
- package/docs/foundations/hooks.mdx +1 -1
- package/docs/foundations/idempotency.mdx +16 -9
- package/docs/how-it-works/cancellation.mdx +2 -2
- package/docs/how-it-works/code-transform.mdx +19 -15
- package/docs/how-it-works/encryption.mdx +3 -3
- package/docs/how-it-works/event-sourcing.mdx +6 -6
- package/docs/how-it-works/framework-integrations.mdx +96 -342
- package/package.json +6 -6
- package/dist/runtime/step-handler.d.ts +0 -2
- package/dist/runtime/step-handler.d.ts.map +0 -1
- package/dist/runtime/step-handler.js +0 -839
- package/dist/step-hydration-cache.d.ts +0 -148
- package/dist/step-hydration-cache.d.ts.map +0 -1
- package/dist/step-hydration-cache.js +0 -171
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-run memoization cache for hydrated step return values.
|
|
3
|
-
*
|
|
4
|
-
* ## Why
|
|
5
|
-
*
|
|
6
|
-
* The inline replay loop (`runtime.ts`) re-runs the workflow body from the top
|
|
7
|
-
* on every iteration, re-consuming the full event log each time. For every
|
|
8
|
-
* already-completed step, the step consumer (`step.ts`) re-runs
|
|
9
|
-
* `hydrateStepReturnValue` — which AES-GCM-decrypts and devalue-parses the
|
|
10
|
-
* serialized result — even though that exact result was already hydrated on
|
|
11
|
-
* every prior replay. For a sequential workflow of N steps, replay K hydrates
|
|
12
|
-
* K results, so the total work across a single invocation is O(N²)
|
|
13
|
-
* decrypt+parse operations.
|
|
14
|
-
*
|
|
15
|
-
* This cache makes a completed step's hydrated result available in O(1) on
|
|
16
|
-
* subsequent replays within the SAME invocation, turning the aggregate cost
|
|
17
|
-
* into O(N).
|
|
18
|
-
*
|
|
19
|
-
* ## Scope / lifetime
|
|
20
|
-
*
|
|
21
|
-
* The cache is owned by the inline loop in `runtime.ts` (one per workflow run
|
|
22
|
-
* invocation) and passed into `runWorkflow` so it survives across the loop's
|
|
23
|
-
* iterations but never leaks across unrelated runs or process-level
|
|
24
|
-
* invocations. A fresh `runWorkflow` / `WorkflowOrchestratorContext` is created
|
|
25
|
-
* each iteration, so the cache must live OUTSIDE the per-iteration context.
|
|
26
|
-
*
|
|
27
|
-
* ## Keying
|
|
28
|
-
*
|
|
29
|
-
* Entries are keyed by the persisted event's `eventId` — a stable,
|
|
30
|
-
* world-assigned identifier for the `step_completed` event whose serialized
|
|
31
|
-
* `result` is being hydrated. The same event (same `eventId`) carries the same
|
|
32
|
-
* immutable serialized bytes across every replay, so a hit is guaranteed to
|
|
33
|
-
* correspond to the identical input.
|
|
34
|
-
*
|
|
35
|
-
* ## Identity safety (why primitives only)
|
|
36
|
-
*
|
|
37
|
-
* `hydrateStepReturnValue` (devalue.parse) produces a FRESH object graph on
|
|
38
|
-
* every call, and each replay iteration runs in a FRESH workflow VM. The
|
|
39
|
-
* current (uncached) behavior therefore hands the workflow a brand-new value
|
|
40
|
-
* on every replay. If we cached and returned the SAME object reference across
|
|
41
|
-
* replays, workflow code that mutates a step result (`const r = await step();
|
|
42
|
-
* r.count++`) would observe the mutation from a previous replay on the next
|
|
43
|
-
* replay — a non-deterministic divergence. Structured-cloning on each hit is
|
|
44
|
-
* both lossy (revivers reconstruct stream handles, step-function proxies,
|
|
45
|
-
* Request/Response, and AbortController/AbortSignal class instances that don't
|
|
46
|
-
* survive a structured clone) and still O(size).
|
|
47
|
-
*
|
|
48
|
-
* So we only cache values for which returning the same reference on every
|
|
49
|
-
* replay is provably indistinguishable from re-hydrating: JavaScript
|
|
50
|
-
* primitives (string, number, boolean, bigint, symbol, null, undefined).
|
|
51
|
-
* Primitives are immutable and compared by value, so sharing the reference is
|
|
52
|
-
* byte-for-byte equivalent to re-parsing. Any non-primitive result falls
|
|
53
|
-
* through to a full re-hydrate every replay, preserving current behavior
|
|
54
|
-
* exactly. This trades some of the optimization away in the object-returning
|
|
55
|
-
* case in exchange for keeping deterministic replay airtight.
|
|
56
|
-
*
|
|
57
|
-
* ## Memory characteristic
|
|
58
|
-
*
|
|
59
|
-
* Cached entries hold the decrypted/devalue-parsed *plaintext* of a step
|
|
60
|
-
* result, which is retained for the rest of the invocation on top of the
|
|
61
|
-
* serialized bytes already held in `cachedEvents`. So the residual cost is:
|
|
62
|
-
*
|
|
63
|
-
* - **Scoped to one workflow-run invocation.** A fresh `Map` is created per
|
|
64
|
-
* invocation (in `runtime.ts`) and is unreachable / GC'd when the invocation
|
|
65
|
-
* returns. Nothing accumulates across runs or across process-level
|
|
66
|
-
* invocations.
|
|
67
|
-
* - **Bounded by the number of primitive-returning completed steps in that
|
|
68
|
-
* run** — at most one small entry per such step.
|
|
69
|
-
* - **Primitives only, and additionally byte-bounded.** Most primitives
|
|
70
|
-
* (numbers, booleans, null/undefined, symbols, short ids/strings) are tiny
|
|
71
|
-
* and fixed-size. The only primitive that can be large is a string (or a
|
|
72
|
-
* pathologically long bigint), so to keep the doubled-residency worst case
|
|
73
|
-
* bounded we *do not* memoize string/bigint results whose character length
|
|
74
|
-
* exceeds {@link MAX_MEMOIZED_PRIMITIVE_LENGTH}. A large string is cheap to
|
|
75
|
-
* re-hydrate relative to its footprint, so letting it fall through to the
|
|
76
|
-
* existing per-replay re-hydrate path costs little and caps peak retained
|
|
77
|
-
* memory.
|
|
78
|
-
*
|
|
79
|
-
* (This is a much weaker concern than a *process-wide* cache: the dominant
|
|
80
|
-
* residency — the full event log in `cachedEvents` — already exists for the
|
|
81
|
-
* same lifetime, and everything here is freed together with it when the
|
|
82
|
-
* invocation ends.)
|
|
83
|
-
*/
|
|
84
|
-
/**
|
|
85
|
-
* Upper bound, in characters, on a string/bigint primitive that may be
|
|
86
|
-
* memoized. Beyond this, the value falls through to a fresh re-hydrate on every
|
|
87
|
-
* replay so the cache never holds a large plaintext payload for the lifetime of
|
|
88
|
-
* the invocation. 4 KiB comfortably covers ids, counts, flags, and typical
|
|
89
|
-
* short string results while excluding the large-payload case the bound exists
|
|
90
|
-
* to guard. Other primitive types (number, boolean, symbol, null, undefined)
|
|
91
|
-
* are inherently small and are never length-checked.
|
|
92
|
-
*/
|
|
93
|
-
export declare const MAX_MEMOIZED_PRIMITIVE_LENGTH = 4096;
|
|
94
|
-
/**
|
|
95
|
-
* Returns true for values that are safe to memoize and return by reference
|
|
96
|
-
* across replays: JS primitives. Objects and functions are excluded because
|
|
97
|
-
* sharing a mutable reference across replays could change observable behavior.
|
|
98
|
-
*
|
|
99
|
-
* Strings and bigints are additionally bounded by length: a value longer than
|
|
100
|
-
* {@link MAX_MEMOIZED_PRIMITIVE_LENGTH} characters is treated as non-memoizable
|
|
101
|
-
* so the cache never retains a large plaintext payload for the whole invocation
|
|
102
|
-
* (see the module-level "Memory characteristic" docs). It re-hydrates fresh on
|
|
103
|
-
* every replay instead — cheap relative to its footprint.
|
|
104
|
-
*
|
|
105
|
-
* Note: `typeof null === 'object'`, so it is handled explicitly. `undefined`,
|
|
106
|
-
* `string`, `number`, `boolean`, `bigint`, and `symbol` are all primitives.
|
|
107
|
-
*/
|
|
108
|
-
export declare function isMemoizablePrimitive(value: unknown): boolean;
|
|
109
|
-
/**
|
|
110
|
-
* Cache of hydrated step return values for a single workflow run invocation.
|
|
111
|
-
*
|
|
112
|
-
* Keyed by `step_completed` event id; the value is the already-hydrated
|
|
113
|
-
* primitive result. Only successful, primitive hydrations are stored (see
|
|
114
|
-
* {@link getOrHydrateStepReturnValue}), so a non-`undefined` `has(eventId)`
|
|
115
|
-
* always means "this step completed with a memoizable primitive value".
|
|
116
|
-
*/
|
|
117
|
-
export type StepHydrationCache = Map<string, unknown>;
|
|
118
|
-
/**
|
|
119
|
-
* Create an empty per-invocation step hydration cache.
|
|
120
|
-
*/
|
|
121
|
-
export declare function createStepHydrationCache(): StepHydrationCache;
|
|
122
|
-
/**
|
|
123
|
-
* Return the hydrated step result for `eventId`, using `cache` as a per-run
|
|
124
|
-
* memo. On a hit, the cached primitive is returned without re-running the
|
|
125
|
-
* expensive decrypt + devalue-parse. On a miss, `hydrate()` runs and its
|
|
126
|
-
* result is memoized only when it is a small primitive (see the module docs for
|
|
127
|
-
* the identity-safety rationale and the length bound on string/bigint results).
|
|
128
|
-
*
|
|
129
|
-
* This always returns a `Promise` and `await`s `hydrate()` even on the miss
|
|
130
|
-
* path, so the caller's `await` inside its serial `promiseQueue` slot keeps the
|
|
131
|
-
* same scheduling on both hit and miss — a cache hit resolves through the exact
|
|
132
|
-
* same promise-chain position a re-hydrate would have, preserving the
|
|
133
|
-
* deterministic delivery order that `pendingDeliveries`, the delivery barriers,
|
|
134
|
-
* and `Promise.race`/`Promise.all` replay all depend on.
|
|
135
|
-
*
|
|
136
|
-
* `has(eventId)` is used rather than `get(eventId) !== undefined` so that a
|
|
137
|
-
* legitimately memoized `undefined` step result still registers as a hit.
|
|
138
|
-
*
|
|
139
|
-
* When `cache` or `eventId` is absent (lightweight test harnesses, or a context
|
|
140
|
-
* that predates this plumbing), this degrades to calling `hydrate()` directly
|
|
141
|
-
* with no memoization — identical to the previous behavior.
|
|
142
|
-
*
|
|
143
|
-
* Errors are intentionally never cached: a rejected hydrate propagates to the
|
|
144
|
-
* caller (which rejects the step promise) and the next replay re-attempts it,
|
|
145
|
-
* matching the uncached behavior and avoiding a parked rejected promise.
|
|
146
|
-
*/
|
|
147
|
-
export declare function getOrHydrateStepReturnValue(cache: StepHydrationCache | undefined, eventId: string | undefined, hydrate: () => Promise<unknown>): Promise<unknown>;
|
|
148
|
-
//# sourceMappingURL=step-hydration-cache.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"step-hydration-cache.d.ts","sourceRoot":"","sources":["../src/step-hydration-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkFG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAY7D;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,kBAAkB,CAE7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,kBAAkB,GAAG,SAAS,EACrC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAC9B,OAAO,CAAC,OAAO,CAAC,CAkBlB"}
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-run memoization cache for hydrated step return values.
|
|
3
|
-
*
|
|
4
|
-
* ## Why
|
|
5
|
-
*
|
|
6
|
-
* The inline replay loop (`runtime.ts`) re-runs the workflow body from the top
|
|
7
|
-
* on every iteration, re-consuming the full event log each time. For every
|
|
8
|
-
* already-completed step, the step consumer (`step.ts`) re-runs
|
|
9
|
-
* `hydrateStepReturnValue` — which AES-GCM-decrypts and devalue-parses the
|
|
10
|
-
* serialized result — even though that exact result was already hydrated on
|
|
11
|
-
* every prior replay. For a sequential workflow of N steps, replay K hydrates
|
|
12
|
-
* K results, so the total work across a single invocation is O(N²)
|
|
13
|
-
* decrypt+parse operations.
|
|
14
|
-
*
|
|
15
|
-
* This cache makes a completed step's hydrated result available in O(1) on
|
|
16
|
-
* subsequent replays within the SAME invocation, turning the aggregate cost
|
|
17
|
-
* into O(N).
|
|
18
|
-
*
|
|
19
|
-
* ## Scope / lifetime
|
|
20
|
-
*
|
|
21
|
-
* The cache is owned by the inline loop in `runtime.ts` (one per workflow run
|
|
22
|
-
* invocation) and passed into `runWorkflow` so it survives across the loop's
|
|
23
|
-
* iterations but never leaks across unrelated runs or process-level
|
|
24
|
-
* invocations. A fresh `runWorkflow` / `WorkflowOrchestratorContext` is created
|
|
25
|
-
* each iteration, so the cache must live OUTSIDE the per-iteration context.
|
|
26
|
-
*
|
|
27
|
-
* ## Keying
|
|
28
|
-
*
|
|
29
|
-
* Entries are keyed by the persisted event's `eventId` — a stable,
|
|
30
|
-
* world-assigned identifier for the `step_completed` event whose serialized
|
|
31
|
-
* `result` is being hydrated. The same event (same `eventId`) carries the same
|
|
32
|
-
* immutable serialized bytes across every replay, so a hit is guaranteed to
|
|
33
|
-
* correspond to the identical input.
|
|
34
|
-
*
|
|
35
|
-
* ## Identity safety (why primitives only)
|
|
36
|
-
*
|
|
37
|
-
* `hydrateStepReturnValue` (devalue.parse) produces a FRESH object graph on
|
|
38
|
-
* every call, and each replay iteration runs in a FRESH workflow VM. The
|
|
39
|
-
* current (uncached) behavior therefore hands the workflow a brand-new value
|
|
40
|
-
* on every replay. If we cached and returned the SAME object reference across
|
|
41
|
-
* replays, workflow code that mutates a step result (`const r = await step();
|
|
42
|
-
* r.count++`) would observe the mutation from a previous replay on the next
|
|
43
|
-
* replay — a non-deterministic divergence. Structured-cloning on each hit is
|
|
44
|
-
* both lossy (revivers reconstruct stream handles, step-function proxies,
|
|
45
|
-
* Request/Response, and AbortController/AbortSignal class instances that don't
|
|
46
|
-
* survive a structured clone) and still O(size).
|
|
47
|
-
*
|
|
48
|
-
* So we only cache values for which returning the same reference on every
|
|
49
|
-
* replay is provably indistinguishable from re-hydrating: JavaScript
|
|
50
|
-
* primitives (string, number, boolean, bigint, symbol, null, undefined).
|
|
51
|
-
* Primitives are immutable and compared by value, so sharing the reference is
|
|
52
|
-
* byte-for-byte equivalent to re-parsing. Any non-primitive result falls
|
|
53
|
-
* through to a full re-hydrate every replay, preserving current behavior
|
|
54
|
-
* exactly. This trades some of the optimization away in the object-returning
|
|
55
|
-
* case in exchange for keeping deterministic replay airtight.
|
|
56
|
-
*
|
|
57
|
-
* ## Memory characteristic
|
|
58
|
-
*
|
|
59
|
-
* Cached entries hold the decrypted/devalue-parsed *plaintext* of a step
|
|
60
|
-
* result, which is retained for the rest of the invocation on top of the
|
|
61
|
-
* serialized bytes already held in `cachedEvents`. So the residual cost is:
|
|
62
|
-
*
|
|
63
|
-
* - **Scoped to one workflow-run invocation.** A fresh `Map` is created per
|
|
64
|
-
* invocation (in `runtime.ts`) and is unreachable / GC'd when the invocation
|
|
65
|
-
* returns. Nothing accumulates across runs or across process-level
|
|
66
|
-
* invocations.
|
|
67
|
-
* - **Bounded by the number of primitive-returning completed steps in that
|
|
68
|
-
* run** — at most one small entry per such step.
|
|
69
|
-
* - **Primitives only, and additionally byte-bounded.** Most primitives
|
|
70
|
-
* (numbers, booleans, null/undefined, symbols, short ids/strings) are tiny
|
|
71
|
-
* and fixed-size. The only primitive that can be large is a string (or a
|
|
72
|
-
* pathologically long bigint), so to keep the doubled-residency worst case
|
|
73
|
-
* bounded we *do not* memoize string/bigint results whose character length
|
|
74
|
-
* exceeds {@link MAX_MEMOIZED_PRIMITIVE_LENGTH}. A large string is cheap to
|
|
75
|
-
* re-hydrate relative to its footprint, so letting it fall through to the
|
|
76
|
-
* existing per-replay re-hydrate path costs little and caps peak retained
|
|
77
|
-
* memory.
|
|
78
|
-
*
|
|
79
|
-
* (This is a much weaker concern than a *process-wide* cache: the dominant
|
|
80
|
-
* residency — the full event log in `cachedEvents` — already exists for the
|
|
81
|
-
* same lifetime, and everything here is freed together with it when the
|
|
82
|
-
* invocation ends.)
|
|
83
|
-
*/
|
|
84
|
-
/**
|
|
85
|
-
* Upper bound, in characters, on a string/bigint primitive that may be
|
|
86
|
-
* memoized. Beyond this, the value falls through to a fresh re-hydrate on every
|
|
87
|
-
* replay so the cache never holds a large plaintext payload for the lifetime of
|
|
88
|
-
* the invocation. 4 KiB comfortably covers ids, counts, flags, and typical
|
|
89
|
-
* short string results while excluding the large-payload case the bound exists
|
|
90
|
-
* to guard. Other primitive types (number, boolean, symbol, null, undefined)
|
|
91
|
-
* are inherently small and are never length-checked.
|
|
92
|
-
*/
|
|
93
|
-
export const MAX_MEMOIZED_PRIMITIVE_LENGTH = 4096;
|
|
94
|
-
/**
|
|
95
|
-
* Returns true for values that are safe to memoize and return by reference
|
|
96
|
-
* across replays: JS primitives. Objects and functions are excluded because
|
|
97
|
-
* sharing a mutable reference across replays could change observable behavior.
|
|
98
|
-
*
|
|
99
|
-
* Strings and bigints are additionally bounded by length: a value longer than
|
|
100
|
-
* {@link MAX_MEMOIZED_PRIMITIVE_LENGTH} characters is treated as non-memoizable
|
|
101
|
-
* so the cache never retains a large plaintext payload for the whole invocation
|
|
102
|
-
* (see the module-level "Memory characteristic" docs). It re-hydrates fresh on
|
|
103
|
-
* every replay instead — cheap relative to its footprint.
|
|
104
|
-
*
|
|
105
|
-
* Note: `typeof null === 'object'`, so it is handled explicitly. `undefined`,
|
|
106
|
-
* `string`, `number`, `boolean`, `bigint`, and `symbol` are all primitives.
|
|
107
|
-
*/
|
|
108
|
-
export function isMemoizablePrimitive(value) {
|
|
109
|
-
if (value === null)
|
|
110
|
-
return true;
|
|
111
|
-
const t = typeof value;
|
|
112
|
-
if (t === 'object' || t === 'function')
|
|
113
|
-
return false;
|
|
114
|
-
// Bound the only primitive types that can carry a large payload.
|
|
115
|
-
if (t === 'string') {
|
|
116
|
-
return value.length <= MAX_MEMOIZED_PRIMITIVE_LENGTH;
|
|
117
|
-
}
|
|
118
|
-
if (t === 'bigint') {
|
|
119
|
-
return value.toString().length <= MAX_MEMOIZED_PRIMITIVE_LENGTH;
|
|
120
|
-
}
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Create an empty per-invocation step hydration cache.
|
|
125
|
-
*/
|
|
126
|
-
export function createStepHydrationCache() {
|
|
127
|
-
return new Map();
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Return the hydrated step result for `eventId`, using `cache` as a per-run
|
|
131
|
-
* memo. On a hit, the cached primitive is returned without re-running the
|
|
132
|
-
* expensive decrypt + devalue-parse. On a miss, `hydrate()` runs and its
|
|
133
|
-
* result is memoized only when it is a small primitive (see the module docs for
|
|
134
|
-
* the identity-safety rationale and the length bound on string/bigint results).
|
|
135
|
-
*
|
|
136
|
-
* This always returns a `Promise` and `await`s `hydrate()` even on the miss
|
|
137
|
-
* path, so the caller's `await` inside its serial `promiseQueue` slot keeps the
|
|
138
|
-
* same scheduling on both hit and miss — a cache hit resolves through the exact
|
|
139
|
-
* same promise-chain position a re-hydrate would have, preserving the
|
|
140
|
-
* deterministic delivery order that `pendingDeliveries`, the delivery barriers,
|
|
141
|
-
* and `Promise.race`/`Promise.all` replay all depend on.
|
|
142
|
-
*
|
|
143
|
-
* `has(eventId)` is used rather than `get(eventId) !== undefined` so that a
|
|
144
|
-
* legitimately memoized `undefined` step result still registers as a hit.
|
|
145
|
-
*
|
|
146
|
-
* When `cache` or `eventId` is absent (lightweight test harnesses, or a context
|
|
147
|
-
* that predates this plumbing), this degrades to calling `hydrate()` directly
|
|
148
|
-
* with no memoization — identical to the previous behavior.
|
|
149
|
-
*
|
|
150
|
-
* Errors are intentionally never cached: a rejected hydrate propagates to the
|
|
151
|
-
* caller (which rejects the step promise) and the next replay re-attempts it,
|
|
152
|
-
* matching the uncached behavior and avoiding a parked rejected promise.
|
|
153
|
-
*/
|
|
154
|
-
export async function getOrHydrateStepReturnValue(cache, eventId, hydrate) {
|
|
155
|
-
if (!cache || eventId === undefined) {
|
|
156
|
-
return hydrate();
|
|
157
|
-
}
|
|
158
|
-
if (cache.has(eventId)) {
|
|
159
|
-
return cache.get(eventId);
|
|
160
|
-
}
|
|
161
|
-
const value = await hydrate();
|
|
162
|
-
// Only memoize values that are safe to return by reference across replays
|
|
163
|
-
// AND small enough to retain for the invocation. Non-primitives and
|
|
164
|
-
// oversized string/bigint values fall through and are re-hydrated fresh on
|
|
165
|
-
// every replay (see isMemoizablePrimitive / MAX_MEMOIZED_PRIMITIVE_LENGTH).
|
|
166
|
-
if (isMemoizablePrimitive(value)) {
|
|
167
|
-
cache.set(eventId, value);
|
|
168
|
-
}
|
|
169
|
-
return value;
|
|
170
|
-
}
|
|
171
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1oeWRyYXRpb24tY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc3RlcC1oeWRyYXRpb24tY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrRkc7QUFFSDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxNQUFNLDZCQUE2QixHQUFHLElBQUksQ0FBQztBQUVsRDs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsTUFBTSxVQUFVLHFCQUFxQixDQUFDLEtBQWM7SUFDbEQsSUFBSSxLQUFLLEtBQUssSUFBSTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ2hDLE1BQU0sQ0FBQyxHQUFHLE9BQU8sS0FBSyxDQUFDO0lBQ3ZCLElBQUksQ0FBQyxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssVUFBVTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ3JELGlFQUFpRTtJQUNqRSxJQUFJLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUNuQixPQUFRLEtBQWdCLENBQUMsTUFBTSxJQUFJLDZCQUE2QixDQUFDO0lBQ25FLENBQUM7SUFDRCxJQUFJLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUNuQixPQUFRLEtBQWdCLENBQUMsUUFBUSxFQUFFLENBQUMsTUFBTSxJQUFJLDZCQUE2QixDQUFDO0lBQzlFLENBQUM7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFZRDs7R0FFRztBQUNILE1BQU0sVUFBVSx3QkFBd0I7SUFDdEMsT0FBTyxJQUFJLEdBQUcsRUFBRSxDQUFDO0FBQ25CLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSwyQkFBMkIsQ0FDL0MsS0FBcUMsRUFDckMsT0FBMkIsRUFDM0IsT0FBK0I7SUFFL0IsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDcEMsT0FBTyxPQUFPLEVBQUUsQ0FBQztJQUNuQixDQUFDO0lBRUQsSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDdkIsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzVCLENBQUM7SUFFRCxNQUFNLEtBQUssR0FBRyxNQUFNLE9BQU8sRUFBRSxDQUFDO0lBQzlCLDBFQUEwRTtJQUMxRSxvRUFBb0U7SUFDcEUsMkVBQTJFO0lBQzNFLDRFQUE0RTtJQUM1RSxJQUFJLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDakMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUGVyLXJ1biBtZW1vaXphdGlvbiBjYWNoZSBmb3IgaHlkcmF0ZWQgc3RlcCByZXR1cm4gdmFsdWVzLlxuICpcbiAqICMjIFdoeVxuICpcbiAqIFRoZSBpbmxpbmUgcmVwbGF5IGxvb3AgKGBydW50aW1lLnRzYCkgcmUtcnVucyB0aGUgd29ya2Zsb3cgYm9keSBmcm9tIHRoZSB0b3BcbiAqIG9uIGV2ZXJ5IGl0ZXJhdGlvbiwgcmUtY29uc3VtaW5nIHRoZSBmdWxsIGV2ZW50IGxvZyBlYWNoIHRpbWUuIEZvciBldmVyeVxuICogYWxyZWFkeS1jb21wbGV0ZWQgc3RlcCwgdGhlIHN0ZXAgY29uc3VtZXIgKGBzdGVwLnRzYCkgcmUtcnVuc1xuICogYGh5ZHJhdGVTdGVwUmV0dXJuVmFsdWVgIOKAlCB3aGljaCBBRVMtR0NNLWRlY3J5cHRzIGFuZCBkZXZhbHVlLXBhcnNlcyB0aGVcbiAqIHNlcmlhbGl6ZWQgcmVzdWx0IOKAlCBldmVuIHRob3VnaCB0aGF0IGV4YWN0IHJlc3VsdCB3YXMgYWxyZWFkeSBoeWRyYXRlZCBvblxuICogZXZlcnkgcHJpb3IgcmVwbGF5LiBGb3IgYSBzZXF1ZW50aWFsIHdvcmtmbG93IG9mIE4gc3RlcHMsIHJlcGxheSBLIGh5ZHJhdGVzXG4gKiBLIHJlc3VsdHMsIHNvIHRoZSB0b3RhbCB3b3JrIGFjcm9zcyBhIHNpbmdsZSBpbnZvY2F0aW9uIGlzIE8oTsKyKVxuICogZGVjcnlwdCtwYXJzZSBvcGVyYXRpb25zLlxuICpcbiAqIFRoaXMgY2FjaGUgbWFrZXMgYSBjb21wbGV0ZWQgc3RlcCdzIGh5ZHJhdGVkIHJlc3VsdCBhdmFpbGFibGUgaW4gTygxKSBvblxuICogc3Vic2VxdWVudCByZXBsYXlzIHdpdGhpbiB0aGUgU0FNRSBpbnZvY2F0aW9uLCB0dXJuaW5nIHRoZSBhZ2dyZWdhdGUgY29zdFxuICogaW50byBPKE4pLlxuICpcbiAqICMjIFNjb3BlIC8gbGlmZXRpbWVcbiAqXG4gKiBUaGUgY2FjaGUgaXMgb3duZWQgYnkgdGhlIGlubGluZSBsb29wIGluIGBydW50aW1lLnRzYCAob25lIHBlciB3b3JrZmxvdyBydW5cbiAqIGludm9jYXRpb24pIGFuZCBwYXNzZWQgaW50byBgcnVuV29ya2Zsb3dgIHNvIGl0IHN1cnZpdmVzIGFjcm9zcyB0aGUgbG9vcCdzXG4gKiBpdGVyYXRpb25zIGJ1dCBuZXZlciBsZWFrcyBhY3Jvc3MgdW5yZWxhdGVkIHJ1bnMgb3IgcHJvY2Vzcy1sZXZlbFxuICogaW52b2NhdGlvbnMuIEEgZnJlc2ggYHJ1bldvcmtmbG93YCAvIGBXb3JrZmxvd09yY2hlc3RyYXRvckNvbnRleHRgIGlzIGNyZWF0ZWRcbiAqIGVhY2ggaXRlcmF0aW9uLCBzbyB0aGUgY2FjaGUgbXVzdCBsaXZlIE9VVFNJREUgdGhlIHBlci1pdGVyYXRpb24gY29udGV4dC5cbiAqXG4gKiAjIyBLZXlpbmdcbiAqXG4gKiBFbnRyaWVzIGFyZSBrZXllZCBieSB0aGUgcGVyc2lzdGVkIGV2ZW50J3MgYGV2ZW50SWRgIOKAlCBhIHN0YWJsZSxcbiAqIHdvcmxkLWFzc2lnbmVkIGlkZW50aWZpZXIgZm9yIHRoZSBgc3RlcF9jb21wbGV0ZWRgIGV2ZW50IHdob3NlIHNlcmlhbGl6ZWRcbiAqIGByZXN1bHRgIGlzIGJlaW5nIGh5ZHJhdGVkLiBUaGUgc2FtZSBldmVudCAoc2FtZSBgZXZlbnRJZGApIGNhcnJpZXMgdGhlIHNhbWVcbiAqIGltbXV0YWJsZSBzZXJpYWxpemVkIGJ5dGVzIGFjcm9zcyBldmVyeSByZXBsYXksIHNvIGEgaGl0IGlzIGd1YXJhbnRlZWQgdG9cbiAqIGNvcnJlc3BvbmQgdG8gdGhlIGlkZW50aWNhbCBpbnB1dC5cbiAqXG4gKiAjIyBJZGVudGl0eSBzYWZldHkgKHdoeSBwcmltaXRpdmVzIG9ubHkpXG4gKlxuICogYGh5ZHJhdGVTdGVwUmV0dXJuVmFsdWVgIChkZXZhbHVlLnBhcnNlKSBwcm9kdWNlcyBhIEZSRVNIIG9iamVjdCBncmFwaCBvblxuICogZXZlcnkgY2FsbCwgYW5kIGVhY2ggcmVwbGF5IGl0ZXJhdGlvbiBydW5zIGluIGEgRlJFU0ggd29ya2Zsb3cgVk0uIFRoZVxuICogY3VycmVudCAodW5jYWNoZWQpIGJlaGF2aW9yIHRoZXJlZm9yZSBoYW5kcyB0aGUgd29ya2Zsb3cgYSBicmFuZC1uZXcgdmFsdWVcbiAqIG9uIGV2ZXJ5IHJlcGxheS4gSWYgd2UgY2FjaGVkIGFuZCByZXR1cm5lZCB0aGUgU0FNRSBvYmplY3QgcmVmZXJlbmNlIGFjcm9zc1xuICogcmVwbGF5cywgd29ya2Zsb3cgY29kZSB0aGF0IG11dGF0ZXMgYSBzdGVwIHJlc3VsdCAoYGNvbnN0IHIgPSBhd2FpdCBzdGVwKCk7XG4gKiByLmNvdW50KytgKSB3b3VsZCBvYnNlcnZlIHRoZSBtdXRhdGlvbiBmcm9tIGEgcHJldmlvdXMgcmVwbGF5IG9uIHRoZSBuZXh0XG4gKiByZXBsYXkg4oCUIGEgbm9uLWRldGVybWluaXN0aWMgZGl2ZXJnZW5jZS4gU3RydWN0dXJlZC1jbG9uaW5nIG9uIGVhY2ggaGl0IGlzXG4gKiBib3RoIGxvc3N5IChyZXZpdmVycyByZWNvbnN0cnVjdCBzdHJlYW0gaGFuZGxlcywgc3RlcC1mdW5jdGlvbiBwcm94aWVzLFxuICogUmVxdWVzdC9SZXNwb25zZSwgYW5kIEFib3J0Q29udHJvbGxlci9BYm9ydFNpZ25hbCBjbGFzcyBpbnN0YW5jZXMgdGhhdCBkb24ndFxuICogc3Vydml2ZSBhIHN0cnVjdHVyZWQgY2xvbmUpIGFuZCBzdGlsbCBPKHNpemUpLlxuICpcbiAqIFNvIHdlIG9ubHkgY2FjaGUgdmFsdWVzIGZvciB3aGljaCByZXR1cm5pbmcgdGhlIHNhbWUgcmVmZXJlbmNlIG9uIGV2ZXJ5XG4gKiByZXBsYXkgaXMgcHJvdmFibHkgaW5kaXN0aW5ndWlzaGFibGUgZnJvbSByZS1oeWRyYXRpbmc6IEphdmFTY3JpcHRcbiAqIHByaW1pdGl2ZXMgKHN0cmluZywgbnVtYmVyLCBib29sZWFuLCBiaWdpbnQsIHN5bWJvbCwgbnVsbCwgdW5kZWZpbmVkKS5cbiAqIFByaW1pdGl2ZXMgYXJlIGltbXV0YWJsZSBhbmQgY29tcGFyZWQgYnkgdmFsdWUsIHNvIHNoYXJpbmcgdGhlIHJlZmVyZW5jZSBpc1xuICogYnl0ZS1mb3ItYnl0ZSBlcXVpdmFsZW50IHRvIHJlLXBhcnNpbmcuIEFueSBub24tcHJpbWl0aXZlIHJlc3VsdCBmYWxsc1xuICogdGhyb3VnaCB0byBhIGZ1bGwgcmUtaHlkcmF0ZSBldmVyeSByZXBsYXksIHByZXNlcnZpbmcgY3VycmVudCBiZWhhdmlvclxuICogZXhhY3RseS4gVGhpcyB0cmFkZXMgc29tZSBvZiB0aGUgb3B0aW1pemF0aW9uIGF3YXkgaW4gdGhlIG9iamVjdC1yZXR1cm5pbmdcbiAqIGNhc2UgaW4gZXhjaGFuZ2UgZm9yIGtlZXBpbmcgZGV0ZXJtaW5pc3RpYyByZXBsYXkgYWlydGlnaHQuXG4gKlxuICogIyMgTWVtb3J5IGNoYXJhY3RlcmlzdGljXG4gKlxuICogQ2FjaGVkIGVudHJpZXMgaG9sZCB0aGUgZGVjcnlwdGVkL2RldmFsdWUtcGFyc2VkICpwbGFpbnRleHQqIG9mIGEgc3RlcFxuICogcmVzdWx0LCB3aGljaCBpcyByZXRhaW5lZCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGludm9jYXRpb24gb24gdG9wIG9mIHRoZVxuICogc2VyaWFsaXplZCBieXRlcyBhbHJlYWR5IGhlbGQgaW4gYGNhY2hlZEV2ZW50c2AuIFNvIHRoZSByZXNpZHVhbCBjb3N0IGlzOlxuICpcbiAqIC0gKipTY29wZWQgdG8gb25lIHdvcmtmbG93LXJ1biBpbnZvY2F0aW9uLioqIEEgZnJlc2ggYE1hcGAgaXMgY3JlYXRlZCBwZXJcbiAqICAgaW52b2NhdGlvbiAoaW4gYHJ1bnRpbWUudHNgKSBhbmQgaXMgdW5yZWFjaGFibGUgLyBHQydkIHdoZW4gdGhlIGludm9jYXRpb25cbiAqICAgcmV0dXJucy4gTm90aGluZyBhY2N1bXVsYXRlcyBhY3Jvc3MgcnVucyBvciBhY3Jvc3MgcHJvY2Vzcy1sZXZlbFxuICogICBpbnZvY2F0aW9ucy5cbiAqIC0gKipCb3VuZGVkIGJ5IHRoZSBudW1iZXIgb2YgcHJpbWl0aXZlLXJldHVybmluZyBjb21wbGV0ZWQgc3RlcHMgaW4gdGhhdFxuICogICBydW4qKiDigJQgYXQgbW9zdCBvbmUgc21hbGwgZW50cnkgcGVyIHN1Y2ggc3RlcC5cbiAqIC0gKipQcmltaXRpdmVzIG9ubHksIGFuZCBhZGRpdGlvbmFsbHkgYnl0ZS1ib3VuZGVkLioqIE1vc3QgcHJpbWl0aXZlc1xuICogICAobnVtYmVycywgYm9vbGVhbnMsIG51bGwvdW5kZWZpbmVkLCBzeW1ib2xzLCBzaG9ydCBpZHMvc3RyaW5ncykgYXJlIHRpbnlcbiAqICAgYW5kIGZpeGVkLXNpemUuIFRoZSBvbmx5IHByaW1pdGl2ZSB0aGF0IGNhbiBiZSBsYXJnZSBpcyBhIHN0cmluZyAob3IgYVxuICogICBwYXRob2xvZ2ljYWxseSBsb25nIGJpZ2ludCksIHNvIHRvIGtlZXAgdGhlIGRvdWJsZWQtcmVzaWRlbmN5IHdvcnN0IGNhc2VcbiAqICAgYm91bmRlZCB3ZSAqZG8gbm90KiBtZW1vaXplIHN0cmluZy9iaWdpbnQgcmVzdWx0cyB3aG9zZSBjaGFyYWN0ZXIgbGVuZ3RoXG4gKiAgIGV4Y2VlZHMge0BsaW5rIE1BWF9NRU1PSVpFRF9QUklNSVRJVkVfTEVOR1RIfS4gQSBsYXJnZSBzdHJpbmcgaXMgY2hlYXAgdG9cbiAqICAgcmUtaHlkcmF0ZSByZWxhdGl2ZSB0byBpdHMgZm9vdHByaW50LCBzbyBsZXR0aW5nIGl0IGZhbGwgdGhyb3VnaCB0byB0aGVcbiAqICAgZXhpc3RpbmcgcGVyLXJlcGxheSByZS1oeWRyYXRlIHBhdGggY29zdHMgbGl0dGxlIGFuZCBjYXBzIHBlYWsgcmV0YWluZWRcbiAqICAgbWVtb3J5LlxuICpcbiAqIChUaGlzIGlzIGEgbXVjaCB3ZWFrZXIgY29uY2VybiB0aGFuIGEgKnByb2Nlc3Mtd2lkZSogY2FjaGU6IHRoZSBkb21pbmFudFxuICogcmVzaWRlbmN5IOKAlCB0aGUgZnVsbCBldmVudCBsb2cgaW4gYGNhY2hlZEV2ZW50c2Ag4oCUIGFscmVhZHkgZXhpc3RzIGZvciB0aGVcbiAqIHNhbWUgbGlmZXRpbWUsIGFuZCBldmVyeXRoaW5nIGhlcmUgaXMgZnJlZWQgdG9nZXRoZXIgd2l0aCBpdCB3aGVuIHRoZVxuICogaW52b2NhdGlvbiBlbmRzLilcbiAqL1xuXG4vKipcbiAqIFVwcGVyIGJvdW5kLCBpbiBjaGFyYWN0ZXJzLCBvbiBhIHN0cmluZy9iaWdpbnQgcHJpbWl0aXZlIHRoYXQgbWF5IGJlXG4gKiBtZW1vaXplZC4gQmV5b25kIHRoaXMsIHRoZSB2YWx1ZSBmYWxscyB0aHJvdWdoIHRvIGEgZnJlc2ggcmUtaHlkcmF0ZSBvbiBldmVyeVxuICogcmVwbGF5IHNvIHRoZSBjYWNoZSBuZXZlciBob2xkcyBhIGxhcmdlIHBsYWludGV4dCBwYXlsb2FkIGZvciB0aGUgbGlmZXRpbWUgb2ZcbiAqIHRoZSBpbnZvY2F0aW9uLiA0IEtpQiBjb21mb3J0YWJseSBjb3ZlcnMgaWRzLCBjb3VudHMsIGZsYWdzLCBhbmQgdHlwaWNhbFxuICogc2hvcnQgc3RyaW5nIHJlc3VsdHMgd2hpbGUgZXhjbHVkaW5nIHRoZSBsYXJnZS1wYXlsb2FkIGNhc2UgdGhlIGJvdW5kIGV4aXN0c1xuICogdG8gZ3VhcmQuIE90aGVyIHByaW1pdGl2ZSB0eXBlcyAobnVtYmVyLCBib29sZWFuLCBzeW1ib2wsIG51bGwsIHVuZGVmaW5lZClcbiAqIGFyZSBpbmhlcmVudGx5IHNtYWxsIGFuZCBhcmUgbmV2ZXIgbGVuZ3RoLWNoZWNrZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBNQVhfTUVNT0laRURfUFJJTUlUSVZFX0xFTkdUSCA9IDQwOTY7XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGZvciB2YWx1ZXMgdGhhdCBhcmUgc2FmZSB0byBtZW1vaXplIGFuZCByZXR1cm4gYnkgcmVmZXJlbmNlXG4gKiBhY3Jvc3MgcmVwbGF5czogSlMgcHJpbWl0aXZlcy4gT2JqZWN0cyBhbmQgZnVuY3Rpb25zIGFyZSBleGNsdWRlZCBiZWNhdXNlXG4gKiBzaGFyaW5nIGEgbXV0YWJsZSByZWZlcmVuY2UgYWNyb3NzIHJlcGxheXMgY291bGQgY2hhbmdlIG9ic2VydmFibGUgYmVoYXZpb3IuXG4gKlxuICogU3RyaW5ncyBhbmQgYmlnaW50cyBhcmUgYWRkaXRpb25hbGx5IGJvdW5kZWQgYnkgbGVuZ3RoOiBhIHZhbHVlIGxvbmdlciB0aGFuXG4gKiB7QGxpbmsgTUFYX01FTU9JWkVEX1BSSU1JVElWRV9MRU5HVEh9IGNoYXJhY3RlcnMgaXMgdHJlYXRlZCBhcyBub24tbWVtb2l6YWJsZVxuICogc28gdGhlIGNhY2hlIG5ldmVyIHJldGFpbnMgYSBsYXJnZSBwbGFpbnRleHQgcGF5bG9hZCBmb3IgdGhlIHdob2xlIGludm9jYXRpb25cbiAqIChzZWUgdGhlIG1vZHVsZS1sZXZlbCBcIk1lbW9yeSBjaGFyYWN0ZXJpc3RpY1wiIGRvY3MpLiBJdCByZS1oeWRyYXRlcyBmcmVzaCBvblxuICogZXZlcnkgcmVwbGF5IGluc3RlYWQg4oCUIGNoZWFwIHJlbGF0aXZlIHRvIGl0cyBmb290cHJpbnQuXG4gKlxuICogTm90ZTogYHR5cGVvZiBudWxsID09PSAnb2JqZWN0J2AsIHNvIGl0IGlzIGhhbmRsZWQgZXhwbGljaXRseS4gYHVuZGVmaW5lZGAsXG4gKiBgc3RyaW5nYCwgYG51bWJlcmAsIGBib29sZWFuYCwgYGJpZ2ludGAsIGFuZCBgc3ltYm9sYCBhcmUgYWxsIHByaW1pdGl2ZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc01lbW9pemFibGVQcmltaXRpdmUodmFsdWU6IHVua25vd24pOiBib29sZWFuIHtcbiAgaWYgKHZhbHVlID09PSBudWxsKSByZXR1cm4gdHJ1ZTtcbiAgY29uc3QgdCA9IHR5cGVvZiB2YWx1ZTtcbiAgaWYgKHQgPT09ICdvYmplY3QnIHx8IHQgPT09ICdmdW5jdGlvbicpIHJldHVybiBmYWxzZTtcbiAgLy8gQm91bmQgdGhlIG9ubHkgcHJpbWl0aXZlIHR5cGVzIHRoYXQgY2FuIGNhcnJ5IGEgbGFyZ2UgcGF5bG9hZC5cbiAgaWYgKHQgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuICh2YWx1ZSBhcyBzdHJpbmcpLmxlbmd0aCA8PSBNQVhfTUVNT0laRURfUFJJTUlUSVZFX0xFTkdUSDtcbiAgfVxuICBpZiAodCA9PT0gJ2JpZ2ludCcpIHtcbiAgICByZXR1cm4gKHZhbHVlIGFzIGJpZ2ludCkudG9TdHJpbmcoKS5sZW5ndGggPD0gTUFYX01FTU9JWkVEX1BSSU1JVElWRV9MRU5HVEg7XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKlxuICogQ2FjaGUgb2YgaHlkcmF0ZWQgc3RlcCByZXR1cm4gdmFsdWVzIGZvciBhIHNpbmdsZSB3b3JrZmxvdyBydW4gaW52b2NhdGlvbi5cbiAqXG4gKiBLZXllZCBieSBgc3RlcF9jb21wbGV0ZWRgIGV2ZW50IGlkOyB0aGUgdmFsdWUgaXMgdGhlIGFscmVhZHktaHlkcmF0ZWRcbiAqIHByaW1pdGl2ZSByZXN1bHQuIE9ubHkgc3VjY2Vzc2Z1bCwgcHJpbWl0aXZlIGh5ZHJhdGlvbnMgYXJlIHN0b3JlZCAoc2VlXG4gKiB7QGxpbmsgZ2V0T3JIeWRyYXRlU3RlcFJldHVyblZhbHVlfSksIHNvIGEgbm9uLWB1bmRlZmluZWRgIGBoYXMoZXZlbnRJZClgXG4gKiBhbHdheXMgbWVhbnMgXCJ0aGlzIHN0ZXAgY29tcGxldGVkIHdpdGggYSBtZW1vaXphYmxlIHByaW1pdGl2ZSB2YWx1ZVwiLlxuICovXG5leHBvcnQgdHlwZSBTdGVwSHlkcmF0aW9uQ2FjaGUgPSBNYXA8c3RyaW5nLCB1bmtub3duPjtcblxuLyoqXG4gKiBDcmVhdGUgYW4gZW1wdHkgcGVyLWludm9jYXRpb24gc3RlcCBoeWRyYXRpb24gY2FjaGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTdGVwSHlkcmF0aW9uQ2FjaGUoKTogU3RlcEh5ZHJhdGlvbkNhY2hlIHtcbiAgcmV0dXJuIG5ldyBNYXAoKTtcbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIGh5ZHJhdGVkIHN0ZXAgcmVzdWx0IGZvciBgZXZlbnRJZGAsIHVzaW5nIGBjYWNoZWAgYXMgYSBwZXItcnVuXG4gKiBtZW1vLiBPbiBhIGhpdCwgdGhlIGNhY2hlZCBwcmltaXRpdmUgaXMgcmV0dXJuZWQgd2l0aG91dCByZS1ydW5uaW5nIHRoZVxuICogZXhwZW5zaXZlIGRlY3J5cHQgKyBkZXZhbHVlLXBhcnNlLiBPbiBhIG1pc3MsIGBoeWRyYXRlKClgIHJ1bnMgYW5kIGl0c1xuICogcmVzdWx0IGlzIG1lbW9pemVkIG9ubHkgd2hlbiBpdCBpcyBhIHNtYWxsIHByaW1pdGl2ZSAoc2VlIHRoZSBtb2R1bGUgZG9jcyBmb3JcbiAqIHRoZSBpZGVudGl0eS1zYWZldHkgcmF0aW9uYWxlIGFuZCB0aGUgbGVuZ3RoIGJvdW5kIG9uIHN0cmluZy9iaWdpbnQgcmVzdWx0cykuXG4gKlxuICogVGhpcyBhbHdheXMgcmV0dXJucyBhIGBQcm9taXNlYCBhbmQgYGF3YWl0YHMgYGh5ZHJhdGUoKWAgZXZlbiBvbiB0aGUgbWlzc1xuICogcGF0aCwgc28gdGhlIGNhbGxlcidzIGBhd2FpdGAgaW5zaWRlIGl0cyBzZXJpYWwgYHByb21pc2VRdWV1ZWAgc2xvdCBrZWVwcyB0aGVcbiAqIHNhbWUgc2NoZWR1bGluZyBvbiBib3RoIGhpdCBhbmQgbWlzcyDigJQgYSBjYWNoZSBoaXQgcmVzb2x2ZXMgdGhyb3VnaCB0aGUgZXhhY3RcbiAqIHNhbWUgcHJvbWlzZS1jaGFpbiBwb3NpdGlvbiBhIHJlLWh5ZHJhdGUgd291bGQgaGF2ZSwgcHJlc2VydmluZyB0aGVcbiAqIGRldGVybWluaXN0aWMgZGVsaXZlcnkgb3JkZXIgdGhhdCBgcGVuZGluZ0RlbGl2ZXJpZXNgLCB0aGUgZGVsaXZlcnkgYmFycmllcnMsXG4gKiBhbmQgYFByb21pc2UucmFjZWAvYFByb21pc2UuYWxsYCByZXBsYXkgYWxsIGRlcGVuZCBvbi5cbiAqXG4gKiBgaGFzKGV2ZW50SWQpYCBpcyB1c2VkIHJhdGhlciB0aGFuIGBnZXQoZXZlbnRJZCkgIT09IHVuZGVmaW5lZGAgc28gdGhhdCBhXG4gKiBsZWdpdGltYXRlbHkgbWVtb2l6ZWQgYHVuZGVmaW5lZGAgc3RlcCByZXN1bHQgc3RpbGwgcmVnaXN0ZXJzIGFzIGEgaGl0LlxuICpcbiAqIFdoZW4gYGNhY2hlYCBvciBgZXZlbnRJZGAgaXMgYWJzZW50IChsaWdodHdlaWdodCB0ZXN0IGhhcm5lc3Nlcywgb3IgYSBjb250ZXh0XG4gKiB0aGF0IHByZWRhdGVzIHRoaXMgcGx1bWJpbmcpLCB0aGlzIGRlZ3JhZGVzIHRvIGNhbGxpbmcgYGh5ZHJhdGUoKWAgZGlyZWN0bHlcbiAqIHdpdGggbm8gbWVtb2l6YXRpb24g4oCUIGlkZW50aWNhbCB0byB0aGUgcHJldmlvdXMgYmVoYXZpb3IuXG4gKlxuICogRXJyb3JzIGFyZSBpbnRlbnRpb25hbGx5IG5ldmVyIGNhY2hlZDogYSByZWplY3RlZCBoeWRyYXRlIHByb3BhZ2F0ZXMgdG8gdGhlXG4gKiBjYWxsZXIgKHdoaWNoIHJlamVjdHMgdGhlIHN0ZXAgcHJvbWlzZSkgYW5kIHRoZSBuZXh0IHJlcGxheSByZS1hdHRlbXB0cyBpdCxcbiAqIG1hdGNoaW5nIHRoZSB1bmNhY2hlZCBiZWhhdmlvciBhbmQgYXZvaWRpbmcgYSBwYXJrZWQgcmVqZWN0ZWQgcHJvbWlzZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldE9ySHlkcmF0ZVN0ZXBSZXR1cm5WYWx1ZShcbiAgY2FjaGU6IFN0ZXBIeWRyYXRpb25DYWNoZSB8IHVuZGVmaW5lZCxcbiAgZXZlbnRJZDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBoeWRyYXRlOiAoKSA9PiBQcm9taXNlPHVua25vd24+XG4pOiBQcm9taXNlPHVua25vd24+IHtcbiAgaWYgKCFjYWNoZSB8fCBldmVudElkID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gaHlkcmF0ZSgpO1xuICB9XG5cbiAgaWYgKGNhY2hlLmhhcyhldmVudElkKSkge1xuICAgIHJldHVybiBjYWNoZS5nZXQoZXZlbnRJZCk7XG4gIH1cblxuICBjb25zdCB2YWx1ZSA9IGF3YWl0IGh5ZHJhdGUoKTtcbiAgLy8gT25seSBtZW1vaXplIHZhbHVlcyB0aGF0IGFyZSBzYWZlIHRvIHJldHVybiBieSByZWZlcmVuY2UgYWNyb3NzIHJlcGxheXNcbiAgLy8gQU5EIHNtYWxsIGVub3VnaCB0byByZXRhaW4gZm9yIHRoZSBpbnZvY2F0aW9uLiBOb24tcHJpbWl0aXZlcyBhbmRcbiAgLy8gb3ZlcnNpemVkIHN0cmluZy9iaWdpbnQgdmFsdWVzIGZhbGwgdGhyb3VnaCBhbmQgYXJlIHJlLWh5ZHJhdGVkIGZyZXNoIG9uXG4gIC8vIGV2ZXJ5IHJlcGxheSAoc2VlIGlzTWVtb2l6YWJsZVByaW1pdGl2ZSAvIE1BWF9NRU1PSVpFRF9QUklNSVRJVkVfTEVOR1RIKS5cbiAgaWYgKGlzTWVtb2l6YWJsZVByaW1pdGl2ZSh2YWx1ZSkpIHtcbiAgICBjYWNoZS5zZXQoZXZlbnRJZCwgdmFsdWUpO1xuICB9XG4gIHJldHVybiB2YWx1ZTtcbn1cbiJdfQ==
|