quidproquo-actionprocessor-node 0.1.3 → 0.1.5
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/lib/commonjs/actionProcessor/core/index.js +1 -0
- package/lib/commonjs/actionProcessor/core/index.js.map +1 -0
- package/lib/commonjs/actionProcessor/core/inlineFunction/getInlineFunctionExecuteActionProcessor.js +1 -0
- package/lib/commonjs/actionProcessor/core/inlineFunction/getInlineFunctionExecuteActionProcessor.js.map +1 -0
- package/lib/commonjs/actionProcessor/core/inlineFunction/index.js +1 -0
- package/lib/commonjs/actionProcessor/core/inlineFunction/index.js.map +1 -0
- package/lib/commonjs/actionProcessor/core/stream/getStreamCloseActionProcessor.js +1 -0
- package/lib/commonjs/actionProcessor/core/stream/getStreamCloseActionProcessor.js.map +1 -0
- package/lib/commonjs/actionProcessor/core/stream/getStreamReadActionProcessor.js +1 -0
- package/lib/commonjs/actionProcessor/core/stream/getStreamReadActionProcessor.js.map +1 -0
- package/lib/commonjs/actionProcessor/core/stream/index.js +1 -0
- package/lib/commonjs/actionProcessor/core/stream/index.js.map +1 -0
- package/lib/commonjs/actionProcessor/index.js +1 -0
- package/lib/commonjs/actionProcessor/index.js.map +1 -0
- package/lib/commonjs/actionProcessor/webserver/index.js +1 -0
- package/lib/commonjs/actionProcessor/webserver/index.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileDeleteActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileDeleteActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileExistsActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileExistsActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileGenerateTemporarySecureUrlActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileGenerateTemporarySecureUrlActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileIsColdStorageActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileIsColdStorageActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileListDirectoryActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileListDirectoryActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadBinaryContentsActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadBinaryContentsActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadObjectJsonActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadObjectJsonActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadTextContentsActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadTextContentsActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileStreamOpenActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileStreamOpenActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteBinaryContentsActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteBinaryContentsActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteObjectJsonActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteObjectJsonActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteTextContentsActionProcessor.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteTextContentsActionProcessor.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/index.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/index.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/secureUrlUtils.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/secureUrlUtils.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/types.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/types.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/utils.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/file/utils.js.map +1 -0
- package/lib/commonjs/dynamicActionProcessor/index.js +1 -0
- package/lib/commonjs/dynamicActionProcessor/index.js.map +1 -0
- package/lib/commonjs/index.d.ts +1 -0
- package/lib/commonjs/index.js +2 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/traceStoryExecution/controllerWorker.d.ts +11 -0
- package/lib/commonjs/traceStoryExecution/controllerWorker.js +409 -0
- package/lib/commonjs/traceStoryExecution/controllerWorker.js.map +1 -0
- package/lib/commonjs/traceStoryExecution/getSystemTraceStoryActionProcessor.d.ts +2 -0
- package/lib/commonjs/traceStoryExecution/getSystemTraceStoryActionProcessor.js +47 -0
- package/lib/commonjs/traceStoryExecution/getSystemTraceStoryActionProcessor.js.map +1 -0
- package/lib/commonjs/traceStoryExecution/index.d.ts +2 -0
- package/lib/commonjs/traceStoryExecution/index.js +19 -0
- package/lib/commonjs/traceStoryExecution/index.js.map +1 -0
- package/lib/commonjs/traceStoryExecution/resolveSourceMaps.d.ts +19 -0
- package/lib/commonjs/traceStoryExecution/resolveSourceMaps.js +159 -0
- package/lib/commonjs/traceStoryExecution/resolveSourceMaps.js.map +1 -0
- package/lib/commonjs/traceStoryExecution/traceStoryExecution.d.ts +17 -0
- package/lib/commonjs/traceStoryExecution/traceStoryExecution.js +140 -0
- package/lib/commonjs/traceStoryExecution/traceStoryExecution.js.map +1 -0
- package/lib/esm/actionProcessor/core/index.js +1 -0
- package/lib/esm/actionProcessor/core/index.js.map +1 -0
- package/lib/esm/actionProcessor/core/inlineFunction/getInlineFunctionExecuteActionProcessor.js +1 -0
- package/lib/esm/actionProcessor/core/inlineFunction/getInlineFunctionExecuteActionProcessor.js.map +1 -0
- package/lib/esm/actionProcessor/core/inlineFunction/index.js +1 -0
- package/lib/esm/actionProcessor/core/inlineFunction/index.js.map +1 -0
- package/lib/esm/actionProcessor/core/stream/getStreamCloseActionProcessor.js +1 -0
- package/lib/esm/actionProcessor/core/stream/getStreamCloseActionProcessor.js.map +1 -0
- package/lib/esm/actionProcessor/core/stream/getStreamReadActionProcessor.js +1 -0
- package/lib/esm/actionProcessor/core/stream/getStreamReadActionProcessor.js.map +1 -0
- package/lib/esm/actionProcessor/core/stream/index.js +1 -0
- package/lib/esm/actionProcessor/core/stream/index.js.map +1 -0
- package/lib/esm/actionProcessor/index.js +1 -0
- package/lib/esm/actionProcessor/index.js.map +1 -0
- package/lib/esm/actionProcessor/webserver/index.js +1 -0
- package/lib/esm/actionProcessor/webserver/index.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileDeleteActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileDeleteActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileExistsActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileExistsActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileGenerateTemporarySecureUrlActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileGenerateTemporarySecureUrlActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileIsColdStorageActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileIsColdStorageActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileListDirectoryActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileListDirectoryActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadBinaryContentsActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadBinaryContentsActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadObjectJsonActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadObjectJsonActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadTextContentsActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadTextContentsActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileStreamOpenActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileStreamOpenActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteBinaryContentsActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteBinaryContentsActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteObjectJsonActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteObjectJsonActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteTextContentsActionProcessor.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteTextContentsActionProcessor.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/index.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/index.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/secureUrlUtils.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/secureUrlUtils.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/types.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/types.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/file/utils.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/utils.js.map +1 -0
- package/lib/esm/dynamicActionProcessor/index.js +1 -0
- package/lib/esm/dynamicActionProcessor/index.js.map +1 -0
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/traceStoryExecution/controllerWorker.d.ts +11 -0
- package/lib/esm/traceStoryExecution/controllerWorker.js +406 -0
- package/lib/esm/traceStoryExecution/controllerWorker.js.map +1 -0
- package/lib/esm/traceStoryExecution/getSystemTraceStoryActionProcessor.d.ts +2 -0
- package/lib/esm/traceStoryExecution/getSystemTraceStoryActionProcessor.js +32 -0
- package/lib/esm/traceStoryExecution/getSystemTraceStoryActionProcessor.js.map +1 -0
- package/lib/esm/traceStoryExecution/index.d.ts +2 -0
- package/lib/esm/traceStoryExecution/index.js +3 -0
- package/lib/esm/traceStoryExecution/index.js.map +1 -0
- package/lib/esm/traceStoryExecution/resolveSourceMaps.d.ts +19 -0
- package/lib/esm/traceStoryExecution/resolveSourceMaps.js +118 -0
- package/lib/esm/traceStoryExecution/resolveSourceMaps.js.map +1 -0
- package/lib/esm/traceStoryExecution/traceStoryExecution.d.ts +17 -0
- package/lib/esm/traceStoryExecution/traceStoryExecution.js +126 -0
- package/lib/esm/traceStoryExecution/traceStoryExecution.js.map +1 -0
- package/package.json +7 -5
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// The debug controller — runs on a WORKER THREAD and drives the V8 inspector against
|
|
3
|
+
// the MAIN thread, which is executing the story replay (see traceStoryExecution).
|
|
4
|
+
//
|
|
5
|
+
// Strategy (chosen by the phase-0 spike, see trace-replay-plan.md): set a breakpoint on
|
|
6
|
+
// every statement position of the traced scripts up front (getPossibleBreakpoints), then
|
|
7
|
+
// plain resume between hits. This survives the yield -> await -> reader.next() chain of
|
|
8
|
+
// the replay loop regardless of async task boundaries, and wastes no pauses on node
|
|
9
|
+
// internals (unlike blackbox + stepInto).
|
|
10
|
+
//
|
|
11
|
+
// SHIPPING CONSTRAINT: lambdas are single-file webpack bundles, so this can't be loaded
|
|
12
|
+
// as a worker FILE — traceStoryExecution serializes this function with
|
|
13
|
+
// Function.prototype.toString() and runs it via new Worker(source, { eval: true }).
|
|
14
|
+
// It must therefore be fully self-contained:
|
|
15
|
+
// - builtin require()s only, nothing captured from module scope
|
|
16
|
+
// - no syntax tsc would downlevel with module-scope helpers under the ES6 target:
|
|
17
|
+
// no async/await (__awaiter), no generators (__generator), no object spread (__assign)
|
|
18
|
+
//
|
|
19
|
+
// Protocol with the parent (traceStoryExecution):
|
|
20
|
+
// worker -> parent: { type: 'ready', tracedScriptUrls } breakpoints armed, start the replay
|
|
21
|
+
// { type: 'trace', steps, scripts, stats } reply to 'done'
|
|
22
|
+
// { type: 'filterLocations', requestId, scriptUrl, locations } onlyOwnCode: map these through the source map
|
|
23
|
+
// { type: 'fatal', error }
|
|
24
|
+
// parent -> worker: { type: 'done' } replay finished, send the trace
|
|
25
|
+
// { type: 'filteredLocations', requestId, locations } reply to 'filterLocations'
|
|
26
|
+
//
|
|
27
|
+
// The story function is located via globalThis.__qpqTraceStoryFunction (set by the
|
|
28
|
+
// parent before spawning): Runtime.evaluate -> [[FunctionLocation]] -> scriptId. Extra
|
|
29
|
+
// scripts (other bundle chunks, dynamically loaded ones) are matched by scriptPatterns.
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.traceControllerWorkerMain = traceControllerWorkerMain;
|
|
32
|
+
function traceControllerWorkerMain() {
|
|
33
|
+
// require, not import: this function body is the ENTIRE worker source (eval mode) —
|
|
34
|
+
// imports at module scope wouldn't exist when it runs. And eval('require'), not a
|
|
35
|
+
// bare require: bundlers rewrite require() calls at build time (webpack lambda builds
|
|
36
|
+
// turn them into __webpack_require__, which doesn't exist when this string is eval'd
|
|
37
|
+
// in the worker) — eval is opaque to them, so the worker's REAL cjs require survives.
|
|
38
|
+
const dynamicRequire = eval('require');
|
|
39
|
+
const inspector = dynamicRequire('node:inspector');
|
|
40
|
+
const workerThreads = dynamicRequire('node:worker_threads');
|
|
41
|
+
const parentPort = workerThreads.parentPort;
|
|
42
|
+
const options = workerThreads.workerData;
|
|
43
|
+
const session = new inspector.Session();
|
|
44
|
+
session.connectToMainThread();
|
|
45
|
+
const post = (method, params) => new Promise((resolve, reject) => session.post(method, params || {}, (error, result) => error ? reject(new Error(method + ': ' + error.message)) : resolve(result)));
|
|
46
|
+
const fatal = (error) => {
|
|
47
|
+
parentPort.postMessage({ type: 'fatal', error: String((error && error.stack) || error) });
|
|
48
|
+
};
|
|
49
|
+
const scriptPatterns = options.scriptPatterns.map((pattern) => new RegExp(pattern));
|
|
50
|
+
const scriptUrlsById = new Map();
|
|
51
|
+
const instrumentedScriptIds = new Set();
|
|
52
|
+
// The directory of the story function's own script (set during init). Bundles are
|
|
53
|
+
// chunk-SPLIT: a story exported through a factory wrapper (export const x = wrap(story))
|
|
54
|
+
// has its function object created in the FACTORY's chunk, while the code it runs lives
|
|
55
|
+
// in sibling chunks — so every script in the same directory is traced too. This covers
|
|
56
|
+
// any bundle layout (federated /tmp cache, lambda shell, dev-server dist) without
|
|
57
|
+
// needing an environment-specific pattern.
|
|
58
|
+
let storyScriptDirUrl = '';
|
|
59
|
+
// CJS require() scripts get plain-path urls, ESM imports get file:// urls — the same
|
|
60
|
+
// directory can appear both ways in one process, so compare scheme-stripped.
|
|
61
|
+
const normalizeScriptUrl = (url) => url.replace(/^file:\/\//, '').replace(/\\/g, '/');
|
|
62
|
+
const isTraceTargetUrl = (url) => !!url && (scriptPatterns.some((pattern) => pattern.test(url)) || (!!storyScriptDirUrl && normalizeScriptUrl(url).startsWith(storyScriptDirUrl)));
|
|
63
|
+
const steps = [];
|
|
64
|
+
let pauses = 0;
|
|
65
|
+
let breakpoints = 0;
|
|
66
|
+
let truncated = false;
|
|
67
|
+
let localsCaptureMs = 0;
|
|
68
|
+
let instrumentMs = 0;
|
|
69
|
+
let firstPauseAt = 0;
|
|
70
|
+
let ready = false;
|
|
71
|
+
// ── Value summarization ─────────────────────────────────────────────────────
|
|
72
|
+
// RemoteObject -> short display string. Depth comes from generatePreview (one level);
|
|
73
|
+
// the caps keep pathological values from exploding the trace.
|
|
74
|
+
const clampText = (text) => (text.length > options.maxValueLength ? text.slice(0, options.maxValueLength) + '…' : text);
|
|
75
|
+
const summarizeValue = (remoteObject) => {
|
|
76
|
+
if (!remoteObject)
|
|
77
|
+
return 'undefined';
|
|
78
|
+
if (remoteObject.type === 'undefined')
|
|
79
|
+
return 'undefined';
|
|
80
|
+
if (remoteObject.subtype === 'null')
|
|
81
|
+
return 'null';
|
|
82
|
+
if (remoteObject.unserializableValue)
|
|
83
|
+
return remoteObject.unserializableValue;
|
|
84
|
+
if (remoteObject.type === 'string' || remoteObject.type === 'number' || remoteObject.type === 'boolean') {
|
|
85
|
+
return clampText(JSON.stringify(remoteObject.value));
|
|
86
|
+
}
|
|
87
|
+
if (remoteObject.preview) {
|
|
88
|
+
const parts = [];
|
|
89
|
+
const previewProperties = remoteObject.preview.properties || [];
|
|
90
|
+
for (let i = 0; i < previewProperties.length && i < options.maxProperties; i += 1) {
|
|
91
|
+
const property = previewProperties[i];
|
|
92
|
+
const value = property.type === 'string' ? "'" + property.value + "'" : property.value;
|
|
93
|
+
parts.push(remoteObject.preview.subtype === 'array' ? value : property.name + ': ' + value);
|
|
94
|
+
}
|
|
95
|
+
const overflow = remoteObject.preview.overflow || previewProperties.length > options.maxProperties ? ', …' : '';
|
|
96
|
+
const body = parts.join(', ') + overflow;
|
|
97
|
+
return clampText(remoteObject.preview.subtype === 'array' ? '[' + body + ']' : '{' + body + '}');
|
|
98
|
+
}
|
|
99
|
+
return clampText(remoteObject.description || remoteObject.type);
|
|
100
|
+
};
|
|
101
|
+
// ── Deep serialization ──────────────────────────────────────────────────────
|
|
102
|
+
// Runs IN THE DEBUGGEE (Runtime.callFunctionOn with `this` = the value) at the pause,
|
|
103
|
+
// returning a JSON string of the value walked to the caps — what powers expandable
|
|
104
|
+
// object inspection in the viewer. Property reads are try/catch'd (getters can throw);
|
|
105
|
+
// circular refs and overflow become «...» placeholder strings. Same serialization
|
|
106
|
+
// constraints as this whole file: no async/generators/spread (it ships via toString).
|
|
107
|
+
function qpqSerializeValue(maxDepth, maxString, maxProps, maxTotal) {
|
|
108
|
+
const seen = [];
|
|
109
|
+
const walk = (value, depth) => {
|
|
110
|
+
if (value === null || typeof value === 'number' || typeof value === 'boolean')
|
|
111
|
+
return value;
|
|
112
|
+
if (typeof value === 'string')
|
|
113
|
+
return value.length > maxString ? value.slice(0, maxString) + '…' : value;
|
|
114
|
+
if (typeof value === 'undefined')
|
|
115
|
+
return '«undefined»';
|
|
116
|
+
if (typeof value === 'function')
|
|
117
|
+
return '«function ' + (value.name || '') + '»';
|
|
118
|
+
if (typeof value === 'bigint')
|
|
119
|
+
return value.toString() + 'n';
|
|
120
|
+
if (typeof value === 'symbol')
|
|
121
|
+
return value.toString();
|
|
122
|
+
if (value instanceof Date)
|
|
123
|
+
return value.toISOString();
|
|
124
|
+
if (value instanceof Error)
|
|
125
|
+
return '«' + (value.name || 'Error') + ': ' + value.message + '»';
|
|
126
|
+
if (value instanceof Map)
|
|
127
|
+
return '«Map(' + value.size + ')»';
|
|
128
|
+
if (value instanceof Set)
|
|
129
|
+
return '«Set(' + value.size + ')»';
|
|
130
|
+
if (depth >= maxDepth)
|
|
131
|
+
return Array.isArray(value) ? '«array[' + value.length + ']»' : '«object»';
|
|
132
|
+
if (seen.indexOf(value) >= 0)
|
|
133
|
+
return '«circular»';
|
|
134
|
+
seen.push(value);
|
|
135
|
+
let result;
|
|
136
|
+
if (Array.isArray(value)) {
|
|
137
|
+
result = [];
|
|
138
|
+
for (let i = 0; i < value.length && i < maxProps; i += 1) {
|
|
139
|
+
try {
|
|
140
|
+
result.push(walk(value[i], depth + 1));
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
result.push('«threw»');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (value.length > maxProps)
|
|
147
|
+
result.push('«+' + (value.length - maxProps) + ' more»');
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
result = {};
|
|
151
|
+
const keys = Object.keys(value);
|
|
152
|
+
for (let i = 0; i < keys.length && i < maxProps; i += 1) {
|
|
153
|
+
try {
|
|
154
|
+
result[keys[i]] = walk(value[keys[i]], depth + 1);
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
result[keys[i]] = '«threw»';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (keys.length > maxProps)
|
|
161
|
+
result['«more»'] = '+' + (keys.length - maxProps) + ' properties';
|
|
162
|
+
}
|
|
163
|
+
seen.pop();
|
|
164
|
+
return result;
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
const json = JSON.stringify(walk(this, 0));
|
|
168
|
+
return json && json.length <= maxTotal ? json : null;
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const isDeepSerializable = (remoteObject) => !!remoteObject && remoteObject.type === 'object' && remoteObject.subtype !== 'null' && !!remoteObject.objectId;
|
|
175
|
+
// ── Value capture ───────────────────────────────────────────────────────────
|
|
176
|
+
// Every value gets a short preview; object values also get a deep JSON serialization
|
|
177
|
+
// (in the debuggee, see qpqSerializeValue). Never fails — a value that can't be
|
|
178
|
+
// serialized keeps its preview.
|
|
179
|
+
const captureRemoteValue = (remoteObject) => {
|
|
180
|
+
const captured = { preview: summarizeValue(remoteObject) };
|
|
181
|
+
if (!isDeepSerializable(remoteObject)) {
|
|
182
|
+
return { captured, work: Promise.resolve() };
|
|
183
|
+
}
|
|
184
|
+
const work = post('Runtime.callFunctionOn', {
|
|
185
|
+
objectId: remoteObject.objectId,
|
|
186
|
+
functionDeclaration: qpqSerializeValue.toString(),
|
|
187
|
+
arguments: [
|
|
188
|
+
{ value: options.maxValueDepth },
|
|
189
|
+
{ value: options.maxValueLength },
|
|
190
|
+
{ value: options.maxProperties },
|
|
191
|
+
{ value: options.maxSerializedLength },
|
|
192
|
+
],
|
|
193
|
+
returnByValue: true,
|
|
194
|
+
}).then((result) => {
|
|
195
|
+
if (result && result.result && typeof result.result.value === 'string') {
|
|
196
|
+
captured.json = result.result.value;
|
|
197
|
+
}
|
|
198
|
+
}, () => undefined);
|
|
199
|
+
return { captured, work };
|
|
200
|
+
};
|
|
201
|
+
// Local + block scopes only, outermost first so inner scopes win name collisions.
|
|
202
|
+
// At a return break position the frame also carries the value being returned.
|
|
203
|
+
const captureStepValues = (frame) => {
|
|
204
|
+
const startedAt = Date.now();
|
|
205
|
+
const values = { locals: {} };
|
|
206
|
+
const scopes = frame.scopeChain
|
|
207
|
+
.filter((scope) => (scope.type === 'local' || scope.type === 'block') && scope.object && scope.object.objectId)
|
|
208
|
+
.reverse();
|
|
209
|
+
let chain = Promise.resolve();
|
|
210
|
+
scopes.forEach((scope) => {
|
|
211
|
+
chain = chain
|
|
212
|
+
.then(() => post('Runtime.getProperties', { objectId: scope.object.objectId, ownProperties: true, generatePreview: true }))
|
|
213
|
+
.then((response) => {
|
|
214
|
+
let valueChain = Promise.resolve();
|
|
215
|
+
(response.result || []).forEach((property) => {
|
|
216
|
+
const capture = captureRemoteValue(property.value);
|
|
217
|
+
values.locals[property.name] = capture.captured;
|
|
218
|
+
valueChain = valueChain.then(() => capture.work);
|
|
219
|
+
});
|
|
220
|
+
return valueChain;
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
if (frame.returnValue) {
|
|
224
|
+
const returnCapture = captureRemoteValue(frame.returnValue);
|
|
225
|
+
values.returnValue = returnCapture.captured;
|
|
226
|
+
chain = chain.then(() => returnCapture.work);
|
|
227
|
+
}
|
|
228
|
+
return chain.then(() => {
|
|
229
|
+
localsCaptureMs += Date.now() - startedAt;
|
|
230
|
+
return values;
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
// ── Script instrumentation ──────────────────────────────────────────────────
|
|
234
|
+
// onlyOwnCode: the parent (traceStoryExecution) filters candidate locations through
|
|
235
|
+
// the script's source map — only positions originating in the service's own code
|
|
236
|
+
// (not node_modules) get breakpoints. Round-tripped over parentPort because this
|
|
237
|
+
// worker can't load the source-map library (see the shipping constraint above).
|
|
238
|
+
let filterRequestSeq = 0;
|
|
239
|
+
const pendingFilterRequests = new Map();
|
|
240
|
+
const filterLocationsViaParent = (scriptId, locations) => {
|
|
241
|
+
if (!options.onlyOwnCode || locations.length === 0)
|
|
242
|
+
return Promise.resolve(locations);
|
|
243
|
+
filterRequestSeq += 1;
|
|
244
|
+
const requestId = filterRequestSeq;
|
|
245
|
+
return new Promise((resolve) => {
|
|
246
|
+
pendingFilterRequests.set(requestId, resolve);
|
|
247
|
+
parentPort.postMessage({ type: 'filterLocations', requestId, scriptUrl: scriptUrlsById.get(scriptId) || '', locations });
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
// getPossibleBreakpoints CAPS its response (~1000 locations) when the range is large —
|
|
251
|
+
// on a real bundle chunk (tens of thousands of lines) a single call covers only the
|
|
252
|
+
// top of the file and everything below it silently gets no breakpoints. Page through
|
|
253
|
+
// the script, restarting just past the last returned location, until a page comes back
|
|
254
|
+
// empty or stops advancing.
|
|
255
|
+
const getAllPossibleBreakpoints = (scriptId) => {
|
|
256
|
+
const allLocations = [];
|
|
257
|
+
const readPage = (startLine, startColumn) => post('Debugger.getPossibleBreakpoints', { start: { scriptId, lineNumber: startLine, columnNumber: startColumn } }).then((response) => {
|
|
258
|
+
const locations = response.locations || [];
|
|
259
|
+
if (locations.length === 0)
|
|
260
|
+
return allLocations;
|
|
261
|
+
locations.forEach((location) => allLocations.push(location));
|
|
262
|
+
const last = locations[locations.length - 1];
|
|
263
|
+
const nextLine = last.lineNumber;
|
|
264
|
+
const nextColumn = (last.columnNumber || 0) + 1;
|
|
265
|
+
if (nextLine < startLine || (nextLine === startLine && nextColumn <= startColumn))
|
|
266
|
+
return allLocations;
|
|
267
|
+
return readPage(nextLine, nextColumn);
|
|
268
|
+
});
|
|
269
|
+
return readPage(0, 0);
|
|
270
|
+
};
|
|
271
|
+
const instrumentScript = (scriptId) => {
|
|
272
|
+
if (instrumentedScriptIds.has(scriptId))
|
|
273
|
+
return Promise.resolve();
|
|
274
|
+
instrumentedScriptIds.add(scriptId);
|
|
275
|
+
return getAllPossibleBreakpoints(scriptId)
|
|
276
|
+
.then((locations) => filterLocationsViaParent(scriptId, locations))
|
|
277
|
+
.then((locations) => {
|
|
278
|
+
// PIPELINED, not chained: a service's chunks can hold tens of thousands of
|
|
279
|
+
// statement positions, and awaiting each setBreakpoint round-trip serially made
|
|
280
|
+
// instrumentation the dominant setup cost (it blew the ready timeout on real
|
|
281
|
+
// services). The session queues the posts; the backend processes them in order.
|
|
282
|
+
// Per-location failures are tolerated: nearby candidate positions can RESOLVE to
|
|
283
|
+
// the same actual breakpoint ("already exists") — one lost position must not
|
|
284
|
+
// abort the whole trace.
|
|
285
|
+
return Promise.all(locations.map((location) => post('Debugger.setBreakpoint', { location }).then(() => {
|
|
286
|
+
breakpoints += 1;
|
|
287
|
+
}, () => undefined))).then(() => undefined);
|
|
288
|
+
});
|
|
289
|
+
};
|
|
290
|
+
session.on('Debugger.scriptParsed', (message) => {
|
|
291
|
+
const url = message.params.url || '';
|
|
292
|
+
scriptUrlsById.set(message.params.scriptId, url);
|
|
293
|
+
// A traced bundle chunk loaded mid-story (async-node chunk loading) — instrument it
|
|
294
|
+
// as it appears so its statements are traced too.
|
|
295
|
+
if (ready && isTraceTargetUrl(url)) {
|
|
296
|
+
instrumentScript(message.params.scriptId).catch(fatal);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
// ── Pause loop ──────────────────────────────────────────────────────────────
|
|
300
|
+
const onPaused = (message) => {
|
|
301
|
+
pauses += 1;
|
|
302
|
+
if (!firstPauseAt)
|
|
303
|
+
firstPauseAt = Date.now();
|
|
304
|
+
const frame = message.params.callFrames[0];
|
|
305
|
+
// Non-traced pause (e.g. the debugger; statement in qpqExecuteLog) — just resume.
|
|
306
|
+
if (!instrumentedScriptIds.has(frame.location.scriptId)) {
|
|
307
|
+
return post('Debugger.resume');
|
|
308
|
+
}
|
|
309
|
+
// Step budget AND wall-clock budget: locals capture costs several CDP round trips
|
|
310
|
+
// per step, so a big story can take MINUTES against maxSteps alone — long-running
|
|
311
|
+
// invocations stress their whole sandbox (a >5min trace exposed a 300s long-poll
|
|
312
|
+
// timeout bug in the qpq-log-extension, killing the lambda). Past either budget,
|
|
313
|
+
// stop pausing entirely so the replay finishes at full speed.
|
|
314
|
+
if (steps.length >= options.maxSteps || Date.now() - firstPauseAt > options.maxTraceMs) {
|
|
315
|
+
truncated = true;
|
|
316
|
+
return post('Debugger.setBreakpointsActive', { active: false }).then(() => post('Debugger.resume'));
|
|
317
|
+
}
|
|
318
|
+
return captureStepValues(frame)
|
|
319
|
+
.then((values) => {
|
|
320
|
+
const step = {
|
|
321
|
+
scriptId: frame.location.scriptId,
|
|
322
|
+
line: frame.location.lineNumber,
|
|
323
|
+
column: frame.location.columnNumber,
|
|
324
|
+
functionName: frame.functionName || '',
|
|
325
|
+
locals: values.locals,
|
|
326
|
+
};
|
|
327
|
+
if (values.returnValue) {
|
|
328
|
+
step.returnValue = values.returnValue;
|
|
329
|
+
}
|
|
330
|
+
steps.push(step);
|
|
331
|
+
})
|
|
332
|
+
.then(() => post('Debugger.resume'));
|
|
333
|
+
};
|
|
334
|
+
session.on('Debugger.paused', (message) => {
|
|
335
|
+
onPaused(message).catch(fatal);
|
|
336
|
+
});
|
|
337
|
+
// ── Parent protocol (also keeps the worker's event loop alive — an inspector
|
|
338
|
+
// session alone does not, the worker would silently exit) ────────────────────
|
|
339
|
+
parentPort.on('message', (message) => {
|
|
340
|
+
if (message && message.type === 'filteredLocations') {
|
|
341
|
+
const resolveFilter = pendingFilterRequests.get(message.requestId);
|
|
342
|
+
if (resolveFilter) {
|
|
343
|
+
pendingFilterRequests.delete(message.requestId);
|
|
344
|
+
resolveFilter(message.locations || []);
|
|
345
|
+
}
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (message && message.type === 'done') {
|
|
349
|
+
const scripts = {};
|
|
350
|
+
scriptUrlsById.forEach((url, scriptId) => {
|
|
351
|
+
scripts[scriptId] = url;
|
|
352
|
+
});
|
|
353
|
+
const instrumentedScriptUrls = [];
|
|
354
|
+
instrumentedScriptIds.forEach((scriptId) => {
|
|
355
|
+
instrumentedScriptUrls.push(scriptUrlsById.get(scriptId) || scriptId);
|
|
356
|
+
});
|
|
357
|
+
parentPort.postMessage({
|
|
358
|
+
type: 'trace',
|
|
359
|
+
steps,
|
|
360
|
+
scripts,
|
|
361
|
+
stats: { pauses, breakpoints, localsCaptureMs, truncated, instrumentMs, instrumentedScriptUrls },
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
// ── Init: enable domains, find the story function's script, arm breakpoints ──
|
|
366
|
+
const initStartedAt = Date.now();
|
|
367
|
+
post('Runtime.enable')
|
|
368
|
+
.then(() => post('Debugger.enable'))
|
|
369
|
+
.then(() => post('Runtime.evaluate', { expression: 'globalThis.__qpqTraceStoryFunction' }))
|
|
370
|
+
.then((evaluation) => {
|
|
371
|
+
const objectId = evaluation && evaluation.result && evaluation.result.objectId;
|
|
372
|
+
if (!objectId)
|
|
373
|
+
return null;
|
|
374
|
+
return post('Runtime.getProperties', { objectId, ownProperties: true }).then((response) => {
|
|
375
|
+
const functionLocation = (response.internalProperties || []).find((property) => property.name === '[[FunctionLocation]]');
|
|
376
|
+
const location = functionLocation && functionLocation.value && functionLocation.value.value;
|
|
377
|
+
return location ? location.scriptId : null;
|
|
378
|
+
});
|
|
379
|
+
})
|
|
380
|
+
.then((storyFunctionScriptId) => {
|
|
381
|
+
const targetScriptIds = new Set();
|
|
382
|
+
if (storyFunctionScriptId) {
|
|
383
|
+
targetScriptIds.add(storyFunctionScriptId);
|
|
384
|
+
const storyScriptUrl = normalizeScriptUrl(scriptUrlsById.get(storyFunctionScriptId) || '');
|
|
385
|
+
storyScriptDirUrl = storyScriptUrl.slice(0, storyScriptUrl.lastIndexOf('/') + 1);
|
|
386
|
+
}
|
|
387
|
+
scriptUrlsById.forEach((url, scriptId) => {
|
|
388
|
+
if (isTraceTargetUrl(url))
|
|
389
|
+
targetScriptIds.add(scriptId);
|
|
390
|
+
});
|
|
391
|
+
if (targetScriptIds.size === 0) {
|
|
392
|
+
throw new Error('trace controller found no scripts to trace (no story function location, no scriptPatterns match)');
|
|
393
|
+
}
|
|
394
|
+
const instrumentations = [];
|
|
395
|
+
targetScriptIds.forEach((scriptId) => {
|
|
396
|
+
instrumentations.push(instrumentScript(scriptId));
|
|
397
|
+
});
|
|
398
|
+
return Promise.all(instrumentations).then(() => targetScriptIds);
|
|
399
|
+
})
|
|
400
|
+
.then((targetScriptIds) => {
|
|
401
|
+
ready = true;
|
|
402
|
+
instrumentMs = Date.now() - initStartedAt;
|
|
403
|
+
const tracedScriptUrls = [];
|
|
404
|
+
targetScriptIds.forEach((scriptId) => tracedScriptUrls.push(scriptUrlsById.get(scriptId) || scriptId));
|
|
405
|
+
parentPort.postMessage({ type: 'ready', tracedScriptUrls });
|
|
406
|
+
})
|
|
407
|
+
.catch(fatal);
|
|
408
|
+
}
|
|
409
|
+
//# sourceMappingURL=controllerWorker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controllerWorker.js","sourceRoot":"","sources":["../../../src/traceStoryExecution/controllerWorker.ts"],"names":[],"mappings":";AAAA,qFAAqF;AACrF,kFAAkF;AAClF,EAAE;AACF,wFAAwF;AACxF,yFAAyF;AACzF,wFAAwF;AACxF,oFAAoF;AACpF,0CAA0C;AAC1C,EAAE;AACF,wFAAwF;AACxF,uEAAuE;AACvE,oFAAoF;AACpF,6CAA6C;AAC7C,kEAAkE;AAClE,oFAAoF;AACpF,2FAA2F;AAC3F,EAAE;AACF,kDAAkD;AAClD,gGAAgG;AAChG,iFAAiF;AACjF,mIAAmI;AACnI,+CAA+C;AAC/C,yEAAyE;AACzE,uGAAuG;AACvG,EAAE;AACF,mFAAmF;AACnF,uFAAuF;AACvF,wFAAwF;;AAiCxF,8DAsaC;AAtaD,SAAgB,yBAAyB;IACvC,oFAAoF;IACpF,kFAAkF;IAClF,sFAAsF;IACtF,qFAAqF;IACrF,sFAAsF;IACtF,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,cAAc,CAAC,qBAAqB,CAAC,CAAC;IAE5D,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC;IAC5C,MAAM,OAAO,GAA8B,aAAa,CAAC,UAAU,CAAC;IAEpE,MAAM,OAAO,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;IACxC,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAE9B,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,MAAe,EAAgB,EAAE,CAC7D,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAC9B,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,KAAmB,EAAE,MAAe,EAAE,EAAE,CAC1E,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAC3E,CACF,CAAC;IAEJ,MAAM,KAAK,GAAG,CAAC,KAAc,EAAQ,EAAE;QACrC,UAAU,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,IAAK,KAAe,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC;IACvG,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACpF,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;IACjD,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhD,kFAAkF;IAClF,yFAAyF;IACzF,uFAAuF;IACvF,uFAAuF;IACvF,kFAAkF;IAClF,2CAA2C;IAC3C,IAAI,iBAAiB,GAAG,EAAE,CAAC;IAE3B,qFAAqF;IACrF,6EAA6E;IAC7E,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEtG,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAAW,EAAE,CAChD,CAAC,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAEnJ,MAAM,KAAK,GAAmB,EAAE,CAAC;IACjC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,KAAK,GAAG,KAAK,CAAC;IAElB,+EAA+E;IAC/E,sFAAsF;IACtF,8DAA8D;IAC9D,MAAM,SAAS,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAExI,MAAM,cAAc,GAAG,CAAC,YAAiB,EAAU,EAAE;QACnD,IAAI,CAAC,YAAY;YAAE,OAAO,WAAW,CAAC;QACtC,IAAI,YAAY,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,WAAW,CAAC;QAC1D,IAAI,YAAY,CAAC,OAAO,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;QACnD,IAAI,YAAY,CAAC,mBAAmB;YAAE,OAAO,YAAY,CAAC,mBAAmB,CAAC;QAC9E,IAAI,YAAY,CAAC,IAAI,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACxG,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;YACzB,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,MAAM,iBAAiB,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;YAChE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,MAAM,IAAI,CAAC,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;gBACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;gBACvF,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC;YAC9F,CAAC;YACD,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAChH,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;YACzC,OAAO,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC;QACnG,CAAC;QACD,OAAO,SAAS,CAAC,YAAY,CAAC,WAAW,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC,CAAC;IAEF,+EAA+E;IAC/E,sFAAsF;IACtF,mFAAmF;IACnF,uFAAuF;IACvF,kFAAkF;IAClF,sFAAsF;IACtF,SAAS,iBAAiB,CAAY,QAAgB,EAAE,SAAiB,EAAE,QAAgB,EAAE,QAAgB;QAC3G,MAAM,IAAI,GAAU,EAAE,CAAC;QAEvB,MAAM,IAAI,GAAG,CAAC,KAAU,EAAE,KAAa,EAAO,EAAE;YAC9C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;YAC5F,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;YACzG,IAAI,OAAO,KAAK,KAAK,WAAW;gBAAE,OAAO,aAAa,CAAC;YACvD,IAAI,OAAO,KAAK,KAAK,UAAU;gBAAE,OAAO,YAAY,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC;YAChF,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC;YAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;YAEvD,IAAI,KAAK,YAAY,IAAI;gBAAE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;YACtD,IAAI,KAAK,YAAY,KAAK;gBAAE,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;YAC9F,IAAI,KAAK,YAAY,GAAG;gBAAE,OAAO,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;YAC7D,IAAI,KAAK,YAAY,GAAG;gBAAE,OAAO,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;YAE7D,IAAI,KAAK,IAAI,QAAQ;gBAAE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;YAClG,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,OAAO,YAAY,CAAC;YAClD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEjB,IAAI,MAAW,CAAC;YAChB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,GAAG,EAAE,CAAC;gBACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzD,IAAI,CAAC;wBACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;oBACzC,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBACzB,CAAC;gBACH,CAAC;gBACD,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ;oBAAE,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC;YACxF,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxD,IAAI,CAAC;wBACH,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;oBACpD,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;oBAC9B,CAAC;gBACH,CAAC;gBACD,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ;oBAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,aAAa,CAAC;YAChG,CAAC;YAED,IAAI,CAAC,GAAG,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC3C,OAAO,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,MAAM,kBAAkB,GAAG,CAAC,YAAiB,EAAW,EAAE,CACxD,CAAC,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,KAAK,QAAQ,IAAI,YAAY,CAAC,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC;IAEjH,+EAA+E;IAC/E,qFAAqF;IACrF,gFAAgF;IAChF,gCAAgC;IAChC,MAAM,kBAAkB,GAAG,CAAC,YAAiB,EAAuD,EAAE;QACpG,MAAM,QAAQ,GAAkB,EAAE,OAAO,EAAE,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC;QAE1E,IAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE,CAAC;YACtC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,wBAAwB,EAAE;YAC1C,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,mBAAmB,EAAE,iBAAiB,CAAC,QAAQ,EAAE;YACjD,SAAS,EAAE;gBACT,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE;gBAChC,EAAE,KAAK,EAAE,OAAO,CAAC,cAAc,EAAE;gBACjC,EAAE,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE;gBAChC,EAAE,KAAK,EAAE,OAAO,CAAC,mBAAmB,EAAE;aACvC;YACD,aAAa,EAAE,IAAI;SACpB,CAAC,CAAC,IAAI,CACL,CAAC,MAAW,EAAE,EAAE;YACd,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACvE,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YACtC,CAAC;QACH,CAAC,EACD,GAAG,EAAE,CAAC,SAAS,CAChB,CAAC;QAEF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC,CAAC;IAOF,kFAAkF;IAClF,8EAA8E;IAC9E,MAAM,iBAAiB,GAAG,CAAC,KAAU,EAA+B,EAAE;QACpE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAuB,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU;aAC5B,MAAM,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC;aACnH,OAAO,EAAE,CAAC;QAEb,IAAI,KAAK,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;QAChD,MAAM,CAAC,OAAO,CAAC,CAAC,KAAU,EAAE,EAAE;YAC5B,KAAK,GAAG,KAAK;iBACV,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;iBAC1H,IAAI,CAAC,CAAC,QAAa,EAAE,EAAE;gBACtB,IAAI,UAAU,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;gBACrD,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE;oBAChD,MAAM,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBACnD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;oBAChD,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACnD,CAAC,CAAC,CAAC;gBACH,OAAO,UAAU,CAAC;YACpB,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,aAAa,GAAG,kBAAkB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAC5D,MAAM,CAAC,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC;YAC5C,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC/C,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;YACrB,eAAe,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAC1C,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,+EAA+E;IAC/E,oFAAoF;IACpF,iFAAiF;IACjF,iFAAiF;IACjF,gFAAgF;IAChF,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAsC,CAAC;IAE5E,MAAM,wBAAwB,GAAG,CAAC,QAAgB,EAAE,SAAgB,EAAkB,EAAE;QACtF,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEtF,gBAAgB,IAAI,CAAC,CAAC;QACtB,MAAM,SAAS,GAAG,gBAAgB,CAAC;QACnC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,qBAAqB,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC9C,UAAU,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3H,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,uFAAuF;IACvF,oFAAoF;IACpF,qFAAqF;IACrF,uFAAuF;IACvF,4BAA4B;IAC5B,MAAM,yBAAyB,GAAG,CAAC,QAAgB,EAAkB,EAAE;QACrE,MAAM,YAAY,GAAU,EAAE,CAAC;QAE/B,MAAM,QAAQ,GAAG,CAAC,SAAiB,EAAE,WAAmB,EAAkB,EAAE,CAC1E,IAAI,CAAC,iCAAiC,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAa,EAAE,EAAE;YACxI,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC;YAC3C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,YAAY,CAAC;YAEhD,SAAS,CAAC,OAAO,CAAC,CAAC,QAAa,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAElE,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC;YACjC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,QAAQ,GAAG,SAAS,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,UAAU,IAAI,WAAW,CAAC;gBAAE,OAAO,YAAY,CAAC;YAEvG,OAAO,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEL,OAAO,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxB,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAiB,EAAE;QAC3D,IAAI,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAClE,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEpC,OAAO,yBAAyB,CAAC,QAAQ,CAAC;aACvC,IAAI,CAAC,CAAC,SAAgB,EAAE,EAAE,CAAC,wBAAwB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;aACzE,IAAI,CAAC,CAAC,SAAgB,EAAE,EAAE;YACzB,2EAA2E;YAC3E,gFAAgF;YAChF,6EAA6E;YAC7E,gFAAgF;YAChF,iFAAiF;YACjF,6EAA6E;YAC7E,yBAAyB;YACzB,OAAO,OAAO,CAAC,GAAG,CAChB,SAAS,CAAC,GAAG,CAAC,CAAC,QAAa,EAAE,EAAE,CAC9B,IAAI,CAAC,wBAAwB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,CAC/C,GAAG,EAAE;gBACH,WAAW,IAAI,CAAC,CAAC;YACnB,CAAC,EACD,GAAG,EAAE,CAAC,SAAS,CAChB,CACF,CACF,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,uBAAuB,EAAE,CAAC,OAAY,EAAE,EAAE;QACnD,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;QACrC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAEjD,oFAAoF;QACpF,kDAAkD;QAClD,IAAI,KAAK,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACzD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,+EAA+E;IAC/E,MAAM,QAAQ,GAAG,CAAC,OAAY,EAAoB,EAAE;QAClD,MAAM,IAAI,CAAC,CAAC;QACZ,IAAI,CAAC,YAAY;YAAE,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAE3C,kFAAkF;QAClF,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;QAED,kFAAkF;QAClF,kFAAkF;QAClF,iFAAiF;QACjF,iFAAiF;QACjF,8DAA8D;QAC9D,IAAI,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YACvF,SAAS,GAAG,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC,+BAA+B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACtG,CAAC;QAED,OAAO,iBAAiB,CAAC,KAAK,CAAC;aAC5B,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,MAAM,IAAI,GAAiB;gBACzB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ;gBACjC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAU;gBAC/B,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,YAAY;gBACnC,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE;gBACtC,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;YACF,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACvB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;YACxC,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC,CAAC;aACD,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,OAAY,EAAE,EAAE;QAC7C,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAY,EAAE,EAAE;QACxC,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YACpD,MAAM,aAAa,GAAG,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACnE,IAAI,aAAa,EAAE,CAAC;gBAClB,qBAAqB,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAChD,aAAa,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;YACzC,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACvC,MAAM,OAAO,GAA2B,EAAE,CAAC;YAC3C,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;gBACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC;YAC1B,CAAC,CAAC,CAAC;YACH,MAAM,sBAAsB,GAAa,EAAE,CAAC;YAC5C,qBAAqB,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;gBACzC,sBAAsB,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC;YACxE,CAAC,CAAC,CAAC;YACH,UAAU,CAAC,WAAW,CAAC;gBACrB,IAAI,EAAE,OAAO;gBACb,KAAK;gBACL,OAAO;gBACP,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,sBAAsB,EAAE;aACjG,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACjC,IAAI,CAAC,gBAAgB,CAAC;SACnB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;SACnC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,UAAU,EAAE,oCAAoC,EAAE,CAAC,CAAC;SAC1F,IAAI,CAAC,CAAC,UAAe,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,UAAU,IAAI,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC/E,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,OAAO,IAAI,CAAC,uBAAuB,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAa,EAAE,EAAE;YAC7F,MAAM,gBAAgB,GAAG,CAAC,QAAQ,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAa,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,sBAAsB,CAAC,CAAC;YAC/H,MAAM,QAAQ,GAAG,gBAAgB,IAAI,gBAAgB,CAAC,KAAK,IAAI,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC;YAC5F,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,qBAAoC,EAAE,EAAE;QAC7C,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;QAC1C,IAAI,qBAAqB,EAAE,CAAC;YAC1B,eAAe,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;YAE3C,MAAM,cAAc,GAAG,kBAAkB,CAAC,cAAc,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3F,iBAAiB,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACnF,CAAC;QAED,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;YACvC,IAAI,gBAAgB,CAAC,GAAG,CAAC;gBAAE,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QAEH,IAAI,eAAe,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,kGAAkG,CAAC,CAAC;QACtH,CAAC;QAED,MAAM,gBAAgB,GAAoB,EAAE,CAAC;QAC7C,eAAe,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;YACnC,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;IACnE,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,eAAoB,EAAE,EAAE;QAC7B,KAAK,GAAG,IAAI,CAAC;QACb,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC;QAC1C,MAAM,gBAAgB,GAAa,EAAE,CAAC;QACtC,eAAe,CAAC,OAAO,CAAC,CAAC,QAAgB,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC;QAC/G,UAAU,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC;SACD,KAAK,CAAC,KAAK,CAAC,CAAC;AAClB,CAAC","sourcesContent":["// The debug controller — runs on a WORKER THREAD and drives the V8 inspector against\n// the MAIN thread, which is executing the story replay (see traceStoryExecution).\n//\n// Strategy (chosen by the phase-0 spike, see trace-replay-plan.md): set a breakpoint on\n// every statement position of the traced scripts up front (getPossibleBreakpoints), then\n// plain resume between hits. This survives the yield -> await -> reader.next() chain of\n// the replay loop regardless of async task boundaries, and wastes no pauses on node\n// internals (unlike blackbox + stepInto).\n//\n// SHIPPING CONSTRAINT: lambdas are single-file webpack bundles, so this can't be loaded\n// as a worker FILE — traceStoryExecution serializes this function with\n// Function.prototype.toString() and runs it via new Worker(source, { eval: true }).\n// It must therefore be fully self-contained:\n// - builtin require()s only, nothing captured from module scope\n// - no syntax tsc would downlevel with module-scope helpers under the ES6 target:\n// no async/await (__awaiter), no generators (__generator), no object spread (__assign)\n//\n// Protocol with the parent (traceStoryExecution):\n// worker -> parent: { type: 'ready', tracedScriptUrls } breakpoints armed, start the replay\n// { type: 'trace', steps, scripts, stats } reply to 'done'\n// { type: 'filterLocations', requestId, scriptUrl, locations } onlyOwnCode: map these through the source map\n// { type: 'fatal', error }\n// parent -> worker: { type: 'done' } replay finished, send the trace\n// { type: 'filteredLocations', requestId, locations } reply to 'filterLocations'\n//\n// The story function is located via globalThis.__qpqTraceStoryFunction (set by the\n// parent before spawning): Runtime.evaluate -> [[FunctionLocation]] -> scriptId. Extra\n// scripts (other bundle chunks, dynamically loaded ones) are matched by scriptPatterns.\n\nexport interface TraceControllerWorkerData {\n // Regex sources matched against script urls; matching scripts are traced in addition\n // to the story function's own script.\n scriptPatterns: string[];\n\n // Ask the parent to source-map-filter breakpoint locations so only the service's own\n // code gets breakpoints (the parent holds trace-mapping; this eval worker can't).\n onlyOwnCode: boolean;\n\n maxSteps: number;\n maxTraceMs: number;\n maxValueLength: number;\n maxProperties: number;\n maxValueDepth: number;\n maxSerializedLength: number;\n}\n\ninterface TraceRawValue {\n preview: string;\n json?: string;\n}\n\ninterface TraceRawStep {\n scriptId: string;\n line: number; // 0-based (CDP)\n column: number;\n functionName: string;\n locals: Record<string, TraceRawValue>;\n returnValue?: TraceRawValue;\n}\n\nexport function traceControllerWorkerMain(): void {\n // require, not import: this function body is the ENTIRE worker source (eval mode) —\n // imports at module scope wouldn't exist when it runs. And eval('require'), not a\n // bare require: bundlers rewrite require() calls at build time (webpack lambda builds\n // turn them into __webpack_require__, which doesn't exist when this string is eval'd\n // in the worker) — eval is opaque to them, so the worker's REAL cjs require survives.\n const dynamicRequire = eval('require');\n const inspector = dynamicRequire('node:inspector');\n const workerThreads = dynamicRequire('node:worker_threads');\n\n const parentPort = workerThreads.parentPort;\n const options: TraceControllerWorkerData = workerThreads.workerData;\n\n const session = new inspector.Session();\n session.connectToMainThread();\n\n const post = (method: string, params?: object): Promise<any> =>\n new Promise((resolve, reject) =>\n session.post(method, params || {}, (error: Error | null, result: unknown) =>\n error ? reject(new Error(method + ': ' + error.message)) : resolve(result),\n ),\n );\n\n const fatal = (error: unknown): void => {\n parentPort.postMessage({ type: 'fatal', error: String((error && (error as Error).stack) || error) });\n };\n\n const scriptPatterns = options.scriptPatterns.map((pattern) => new RegExp(pattern));\n const scriptUrlsById = new Map<string, string>();\n const instrumentedScriptIds = new Set<string>();\n\n // The directory of the story function's own script (set during init). Bundles are\n // chunk-SPLIT: a story exported through a factory wrapper (export const x = wrap(story))\n // has its function object created in the FACTORY's chunk, while the code it runs lives\n // in sibling chunks — so every script in the same directory is traced too. This covers\n // any bundle layout (federated /tmp cache, lambda shell, dev-server dist) without\n // needing an environment-specific pattern.\n let storyScriptDirUrl = '';\n\n // CJS require() scripts get plain-path urls, ESM imports get file:// urls — the same\n // directory can appear both ways in one process, so compare scheme-stripped.\n const normalizeScriptUrl = (url: string): string => url.replace(/^file:\\/\\//, '').replace(/\\\\/g, '/');\n\n const isTraceTargetUrl = (url: string): boolean =>\n !!url && (scriptPatterns.some((pattern) => pattern.test(url)) || (!!storyScriptDirUrl && normalizeScriptUrl(url).startsWith(storyScriptDirUrl)));\n\n const steps: TraceRawStep[] = [];\n let pauses = 0;\n let breakpoints = 0;\n let truncated = false;\n let localsCaptureMs = 0;\n let instrumentMs = 0;\n let firstPauseAt = 0;\n let ready = false;\n\n // ── Value summarization ─────────────────────────────────────────────────────\n // RemoteObject -> short display string. Depth comes from generatePreview (one level);\n // the caps keep pathological values from exploding the trace.\n const clampText = (text: string): string => (text.length > options.maxValueLength ? text.slice(0, options.maxValueLength) + '…' : text);\n\n const summarizeValue = (remoteObject: any): string => {\n if (!remoteObject) return 'undefined';\n if (remoteObject.type === 'undefined') return 'undefined';\n if (remoteObject.subtype === 'null') return 'null';\n if (remoteObject.unserializableValue) return remoteObject.unserializableValue;\n if (remoteObject.type === 'string' || remoteObject.type === 'number' || remoteObject.type === 'boolean') {\n return clampText(JSON.stringify(remoteObject.value));\n }\n if (remoteObject.preview) {\n const parts: string[] = [];\n const previewProperties = remoteObject.preview.properties || [];\n for (let i = 0; i < previewProperties.length && i < options.maxProperties; i += 1) {\n const property = previewProperties[i];\n const value = property.type === 'string' ? \"'\" + property.value + \"'\" : property.value;\n parts.push(remoteObject.preview.subtype === 'array' ? value : property.name + ': ' + value);\n }\n const overflow = remoteObject.preview.overflow || previewProperties.length > options.maxProperties ? ', …' : '';\n const body = parts.join(', ') + overflow;\n return clampText(remoteObject.preview.subtype === 'array' ? '[' + body + ']' : '{' + body + '}');\n }\n return clampText(remoteObject.description || remoteObject.type);\n };\n\n // ── Deep serialization ──────────────────────────────────────────────────────\n // Runs IN THE DEBUGGEE (Runtime.callFunctionOn with `this` = the value) at the pause,\n // returning a JSON string of the value walked to the caps — what powers expandable\n // object inspection in the viewer. Property reads are try/catch'd (getters can throw);\n // circular refs and overflow become «...» placeholder strings. Same serialization\n // constraints as this whole file: no async/generators/spread (it ships via toString).\n function qpqSerializeValue(this: any, maxDepth: number, maxString: number, maxProps: number, maxTotal: number): string | null {\n const seen: any[] = [];\n\n const walk = (value: any, depth: number): any => {\n if (value === null || typeof value === 'number' || typeof value === 'boolean') return value;\n if (typeof value === 'string') return value.length > maxString ? value.slice(0, maxString) + '…' : value;\n if (typeof value === 'undefined') return '«undefined»';\n if (typeof value === 'function') return '«function ' + (value.name || '') + '»';\n if (typeof value === 'bigint') return value.toString() + 'n';\n if (typeof value === 'symbol') return value.toString();\n\n if (value instanceof Date) return value.toISOString();\n if (value instanceof Error) return '«' + (value.name || 'Error') + ': ' + value.message + '»';\n if (value instanceof Map) return '«Map(' + value.size + ')»';\n if (value instanceof Set) return '«Set(' + value.size + ')»';\n\n if (depth >= maxDepth) return Array.isArray(value) ? '«array[' + value.length + ']»' : '«object»';\n if (seen.indexOf(value) >= 0) return '«circular»';\n seen.push(value);\n\n let result: any;\n if (Array.isArray(value)) {\n result = [];\n for (let i = 0; i < value.length && i < maxProps; i += 1) {\n try {\n result.push(walk(value[i], depth + 1));\n } catch (error) {\n result.push('«threw»');\n }\n }\n if (value.length > maxProps) result.push('«+' + (value.length - maxProps) + ' more»');\n } else {\n result = {};\n const keys = Object.keys(value);\n for (let i = 0; i < keys.length && i < maxProps; i += 1) {\n try {\n result[keys[i]] = walk(value[keys[i]], depth + 1);\n } catch (error) {\n result[keys[i]] = '«threw»';\n }\n }\n if (keys.length > maxProps) result['«more»'] = '+' + (keys.length - maxProps) + ' properties';\n }\n\n seen.pop();\n return result;\n };\n\n try {\n const json = JSON.stringify(walk(this, 0));\n return json && json.length <= maxTotal ? json : null;\n } catch (error) {\n return null;\n }\n }\n\n const isDeepSerializable = (remoteObject: any): boolean =>\n !!remoteObject && remoteObject.type === 'object' && remoteObject.subtype !== 'null' && !!remoteObject.objectId;\n\n // ── Value capture ───────────────────────────────────────────────────────────\n // Every value gets a short preview; object values also get a deep JSON serialization\n // (in the debuggee, see qpqSerializeValue). Never fails — a value that can't be\n // serialized keeps its preview.\n const captureRemoteValue = (remoteObject: any): { captured: TraceRawValue; work: Promise<unknown> } => {\n const captured: TraceRawValue = { preview: summarizeValue(remoteObject) };\n\n if (!isDeepSerializable(remoteObject)) {\n return { captured, work: Promise.resolve() };\n }\n\n const work = post('Runtime.callFunctionOn', {\n objectId: remoteObject.objectId,\n functionDeclaration: qpqSerializeValue.toString(),\n arguments: [\n { value: options.maxValueDepth },\n { value: options.maxValueLength },\n { value: options.maxProperties },\n { value: options.maxSerializedLength },\n ],\n returnByValue: true,\n }).then(\n (result: any) => {\n if (result && result.result && typeof result.result.value === 'string') {\n captured.json = result.result.value;\n }\n },\n () => undefined,\n );\n\n return { captured, work };\n };\n\n interface CapturedStepValues {\n locals: Record<string, TraceRawValue>;\n returnValue?: TraceRawValue;\n }\n\n // Local + block scopes only, outermost first so inner scopes win name collisions.\n // At a return break position the frame also carries the value being returned.\n const captureStepValues = (frame: any): Promise<CapturedStepValues> => {\n const startedAt = Date.now();\n const values: CapturedStepValues = { locals: {} };\n const scopes = frame.scopeChain\n .filter((scope: any) => (scope.type === 'local' || scope.type === 'block') && scope.object && scope.object.objectId)\n .reverse();\n\n let chain: Promise<unknown> = Promise.resolve();\n scopes.forEach((scope: any) => {\n chain = chain\n .then(() => post('Runtime.getProperties', { objectId: scope.object.objectId, ownProperties: true, generatePreview: true }))\n .then((response: any) => {\n let valueChain: Promise<unknown> = Promise.resolve();\n (response.result || []).forEach((property: any) => {\n const capture = captureRemoteValue(property.value);\n values.locals[property.name] = capture.captured;\n valueChain = valueChain.then(() => capture.work);\n });\n return valueChain;\n });\n });\n\n if (frame.returnValue) {\n const returnCapture = captureRemoteValue(frame.returnValue);\n values.returnValue = returnCapture.captured;\n chain = chain.then(() => returnCapture.work);\n }\n\n return chain.then(() => {\n localsCaptureMs += Date.now() - startedAt;\n return values;\n });\n };\n\n // ── Script instrumentation ──────────────────────────────────────────────────\n // onlyOwnCode: the parent (traceStoryExecution) filters candidate locations through\n // the script's source map — only positions originating in the service's own code\n // (not node_modules) get breakpoints. Round-tripped over parentPort because this\n // worker can't load the source-map library (see the shipping constraint above).\n let filterRequestSeq = 0;\n const pendingFilterRequests = new Map<number, (locations: any[]) => void>();\n\n const filterLocationsViaParent = (scriptId: string, locations: any[]): Promise<any[]> => {\n if (!options.onlyOwnCode || locations.length === 0) return Promise.resolve(locations);\n\n filterRequestSeq += 1;\n const requestId = filterRequestSeq;\n return new Promise((resolve) => {\n pendingFilterRequests.set(requestId, resolve);\n parentPort.postMessage({ type: 'filterLocations', requestId, scriptUrl: scriptUrlsById.get(scriptId) || '', locations });\n });\n };\n\n // getPossibleBreakpoints CAPS its response (~1000 locations) when the range is large —\n // on a real bundle chunk (tens of thousands of lines) a single call covers only the\n // top of the file and everything below it silently gets no breakpoints. Page through\n // the script, restarting just past the last returned location, until a page comes back\n // empty or stops advancing.\n const getAllPossibleBreakpoints = (scriptId: string): Promise<any[]> => {\n const allLocations: any[] = [];\n\n const readPage = (startLine: number, startColumn: number): Promise<any[]> =>\n post('Debugger.getPossibleBreakpoints', { start: { scriptId, lineNumber: startLine, columnNumber: startColumn } }).then((response: any) => {\n const locations = response.locations || [];\n if (locations.length === 0) return allLocations;\n\n locations.forEach((location: any) => allLocations.push(location));\n\n const last = locations[locations.length - 1];\n const nextLine = last.lineNumber;\n const nextColumn = (last.columnNumber || 0) + 1;\n if (nextLine < startLine || (nextLine === startLine && nextColumn <= startColumn)) return allLocations;\n\n return readPage(nextLine, nextColumn);\n });\n\n return readPage(0, 0);\n };\n\n const instrumentScript = (scriptId: string): Promise<void> => {\n if (instrumentedScriptIds.has(scriptId)) return Promise.resolve();\n instrumentedScriptIds.add(scriptId);\n\n return getAllPossibleBreakpoints(scriptId)\n .then((locations: any[]) => filterLocationsViaParent(scriptId, locations))\n .then((locations: any[]) => {\n // PIPELINED, not chained: a service's chunks can hold tens of thousands of\n // statement positions, and awaiting each setBreakpoint round-trip serially made\n // instrumentation the dominant setup cost (it blew the ready timeout on real\n // services). The session queues the posts; the backend processes them in order.\n // Per-location failures are tolerated: nearby candidate positions can RESOLVE to\n // the same actual breakpoint (\"already exists\") — one lost position must not\n // abort the whole trace.\n return Promise.all(\n locations.map((location: any) =>\n post('Debugger.setBreakpoint', { location }).then(\n () => {\n breakpoints += 1;\n },\n () => undefined,\n ),\n ),\n ).then(() => undefined);\n });\n };\n\n session.on('Debugger.scriptParsed', (message: any) => {\n const url = message.params.url || '';\n scriptUrlsById.set(message.params.scriptId, url);\n\n // A traced bundle chunk loaded mid-story (async-node chunk loading) — instrument it\n // as it appears so its statements are traced too.\n if (ready && isTraceTargetUrl(url)) {\n instrumentScript(message.params.scriptId).catch(fatal);\n }\n });\n\n // ── Pause loop ──────────────────────────────────────────────────────────────\n const onPaused = (message: any): Promise<unknown> => {\n pauses += 1;\n if (!firstPauseAt) firstPauseAt = Date.now();\n const frame = message.params.callFrames[0];\n\n // Non-traced pause (e.g. the debugger; statement in qpqExecuteLog) — just resume.\n if (!instrumentedScriptIds.has(frame.location.scriptId)) {\n return post('Debugger.resume');\n }\n\n // Step budget AND wall-clock budget: locals capture costs several CDP round trips\n // per step, so a big story can take MINUTES against maxSteps alone — long-running\n // invocations stress their whole sandbox (a >5min trace exposed a 300s long-poll\n // timeout bug in the qpq-log-extension, killing the lambda). Past either budget,\n // stop pausing entirely so the replay finishes at full speed.\n if (steps.length >= options.maxSteps || Date.now() - firstPauseAt > options.maxTraceMs) {\n truncated = true;\n return post('Debugger.setBreakpointsActive', { active: false }).then(() => post('Debugger.resume'));\n }\n\n return captureStepValues(frame)\n .then((values) => {\n const step: TraceRawStep = {\n scriptId: frame.location.scriptId,\n line: frame.location.lineNumber,\n column: frame.location.columnNumber,\n functionName: frame.functionName || '',\n locals: values.locals,\n };\n if (values.returnValue) {\n step.returnValue = values.returnValue;\n }\n steps.push(step);\n })\n .then(() => post('Debugger.resume'));\n };\n\n session.on('Debugger.paused', (message: any) => {\n onPaused(message).catch(fatal);\n });\n\n // ── Parent protocol (also keeps the worker's event loop alive — an inspector\n // session alone does not, the worker would silently exit) ────────────────────\n parentPort.on('message', (message: any) => {\n if (message && message.type === 'filteredLocations') {\n const resolveFilter = pendingFilterRequests.get(message.requestId);\n if (resolveFilter) {\n pendingFilterRequests.delete(message.requestId);\n resolveFilter(message.locations || []);\n }\n return;\n }\n\n if (message && message.type === 'done') {\n const scripts: Record<string, string> = {};\n scriptUrlsById.forEach((url, scriptId) => {\n scripts[scriptId] = url;\n });\n const instrumentedScriptUrls: string[] = [];\n instrumentedScriptIds.forEach((scriptId) => {\n instrumentedScriptUrls.push(scriptUrlsById.get(scriptId) || scriptId);\n });\n parentPort.postMessage({\n type: 'trace',\n steps,\n scripts,\n stats: { pauses, breakpoints, localsCaptureMs, truncated, instrumentMs, instrumentedScriptUrls },\n });\n }\n });\n\n // ── Init: enable domains, find the story function's script, arm breakpoints ──\n const initStartedAt = Date.now();\n post('Runtime.enable')\n .then(() => post('Debugger.enable'))\n .then(() => post('Runtime.evaluate', { expression: 'globalThis.__qpqTraceStoryFunction' }))\n .then((evaluation: any) => {\n const objectId = evaluation && evaluation.result && evaluation.result.objectId;\n if (!objectId) return null;\n return post('Runtime.getProperties', { objectId, ownProperties: true }).then((response: any) => {\n const functionLocation = (response.internalProperties || []).find((property: any) => property.name === '[[FunctionLocation]]');\n const location = functionLocation && functionLocation.value && functionLocation.value.value;\n return location ? location.scriptId : null;\n });\n })\n .then((storyFunctionScriptId: string | null) => {\n const targetScriptIds = new Set<string>();\n if (storyFunctionScriptId) {\n targetScriptIds.add(storyFunctionScriptId);\n\n const storyScriptUrl = normalizeScriptUrl(scriptUrlsById.get(storyFunctionScriptId) || '');\n storyScriptDirUrl = storyScriptUrl.slice(0, storyScriptUrl.lastIndexOf('/') + 1);\n }\n\n scriptUrlsById.forEach((url, scriptId) => {\n if (isTraceTargetUrl(url)) targetScriptIds.add(scriptId);\n });\n\n if (targetScriptIds.size === 0) {\n throw new Error('trace controller found no scripts to trace (no story function location, no scriptPatterns match)');\n }\n\n const instrumentations: Promise<void>[] = [];\n targetScriptIds.forEach((scriptId) => {\n instrumentations.push(instrumentScript(scriptId));\n });\n return Promise.all(instrumentations).then(() => targetScriptIds);\n })\n .then((targetScriptIds: any) => {\n ready = true;\n instrumentMs = Date.now() - initStartedAt;\n const tracedScriptUrls: string[] = [];\n targetScriptIds.forEach((scriptId: string) => tracedScriptUrls.push(scriptUrlsById.get(scriptId) || scriptId));\n parentPort.postMessage({ type: 'ready', tracedScriptUrls });\n })\n .catch(fatal);\n}\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getSystemTraceStoryActionProcessor = void 0;
|
|
13
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
14
|
+
const traceStoryExecution_1 = require("./traceStoryExecution");
|
|
15
|
+
// Shared System::TraceStory processor for node runtimes (lambda and the dev server).
|
|
16
|
+
// Loads the recorded story's real code through the runtime's dynamicModuleLoader (which
|
|
17
|
+
// federates on lambda), then replays it under the tracer. defaultScriptPatterns lets the
|
|
18
|
+
// host add environment-specific scripts to trace (e.g. the lambda federated code cache).
|
|
19
|
+
const getProcessTraceStory = (qpqConfig, defaultScriptPatterns) => {
|
|
20
|
+
return (payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
+
const { storyResult, scriptPatterns, onlyOwnCode } = payload;
|
|
22
|
+
if (!storyResult.qpqFunctionRuntimeInfo) {
|
|
23
|
+
return (0, quidproquo_core_1.actionResultError)(quidproquo_core_1.ErrorTypeEnum.BadRequest, `Story [${storyResult.correlation}] has no qpqFunctionRuntimeInfo - cannot locate its code to trace`);
|
|
24
|
+
}
|
|
25
|
+
const story = yield dynamicModuleLoader(storyResult.qpqFunctionRuntimeInfo);
|
|
26
|
+
if (!story) {
|
|
27
|
+
return (0, quidproquo_core_1.actionResultError)(quidproquo_core_1.ErrorTypeEnum.NotFound, `Unable to dynamically load story for [${storyResult.correlation}]`);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const { trace } = yield (0, traceStoryExecution_1.traceStoryExecution)(storyResult, story, {
|
|
31
|
+
scriptPatterns: [...defaultScriptPatterns, ...(scriptPatterns || [])],
|
|
32
|
+
onlyOwnCode,
|
|
33
|
+
});
|
|
34
|
+
return (0, quidproquo_core_1.actionResult)(trace);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return (0, quidproquo_core_1.actionResultError)(quidproquo_core_1.ErrorTypeEnum.GenericError, `Trace failed for [${storyResult.correlation}]: ${error.message}`);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
const getSystemTraceStoryActionProcessor = (defaultScriptPatterns = []) => (qpqConfig) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
+
return ({
|
|
43
|
+
[quidproquo_core_1.SystemActionType.TraceStory]: getProcessTraceStory(qpqConfig, defaultScriptPatterns),
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
exports.getSystemTraceStoryActionProcessor = getSystemTraceStoryActionProcessor;
|
|
47
|
+
//# sourceMappingURL=getSystemTraceStoryActionProcessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getSystemTraceStoryActionProcessor.js","sourceRoot":"","sources":["../../../src/traceStoryExecution/getSystemTraceStoryActionProcessor.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAcyB;AAEzB,+DAA4D;AAE5D,qFAAqF;AACrF,wFAAwF;AACxF,yFAAyF;AACzF,yFAAyF;AACzF,MAAM,oBAAoB,GAAG,CAAC,SAAoB,EAAE,qBAA+B,EAAmC,EAAE;IACtH,OAAO,CACL,OAAsC,EACtC,OAAqB,EACrB,gBAAqC,EACrC,MAAiB,EACjB,aAAkC,EAClC,mBAAwC,EACxC,EAAE;QACF,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;QAE7D,IAAI,CAAC,WAAW,CAAC,sBAAsB,EAAE,CAAC;YACxC,OAAO,IAAA,mCAAiB,EACtB,+BAAa,CAAC,UAAU,EACxB,UAAU,WAAW,CAAC,WAAW,mEAAmE,CACrG,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC;QAC5E,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAA,mCAAiB,EAAC,+BAAa,CAAC,QAAQ,EAAE,yCAAyC,WAAW,CAAC,WAAW,GAAG,CAAC,CAAC;QACxH,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAA,yCAAmB,EAAC,WAAW,EAAE,KAAK,EAAE;gBAC9D,cAAc,EAAE,CAAC,GAAG,qBAAqB,EAAE,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;gBACrE,WAAW;aACZ,CAAC,CAAC;YAEH,OAAO,IAAA,8BAAY,EAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAA,mCAAiB,EAAC,+BAAa,CAAC,YAAY,EAAE,qBAAqB,WAAW,CAAC,WAAW,MAAO,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QACrI,CAAC;IACH,CAAC,CAAA,CAAC;AACJ,CAAC,CAAC;AAEK,MAAM,kCAAkC,GAC7C,CAAC,wBAAkC,EAAE,EAA+B,EAAE,CACtE,CAAO,SAAoB,EAAgC,EAAE;IAAC,OAAA,CAAC;QAC7D,CAAC,kCAAgB,CAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC,SAAS,EAAE,qBAAqB,CAAC;KACtF,CAAC,CAAA;EAAA,CAAC;AAJQ,QAAA,kCAAkC,sCAI1C","sourcesContent":["import {\n ActionProcessorList,\n ActionProcessorListResolver,\n actionResult,\n actionResultError,\n DynamicModuleLoader,\n ErrorTypeEnum,\n QPQConfig,\n QpqLogger,\n StorySession,\n StorySessionUpdater,\n SystemActionType,\n SystemTraceStoryActionPayload,\n SystemTraceStoryActionProcessor,\n} from 'quidproquo-core';\n\nimport { traceStoryExecution } from './traceStoryExecution';\n\n// Shared System::TraceStory processor for node runtimes (lambda and the dev server).\n// Loads the recorded story's real code through the runtime's dynamicModuleLoader (which\n// federates on lambda), then replays it under the tracer. defaultScriptPatterns lets the\n// host add environment-specific scripts to trace (e.g. the lambda federated code cache).\nconst getProcessTraceStory = (qpqConfig: QPQConfig, defaultScriptPatterns: string[]): SystemTraceStoryActionProcessor => {\n return async (\n payload: SystemTraceStoryActionPayload,\n session: StorySession,\n actionProcessors: ActionProcessorList,\n logger: QpqLogger,\n updateSession: StorySessionUpdater,\n dynamicModuleLoader: DynamicModuleLoader,\n ) => {\n const { storyResult, scriptPatterns, onlyOwnCode } = payload;\n\n if (!storyResult.qpqFunctionRuntimeInfo) {\n return actionResultError(\n ErrorTypeEnum.BadRequest,\n `Story [${storyResult.correlation}] has no qpqFunctionRuntimeInfo - cannot locate its code to trace`,\n );\n }\n\n const story = await dynamicModuleLoader(storyResult.qpqFunctionRuntimeInfo);\n if (!story) {\n return actionResultError(ErrorTypeEnum.NotFound, `Unable to dynamically load story for [${storyResult.correlation}]`);\n }\n\n try {\n const { trace } = await traceStoryExecution(storyResult, story, {\n scriptPatterns: [...defaultScriptPatterns, ...(scriptPatterns || [])],\n onlyOwnCode,\n });\n\n return actionResult(trace);\n } catch (error) {\n return actionResultError(ErrorTypeEnum.GenericError, `Trace failed for [${storyResult.correlation}]: ${(error as Error).message}`);\n }\n };\n};\n\nexport const getSystemTraceStoryActionProcessor =\n (defaultScriptPatterns: string[] = []): ActionProcessorListResolver =>\n async (qpqConfig: QPQConfig): Promise<ActionProcessorList> => ({\n [SystemActionType.TraceStory]: getProcessTraceStory(qpqConfig, defaultScriptPatterns),\n });\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./getSystemTraceStoryActionProcessor"), exports);
|
|
18
|
+
__exportStar(require("./traceStoryExecution"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/traceStoryExecution/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uEAAqD;AACrD,wDAAsC","sourcesContent":["export * from './getSystemTraceStoryActionProcessor';\nexport * from './traceStoryExecution';\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { QpqExecutionTraceSource, QpqExecutionTraceStep, QpqExecutionTraceValue } from 'quidproquo-core';
|
|
2
|
+
interface RawTraceStep {
|
|
3
|
+
scriptId: string;
|
|
4
|
+
line: number;
|
|
5
|
+
column: number;
|
|
6
|
+
functionName: string;
|
|
7
|
+
locals: Record<string, QpqExecutionTraceValue>;
|
|
8
|
+
returnValue?: QpqExecutionTraceValue;
|
|
9
|
+
}
|
|
10
|
+
export declare const filterOwnCodeLocations: <TLocation extends {
|
|
11
|
+
lineNumber: number;
|
|
12
|
+
columnNumber?: number;
|
|
13
|
+
}>(scriptUrl: string, locations: TLocation[]) => TLocation[];
|
|
14
|
+
export interface ResolvedTraceSteps {
|
|
15
|
+
sources: QpqExecutionTraceSource[];
|
|
16
|
+
steps: QpqExecutionTraceStep[];
|
|
17
|
+
}
|
|
18
|
+
export declare const resolveSourceMappedSteps: (rawSteps: RawTraceStep[], scriptUrlsById: Record<string, string>) => ResolvedTraceSteps;
|
|
19
|
+
export {};
|