@workflow/core 5.0.0-beta.2 → 5.0.0-beta.21
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/attribute-changes.d.ts +7 -0
- package/dist/attribute-changes.d.ts.map +1 -0
- package/dist/attribute-changes.js +25 -0
- package/dist/capabilities.d.ts +22 -1
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +41 -4
- package/dist/capture-stack.d.ts +16 -0
- package/dist/capture-stack.d.ts.map +1 -0
- package/dist/capture-stack.js +21 -0
- package/dist/class-serialization.d.ts +32 -0
- package/dist/class-serialization.d.ts.map +1 -1
- package/dist/class-serialization.js +37 -1
- package/dist/classify-error.d.ts +11 -3
- package/dist/classify-error.d.ts.map +1 -1
- package/dist/classify-error.js +59 -6
- package/dist/context-errors.d.ts +27 -0
- package/dist/context-errors.d.ts.map +1 -0
- package/dist/context-errors.js +101 -0
- package/dist/context-violation-error.d.ts +97 -0
- package/dist/context-violation-error.d.ts.map +1 -0
- package/dist/context-violation-error.js +147 -0
- package/dist/create-hook.d.ts +40 -1
- package/dist/create-hook.d.ts.map +1 -1
- package/dist/create-hook.js +4 -3
- package/dist/define-hook.d.ts.map +1 -1
- package/dist/define-hook.js +20 -5
- package/dist/describe-error.d.ts +70 -0
- package/dist/describe-error.d.ts.map +1 -0
- package/dist/describe-error.js +165 -0
- package/dist/encryption.d.ts +22 -1
- package/dist/encryption.d.ts.map +1 -1
- package/dist/encryption.js +72 -27
- package/dist/events-consumer.d.ts +24 -0
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +79 -16
- package/dist/flushable-stream.d.ts +10 -10
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +18 -13
- package/dist/global.d.ts +15 -1
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +21 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/log-format.d.ts +25 -0
- package/dist/log-format.d.ts.map +1 -0
- package/dist/log-format.js +250 -0
- package/dist/logger.d.ts +28 -30
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +77 -31
- package/dist/private.d.ts +107 -2
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +80 -3
- package/dist/runtime/constants.d.ts +121 -0
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +206 -8
- package/dist/runtime/get-port-lazy.d.ts +25 -0
- package/dist/runtime/get-port-lazy.d.ts.map +1 -0
- package/dist/runtime/get-port-lazy.js +92 -0
- package/dist/runtime/get-world-lazy.d.ts +32 -0
- package/dist/runtime/get-world-lazy.d.ts.map +1 -0
- package/dist/runtime/get-world-lazy.js +56 -0
- package/dist/runtime/helpers.d.ts +50 -7
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +149 -31
- package/dist/runtime/replay-budget.d.ts +98 -0
- package/dist/runtime/replay-budget.d.ts.map +1 -0
- package/dist/runtime/replay-budget.js +191 -0
- package/dist/runtime/resume-hook.d.ts.map +1 -1
- package/dist/runtime/resume-hook.js +39 -23
- package/dist/runtime/run-id-time.d.ts +10 -0
- package/dist/runtime/run-id-time.d.ts.map +1 -0
- package/dist/runtime/run-id-time.js +31 -0
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +44 -9
- package/dist/runtime/runs.d.ts.map +1 -1
- package/dist/runtime/runs.js +4 -1
- package/dist/runtime/start.d.ts +30 -1
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +138 -20
- package/dist/runtime/step-executor.d.ts +108 -0
- package/dist/runtime/step-executor.d.ts.map +1 -0
- package/dist/runtime/step-executor.js +715 -0
- package/dist/runtime/step-handler.d.ts.map +1 -1
- package/dist/runtime/step-handler.js +715 -556
- package/dist/runtime/suspension-handler.d.ts +74 -7
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +308 -116
- package/dist/runtime/wait-continuation.d.ts +84 -0
- package/dist/runtime/wait-continuation.d.ts.map +1 -0
- package/dist/runtime/wait-continuation.js +92 -0
- package/dist/runtime/wait-until.d.ts +18 -0
- package/dist/runtime/wait-until.d.ts.map +1 -0
- package/dist/runtime/wait-until.js +42 -0
- package/dist/runtime/world-init.d.ts +75 -0
- package/dist/runtime/world-init.d.ts.map +1 -0
- package/dist/runtime/world-init.js +75 -0
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +47 -18
- package/dist/runtime.d.ts +11 -8
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +1395 -319
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +1 -1
- package/dist/serialization/client.d.ts +17 -0
- package/dist/serialization/client.d.ts.map +1 -0
- package/dist/serialization/client.js +48 -0
- package/dist/serialization/codec-devalue.d.ts +14 -0
- package/dist/serialization/codec-devalue.d.ts.map +1 -0
- package/dist/serialization/codec-devalue.js +98 -0
- package/dist/serialization/codec.d.ts +106 -0
- package/dist/serialization/codec.d.ts.map +1 -0
- package/dist/serialization/codec.js +17 -0
- package/dist/serialization/compression.d.ts +104 -0
- package/dist/serialization/compression.d.ts.map +1 -0
- package/dist/serialization/compression.js +260 -0
- package/dist/serialization/encryption.d.ts +33 -0
- package/dist/serialization/encryption.d.ts.map +1 -0
- package/dist/serialization/encryption.js +70 -0
- package/dist/serialization/errors.d.ts +34 -0
- package/dist/serialization/errors.d.ts.map +1 -0
- package/dist/serialization/errors.js +59 -0
- package/dist/serialization/format.d.ts +60 -0
- package/dist/serialization/format.d.ts.map +1 -0
- package/dist/serialization/format.js +97 -0
- package/dist/serialization/index.d.ts +19 -0
- package/dist/serialization/index.d.ts.map +1 -0
- package/dist/serialization/index.js +22 -0
- package/dist/serialization/reducers/class.d.ts +11 -0
- package/dist/serialization/reducers/class.d.ts.map +1 -0
- package/dist/serialization/reducers/class.js +68 -0
- package/dist/serialization/reducers/common.d.ts +16 -0
- package/dist/serialization/reducers/common.d.ts.map +1 -0
- package/dist/serialization/reducers/common.js +417 -0
- package/dist/serialization/reducers/step-function.d.ts +35 -0
- package/dist/serialization/reducers/step-function.d.ts.map +1 -0
- package/dist/serialization/reducers/step-function.js +88 -0
- package/dist/serialization/step.d.ts +17 -0
- package/dist/serialization/step.d.ts.map +1 -0
- package/dist/serialization/step.js +48 -0
- package/dist/serialization/types.d.ts +253 -0
- package/dist/serialization/types.d.ts.map +1 -0
- package/dist/serialization/types.js +25 -0
- package/dist/serialization/workflow.d.ts +29 -0
- package/dist/serialization/workflow.d.ts.map +1 -0
- package/dist/serialization/workflow.js +54 -0
- package/dist/serialization-format.d.ts +15 -0
- package/dist/serialization-format.d.ts.map +1 -1
- package/dist/serialization-format.js +209 -11
- package/dist/serialization.d.ts +313 -214
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +1430 -658
- package/dist/set-attributes.d.ts +13 -0
- package/dist/set-attributes.d.ts.map +1 -0
- package/dist/set-attributes.js +42 -0
- package/dist/sleep.d.ts.map +1 -1
- package/dist/sleep.js +3 -2
- package/dist/source-map.d.ts +5 -0
- package/dist/source-map.d.ts.map +1 -1
- package/dist/source-map.js +102 -10
- package/dist/step/context-storage.d.ts +43 -0
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +1 -1
- package/dist/step/get-closure-vars.d.ts.map +1 -1
- package/dist/step/get-closure-vars.js +3 -2
- package/dist/step/get-step-metadata.d.ts.map +1 -1
- package/dist/step/get-step-metadata.js +3 -2
- package/dist/step/get-workflow-metadata.d.ts.map +1 -1
- package/dist/step/get-workflow-metadata.js +3 -2
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +49 -5
- package/dist/step-hydration-cache.d.ts +148 -0
- package/dist/step-hydration-cache.d.ts.map +1 -0
- package/dist/step-hydration-cache.js +171 -0
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +115 -21
- package/dist/symbols.d.ts +28 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +29 -1
- package/dist/telemetry/semantic-conventions.d.ts +30 -2
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +21 -1
- package/dist/telemetry.d.ts +60 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +82 -4
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +23 -1
- package/dist/util.d.ts +16 -6
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +25 -16
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +2 -2
- package/dist/vm/index.d.ts.map +1 -1
- package/dist/vm/index.js +3 -2
- package/dist/vm/script-cache.d.ts +28 -0
- package/dist/vm/script-cache.d.ts.map +1 -0
- package/dist/vm/script-cache.js +140 -0
- package/dist/workflow/abort-controller.d.ts +65 -0
- package/dist/workflow/abort-controller.d.ts.map +1 -0
- package/dist/workflow/abort-controller.js +277 -0
- package/dist/workflow/attribute-dispatcher.d.ts +6 -0
- package/dist/workflow/attribute-dispatcher.d.ts.map +1 -0
- package/dist/workflow/attribute-dispatcher.js +48 -0
- package/dist/workflow/create-hook.d.ts.map +1 -1
- package/dist/workflow/create-hook.js +23 -2
- package/dist/workflow/define-hook.d.ts +1 -1
- package/dist/workflow/define-hook.d.ts.map +1 -1
- package/dist/workflow/define-hook.js +8 -4
- package/dist/workflow/get-workflow-metadata.d.ts.map +1 -1
- package/dist/workflow/get-workflow-metadata.js +14 -3
- package/dist/workflow/hook.d.ts.map +1 -1
- package/dist/workflow/hook.js +207 -33
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +5 -3
- package/dist/workflow/set-attributes.d.ts +73 -0
- package/dist/workflow/set-attributes.d.ts.map +1 -0
- package/dist/workflow/set-attributes.js +65 -0
- package/dist/workflow/sleep.d.ts.map +1 -1
- package/dist/workflow/sleep.js +45 -8
- package/dist/workflow/world-init-stub.d.ts +15 -0
- package/dist/workflow/world-init-stub.d.ts.map +1 -0
- package/dist/workflow/world-init-stub.js +15 -0
- package/dist/workflow.d.ts +10 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +168 -49
- package/docs/api-reference/create-hook.mdx +38 -0
- package/docs/api-reference/create-webhook.mdx +1 -0
- package/docs/api-reference/experimental-set-attributes.mdx +65 -0
- package/docs/api-reference/fetch.mdx +5 -0
- package/docs/api-reference/index.mdx +3 -0
- package/docs/foundations/cancellation.mdx +459 -0
- package/docs/foundations/errors-and-retries.mdx +7 -3
- package/docs/foundations/hooks.mdx +29 -0
- package/docs/foundations/idempotency.mdx +236 -11
- package/docs/foundations/index.mdx +3 -3
- package/docs/foundations/meta.json +3 -2
- package/docs/foundations/serialization.mdx +78 -42
- package/docs/foundations/starting-workflows.mdx +6 -2
- package/docs/foundations/streaming.mdx +14 -23
- package/docs/foundations/versioning.mdx +263 -0
- package/docs/how-it-works/cancellation.mdx +287 -0
- package/docs/how-it-works/code-transform.mdx +2 -2
- package/docs/how-it-works/encryption.mdx +2 -2
- package/docs/how-it-works/event-sourcing.mdx +2 -2
- package/docs/how-it-works/meta.json +2 -1
- package/package.json +22 -10
- package/docs/foundations/common-patterns.mdx +0 -265
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable compression layer for serialized data.
|
|
3
|
+
*
|
|
4
|
+
* Wraps/unwraps serialized payloads with a compression codec, using the
|
|
5
|
+
* format prefix system to mark compressed data (e.g. 'zstd' or 'gzip'
|
|
6
|
+
* wrapping the inner format: 'zstd' + zstd('devl' + payload)).
|
|
7
|
+
*
|
|
8
|
+
* Codec selection (write side): zstd is preferred — it is markedly faster
|
|
9
|
+
* than gzip at a comparable-or-better ratio (see scripts/README.md), and
|
|
10
|
+
* compression runs at every step boundary so the write CPU is a per-step
|
|
11
|
+
* tax. zstd requires `node:zlib` >= 22.15 (Web `CompressionStream` has no
|
|
12
|
+
* zstd), so on a runtime without it we fall back to gzip via the portable
|
|
13
|
+
* `CompressionStream`. `WORKFLOW_COMPRESSION_CODEC=gzip` forces the
|
|
14
|
+
* portable codec.
|
|
15
|
+
*
|
|
16
|
+
* Read side: dispatch on the format prefix, so both 'zstd' and 'gzip'
|
|
17
|
+
* payloads are always decodable regardless of which codec wrote them.
|
|
18
|
+
* (The browser o11y read path decodes zstd via a registered WASM decoder —
|
|
19
|
+
* see `serialization-format.ts`; this module's `decompress` is the Node
|
|
20
|
+
* runtime/replay path and uses `node:zlib`.)
|
|
21
|
+
*
|
|
22
|
+
* Layering order with encryption: compression is applied BEFORE
|
|
23
|
+
* encryption (encr(zstd(devl))) — encrypted bytes are high-entropy and
|
|
24
|
+
* do not compress, so the reverse order would be a no-op.
|
|
25
|
+
*
|
|
26
|
+
* Compression is conditional:
|
|
27
|
+
* - Payloads smaller than {@link COMPRESSION_MIN_BYTES} are passed
|
|
28
|
+
* through unchanged (codec overhead isn't worth it).
|
|
29
|
+
* - If the compressed result isn't meaningfully smaller than the
|
|
30
|
+
* original (see {@link COMPRESSION_MIN_SAVINGS_RATIO}), the original
|
|
31
|
+
* is kept. This protects already-compressed binary payloads (images,
|
|
32
|
+
* archives, etc.) from wasted CPU and size inflation.
|
|
33
|
+
*/
|
|
34
|
+
import { decodeFormatPrefix, encodeWithFormatPrefix, peekFormatPrefix, } from './format.js';
|
|
35
|
+
import { SerializationFormat } from './types.js';
|
|
36
|
+
/**
|
|
37
|
+
* Payloads below this size are never compressed. The 4-byte format
|
|
38
|
+
* prefix + codec header/trailer overhead means small payloads gain
|
|
39
|
+
* nothing, and tiny ones would grow.
|
|
40
|
+
*/
|
|
41
|
+
export const COMPRESSION_MIN_BYTES = 1024;
|
|
42
|
+
/**
|
|
43
|
+
* Compression must shave off at least this fraction of the payload
|
|
44
|
+
* size to be kept; otherwise the uncompressed original is stored.
|
|
45
|
+
* Guards against incompressible (already-compressed / high-entropy)
|
|
46
|
+
* data paying a permanent decompression tax for a negligible win.
|
|
47
|
+
*/
|
|
48
|
+
export const COMPRESSION_MIN_SAVINGS_RATIO = 0.05;
|
|
49
|
+
/** Default zstd compression level — the sweet spot of speed vs ratio. */
|
|
50
|
+
const ZSTD_LEVEL = 3;
|
|
51
|
+
/**
|
|
52
|
+
* Escape hatch: set WORKFLOW_DISABLE_COMPRESSION=1 to disable
|
|
53
|
+
* write-side compression entirely. Reads are unaffected — payloads
|
|
54
|
+
* that were already written compressed remain readable.
|
|
55
|
+
*/
|
|
56
|
+
function isCompressionDisabledByEnv() {
|
|
57
|
+
try {
|
|
58
|
+
return (typeof process !== 'undefined' &&
|
|
59
|
+
process.env?.WORKFLOW_DISABLE_COMPRESSION === '1');
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Optional codec override (`WORKFLOW_COMPRESSION_CODEC=gzip|zstd`). Lets an
|
|
67
|
+
* operator pin the portable codec (gzip) — useful for A/B comparisons or
|
|
68
|
+
* runtimes where zstd read support isn't yet everywhere.
|
|
69
|
+
*/
|
|
70
|
+
function codecOverrideFromEnv() {
|
|
71
|
+
try {
|
|
72
|
+
const v = process.env?.WORKFLOW_COMPRESSION_CODEC;
|
|
73
|
+
return v === 'gzip' || v === 'zstd' ? v : undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Resolve `node:zlib` via `process.getBuiltinModule` — no static import, so
|
|
81
|
+
* this module stays bundler-safe for browser/edge targets (where it returns
|
|
82
|
+
* undefined and we fall back to gzip).
|
|
83
|
+
*/
|
|
84
|
+
function getNodeZlib() {
|
|
85
|
+
try {
|
|
86
|
+
return globalThis.process?.getBuiltinModule?.('node:zlib');
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function isZstdAvailable() {
|
|
93
|
+
const z = getNodeZlib();
|
|
94
|
+
return (typeof z?.zstdCompressSync === 'function' &&
|
|
95
|
+
typeof z?.zstdDecompressSync === 'function');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* gzip via the web-standard `CompressionStream` (Node 18+, browsers, edge).
|
|
99
|
+
*/
|
|
100
|
+
function isGzipAvailable() {
|
|
101
|
+
return (typeof CompressionStream === 'function' &&
|
|
102
|
+
typeof DecompressionStream === 'function');
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Pipe bytes through a (De)CompressionStream and collect the output.
|
|
106
|
+
*/
|
|
107
|
+
async function pipeThroughTransform(data, transform) {
|
|
108
|
+
const writer = transform.writable.getWriter();
|
|
109
|
+
// Don't await the write before reading — the transform's internal
|
|
110
|
+
// queue can fill up on large payloads, deadlocking writer vs reader.
|
|
111
|
+
const writePromise = writer.write(data).then(() => writer.close());
|
|
112
|
+
// If the transform errors, the reader.read() below rejects first and
|
|
113
|
+
// propagates; mark the write side as handled so the mirrored rejection
|
|
114
|
+
// doesn't surface as an unhandled rejection.
|
|
115
|
+
writePromise.catch(() => { });
|
|
116
|
+
const chunks = [];
|
|
117
|
+
let total = 0;
|
|
118
|
+
const reader = transform.readable.getReader();
|
|
119
|
+
for (;;) {
|
|
120
|
+
const { done, value } = await reader.read();
|
|
121
|
+
if (done)
|
|
122
|
+
break;
|
|
123
|
+
chunks.push(value);
|
|
124
|
+
total += value.length;
|
|
125
|
+
}
|
|
126
|
+
await writePromise;
|
|
127
|
+
const out = new Uint8Array(total);
|
|
128
|
+
let offset = 0;
|
|
129
|
+
for (const chunk of chunks) {
|
|
130
|
+
out.set(chunk, offset);
|
|
131
|
+
offset += chunk.length;
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
async function gzipBytes(data) {
|
|
136
|
+
return pipeThroughTransform(data, new CompressionStream('gzip'));
|
|
137
|
+
}
|
|
138
|
+
async function gunzipBytes(data) {
|
|
139
|
+
return pipeThroughTransform(data, new DecompressionStream('gzip'));
|
|
140
|
+
}
|
|
141
|
+
function zstdBytes(data) {
|
|
142
|
+
const z = getNodeZlib();
|
|
143
|
+
const level = z?.constants?.ZSTD_c_compressionLevel;
|
|
144
|
+
const opts = level !== undefined ? { params: { [level]: ZSTD_LEVEL } } : undefined;
|
|
145
|
+
// biome-ignore lint/style/noNonNullAssertion: guarded by isZstdAvailable()
|
|
146
|
+
return new Uint8Array(z.zstdCompressSync(data, opts));
|
|
147
|
+
}
|
|
148
|
+
function unzstdBytes(data) {
|
|
149
|
+
const z = getNodeZlib();
|
|
150
|
+
if (!z?.zstdDecompressSync) {
|
|
151
|
+
throw new Error('Compressed (zstd) workflow data encountered but node:zlib zstd ' +
|
|
152
|
+
'support is not available in this runtime (requires Node.js 22.15+). ' +
|
|
153
|
+
'In the browser, register a zstd decoder via registerZstdDecoder ' +
|
|
154
|
+
'(serialization-format.ts).');
|
|
155
|
+
}
|
|
156
|
+
return new Uint8Array(z.zstdDecompressSync(data));
|
|
157
|
+
}
|
|
158
|
+
function recordStats(stats, codec, uncompressedBytes, storedBytes) {
|
|
159
|
+
if (!stats)
|
|
160
|
+
return;
|
|
161
|
+
stats.recorded = true;
|
|
162
|
+
stats.compressed = codec !== 'none';
|
|
163
|
+
stats.codec = codec;
|
|
164
|
+
stats.uncompressedBytes = uncompressedBytes;
|
|
165
|
+
stats.storedBytes = storedBytes;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Choose the write-side codec given runtime availability and the optional
|
|
169
|
+
* env override. zstd is preferred; gzip is the portable fallback.
|
|
170
|
+
*/
|
|
171
|
+
function selectWriteCodec() {
|
|
172
|
+
const override = codecOverrideFromEnv();
|
|
173
|
+
if (override === 'gzip')
|
|
174
|
+
return isGzipAvailable() ? 'gzip' : 'none';
|
|
175
|
+
// Default and explicit 'zstd' both prefer zstd, then fall back to gzip.
|
|
176
|
+
if (isZstdAvailable())
|
|
177
|
+
return 'zstd';
|
|
178
|
+
if (isGzipAvailable())
|
|
179
|
+
return 'gzip';
|
|
180
|
+
return 'none';
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Compress a format-prefixed payload if compression is enabled for the
|
|
184
|
+
* target run and the payload is worth compressing.
|
|
185
|
+
*
|
|
186
|
+
* @param data - The format-prefixed serialized data (e.g. 'devl' + bytes)
|
|
187
|
+
* @param enabled - Whether the target run supports compressed payloads
|
|
188
|
+
* (run specVersion >= SPEC_VERSION_SUPPORTS_COMPRESSION, and for
|
|
189
|
+
* cross-deployment writes, the target deployment's capabilities —
|
|
190
|
+
* see `getRunCapabilities` in capabilities.ts). zstd and gzip read
|
|
191
|
+
* support co-ship, so a single boolean is sufficient.
|
|
192
|
+
* @param stats - Optional telemetry sink; populated when `data` is binary.
|
|
193
|
+
* @returns The compressed data with a codec prefix, or the original data
|
|
194
|
+
* when compression is disabled, unavailable, or not worthwhile.
|
|
195
|
+
*/
|
|
196
|
+
export async function compress(data, enabled, stats) {
|
|
197
|
+
if (!(data instanceof Uint8Array))
|
|
198
|
+
return data;
|
|
199
|
+
// From here `data` is binary, so every return path records stats.
|
|
200
|
+
if (!enabled ||
|
|
201
|
+
data.length < COMPRESSION_MIN_BYTES ||
|
|
202
|
+
isCompressionDisabledByEnv()) {
|
|
203
|
+
recordStats(stats, 'none', data.length, data.length);
|
|
204
|
+
return data;
|
|
205
|
+
}
|
|
206
|
+
const codec = selectWriteCodec();
|
|
207
|
+
if (codec === 'none') {
|
|
208
|
+
recordStats(stats, 'none', data.length, data.length);
|
|
209
|
+
return data;
|
|
210
|
+
}
|
|
211
|
+
const compressed = codec === 'zstd' ? zstdBytes(data) : await gzipBytes(data);
|
|
212
|
+
const format = codec === 'zstd' ? SerializationFormat.ZSTD : SerializationFormat.GZIP;
|
|
213
|
+
const wrappedLength = 4 + compressed.length; // format prefix + payload
|
|
214
|
+
if (wrappedLength >= data.length * (1 - COMPRESSION_MIN_SAVINGS_RATIO)) {
|
|
215
|
+
recordStats(stats, 'none', data.length, data.length);
|
|
216
|
+
return data;
|
|
217
|
+
}
|
|
218
|
+
recordStats(stats, codec, data.length, wrappedLength);
|
|
219
|
+
return encodeWithFormatPrefix(format, compressed);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Decompress a format-prefixed payload if it's compressed.
|
|
223
|
+
* Dispatches on the prefix ('zstd' or 'gzip') and inflates the inner
|
|
224
|
+
* payload (which carries its own format prefix, e.g. 'devl').
|
|
225
|
+
*
|
|
226
|
+
* Non-compressed data (including non-binary legacy data) is returned
|
|
227
|
+
* unchanged, so this is safe to apply unconditionally on read paths.
|
|
228
|
+
*/
|
|
229
|
+
export async function decompress(data, stats) {
|
|
230
|
+
if (!(data instanceof Uint8Array))
|
|
231
|
+
return data;
|
|
232
|
+
const prefix = peekFormatPrefix(data);
|
|
233
|
+
if (prefix === SerializationFormat.ZSTD) {
|
|
234
|
+
const { payload } = decodeFormatPrefix(data);
|
|
235
|
+
const inflated = unzstdBytes(payload);
|
|
236
|
+
recordStats(stats, 'zstd', inflated.length, data.length);
|
|
237
|
+
return inflated;
|
|
238
|
+
}
|
|
239
|
+
if (prefix === SerializationFormat.GZIP) {
|
|
240
|
+
if (!isGzipAvailable()) {
|
|
241
|
+
throw new Error('Compressed (gzip) workflow data encountered but DecompressionStream ' +
|
|
242
|
+
'is not available in this runtime. Node.js 18+, browsers, and edge ' +
|
|
243
|
+
'runtimes all support it.');
|
|
244
|
+
}
|
|
245
|
+
const { payload } = decodeFormatPrefix(data);
|
|
246
|
+
const inflated = await gunzipBytes(payload);
|
|
247
|
+
recordStats(stats, 'gzip', inflated.length, data.length);
|
|
248
|
+
return inflated;
|
|
249
|
+
}
|
|
250
|
+
recordStats(stats, 'none', data.length, data.length);
|
|
251
|
+
return data;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Check if data is compressed (has a 'zstd' or 'gzip' format prefix).
|
|
255
|
+
*/
|
|
256
|
+
export function isCompressed(data) {
|
|
257
|
+
const prefix = peekFormatPrefix(data);
|
|
258
|
+
return (prefix === SerializationFormat.ZSTD || prefix === SerializationFormat.GZIP);
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcHJlc3Npb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VyaWFsaXphdGlvbi9jb21wcmVzc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQ0c7QUFFSCxPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLHNCQUFzQixFQUN0QixnQkFBZ0IsR0FDakIsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRWpEOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLENBQUM7QUFFMUM7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsTUFBTSw2QkFBNkIsR0FBRyxJQUFJLENBQUM7QUFFbEQseUVBQXlFO0FBQ3pFLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQztBQUtyQjs7OztHQUlHO0FBQ0gsU0FBUywwQkFBMEI7SUFDakMsSUFBSSxDQUFDO1FBQ0gsT0FBTyxDQUNMLE9BQU8sT0FBTyxLQUFLLFdBQVc7WUFDOUIsT0FBTyxDQUFDLEdBQUcsRUFBRSw0QkFBNEIsS0FBSyxHQUFHLENBQ2xELENBQUM7SUFDSixDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLG9CQUFvQjtJQUMzQixJQUFJLENBQUM7UUFDSCxNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsR0FBRyxFQUFFLDBCQUEwQixDQUFDO1FBQ2xELE9BQU8sQ0FBQyxLQUFLLE1BQU0sSUFBSSxDQUFDLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUN0RCxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztBQUNILENBQUM7QUFR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LHNFQUFzRTtnQkFDcEUsb0VBQW9FO2dCQUNwRSwwQkFBMEIsQ0FDN0IsQ0FBQztRQUNKLENBQUM7UUFDRCxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDN0MsTUFBTSxRQUFRLEdBQUcsTUFBTSxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDNUMsV0FBVyxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDekQsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVELFdBQVcsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxJQUEwQjtJQUNyRCxNQUFNLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0QyxPQUFPLENBQ0wsTUFBTSxLQUFLLG1CQUFtQixDQUFDLElBQUksSUFBSSxNQUFNLEtBQUssbUJBQW1CLENBQUMsSUFBSSxDQUMzRSxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29tcG9zYWJsZSBjb21wcmVzc2lvbiBsYXllciBmb3Igc2VyaWFsaXplZCBkYXRhLlxuICpcbiAqIFdyYXBzL3Vud3JhcHMgc2VyaWFsaXplZCBwYXlsb2FkcyB3aXRoIGEgY29tcHJlc3Npb24gY29kZWMsIHVzaW5nIHRoZVxuICogZm9ybWF0IHByZWZpeCBzeXN0ZW0gdG8gbWFyayBjb21wcmVzc2VkIGRhdGEgKGUuZy4gJ3pzdGQnIG9yICdnemlwJ1xuICogd3JhcHBpbmcgdGhlIGlubmVyIGZvcm1hdDogJ3pzdGQnICsgenN0ZCgnZGV2bCcgKyBwYXlsb2FkKSkuXG4gKlxuICogQ29kZWMgc2VsZWN0aW9uICh3cml0ZSBzaWRlKTogenN0ZCBpcyBwcmVmZXJyZWQg4oCUIGl0IGlzIG1hcmtlZGx5IGZhc3RlclxuICogdGhhbiBnemlwIGF0IGEgY29tcGFyYWJsZS1vci1iZXR0ZXIgcmF0aW8gKHNlZSBzY3JpcHRzL1JFQURNRS5tZCksIGFuZFxuICogY29tcHJlc3Npb24gcnVucyBhdCBldmVyeSBzdGVwIGJvdW5kYXJ5IHNvIHRoZSB3cml0ZSBDUFUgaXMgYSBwZXItc3RlcFxuICogdGF4LiB6c3RkIHJlcXVpcmVzIGBub2RlOnpsaWJgID49IDIyLjE1IChXZWIgYENvbXByZXNzaW9uU3RyZWFtYCBoYXMgbm9cbiAqIHpzdGQpLCBzbyBvbiBhIHJ1bnRpbWUgd2l0aG91dCBpdCB3ZSBmYWxsIGJhY2sgdG8gZ3ppcCB2aWEgdGhlIHBvcnRhYmxlXG4gKiBgQ29tcHJlc3Npb25TdHJlYW1gLiBgV09SS0ZMT1dfQ09NUFJFU1NJT05fQ09ERUM9Z3ppcGAgZm9yY2VzIHRoZVxuICogcG9ydGFibGUgY29kZWMuXG4gKlxuICogUmVhZCBzaWRlOiBkaXNwYXRjaCBvbiB0aGUgZm9ybWF0IHByZWZpeCwgc28gYm90aCAnenN0ZCcgYW5kICdnemlwJ1xuICogcGF5bG9hZHMgYXJlIGFsd2F5cyBkZWNvZGFibGUgcmVnYXJkbGVzcyBvZiB3aGljaCBjb2RlYyB3cm90ZSB0aGVtLlxuICogKFRoZSBicm93c2VyIG8xMXkgcmVhZCBwYXRoIGRlY29kZXMgenN0ZCB2aWEgYSByZWdpc3RlcmVkIFdBU00gZGVjb2RlciDigJRcbiAqIHNlZSBgc2VyaWFsaXphdGlvbi1mb3JtYXQudHNgOyB0aGlzIG1vZHVsZSdzIGBkZWNvbXByZXNzYCBpcyB0aGUgTm9kZVxuICogcnVudGltZS9yZXBsYXkgcGF0aCBhbmQgdXNlcyBgbm9kZTp6bGliYC4pXG4gKlxuICogTGF5ZXJpbmcgb3JkZXIgd2l0aCBlbmNyeXB0aW9uOiBjb21wcmVzc2lvbiBpcyBhcHBsaWVkIEJFRk9SRVxuICogZW5jcnlwdGlvbiAoZW5jcih6c3RkKGRldmwpKSkg4oCUIGVuY3J5cHRlZCBieXRlcyBhcmUgaGlnaC1lbnRyb3B5IGFuZFxuICogZG8gbm90IGNvbXByZXNzLCBzbyB0aGUgcmV2ZXJzZSBvcmRlciB3b3VsZCBiZSBhIG5vLW9wLlxuICpcbiAqIENvbXByZXNzaW9uIGlzIGNvbmRpdGlvbmFsOlxuICogLSBQYXlsb2FkcyBzbWFsbGVyIHRoYW4ge0BsaW5rIENPTVBSRVNTSU9OX01JTl9CWVRFU30gYXJlIHBhc3NlZFxuICogICB0aHJvdWdoIHVuY2hhbmdlZCAoY29kZWMgb3ZlcmhlYWQgaXNuJ3Qgd29ydGggaXQpLlxuICogLSBJZiB0aGUgY29tcHJlc3NlZCByZXN1bHQgaXNuJ3QgbWVhbmluZ2Z1bGx5IHNtYWxsZXIgdGhhbiB0aGVcbiAqICAgb3JpZ2luYWwgKHNlZSB7QGxpbmsgQ09NUFJFU1NJT05fTUlOX1NBVklOR1NfUkFUSU99KSwgdGhlIG9yaWdpbmFsXG4gKiAgIGlzIGtlcHQuIFRoaXMgcHJvdGVjdHMgYWxyZWFkeS1jb21wcmVzc2VkIGJpbmFyeSBwYXlsb2FkcyAoaW1hZ2VzLFxuICogICBhcmNoaXZlcywgZXRjLikgZnJvbSB3YXN0ZWQgQ1BVIGFuZCBzaXplIGluZmxhdGlvbi5cbiAqL1xuXG5pbXBvcnQge1xuICBkZWNvZGVGb3JtYXRQcmVmaXgsXG4gIGVuY29kZVdpdGhGb3JtYXRQcmVmaXgsXG4gIHBlZWtGb3JtYXRQcmVmaXgsXG59IGZyb20gJy4vZm9ybWF0LmpzJztcbmltcG9ydCB7IFNlcmlhbGl6YXRpb25Gb3JtYXQgfSBmcm9tICcuL3R5cGVzLmpzJztcblxuLyoqXG4gKiBQYXlsb2FkcyBiZWxvdyB0aGlzIHNpemUgYXJlIG5ldmVyIGNvbXByZXNzZWQuIFRoZSA0LWJ5dGUgZm9ybWF0XG4gKiBwcmVmaXggKyBjb2RlYyBoZWFkZXIvdHJhaWxlciBvdmVyaGVhZCBtZWFucyBzbWFsbCBwYXlsb2FkcyBnYWluXG4gKiBub3RoaW5nLCBhbmQgdGlueSBvbmVzIHdvdWxkIGdyb3cuXG4gKi9cbmV4cG9ydCBjb25zdCBDT01QUkVTU0lPTl9NSU5fQllURVMgPSAxMDI0O1xuXG4vKipcbiAqIENvbXByZXNzaW9uIG11c3Qgc2hhdmUgb2ZmIGF0IGxlYXN0IHRoaXMgZnJhY3Rpb24gb2YgdGhlIHBheWxvYWRcbiAqIHNpemUgdG8gYmUga2VwdDsgb3RoZXJ3aXNlIHRoZSB1bmNvbXByZXNzZWQgb3JpZ2luYWwgaXMgc3RvcmVkLlxuICogR3VhcmRzIGFnYWluc3QgaW5jb21wcmVzc2libGUgKGFscmVhZHktY29tcHJlc3NlZCAvIGhpZ2gtZW50cm9weSlcbiAqIGRhdGEgcGF5aW5nIGEgcGVybWFuZW50IGRlY29tcHJlc3Npb24gdGF4IGZvciBhIG5lZ2xpZ2libGUgd2luLlxuICovXG5leHBvcnQgY29uc3QgQ09NUFJFU1NJT05fTUlOX1NBVklOR1NfUkFUSU8gPSAwLjA1O1xuXG4vKiogRGVmYXVsdCB6c3RkIGNvbXByZXNzaW9uIGxldmVsIOKAlCB0aGUgc3dlZXQgc3BvdCBvZiBzcGVlZCB2cyByYXRpby4gKi9cbmNvbnN0IFpTVERfTEVWRUwgPSAzO1xuXG4vKiogV2hpY2ggY29kZWMgY29tcHJlc3NlZCBhIHBheWxvYWQgKG9yIGBub25lYCB3aGVuIHN0b3JlZCB1bmNvbXByZXNzZWQpLiAqL1xuZXhwb3J0IHR5cGUgQ29tcHJlc3Npb25Db2RlYyA9ICd6c3RkJyB8ICdnemlwJyB8ICdub25lJztcblxuLyoqXG4gKiBFc2NhcGUgaGF0Y2g6IHNldCBXT1JLRkxPV19ESVNBQkxFX0NPTVBSRVNTSU9OPTEgdG8gZGlzYWJsZVxuICogd3JpdGUtc2lkZSBjb21wcmVzc2lvbiBlbnRpcmVseS4gUmVhZHMgYXJlIHVuYWZmZWN0ZWQg4oCUIHBheWxvYWRzXG4gKiB0aGF0IHdlcmUgYWxyZWFkeSB3cml0dGVuIGNvbXByZXNzZWQgcmVtYWluIHJlYWRhYmxlLlxuICovXG5mdW5jdGlvbiBpc0NvbXByZXNzaW9uRGlzYWJsZWRCeUVudigpOiBib29sZWFuIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gKFxuICAgICAgdHlwZW9mIHByb2Nlc3MgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICBwcm9jZXNzLmVudj8uV09SS0ZMT1dfRElTQUJMRV9DT01QUkVTU0lPTiA9PT0gJzEnXG4gICAgKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogT3B0aW9uYWwgY29kZWMgb3ZlcnJpZGUgKGBXT1JLRkxPV19DT01QUkVTU0lPTl9DT0RFQz1nemlwfHpzdGRgKS4gTGV0cyBhblxuICogb3BlcmF0b3IgcGluIHRoZSBwb3J0YWJsZSBjb2RlYyAoZ3ppcCkg4oCUIHVzZWZ1bCBmb3IgQS9CIGNvbXBhcmlzb25zIG9yXG4gKiBydW50aW1lcyB3aGVyZSB6c3RkIHJlYWQgc3VwcG9ydCBpc24ndCB5ZXQgZXZlcnl3aGVyZS5cbiAqL1xuZnVuY3Rpb24gY29kZWNPdmVycmlkZUZyb21FbnYoKTogJ2d6aXAnIHwgJ3pzdGQnIHwgdW5kZWZpbmVkIHtcbiAgdHJ5IHtcbiAgICBjb25zdCB2ID0gcHJvY2Vzcy5lbnY/LldPUktGTE9XX0NPTVBSRVNTSU9OX0NPREVDO1xuICAgIHJldHVybiB2ID09PSAnZ3ppcCcgfHwgdiA9PT0gJ3pzdGQnID8gdiA6IHVuZGVmaW5lZDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG5pbnRlcmZhY2UgTm9kZVpsaWIge1xuICB6c3RkQ29tcHJlc3NTeW5jPzogKGRhdGE6IFVpbnQ4QXJyYXksIG9wdHM/OiB1bmtub3duKSA9PiBVaW50OEFycmF5O1xuICB6c3RkRGVjb21wcmVzc1N5bmM/OiAoZGF0YTogVWludDhBcnJheSkgPT4gVWludDhBcnJheTtcbiAgY29uc3RhbnRzPzogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGBub2RlOnpsaWJgIHZpYSBgcHJvY2Vzcy5nZXRCdWlsdGluTW9kdWxlYCDigJQgbm8gc3RhdGljIGltcG9ydCwgc29cbiAqIHRoaXMgbW9kdWxlIHN0YXlzIGJ1bmRsZXItc2FmZSBmb3IgYnJvd3Nlci9lZGdlIHRhcmdldHMgKHdoZXJlIGl0IHJldHVybnNcbiAqIHVuZGVmaW5lZCBhbmQgd2UgZmFsbCBiYWNrIHRvIGd6aXApLlxuICovXG5mdW5jdGlvbiBnZXROb2RlWmxpYigpOiBOb2RlWmxpYiB8IHVuZGVmaW5lZCB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIChcbiAgICAgIGdsb2JhbFRoaXMgYXMge1xuICAgICAgICBwcm9jZXNzPzogeyBnZXRCdWlsdGluTW9kdWxlPzogKGlkOiBzdHJpbmcpID0+IE5vZGVabGliIH07XG4gICAgICB9XG4gICAgKS5wcm9jZXNzPy5nZXRCdWlsdGluTW9kdWxlPy4oJ25vZGU6emxpYicpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbmZ1bmN0aW9uIGlzWnN0ZEF2YWlsYWJsZSgpOiBib29sZWFuIHtcbiAgY29uc3QgeiA9IGdldE5vZGVabGliKCk7XG4gIHJldHVybiAoXG4gICAgdHlwZW9mIHo/LnpzdGRDb21wcmVzc1N5bmMgPT09ICdmdW5jdGlvbicgJiZcbiAgICB0eXBlb2Ygej8uenN0ZERlY29tcHJlc3NTeW5jID09PSAnZnVuY3Rpb24nXG4gICk7XG59XG5cbi8qKlxuICogZ3ppcCB2aWEgdGhlIHdlYi1zdGFuZGFyZCBgQ29tcHJlc3Npb25TdHJlYW1gIChOb2RlIDE4KywgYnJvd3NlcnMsIGVkZ2UpLlxuICovXG5mdW5jdGlvbiBpc0d6aXBBdmFpbGFibGUoKTogYm9vbGVhbiB7XG4gIHJldHVybiAoXG4gICAgdHlwZW9mIENvbXByZXNzaW9uU3RyZWFtID09PSAnZnVuY3Rpb24nICYmXG4gICAgdHlwZW9mIERlY29tcHJlc3Npb25TdHJlYW0gPT09ICdmdW5jdGlvbidcbiAgKTtcbn1cblxuLyoqXG4gKiBQaXBlIGJ5dGVzIHRocm91Z2ggYSAoRGUpQ29tcHJlc3Npb25TdHJlYW0gYW5kIGNvbGxlY3QgdGhlIG91dHB1dC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcGlwZVRocm91Z2hUcmFuc2Zvcm0oXG4gIGRhdGE6IFVpbnQ4QXJyYXksXG4gIHRyYW5zZm9ybToge1xuICAgIHJlYWRhYmxlOiBSZWFkYWJsZVN0cmVhbTxVaW50OEFycmF5PjtcbiAgICB3cml0YWJsZTogV3JpdGFibGVTdHJlYW08VWludDhBcnJheT47XG4gIH1cbik6IFByb21pc2U8VWludDhBcnJheT4ge1xuICBjb25zdCB3cml0ZXIgPSB0cmFuc2Zvcm0ud3JpdGFibGUuZ2V0V3JpdGVyKCk7XG4gIC8vIERvbid0IGF3YWl0IHRoZSB3cml0ZSBiZWZvcmUgcmVhZGluZyDigJQgdGhlIHRyYW5zZm9ybSdzIGludGVybmFsXG4gIC8vIHF1ZXVlIGNhbiBmaWxsIHVwIG9uIGxhcmdlIHBheWxvYWRzLCBkZWFkbG9ja2luZyB3cml0ZXIgdnMgcmVhZGVyLlxuICBjb25zdCB3cml0ZVByb21pc2UgPSB3cml0ZXIud3JpdGUoZGF0YSkudGhlbigoKSA9PiB3cml0ZXIuY2xvc2UoKSk7XG4gIC8vIElmIHRoZSB0cmFuc2Zvcm0gZXJyb3JzLCB0aGUgcmVhZGVyLnJlYWQoKSBiZWxvdyByZWplY3RzIGZpcnN0IGFuZFxuICAvLyBwcm9wYWdhdGVzOyBtYXJrIHRoZSB3cml0ZSBzaWRlIGFzIGhhbmRsZWQgc28gdGhlIG1pcnJvcmVkIHJlamVjdGlvblxuICAvLyBkb2Vzbid0IHN1cmZhY2UgYXMgYW4gdW5oYW5kbGVkIHJlamVjdGlvbi5cbiAgd3JpdGVQcm9taXNlLmNhdGNoKCgpID0+IHt9KTtcbiAgY29uc3QgY2h1bmtzOiBVaW50OEFycmF5W10gPSBbXTtcbiAgbGV0IHRvdGFsID0gMDtcbiAgY29uc3QgcmVhZGVyID0gdHJhbnNmb3JtLnJlYWRhYmxlLmdldFJlYWRlcigpO1xuICBmb3IgKDs7KSB7XG4gICAgY29uc3QgeyBkb25lLCB2YWx1ZSB9ID0gYXdhaXQgcmVhZGVyLnJlYWQoKTtcbiAgICBpZiAoZG9uZSkgYnJlYWs7XG4gICAgY2h1bmtzLnB1c2godmFsdWUpO1xuICAgIHRvdGFsICs9IHZhbHVlLmxlbmd0aDtcbiAgfVxuICBhd2FpdCB3cml0ZVByb21pc2U7XG4gIGNvbnN0IG91dCA9IG5ldyBVaW50OEFycmF5KHRvdGFsKTtcbiAgbGV0IG9mZnNldCA9IDA7XG4gIGZvciAoY29uc3QgY2h1bmsgb2YgY2h1bmtzKSB7XG4gICAgb3V0LnNldChjaHVuaywgb2Zmc2V0KTtcbiAgICBvZmZzZXQgKz0gY2h1bmsubGVuZ3RoO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGd6aXBCeXRlcyhkYXRhOiBVaW50OEFycmF5KTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gIHJldHVybiBwaXBlVGhyb3VnaFRyYW5zZm9ybShkYXRhLCBuZXcgQ29tcHJlc3Npb25TdHJlYW0oJ2d6aXAnKSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGd1bnppcEJ5dGVzKGRhdGE6IFVpbnQ4QXJyYXkpOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgcmV0dXJuIHBpcGVUaHJvdWdoVHJhbnNmb3JtKGRhdGEsIG5ldyBEZWNvbXByZXNzaW9uU3RyZWFtKCdnemlwJykpO1xufVxuXG5mdW5jdGlvbiB6c3RkQnl0ZXMoZGF0YTogVWludDhBcnJheSk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCB6ID0gZ2V0Tm9kZVpsaWIoKTtcbiAgY29uc3QgbGV2ZWwgPSB6Py5jb25zdGFudHM/LlpTVERfY19jb21wcmVzc2lvbkxldmVsO1xuICBjb25zdCBvcHRzID1cbiAgICBsZXZlbCAhPT0gdW5kZWZpbmVkID8geyBwYXJhbXM6IHsgW2xldmVsXTogWlNURF9MRVZFTCB9IH0gOiB1bmRlZmluZWQ7XG4gIC8vIGJpb21lLWlnbm9yZSBsaW50L3N0eWxlL25vTm9uTnVsbEFzc2VydGlvbjogZ3VhcmRlZCBieSBpc1pzdGRBdmFpbGFibGUoKVxuICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkoeiEuenN0ZENvbXByZXNzU3luYyEoZGF0YSwgb3B0cykpO1xufVxuXG5mdW5jdGlvbiB1bnpzdGRCeXRlcyhkYXRhOiBVaW50OEFycmF5KTogVWludDhBcnJheSB7XG4gIGNvbnN0IHogPSBnZXROb2RlWmxpYigpO1xuICBpZiAoIXo/LnpzdGREZWNvbXByZXNzU3luYykge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICdDb21wcmVzc2VkICh6c3RkKSB3b3JrZmxvdyBkYXRhIGVuY291bnRlcmVkIGJ1dCBub2RlOnpsaWIgenN0ZCAnICtcbiAgICAgICAgJ3N1cHBvcnQgaXMgbm90IGF2YWlsYWJsZSBpbiB0aGlzIHJ1bnRpbWUgKHJlcXVpcmVzIE5vZGUuanMgMjIuMTUrKS4gJyArXG4gICAgICAgICdJbiB0aGUgYnJvd3NlciwgcmVnaXN0ZXIgYSB6c3RkIGRlY29kZXIgdmlhIHJlZ2lzdGVyWnN0ZERlY29kZXIgJyArXG4gICAgICAgICcoc2VyaWFsaXphdGlvbi1mb3JtYXQudHMpLidcbiAgICApO1xuICB9XG4gIHJldHVybiBuZXcgVWludDhBcnJheSh6LnpzdGREZWNvbXByZXNzU3luYyhkYXRhKSk7XG59XG5cbi8qKlxuICogVGVsZW1ldHJ5IHNpbmsgZGVzY3JpYmluZyB3aGF0IHRoZSBjb21wcmVzc2lvbiBsYXllciBkaWQgdG8gYSBwYXlsb2FkLlxuICogUG9wdWxhdGVkIGJ5IHtAbGluayBjb21wcmVzc30gKHdyaXRlKSBhbmQge0BsaW5rIGRlY29tcHJlc3N9IChyZWFkKSB3aGVuXG4gKiBhIGBzdGF0c2Agb2JqZWN0IGlzIHBhc3NlZC4gU2l6ZXMgYXJlIG1lYXN1cmVkIGF0IHRoZSBjb21wcmVzc2lvblxuICogYm91bmRhcnkg4oCUIGkuZS4gYmVmb3JlIGVuY3J5cHRpb24gaXMgbGF5ZXJlZCBvbiB0aGUgd3JpdGUgc2lkZSBhbmQgYWZ0ZXJcbiAqIGRlY3J5cHRpb24gb24gdGhlIHJlYWQgc2lkZSDigJQgc28gdGhleSByZWZsZWN0IGNvbXByZXNzaW9uJ3MgZWZmZWN0LCBub3RcbiAqIHRoZSBhdC1yZXN0IHNpemUgKHdoaWNoIGFsc28gaW5jbHVkZXMgdGhlIGBlbmNyYCBlbnZlbG9wZSBhbmQsIG9uIHNvbWVcbiAqIGJhY2tlbmRzLCBiYXNlNjQgZXhwYW5zaW9uKS5cbiAqXG4gKiBGaWVsZCBtZWFuaW5ncyBhcmUgaWRlbnRpY2FsIGZvciBib3RoIGRpcmVjdGlvbnM6XG4gKiAtIGB1bmNvbXByZXNzZWRCeXRlc2A6IHRoZSBsb2dpY2FsIChkZXZhbHVlLXByZWZpeGVkKSBwYXlsb2FkIHNpemUuXG4gKiAtIGBzdG9yZWRCeXRlc2A6IHRoZSBzaXplIGhhbmRlZCB0byAvIHJlYWQgZnJvbSBzdG9yYWdlIChjb21wcmVzc2VkIHdoZW5cbiAqICAgYSBjb2RlYyBhcHBsaWVkLCBvdGhlcndpc2UgZXF1YWwgdG8gYHVuY29tcHJlc3NlZEJ5dGVzYCkuXG4gKiAtIGBjb2RlY2A6IHdoaWNoIGNvZGVjIGFwcGxpZWQgKGBub25lYCB3aGVuIHN0b3JlZCB1bmNvbXByZXNzZWQpLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbXByZXNzaW9uU3RhdHMge1xuICAvKiogVHJ1ZSBvbmNlIHRoZSBjb21wcmVzc2lvbiBsYXllciByYW4gKGkuZS4gc2F3IGJpbmFyeSBkYXRhKS4gKi9cbiAgcmVjb3JkZWQ/OiBib29sZWFuO1xuICAvKiogV2hldGhlciBhIGNvZGVjIHdhcyBhcHBsaWVkICh3cml0ZSkgb3IgcHJlc2VudCAocmVhZCkuICovXG4gIGNvbXByZXNzZWQ/OiBib29sZWFuO1xuICAvKiogV2hpY2ggY29kZWMgYXBwbGllZCAvIHdhcyBwcmVzZW50LiAqL1xuICBjb2RlYz86IENvbXByZXNzaW9uQ29kZWM7XG4gIC8qKiBMb2dpY2FsLCB1bmNvbXByZXNzZWQgcGF5bG9hZCBzaXplIGluIGJ5dGVzLiAqL1xuICB1bmNvbXByZXNzZWRCeXRlcz86IG51bWJlcjtcbiAgLyoqIFN0b3JlZCAocG9zdC1jb21wcmVzc2lvbikgcGF5bG9hZCBzaXplIGluIGJ5dGVzLiAqL1xuICBzdG9yZWRCeXRlcz86IG51bWJlcjtcbn1cblxuZnVuY3Rpb24gcmVjb3JkU3RhdHMoXG4gIHN0YXRzOiBDb21wcmVzc2lvblN0YXRzIHwgdW5kZWZpbmVkLFxuICBjb2RlYzogQ29tcHJlc3Npb25Db2RlYyxcbiAgdW5jb21wcmVzc2VkQnl0ZXM6IG51bWJlcixcbiAgc3RvcmVkQnl0ZXM6IG51bWJlclxuKTogdm9pZCB7XG4gIGlmICghc3RhdHMpIHJldHVybjtcbiAgc3RhdHMucmVjb3JkZWQgPSB0cnVlO1xuICBzdGF0cy5jb21wcmVzc2VkID0gY29kZWMgIT09ICdub25lJztcbiAgc3RhdHMuY29kZWMgPSBjb2RlYztcbiAgc3RhdHMudW5jb21wcmVzc2VkQnl0ZXMgPSB1bmNvbXByZXNzZWRCeXRlcztcbiAgc3RhdHMuc3RvcmVkQnl0ZXMgPSBzdG9yZWRCeXRlcztcbn1cblxuLyoqXG4gKiBDaG9vc2UgdGhlIHdyaXRlLXNpZGUgY29kZWMgZ2l2ZW4gcnVudGltZSBhdmFpbGFiaWxpdHkgYW5kIHRoZSBvcHRpb25hbFxuICogZW52IG92ZXJyaWRlLiB6c3RkIGlzIHByZWZlcnJlZDsgZ3ppcCBpcyB0aGUgcG9ydGFibGUgZmFsbGJhY2suXG4gKi9cbmZ1bmN0aW9uIHNlbGVjdFdyaXRlQ29kZWMoKTogJ3pzdGQnIHwgJ2d6aXAnIHwgJ25vbmUnIHtcbiAgY29uc3Qgb3ZlcnJpZGUgPSBjb2RlY092ZXJyaWRlRnJvbUVudigpO1xuICBpZiAob3ZlcnJpZGUgPT09ICdnemlwJykgcmV0dXJuIGlzR3ppcEF2YWlsYWJsZSgpID8gJ2d6aXAnIDogJ25vbmUnO1xuICAvLyBEZWZhdWx0IGFuZCBleHBsaWNpdCAnenN0ZCcgYm90aCBwcmVmZXIgenN0ZCwgdGhlbiBmYWxsIGJhY2sgdG8gZ3ppcC5cbiAgaWYgKGlzWnN0ZEF2YWlsYWJsZSgpKSByZXR1cm4gJ3pzdGQnO1xuICBpZiAoaXNHemlwQXZhaWxhYmxlKCkpIHJldHVybiAnZ3ppcCc7XG4gIHJldHVybiAnbm9uZSc7XG59XG5cbi8qKlxuICogQ29tcHJlc3MgYSBmb3JtYXQtcHJlZml4ZWQgcGF5bG9hZCBpZiBjb21wcmVzc2lvbiBpcyBlbmFibGVkIGZvciB0aGVcbiAqIHRhcmdldCBydW4gYW5kIHRoZSBwYXlsb2FkIGlzIHdvcnRoIGNvbXByZXNzaW5nLlxuICpcbiAqIEBwYXJhbSBkYXRhIC0gVGhlIGZvcm1hdC1wcmVmaXhlZCBzZXJpYWxpemVkIGRhdGEgKGUuZy4gJ2RldmwnICsgYnl0ZXMpXG4gKiBAcGFyYW0gZW5hYmxlZCAtIFdoZXRoZXIgdGhlIHRhcmdldCBydW4gc3VwcG9ydHMgY29tcHJlc3NlZCBwYXlsb2Fkc1xuICogICAocnVuIHNwZWNWZXJzaW9uID49IFNQRUNfVkVSU0lPTl9TVVBQT1JUU19DT01QUkVTU0lPTiwgYW5kIGZvclxuICogICBjcm9zcy1kZXBsb3ltZW50IHdyaXRlcywgdGhlIHRhcmdldCBkZXBsb3ltZW50J3MgY2FwYWJpbGl0aWVzIOKAlFxuICogICBzZWUgYGdldFJ1bkNhcGFiaWxpdGllc2AgaW4gY2FwYWJpbGl0aWVzLnRzKS4genN0ZCBhbmQgZ3ppcCByZWFkXG4gKiAgIHN1cHBvcnQgY28tc2hpcCwgc28gYSBzaW5nbGUgYm9vbGVhbiBpcyBzdWZmaWNpZW50LlxuICogQHBhcmFtIHN0YXRzIC0gT3B0aW9uYWwgdGVsZW1ldHJ5IHNpbms7IHBvcHVsYXRlZCB3aGVuIGBkYXRhYCBpcyBiaW5hcnkuXG4gKiBAcmV0dXJucyBUaGUgY29tcHJlc3NlZCBkYXRhIHdpdGggYSBjb2RlYyBwcmVmaXgsIG9yIHRoZSBvcmlnaW5hbCBkYXRhXG4gKiAgIHdoZW4gY29tcHJlc3Npb24gaXMgZGlzYWJsZWQsIHVuYXZhaWxhYmxlLCBvciBub3Qgd29ydGh3aGlsZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvbXByZXNzKFxuICBkYXRhOiBVaW50OEFycmF5IHwgdW5rbm93bixcbiAgZW5hYmxlZDogYm9vbGVhbixcbiAgc3RhdHM/OiBDb21wcmVzc2lvblN0YXRzXG4pOiBQcm9taXNlPFVpbnQ4QXJyYXkgfCB1bmtub3duPiB7XG4gIGlmICghKGRhdGEgaW5zdGFuY2VvZiBVaW50OEFycmF5KSkgcmV0dXJuIGRhdGE7XG4gIC8vIEZyb20gaGVyZSBgZGF0YWAgaXMgYmluYXJ5LCBzbyBldmVyeSByZXR1cm4gcGF0aCByZWNvcmRzIHN0YXRzLlxuICBpZiAoXG4gICAgIWVuYWJsZWQgfHxcbiAgICBkYXRhLmxlbmd0aCA8IENPTVBSRVNTSU9OX01JTl9CWVRFUyB8fFxuICAgIGlzQ29tcHJlc3Npb25EaXNhYmxlZEJ5RW52KClcbiAgKSB7XG4gICAgcmVjb3JkU3RhdHMoc3RhdHMsICdub25lJywgZGF0YS5sZW5ndGgsIGRhdGEubGVuZ3RoKTtcbiAgICByZXR1cm4gZGF0YTtcbiAgfVxuXG4gIGNvbnN0IGNvZGVjID0gc2VsZWN0V3JpdGVDb2RlYygpO1xuICBpZiAoY29kZWMgPT09ICdub25lJykge1xuICAgIHJlY29yZFN0YXRzKHN0YXRzLCAnbm9uZScsIGRhdGEubGVuZ3RoLCBkYXRhLmxlbmd0aCk7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICBjb25zdCBjb21wcmVzc2VkID0gY29kZWMgPT09ICd6c3RkJyA/IHpzdGRCeXRlcyhkYXRhKSA6IGF3YWl0IGd6aXBCeXRlcyhkYXRhKTtcbiAgY29uc3QgZm9ybWF0ID1cbiAgICBjb2RlYyA9PT0gJ3pzdGQnID8gU2VyaWFsaXphdGlvbkZvcm1hdC5aU1REIDogU2VyaWFsaXphdGlvbkZvcm1hdC5HWklQO1xuICBjb25zdCB3cmFwcGVkTGVuZ3RoID0gNCArIGNvbXByZXNzZWQubGVuZ3RoOyAvLyBmb3JtYXQgcHJlZml4ICsgcGF5bG9hZFxuICBpZiAod3JhcHBlZExlbmd0aCA+PSBkYXRhLmxlbmd0aCAqICgxIC0gQ09NUFJFU1NJT05fTUlOX1NBVklOR1NfUkFUSU8pKSB7XG4gICAgcmVjb3JkU3RhdHMoc3RhdHMsICdub25lJywgZGF0YS5sZW5ndGgsIGRhdGEubGVuZ3RoKTtcbiAgICByZXR1cm4gZGF0YTtcbiAgfVxuICByZWNvcmRTdGF0cyhzdGF0cywgY29kZWMsIGRhdGEubGVuZ3RoLCB3cmFwcGVkTGVuZ3RoKTtcbiAgcmV0dXJuIGVuY29kZVdpdGhGb3JtYXRQcmVmaXgoZm9ybWF0LCBjb21wcmVzc2VkKTtcbn1cblxuLyoqXG4gKiBEZWNvbXByZXNzIGEgZm9ybWF0LXByZWZpeGVkIHBheWxvYWQgaWYgaXQncyBjb21wcmVzc2VkLlxuICogRGlzcGF0Y2hlcyBvbiB0aGUgcHJlZml4ICgnenN0ZCcgb3IgJ2d6aXAnKSBhbmQgaW5mbGF0ZXMgdGhlIGlubmVyXG4gKiBwYXlsb2FkICh3aGljaCBjYXJyaWVzIGl0cyBvd24gZm9ybWF0IHByZWZpeCwgZS5nLiAnZGV2bCcpLlxuICpcbiAqIE5vbi1jb21wcmVzc2VkIGRhdGEgKGluY2x1ZGluZyBub24tYmluYXJ5IGxlZ2FjeSBkYXRhKSBpcyByZXR1cm5lZFxuICogdW5jaGFuZ2VkLCBzbyB0aGlzIGlzIHNhZmUgdG8gYXBwbHkgdW5jb25kaXRpb25hbGx5IG9uIHJlYWQgcGF0aHMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWNvbXByZXNzKFxuICBkYXRhOiBVaW50OEFycmF5IHwgdW5rbm93bixcbiAgc3RhdHM/OiBDb21wcmVzc2lvblN0YXRzXG4pOiBQcm9taXNlPFVpbnQ4QXJyYXkgfCB1bmtub3duPiB7XG4gIGlmICghKGRhdGEgaW5zdGFuY2VvZiBVaW50OEFycmF5KSkgcmV0dXJuIGRhdGE7XG4gIGNvbnN0IHByZWZpeCA9IHBlZWtGb3JtYXRQcmVmaXgoZGF0YSk7XG5cbiAgaWYgKHByZWZpeCA9PT0gU2VyaWFsaXphdGlvbkZvcm1hdC5aU1REKSB7XG4gICAgY29uc3QgeyBwYXlsb2FkIH0gPSBkZWNvZGVGb3JtYXRQcmVmaXgoZGF0YSk7XG4gICAgY29uc3QgaW5mbGF0ZWQgPSB1bnpzdGRCeXRlcyhwYXlsb2FkKTtcbiAgICByZWNvcmRTdGF0cyhzdGF0cywgJ3pzdGQnLCBpbmZsYXRlZC5sZW5ndGgsIGRhdGEubGVuZ3RoKTtcbiAgICByZXR1cm4gaW5mbGF0ZWQ7XG4gIH1cblxuICBpZiAocHJlZml4ID09PSBTZXJpYWxpemF0aW9uRm9ybWF0LkdaSVApIHtcbiAgICBpZiAoIWlzR3ppcEF2YWlsYWJsZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdDb21wcmVzc2VkIChnemlwKSB3b3JrZmxvdyBkYXRhIGVuY291bnRlcmVkIGJ1dCBEZWNvbXByZXNzaW9uU3RyZWFtICcgK1xuICAgICAgICAgICdpcyBub3QgYXZhaWxhYmxlIGluIHRoaXMgcnVudGltZS4gTm9kZS5qcyAxOCssIGJyb3dzZXJzLCBhbmQgZWRnZSAnICtcbiAgICAgICAgICAncnVudGltZXMgYWxsIHN1cHBvcnQgaXQuJ1xuICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgeyBwYXlsb2FkIH0gPSBkZWNvZGVGb3JtYXRQcmVmaXgoZGF0YSk7XG4gICAgY29uc3QgaW5mbGF0ZWQgPSBhd2FpdCBndW56aXBCeXRlcyhwYXlsb2FkKTtcbiAgICByZWNvcmRTdGF0cyhzdGF0cywgJ2d6aXAnLCBpbmZsYXRlZC5sZW5ndGgsIGRhdGEubGVuZ3RoKTtcbiAgICByZXR1cm4gaW5mbGF0ZWQ7XG4gIH1cblxuICByZWNvcmRTdGF0cyhzdGF0cywgJ25vbmUnLCBkYXRhLmxlbmd0aCwgZGF0YS5sZW5ndGgpO1xuICByZXR1cm4gZGF0YTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBkYXRhIGlzIGNvbXByZXNzZWQgKGhhcyBhICd6c3RkJyBvciAnZ3ppcCcgZm9ybWF0IHByZWZpeCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0NvbXByZXNzZWQoZGF0YTogVWludDhBcnJheSB8IHVua25vd24pOiBib29sZWFuIHtcbiAgY29uc3QgcHJlZml4ID0gcGVla0Zvcm1hdFByZWZpeChkYXRhKTtcbiAgcmV0dXJuIChcbiAgICBwcmVmaXggPT09IFNlcmlhbGl6YXRpb25Gb3JtYXQuWlNURCB8fCBwcmVmaXggPT09IFNlcmlhbGl6YXRpb25Gb3JtYXQuR1pJUFxuICApO1xufVxuIl19
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable encryption layer for serialized data.
|
|
3
|
+
*
|
|
4
|
+
* Wraps/unwraps serialized payloads with AES-256-GCM encryption,
|
|
5
|
+
* using the format prefix system to mark encrypted data.
|
|
6
|
+
*/
|
|
7
|
+
import { type CryptoKey } from '../encryption.js';
|
|
8
|
+
export type { CryptoKey };
|
|
9
|
+
/**
|
|
10
|
+
* Encryption key parameter type. Accepts a resolved key, undefined (no encryption),
|
|
11
|
+
* a promise, or a resolver that can defer fetching the key until data needs it.
|
|
12
|
+
*/
|
|
13
|
+
export type EncryptionKeyParam = CryptoKey | undefined | Promise<CryptoKey | undefined> | (() => Promise<CryptoKey | undefined>);
|
|
14
|
+
export declare function resolveEncryptionKey(key: EncryptionKeyParam): Promise<CryptoKey | undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* Encrypt a format-prefixed payload if a key is provided.
|
|
17
|
+
* Wraps the data with the 'encr' format prefix.
|
|
18
|
+
*
|
|
19
|
+
* @param data - The format-prefixed serialized data
|
|
20
|
+
* @param key - Encryption key (undefined to skip encryption)
|
|
21
|
+
* @returns The encrypted data with 'encr' prefix, or the original data if no key
|
|
22
|
+
*/
|
|
23
|
+
export declare function encrypt(data: Uint8Array | unknown, key: CryptoKey | undefined): Promise<Uint8Array | unknown>;
|
|
24
|
+
/**
|
|
25
|
+
* Decrypt a format-prefixed payload if it's encrypted.
|
|
26
|
+
* Strips the 'encr' format prefix and decrypts the inner payload.
|
|
27
|
+
*
|
|
28
|
+
* @param data - The potentially encrypted data
|
|
29
|
+
* @param key - Encryption key (undefined to skip decryption)
|
|
30
|
+
* @returns The decrypted inner payload, or the original data if not encrypted
|
|
31
|
+
*/
|
|
32
|
+
export declare function decrypt(data: Uint8Array | unknown, key: CryptoKey | undefined): Promise<Uint8Array | unknown>;
|
|
33
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/serialization/encryption.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAQ1B,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAC1B,SAAS,GACT,SAAS,GACT,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,GAC9B,CAAC,MAAM,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC;AAE3C,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAEhC;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,UAAU,GAAG,OAAO,EAC1B,GAAG,EAAE,SAAS,GAAG,SAAS,GACzB,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,CAI/B;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,UAAU,GAAG,OAAO,EAC1B,GAAG,EAAE,SAAS,GAAG,SAAS,GACzB,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,CAqC/B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable encryption layer for serialized data.
|
|
3
|
+
*
|
|
4
|
+
* Wraps/unwraps serialized payloads with AES-256-GCM encryption,
|
|
5
|
+
* using the format prefix system to mark encrypted data.
|
|
6
|
+
*/
|
|
7
|
+
import { RuntimeDecryptionError } from '@workflow/errors';
|
|
8
|
+
import { decrypt as aesGcmDecrypt, encrypt as aesGcmEncrypt, } from '../encryption.js';
|
|
9
|
+
import { decodeFormatPrefix, encodeWithFormatPrefix, peekFormatPrefix, } from './format.js';
|
|
10
|
+
import { SerializationFormat } from './types.js';
|
|
11
|
+
export async function resolveEncryptionKey(key) {
|
|
12
|
+
return typeof key === 'function' ? key() : key;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Encrypt a format-prefixed payload if a key is provided.
|
|
16
|
+
* Wraps the data with the 'encr' format prefix.
|
|
17
|
+
*
|
|
18
|
+
* @param data - The format-prefixed serialized data
|
|
19
|
+
* @param key - Encryption key (undefined to skip encryption)
|
|
20
|
+
* @returns The encrypted data with 'encr' prefix, or the original data if no key
|
|
21
|
+
*/
|
|
22
|
+
export async function encrypt(data, key) {
|
|
23
|
+
if (!key || !(data instanceof Uint8Array))
|
|
24
|
+
return data;
|
|
25
|
+
const encrypted = await aesGcmEncrypt(key, data);
|
|
26
|
+
return encodeWithFormatPrefix(SerializationFormat.ENCRYPTED, encrypted);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Decrypt a format-prefixed payload if it's encrypted.
|
|
30
|
+
* Strips the 'encr' format prefix and decrypts the inner payload.
|
|
31
|
+
*
|
|
32
|
+
* @param data - The potentially encrypted data
|
|
33
|
+
* @param key - Encryption key (undefined to skip decryption)
|
|
34
|
+
* @returns The decrypted inner payload, or the original data if not encrypted
|
|
35
|
+
*/
|
|
36
|
+
export async function decrypt(data, key) {
|
|
37
|
+
// Non-binary data is returned as-is.
|
|
38
|
+
if (!(data instanceof Uint8Array))
|
|
39
|
+
return data;
|
|
40
|
+
const format = peekFormatPrefix(data);
|
|
41
|
+
// If the data is encrypted but no key was provided, fail fast.
|
|
42
|
+
if (format === SerializationFormat.ENCRYPTED && !key) {
|
|
43
|
+
throw new RuntimeDecryptionError('Encrypted data encountered but no encryption key is available. ' +
|
|
44
|
+
'Encryption is not configured or no key was provided for this run.', {
|
|
45
|
+
context: {
|
|
46
|
+
operation: 'decrypt',
|
|
47
|
+
byteLength: data.byteLength,
|
|
48
|
+
formatPrefix: 'encr',
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// If the data is not encrypted, return it unchanged.
|
|
53
|
+
if (format !== SerializationFormat.ENCRYPTED)
|
|
54
|
+
return data;
|
|
55
|
+
const { payload } = decodeFormatPrefix(data);
|
|
56
|
+
try {
|
|
57
|
+
return await aesGcmDecrypt(key, payload);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
// The low-level AES layer only sees the stripped payload, so it cannot
|
|
61
|
+
// record the outer envelope prefix. This layer peeked it (`encr`), so
|
|
62
|
+
// enrich the diagnostic context with the real format prefix before
|
|
63
|
+
// rethrowing.
|
|
64
|
+
if (RuntimeDecryptionError.is(error) && error.context) {
|
|
65
|
+
error.context.formatPrefix = format;
|
|
66
|
+
}
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5jcnlwdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJpYWxpemF0aW9uL2VuY3J5cHRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMxRCxPQUFPLEVBQ0wsT0FBTyxJQUFJLGFBQWEsRUFDeEIsT0FBTyxJQUFJLGFBQWEsR0FFekIsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLHNCQUFzQixFQUN0QixnQkFBZ0IsR0FDakIsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBY2pELE1BQU0sQ0FBQyxLQUFLLFVBQVUsb0JBQW9CLENBQ3hDLEdBQXVCO0lBRXZCLE9BQU8sT0FBTyxHQUFHLEtBQUssVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO0FBQ2pELENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxPQUFPLENBQzNCLElBQTBCLEVBQzFCLEdBQTBCO0lBRTFCLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLElBQUksWUFBWSxVQUFVLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUN2RCxNQUFNLFNBQVMsR0FBRyxNQUFNLGFBQWEsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDakQsT0FBTyxzQkFBc0IsQ0FBQyxtQkFBbUIsQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFDMUUsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLE9BQU8sQ0FDM0IsSUFBMEIsRUFDMUIsR0FBMEI7SUFFMUIscUNBQXFDO0lBQ3JDLElBQUksQ0FBQyxDQUFDLElBQUksWUFBWSxVQUFVLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUUvQyxNQUFNLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUV0QywrREFBK0Q7SUFDL0QsSUFBSSxNQUFNLEtBQUssbUJBQW1CLENBQUMsU0FBUyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDckQsTUFBTSxJQUFJLHNCQUFzQixDQUM5QixpRUFBaUU7WUFDL0QsbUVBQW1FLEVBQ3JFO1lBQ0UsT0FBTyxFQUFFO2dCQUNQLFNBQVMsRUFBRSxTQUFTO2dCQUNwQixVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVU7Z0JBQzNCLFlBQVksRUFBRSxNQUFNO2FBQ3JCO1NBQ0YsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVELHFEQUFxRDtJQUNyRCxJQUFJLE1BQU0sS0FBSyxtQkFBbUIsQ0FBQyxTQUFTO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFFMUQsTUFBTSxFQUFFLE9BQU8sRUFBRSxHQUFHLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdDLElBQUksQ0FBQztRQUNILE9BQU8sTUFBTSxhQUFhLENBQUMsR0FBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsdUVBQXVFO1FBQ3ZFLHNFQUFzRTtRQUN0RSxtRUFBbUU7UUFDbkUsY0FBYztRQUNkLElBQUksc0JBQXNCLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN0RCxLQUFLLENBQUMsT0FBTyxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUM7UUFDdEMsQ0FBQztRQUNELE1BQU0sS0FBSyxDQUFDO0lBQ2QsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvbXBvc2FibGUgZW5jcnlwdGlvbiBsYXllciBmb3Igc2VyaWFsaXplZCBkYXRhLlxuICpcbiAqIFdyYXBzL3Vud3JhcHMgc2VyaWFsaXplZCBwYXlsb2FkcyB3aXRoIEFFUy0yNTYtR0NNIGVuY3J5cHRpb24sXG4gKiB1c2luZyB0aGUgZm9ybWF0IHByZWZpeCBzeXN0ZW0gdG8gbWFyayBlbmNyeXB0ZWQgZGF0YS5cbiAqL1xuXG5pbXBvcnQgeyBSdW50aW1lRGVjcnlwdGlvbkVycm9yIH0gZnJvbSAnQHdvcmtmbG93L2Vycm9ycyc7XG5pbXBvcnQge1xuICBkZWNyeXB0IGFzIGFlc0djbURlY3J5cHQsXG4gIGVuY3J5cHQgYXMgYWVzR2NtRW5jcnlwdCxcbiAgdHlwZSBDcnlwdG9LZXksXG59IGZyb20gJy4uL2VuY3J5cHRpb24uanMnO1xuaW1wb3J0IHtcbiAgZGVjb2RlRm9ybWF0UHJlZml4LFxuICBlbmNvZGVXaXRoRm9ybWF0UHJlZml4LFxuICBwZWVrRm9ybWF0UHJlZml4LFxufSBmcm9tICcuL2Zvcm1hdC5qcyc7XG5pbXBvcnQgeyBTZXJpYWxpemF0aW9uRm9ybWF0IH0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbmV4cG9ydCB0eXBlIHsgQ3J5cHRvS2V5IH07XG5cbi8qKlxuICogRW5jcnlwdGlvbiBrZXkgcGFyYW1ldGVyIHR5cGUuIEFjY2VwdHMgYSByZXNvbHZlZCBrZXksIHVuZGVmaW5lZCAobm8gZW5jcnlwdGlvbiksXG4gKiBhIHByb21pc2UsIG9yIGEgcmVzb2x2ZXIgdGhhdCBjYW4gZGVmZXIgZmV0Y2hpbmcgdGhlIGtleSB1bnRpbCBkYXRhIG5lZWRzIGl0LlxuICovXG5leHBvcnQgdHlwZSBFbmNyeXB0aW9uS2V5UGFyYW0gPVxuICB8IENyeXB0b0tleVxuICB8IHVuZGVmaW5lZFxuICB8IFByb21pc2U8Q3J5cHRvS2V5IHwgdW5kZWZpbmVkPlxuICB8ICgoKSA9PiBQcm9taXNlPENyeXB0b0tleSB8IHVuZGVmaW5lZD4pO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUVuY3J5cHRpb25LZXkoXG4gIGtleTogRW5jcnlwdGlvbktleVBhcmFtXG4pOiBQcm9taXNlPENyeXB0b0tleSB8IHVuZGVmaW5lZD4ge1xuICByZXR1cm4gdHlwZW9mIGtleSA9PT0gJ2Z1bmN0aW9uJyA/IGtleSgpIDoga2V5O1xufVxuXG4vKipcbiAqIEVuY3J5cHQgYSBmb3JtYXQtcHJlZml4ZWQgcGF5bG9hZCBpZiBhIGtleSBpcyBwcm92aWRlZC5cbiAqIFdyYXBzIHRoZSBkYXRhIHdpdGggdGhlICdlbmNyJyBmb3JtYXQgcHJlZml4LlxuICpcbiAqIEBwYXJhbSBkYXRhIC0gVGhlIGZvcm1hdC1wcmVmaXhlZCBzZXJpYWxpemVkIGRhdGFcbiAqIEBwYXJhbSBrZXkgLSBFbmNyeXB0aW9uIGtleSAodW5kZWZpbmVkIHRvIHNraXAgZW5jcnlwdGlvbilcbiAqIEByZXR1cm5zIFRoZSBlbmNyeXB0ZWQgZGF0YSB3aXRoICdlbmNyJyBwcmVmaXgsIG9yIHRoZSBvcmlnaW5hbCBkYXRhIGlmIG5vIGtleVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZW5jcnlwdChcbiAgZGF0YTogVWludDhBcnJheSB8IHVua25vd24sXG4gIGtleTogQ3J5cHRvS2V5IHwgdW5kZWZpbmVkXG4pOiBQcm9taXNlPFVpbnQ4QXJyYXkgfCB1bmtub3duPiB7XG4gIGlmICgha2V5IHx8ICEoZGF0YSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpKSByZXR1cm4gZGF0YTtcbiAgY29uc3QgZW5jcnlwdGVkID0gYXdhaXQgYWVzR2NtRW5jcnlwdChrZXksIGRhdGEpO1xuICByZXR1cm4gZW5jb2RlV2l0aEZvcm1hdFByZWZpeChTZXJpYWxpemF0aW9uRm9ybWF0LkVOQ1JZUFRFRCwgZW5jcnlwdGVkKTtcbn1cblxuLyoqXG4gKiBEZWNyeXB0IGEgZm9ybWF0LXByZWZpeGVkIHBheWxvYWQgaWYgaXQncyBlbmNyeXB0ZWQuXG4gKiBTdHJpcHMgdGhlICdlbmNyJyBmb3JtYXQgcHJlZml4IGFuZCBkZWNyeXB0cyB0aGUgaW5uZXIgcGF5bG9hZC5cbiAqXG4gKiBAcGFyYW0gZGF0YSAtIFRoZSBwb3RlbnRpYWxseSBlbmNyeXB0ZWQgZGF0YVxuICogQHBhcmFtIGtleSAtIEVuY3J5cHRpb24ga2V5ICh1bmRlZmluZWQgdG8gc2tpcCBkZWNyeXB0aW9uKVxuICogQHJldHVybnMgVGhlIGRlY3J5cHRlZCBpbm5lciBwYXlsb2FkLCBvciB0aGUgb3JpZ2luYWwgZGF0YSBpZiBub3QgZW5jcnlwdGVkXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWNyeXB0KFxuICBkYXRhOiBVaW50OEFycmF5IHwgdW5rbm93bixcbiAga2V5OiBDcnlwdG9LZXkgfCB1bmRlZmluZWRcbik6IFByb21pc2U8VWludDhBcnJheSB8IHVua25vd24+IHtcbiAgLy8gTm9uLWJpbmFyeSBkYXRhIGlzIHJldHVybmVkIGFzLWlzLlxuICBpZiAoIShkYXRhIGluc3RhbmNlb2YgVWludDhBcnJheSkpIHJldHVybiBkYXRhO1xuXG4gIGNvbnN0IGZvcm1hdCA9IHBlZWtGb3JtYXRQcmVmaXgoZGF0YSk7XG5cbiAgLy8gSWYgdGhlIGRhdGEgaXMgZW5jcnlwdGVkIGJ1dCBubyBrZXkgd2FzIHByb3ZpZGVkLCBmYWlsIGZhc3QuXG4gIGlmIChmb3JtYXQgPT09IFNlcmlhbGl6YXRpb25Gb3JtYXQuRU5DUllQVEVEICYmICFrZXkpIHtcbiAgICB0aHJvdyBuZXcgUnVudGltZURlY3J5cHRpb25FcnJvcihcbiAgICAgICdFbmNyeXB0ZWQgZGF0YSBlbmNvdW50ZXJlZCBidXQgbm8gZW5jcnlwdGlvbiBrZXkgaXMgYXZhaWxhYmxlLiAnICtcbiAgICAgICAgJ0VuY3J5cHRpb24gaXMgbm90IGNvbmZpZ3VyZWQgb3Igbm8ga2V5IHdhcyBwcm92aWRlZCBmb3IgdGhpcyBydW4uJyxcbiAgICAgIHtcbiAgICAgICAgY29udGV4dDoge1xuICAgICAgICAgIG9wZXJhdGlvbjogJ2RlY3J5cHQnLFxuICAgICAgICAgIGJ5dGVMZW5ndGg6IGRhdGEuYnl0ZUxlbmd0aCxcbiAgICAgICAgICBmb3JtYXRQcmVmaXg6ICdlbmNyJyxcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgLy8gSWYgdGhlIGRhdGEgaXMgbm90IGVuY3J5cHRlZCwgcmV0dXJuIGl0IHVuY2hhbmdlZC5cbiAgaWYgKGZvcm1hdCAhPT0gU2VyaWFsaXphdGlvbkZvcm1hdC5FTkNSWVBURUQpIHJldHVybiBkYXRhO1xuXG4gIGNvbnN0IHsgcGF5bG9hZCB9ID0gZGVjb2RlRm9ybWF0UHJlZml4KGRhdGEpO1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBhZXNHY21EZWNyeXB0KGtleSEsIHBheWxvYWQpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIC8vIFRoZSBsb3ctbGV2ZWwgQUVTIGxheWVyIG9ubHkgc2VlcyB0aGUgc3RyaXBwZWQgcGF5bG9hZCwgc28gaXQgY2Fubm90XG4gICAgLy8gcmVjb3JkIHRoZSBvdXRlciBlbnZlbG9wZSBwcmVmaXguIFRoaXMgbGF5ZXIgcGVla2VkIGl0IChgZW5jcmApLCBzb1xuICAgIC8vIGVucmljaCB0aGUgZGlhZ25vc3RpYyBjb250ZXh0IHdpdGggdGhlIHJlYWwgZm9ybWF0IHByZWZpeCBiZWZvcmVcbiAgICAvLyByZXRocm93aW5nLlxuICAgIGlmIChSdW50aW1lRGVjcnlwdGlvbkVycm9yLmlzKGVycm9yKSAmJiBlcnJvci5jb250ZXh0KSB7XG4gICAgICBlcnJvci5jb250ZXh0LmZvcm1hdFByZWZpeCA9IGZvcm1hdDtcbiAgICB9XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared error formatting utility for serialization failures.
|
|
3
|
+
*
|
|
4
|
+
* Used by the mode-specific serializers (workflow, step, client) to
|
|
5
|
+
* produce consistent error messages with devalue path information.
|
|
6
|
+
*
|
|
7
|
+
* Returns a `{ message, hint }` pair so callers can throw a
|
|
8
|
+
* `SerializationError(message, { hint, cause })` and have the hint flow
|
|
9
|
+
* through the standard friendly-errors framing instead of being baked
|
|
10
|
+
* into the message string.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Rethrow SDK runtime errors that must not be reframed as
|
|
14
|
+
* `SerializationError`.
|
|
15
|
+
*
|
|
16
|
+
* The serialize/dehydrate wrappers catch every throw and reframe it as a
|
|
17
|
+
* `SerializationError` (which classifies as `USER_ERROR`). That's correct
|
|
18
|
+
* for genuine serialization failures, but a `RuntimeDecryptionError` from
|
|
19
|
+
* the AES-GCM layer is an SDK-internal failure that must keep its identity
|
|
20
|
+
* so the run-failure classifier routes it to `RUNTIME_ERROR`. Call this at
|
|
21
|
+
* the top of each serialize catch block to let those errors propagate
|
|
22
|
+
* unchanged.
|
|
23
|
+
*/
|
|
24
|
+
export declare function rethrowIfRuntimeError(error: unknown): void;
|
|
25
|
+
/**
|
|
26
|
+
* Format a serialization error with context about what failed.
|
|
27
|
+
* Extracts path, value, and reason from devalue's DevalueError when available.
|
|
28
|
+
* Logs the problematic value to the console for better debugging.
|
|
29
|
+
*/
|
|
30
|
+
export declare function formatSerializationError(context: string, error: unknown): {
|
|
31
|
+
message: string;
|
|
32
|
+
hint: string;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/serialization/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAI1D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,GACb;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAqBnC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared error formatting utility for serialization failures.
|
|
3
|
+
*
|
|
4
|
+
* Used by the mode-specific serializers (workflow, step, client) to
|
|
5
|
+
* produce consistent error messages with devalue path information.
|
|
6
|
+
*
|
|
7
|
+
* Returns a `{ message, hint }` pair so callers can throw a
|
|
8
|
+
* `SerializationError(message, { hint, cause })` and have the hint flow
|
|
9
|
+
* through the standard friendly-errors framing instead of being baked
|
|
10
|
+
* into the message string.
|
|
11
|
+
*/
|
|
12
|
+
import { RuntimeDecryptionError } from '@workflow/errors';
|
|
13
|
+
import { DevalueError } from 'devalue';
|
|
14
|
+
import { runtimeLogger } from '../logger.js';
|
|
15
|
+
/**
|
|
16
|
+
* Rethrow SDK runtime errors that must not be reframed as
|
|
17
|
+
* `SerializationError`.
|
|
18
|
+
*
|
|
19
|
+
* The serialize/dehydrate wrappers catch every throw and reframe it as a
|
|
20
|
+
* `SerializationError` (which classifies as `USER_ERROR`). That's correct
|
|
21
|
+
* for genuine serialization failures, but a `RuntimeDecryptionError` from
|
|
22
|
+
* the AES-GCM layer is an SDK-internal failure that must keep its identity
|
|
23
|
+
* so the run-failure classifier routes it to `RUNTIME_ERROR`. Call this at
|
|
24
|
+
* the top of each serialize catch block to let those errors propagate
|
|
25
|
+
* unchanged.
|
|
26
|
+
*/
|
|
27
|
+
export function rethrowIfRuntimeError(error) {
|
|
28
|
+
if (RuntimeDecryptionError.is(error)) {
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Format a serialization error with context about what failed.
|
|
34
|
+
* Extracts path, value, and reason from devalue's DevalueError when available.
|
|
35
|
+
* Logs the problematic value to the console for better debugging.
|
|
36
|
+
*/
|
|
37
|
+
export function formatSerializationError(context, error) {
|
|
38
|
+
// `returning` for outputs, `passing` for everything that crosses the
|
|
39
|
+
// boundary the other way (arguments, stream messages, etc.).
|
|
40
|
+
const verb = context.includes('return value') ? 'returning' : 'passing';
|
|
41
|
+
let message = `Failed to serialize ${context}`;
|
|
42
|
+
if (error instanceof DevalueError && error.path) {
|
|
43
|
+
message += ` at path "${error.path}"`;
|
|
44
|
+
}
|
|
45
|
+
// Workflow can serialize a much richer set than the devalue defaults —
|
|
46
|
+
// classes registered via `WORKFLOW_SERIALIZE`, FatalError / RetryableError
|
|
47
|
+
// subclasses, AbortSignal, etc. Pointing at the foundations doc keeps
|
|
48
|
+
// this hint accurate as the supported set grows, instead of repeating
|
|
49
|
+
// a hardcoded list that drifts out of sync.
|
|
50
|
+
const hint = `Ensure you're ${verb} workflow serializable types. Check the serialization docs to see what's serializable: https://workflow-sdk.dev/docs/foundations/serialization`;
|
|
51
|
+
if (error instanceof DevalueError && error.value !== undefined) {
|
|
52
|
+
runtimeLogger.error('Serialization failed', {
|
|
53
|
+
context,
|
|
54
|
+
problematicValue: error.value,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return { message, hint };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcmlhbGl6YXRpb24vZXJyb3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFN0M7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBQUMsS0FBYztJQUNsRCxJQUFJLHNCQUFzQixDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3JDLE1BQU0sS0FBSyxDQUFDO0lBQ2QsQ0FBQztBQUNILENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLHdCQUF3QixDQUN0QyxPQUFlLEVBQ2YsS0FBYztJQUVkLHFFQUFxRTtJQUNyRSw2REFBNkQ7SUFDN0QsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDeEUsSUFBSSxPQUFPLEdBQUcsdUJBQXVCLE9BQU8sRUFBRSxDQUFDO0lBQy9DLElBQUksS0FBSyxZQUFZLFlBQVksSUFBSSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDaEQsT0FBTyxJQUFJLGFBQWEsS0FBSyxDQUFDLElBQUksR0FBRyxDQUFDO0lBQ3hDLENBQUM7SUFDRCx1RUFBdUU7SUFDdkUsMkVBQTJFO0lBQzNFLHNFQUFzRTtJQUN0RSxzRUFBc0U7SUFDdEUsNENBQTRDO0lBQzVDLE1BQU0sSUFBSSxHQUFHLGlCQUFpQixJQUFJLGdKQUFnSixDQUFDO0lBQ25MLElBQUksS0FBSyxZQUFZLFlBQVksSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQy9ELGFBQWEsQ0FBQyxLQUFLLENBQUMsc0JBQXNCLEVBQUU7WUFDMUMsT0FBTztZQUNQLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxLQUFLO1NBQzlCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDO0FBQzNCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNoYXJlZCBlcnJvciBmb3JtYXR0aW5nIHV0aWxpdHkgZm9yIHNlcmlhbGl6YXRpb24gZmFpbHVyZXMuXG4gKlxuICogVXNlZCBieSB0aGUgbW9kZS1zcGVjaWZpYyBzZXJpYWxpemVycyAod29ya2Zsb3csIHN0ZXAsIGNsaWVudCkgdG9cbiAqIHByb2R1Y2UgY29uc2lzdGVudCBlcnJvciBtZXNzYWdlcyB3aXRoIGRldmFsdWUgcGF0aCBpbmZvcm1hdGlvbi5cbiAqXG4gKiBSZXR1cm5zIGEgYHsgbWVzc2FnZSwgaGludCB9YCBwYWlyIHNvIGNhbGxlcnMgY2FuIHRocm93IGFcbiAqIGBTZXJpYWxpemF0aW9uRXJyb3IobWVzc2FnZSwgeyBoaW50LCBjYXVzZSB9KWAgYW5kIGhhdmUgdGhlIGhpbnQgZmxvd1xuICogdGhyb3VnaCB0aGUgc3RhbmRhcmQgZnJpZW5kbHktZXJyb3JzIGZyYW1pbmcgaW5zdGVhZCBvZiBiZWluZyBiYWtlZFxuICogaW50byB0aGUgbWVzc2FnZSBzdHJpbmcuXG4gKi9cblxuaW1wb3J0IHsgUnVudGltZURlY3J5cHRpb25FcnJvciB9IGZyb20gJ0B3b3JrZmxvdy9lcnJvcnMnO1xuaW1wb3J0IHsgRGV2YWx1ZUVycm9yIH0gZnJvbSAnZGV2YWx1ZSc7XG5pbXBvcnQgeyBydW50aW1lTG9nZ2VyIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcblxuLyoqXG4gKiBSZXRocm93IFNESyBydW50aW1lIGVycm9ycyB0aGF0IG11c3Qgbm90IGJlIHJlZnJhbWVkIGFzXG4gKiBgU2VyaWFsaXphdGlvbkVycm9yYC5cbiAqXG4gKiBUaGUgc2VyaWFsaXplL2RlaHlkcmF0ZSB3cmFwcGVycyBjYXRjaCBldmVyeSB0aHJvdyBhbmQgcmVmcmFtZSBpdCBhcyBhXG4gKiBgU2VyaWFsaXphdGlvbkVycm9yYCAod2hpY2ggY2xhc3NpZmllcyBhcyBgVVNFUl9FUlJPUmApLiBUaGF0J3MgY29ycmVjdFxuICogZm9yIGdlbnVpbmUgc2VyaWFsaXphdGlvbiBmYWlsdXJlcywgYnV0IGEgYFJ1bnRpbWVEZWNyeXB0aW9uRXJyb3JgIGZyb21cbiAqIHRoZSBBRVMtR0NNIGxheWVyIGlzIGFuIFNESy1pbnRlcm5hbCBmYWlsdXJlIHRoYXQgbXVzdCBrZWVwIGl0cyBpZGVudGl0eVxuICogc28gdGhlIHJ1bi1mYWlsdXJlIGNsYXNzaWZpZXIgcm91dGVzIGl0IHRvIGBSVU5USU1FX0VSUk9SYC4gQ2FsbCB0aGlzIGF0XG4gKiB0aGUgdG9wIG9mIGVhY2ggc2VyaWFsaXplIGNhdGNoIGJsb2NrIHRvIGxldCB0aG9zZSBlcnJvcnMgcHJvcGFnYXRlXG4gKiB1bmNoYW5nZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXRocm93SWZSdW50aW1lRXJyb3IoZXJyb3I6IHVua25vd24pOiB2b2lkIHtcbiAgaWYgKFJ1bnRpbWVEZWNyeXB0aW9uRXJyb3IuaXMoZXJyb3IpKSB7XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn1cblxuLyoqXG4gKiBGb3JtYXQgYSBzZXJpYWxpemF0aW9uIGVycm9yIHdpdGggY29udGV4dCBhYm91dCB3aGF0IGZhaWxlZC5cbiAqIEV4dHJhY3RzIHBhdGgsIHZhbHVlLCBhbmQgcmVhc29uIGZyb20gZGV2YWx1ZSdzIERldmFsdWVFcnJvciB3aGVuIGF2YWlsYWJsZS5cbiAqIExvZ3MgdGhlIHByb2JsZW1hdGljIHZhbHVlIHRvIHRoZSBjb25zb2xlIGZvciBiZXR0ZXIgZGVidWdnaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0U2VyaWFsaXphdGlvbkVycm9yKFxuICBjb250ZXh0OiBzdHJpbmcsXG4gIGVycm9yOiB1bmtub3duXG4pOiB7IG1lc3NhZ2U6IHN0cmluZzsgaGludDogc3RyaW5nIH0ge1xuICAvLyBgcmV0dXJuaW5nYCBmb3Igb3V0cHV0cywgYHBhc3NpbmdgIGZvciBldmVyeXRoaW5nIHRoYXQgY3Jvc3NlcyB0aGVcbiAgLy8gYm91bmRhcnkgdGhlIG90aGVyIHdheSAoYXJndW1lbnRzLCBzdHJlYW0gbWVzc2FnZXMsIGV0Yy4pLlxuICBjb25zdCB2ZXJiID0gY29udGV4dC5pbmNsdWRlcygncmV0dXJuIHZhbHVlJykgPyAncmV0dXJuaW5nJyA6ICdwYXNzaW5nJztcbiAgbGV0IG1lc3NhZ2UgPSBgRmFpbGVkIHRvIHNlcmlhbGl6ZSAke2NvbnRleHR9YDtcbiAgaWYgKGVycm9yIGluc3RhbmNlb2YgRGV2YWx1ZUVycm9yICYmIGVycm9yLnBhdGgpIHtcbiAgICBtZXNzYWdlICs9IGAgYXQgcGF0aCBcIiR7ZXJyb3IucGF0aH1cImA7XG4gIH1cbiAgLy8gV29ya2Zsb3cgY2FuIHNlcmlhbGl6ZSBhIG11Y2ggcmljaGVyIHNldCB0aGFuIHRoZSBkZXZhbHVlIGRlZmF1bHRzIOKAlFxuICAvLyBjbGFzc2VzIHJlZ2lzdGVyZWQgdmlhIGBXT1JLRkxPV19TRVJJQUxJWkVgLCBGYXRhbEVycm9yIC8gUmV0cnlhYmxlRXJyb3JcbiAgLy8gc3ViY2xhc3NlcywgQWJvcnRTaWduYWwsIGV0Yy4gUG9pbnRpbmcgYXQgdGhlIGZvdW5kYXRpb25zIGRvYyBrZWVwc1xuICAvLyB0aGlzIGhpbnQgYWNjdXJhdGUgYXMgdGhlIHN1cHBvcnRlZCBzZXQgZ3Jvd3MsIGluc3RlYWQgb2YgcmVwZWF0aW5nXG4gIC8vIGEgaGFyZGNvZGVkIGxpc3QgdGhhdCBkcmlmdHMgb3V0IG9mIHN5bmMuXG4gIGNvbnN0IGhpbnQgPSBgRW5zdXJlIHlvdSdyZSAke3ZlcmJ9IHdvcmtmbG93IHNlcmlhbGl6YWJsZSB0eXBlcy4gQ2hlY2sgdGhlIHNlcmlhbGl6YXRpb24gZG9jcyB0byBzZWUgd2hhdCdzIHNlcmlhbGl6YWJsZTogaHR0cHM6Ly93b3JrZmxvdy1zZGsuZGV2L2RvY3MvZm91bmRhdGlvbnMvc2VyaWFsaXphdGlvbmA7XG4gIGlmIChlcnJvciBpbnN0YW5jZW9mIERldmFsdWVFcnJvciAmJiBlcnJvci52YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcnVudGltZUxvZ2dlci5lcnJvcignU2VyaWFsaXphdGlvbiBmYWlsZWQnLCB7XG4gICAgICBjb250ZXh0LFxuICAgICAgcHJvYmxlbWF0aWNWYWx1ZTogZXJyb3IudmFsdWUsXG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIHsgbWVzc2FnZSwgaGludCB9O1xufVxuIl19
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format prefix system for serialized payloads.
|
|
3
|
+
*
|
|
4
|
+
* All serialized payloads are prefixed with a 4-byte format identifier that
|
|
5
|
+
* allows the deserializer to determine how to decode the payload. This enables:
|
|
6
|
+
*
|
|
7
|
+
* 1. Self-describing payloads — the World layer is agnostic to serialization format
|
|
8
|
+
* 2. Gradual migration — old runs keep working, new runs can use new formats
|
|
9
|
+
* 3. Composability — encryption can wrap any format ("encr" wrapping "devl")
|
|
10
|
+
* 4. Debugging — raw data inspection immediately reveals the format
|
|
11
|
+
*
|
|
12
|
+
* Format: [4 bytes: format identifier][payload]
|
|
13
|
+
*
|
|
14
|
+
* The format prefix is open-ended — any 4-character [a-z0-9] string is valid.
|
|
15
|
+
* This allows new codecs to be added without modifying this module.
|
|
16
|
+
*/
|
|
17
|
+
import { type FormatPrefix } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Encode a payload with a format prefix.
|
|
20
|
+
*
|
|
21
|
+
* @param format - The format identifier (4 chars, [a-z0-9])
|
|
22
|
+
* @param payload - The serialized payload bytes
|
|
23
|
+
* @returns A new Uint8Array with format prefix prepended
|
|
24
|
+
*/
|
|
25
|
+
export declare function encodeWithFormatPrefix(format: FormatPrefix, payload: Uint8Array | unknown): Uint8Array | unknown;
|
|
26
|
+
/**
|
|
27
|
+
* Peek at the format prefix without consuming it.
|
|
28
|
+
*
|
|
29
|
+
* Returns the prefix if it's a valid format prefix ([a-z0-9]{4}),
|
|
30
|
+
* or null if the data is legacy/non-binary or doesn't start with a
|
|
31
|
+
* valid prefix.
|
|
32
|
+
*
|
|
33
|
+
* @param data - The format-prefixed data
|
|
34
|
+
* @returns The format prefix, or null
|
|
35
|
+
*/
|
|
36
|
+
export declare function peekFormatPrefix(data: Uint8Array | unknown): FormatPrefix | null;
|
|
37
|
+
/**
|
|
38
|
+
* Check if data is encrypted (has 'encr' format prefix).
|
|
39
|
+
*/
|
|
40
|
+
export declare function isEncrypted(data: Uint8Array | unknown): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Decode a format-prefixed payload.
|
|
43
|
+
*
|
|
44
|
+
* Unlike the legacy implementation which only accepted known formats
|
|
45
|
+
* (`devl`, `encr`), this function accepts any valid format prefix
|
|
46
|
+
* (`[a-z0-9]{4}`). This is intentional for forward compatibility —
|
|
47
|
+
* new codecs (e.g. `cbor`) can be added without modifying this module.
|
|
48
|
+
* Callers are responsible for checking whether they support the returned
|
|
49
|
+
* format and throwing an appropriate error if not (e.g. "Unsupported
|
|
50
|
+
* serialization format").
|
|
51
|
+
*
|
|
52
|
+
* @param data - The format-prefixed data
|
|
53
|
+
* @returns An object with the format prefix and payload
|
|
54
|
+
* @throws Error if the data is too short or has an invalid prefix
|
|
55
|
+
*/
|
|
56
|
+
export declare function decodeFormatPrefix(data: Uint8Array | unknown): {
|
|
57
|
+
format: FormatPrefix;
|
|
58
|
+
payload: Uint8Array;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/serialization/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,YAAY,CAAC;AAQpB;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,UAAU,GAAG,OAAO,GAC5B,UAAU,GAAG,OAAO,CAUtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,GAAG,OAAO,GACzB,YAAY,GAAG,IAAI,CAOrB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,OAAO,CAE/D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG;IAC9D,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;CACrB,CA0BA"}
|