@arronqzy/blueprint-dsl 1.0.8 → 1.0.10
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/index.cjs +2885 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +778 -0
- package/dist/index.d.ts +778 -0
- package/dist/index.js +2747 -0
- package/dist/index.js.map +1 -0
- package/package.json +14 -5
- package/src/behaviors/default.ts +0 -64
- package/src/blueprint-signal.ts +0 -14
- package/src/clock-config.ts +0 -232
- package/src/core/behavior-registry.ts +0 -32
- package/src/core/behavior.ts +0 -13
- package/src/core/executor.ts +0 -51
- package/src/core/scheduler-loop.ts +0 -13
- package/src/event-config.ts +0 -211
- package/src/fetch-config.ts +0 -281
- package/src/incoming-node-scope.ts +0 -411
- package/src/index.ts +0 -33
- package/src/json-config.ts +0 -37
- package/src/lifecycle.ts +0 -45
- package/src/logic-config.ts +0 -53
- package/src/node-signal.ts +0 -83
- package/src/nodes/definitions.ts +0 -105
- package/src/runtime/blueprint-cycle.ts +0 -136
- package/src/runtime/clock-active-registry.ts +0 -30
- package/src/runtime/clock-scheduler.ts +0 -49
- package/src/runtime/execution-trace.ts +0 -55
- package/src/runtime/graph-runner.ts +0 -1523
- package/src/scope-autocomplete.ts +0 -114
- package/src/scope-template.ts +0 -93
- package/src/swagger.ts +0 -192
- package/src/type.ts +0 -34
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2885 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/lifecycle.ts
|
|
4
|
+
var PAGE_LIFECYCLE_PHASES = [
|
|
5
|
+
"created",
|
|
6
|
+
"beforeMount",
|
|
7
|
+
"mounted",
|
|
8
|
+
"updated",
|
|
9
|
+
"beforeDestroy",
|
|
10
|
+
"destroy",
|
|
11
|
+
"activated",
|
|
12
|
+
"deactivated",
|
|
13
|
+
/** 被其他蓝图的蓝图配置节点引用且收到真信号时触发 */
|
|
14
|
+
"blueprintActivated"
|
|
15
|
+
];
|
|
16
|
+
var PAGE_LIFECYCLE_LABELS = {
|
|
17
|
+
created: "\u5DF2\u521B\u5EFA (created)",
|
|
18
|
+
beforeMount: "\u6302\u8F7D\u524D (beforeMount)",
|
|
19
|
+
mounted: "\u5DF2\u6302\u8F7D (mounted)",
|
|
20
|
+
updated: "\u5DF2\u66F4\u65B0 (updated)",
|
|
21
|
+
beforeDestroy: "\u9500\u6BC1\u524D (beforeDestroy)",
|
|
22
|
+
destroy: "\u5DF2\u9500\u6BC1 (destroy)",
|
|
23
|
+
activated: "\u5DF2\u6FC0\u6D3B (activated)",
|
|
24
|
+
deactivated: "\u5DF2\u505C\u7528 (deactivated)",
|
|
25
|
+
blueprintActivated: "\u84DD\u56FE\u6FC0\u6D3B (blueprintActivated)"
|
|
26
|
+
};
|
|
27
|
+
function createLifecycleSignal(phase) {
|
|
28
|
+
const timestamp = Date.now();
|
|
29
|
+
return {
|
|
30
|
+
phase,
|
|
31
|
+
timestamp,
|
|
32
|
+
isoTime: new Date(timestamp).toISOString()
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/node-signal.ts
|
|
37
|
+
function isTrueSignal(signal) {
|
|
38
|
+
return !!signal && typeof signal === "object" && signal.kind === "true";
|
|
39
|
+
}
|
|
40
|
+
function isFalseSignal(signal) {
|
|
41
|
+
return !!signal && typeof signal === "object" && signal.kind === "false";
|
|
42
|
+
}
|
|
43
|
+
function createTrueSignal(value) {
|
|
44
|
+
const timestamp = Date.now();
|
|
45
|
+
return {
|
|
46
|
+
kind: "true",
|
|
47
|
+
value,
|
|
48
|
+
timestamp,
|
|
49
|
+
isoTime: new Date(timestamp).toISOString()
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function createFalseSignal(error) {
|
|
53
|
+
const timestamp = Date.now();
|
|
54
|
+
return {
|
|
55
|
+
kind: "false",
|
|
56
|
+
error,
|
|
57
|
+
timestamp,
|
|
58
|
+
isoTime: new Date(timestamp).toISOString()
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function combinePortSignalsOr(values) {
|
|
62
|
+
const defined = values.filter((value) => value !== void 0);
|
|
63
|
+
if (defined.length === 0) return void 0;
|
|
64
|
+
for (const value of defined) {
|
|
65
|
+
if (isTrueSignal(value)) {
|
|
66
|
+
return createTrueSignal(value.value);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const falseSignals = defined.filter(isFalseSignal);
|
|
70
|
+
if (falseSignals.length > 0) {
|
|
71
|
+
return createFalseSignal(
|
|
72
|
+
falseSignals.map((signal) => signal.error).join("\uFF1B")
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/core/behavior-registry.ts
|
|
79
|
+
var BehaviorRegistry = class {
|
|
80
|
+
map = /* @__PURE__ */ new Map();
|
|
81
|
+
registerJS(id, fn) {
|
|
82
|
+
this.map.set(id, { kind: "js", run: fn });
|
|
83
|
+
}
|
|
84
|
+
registerBlueprint(id, blueprintId) {
|
|
85
|
+
this.map.set(id, { kind: "blueprint", blueprintId });
|
|
86
|
+
}
|
|
87
|
+
get(id) {
|
|
88
|
+
const b = this.map.get(id);
|
|
89
|
+
if (!b) throw new Error(`Behavior not found: ${id}`);
|
|
90
|
+
return b;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// src/core/executor.ts
|
|
95
|
+
var Executor = class {
|
|
96
|
+
constructor(deps) {
|
|
97
|
+
this.deps = deps;
|
|
98
|
+
}
|
|
99
|
+
deps;
|
|
100
|
+
async executeToken(token) {
|
|
101
|
+
const def = this.deps.getNodeDefinition(token.nodeType);
|
|
102
|
+
const behavior = this.deps.behaviors.get(def.behavior.ref);
|
|
103
|
+
const io = {
|
|
104
|
+
getInput: (name) => this.deps.getInputValue(token, name),
|
|
105
|
+
setOutput: (name, value) => this.deps.setNodeOutput(token, name, value),
|
|
106
|
+
emitFlow: (port = "out") => this.deps.emitFlow(token, port)
|
|
107
|
+
};
|
|
108
|
+
if (behavior.kind === "js") {
|
|
109
|
+
await behavior.run({ token, io });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (behavior.kind === "blueprint") {
|
|
113
|
+
await this.deps.runBlueprint({
|
|
114
|
+
blueprintId: behavior.blueprintId,
|
|
115
|
+
token
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// src/behaviors/default.ts
|
|
123
|
+
var LIFECYCLE_SIGNAL_KEY = "__lifecycleSignal";
|
|
124
|
+
var BLUEPRINT_ACTIVATION_INPUT_KEY = "__blueprintActivationInput";
|
|
125
|
+
var UI_EVENT_PAYLOAD_KEY = "__uiEventPayload";
|
|
126
|
+
var VIEW_EVENT_SIGNAL_KEY = "__viewEventSignal";
|
|
127
|
+
function registerDefaultBehaviors(registry) {
|
|
128
|
+
registry.registerJS("logic-noop", async ({ io }) => {
|
|
129
|
+
const input = await io.getInput("in");
|
|
130
|
+
if (isFalseSignal(input)) {
|
|
131
|
+
io.setOutput("out", input);
|
|
132
|
+
} else if (isTrueSignal(input)) {
|
|
133
|
+
io.setOutput("out", createTrueSignal(input.value));
|
|
134
|
+
} else {
|
|
135
|
+
io.setOutput("out", createTrueSignal(void 0));
|
|
136
|
+
}
|
|
137
|
+
io.emitFlow("out");
|
|
138
|
+
});
|
|
139
|
+
registry.registerJS("lifecycle-emit", async ({ token, io }) => {
|
|
140
|
+
const lifecycle = token.scope.vars.get(LIFECYCLE_SIGNAL_KEY);
|
|
141
|
+
if (!lifecycle) {
|
|
142
|
+
io.setOutput("out", createFalseSignal("\u751F\u547D\u5468\u671F\u4FE1\u53F7\u7F3A\u5931"));
|
|
143
|
+
} else if (lifecycle.phase === "blueprintActivated") {
|
|
144
|
+
io.setOutput(
|
|
145
|
+
"out",
|
|
146
|
+
createTrueSignal(token.scope.vars.get(BLUEPRINT_ACTIVATION_INPUT_KEY))
|
|
147
|
+
);
|
|
148
|
+
} else {
|
|
149
|
+
io.setOutput("out", createTrueSignal(lifecycle));
|
|
150
|
+
}
|
|
151
|
+
io.emitFlow("out");
|
|
152
|
+
});
|
|
153
|
+
registry.registerJS("event-emit", async ({ token, io }) => {
|
|
154
|
+
const payload = token.scope.vars.get(VIEW_EVENT_SIGNAL_KEY);
|
|
155
|
+
if (!payload) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
io.setOutput("out", createTrueSignal(payload));
|
|
159
|
+
io.emitFlow("out");
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/scope-template.ts
|
|
164
|
+
var SCOPE_TOKEN_RE = /\{(scope[^}]*)\}/g;
|
|
165
|
+
function hasScopeTemplate(value) {
|
|
166
|
+
SCOPE_TOKEN_RE.lastIndex = 0;
|
|
167
|
+
return SCOPE_TOKEN_RE.test(value);
|
|
168
|
+
}
|
|
169
|
+
function evaluateScopeExpression(expression, scope) {
|
|
170
|
+
const trimmed = expression.trim();
|
|
171
|
+
if (!trimmed) return void 0;
|
|
172
|
+
try {
|
|
173
|
+
const fn = new Function("scope", `"use strict"; return (${trimmed});`);
|
|
174
|
+
return fn(scope);
|
|
175
|
+
} catch {
|
|
176
|
+
return void 0;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function stringifyScopeValue(value) {
|
|
180
|
+
if (value === null || value === void 0) return "";
|
|
181
|
+
if (typeof value === "string") return value;
|
|
182
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
183
|
+
return String(value);
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
return JSON.stringify(value);
|
|
187
|
+
} catch {
|
|
188
|
+
return String(value);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function isInsideJsonString(before) {
|
|
192
|
+
let inString = false;
|
|
193
|
+
let escape = false;
|
|
194
|
+
for (const ch of before) {
|
|
195
|
+
if (inString) {
|
|
196
|
+
if (escape) {
|
|
197
|
+
escape = false;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (ch === "\\") {
|
|
201
|
+
escape = true;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (ch === '"') inString = false;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (ch === '"') inString = true;
|
|
208
|
+
}
|
|
209
|
+
return inString;
|
|
210
|
+
}
|
|
211
|
+
function replaceScopeTokens(template, scope, replacer) {
|
|
212
|
+
SCOPE_TOKEN_RE.lastIndex = 0;
|
|
213
|
+
return template.replace(
|
|
214
|
+
SCOPE_TOKEN_RE,
|
|
215
|
+
(_match, rawExpr, offset) => replacer(evaluateScopeExpression(rawExpr, scope), offset)
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
function evaluateScopeTemplate(template, scope) {
|
|
219
|
+
if (!hasScopeTemplate(template)) return template;
|
|
220
|
+
return replaceScopeTokens(template, scope, (value) => stringifyScopeValue(value));
|
|
221
|
+
}
|
|
222
|
+
function evaluateScopeTemplateInJson(template, scope) {
|
|
223
|
+
if (!hasScopeTemplate(template)) return template;
|
|
224
|
+
return replaceScopeTokens(template, scope, (value, offset) => {
|
|
225
|
+
if (isInsideJsonString(template.slice(0, offset))) {
|
|
226
|
+
return JSON.stringify(stringifyScopeValue(value)).slice(1, -1);
|
|
227
|
+
}
|
|
228
|
+
if (value === void 0) return "null";
|
|
229
|
+
return JSON.stringify(value);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function looksLikeJsonText(text) {
|
|
233
|
+
const trimmed = text.trim();
|
|
234
|
+
return trimmed.startsWith("{") || trimmed.startsWith("[");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/fetch-config.ts
|
|
238
|
+
var FETCH_HTTP_METHODS = [
|
|
239
|
+
"GET",
|
|
240
|
+
"POST",
|
|
241
|
+
"PUT",
|
|
242
|
+
"PATCH",
|
|
243
|
+
"DELETE",
|
|
244
|
+
"HEAD",
|
|
245
|
+
"OPTIONS"
|
|
246
|
+
];
|
|
247
|
+
var FETCH_RESPONSE_TYPES = ["json", "text"];
|
|
248
|
+
var FETCH_CREDENTIALS = ["omit", "same-origin", "include"];
|
|
249
|
+
var FETCH_MODES = ["cors", "no-cors", "same-origin", "navigate"];
|
|
250
|
+
var FETCH_CACHES = [
|
|
251
|
+
"default",
|
|
252
|
+
"no-store",
|
|
253
|
+
"reload",
|
|
254
|
+
"no-cache",
|
|
255
|
+
"force-cache",
|
|
256
|
+
"only-if-cached"
|
|
257
|
+
];
|
|
258
|
+
var FETCH_REDIRECTS = ["follow", "error", "manual"];
|
|
259
|
+
var DEFAULT_FETCH_REQUEST_CONFIG = {
|
|
260
|
+
url: "",
|
|
261
|
+
method: "GET",
|
|
262
|
+
headers: {},
|
|
263
|
+
body: "",
|
|
264
|
+
credentials: "same-origin",
|
|
265
|
+
mode: "cors",
|
|
266
|
+
cache: "default",
|
|
267
|
+
redirect: "follow",
|
|
268
|
+
responseType: "json",
|
|
269
|
+
timeoutMs: 3e4
|
|
270
|
+
};
|
|
271
|
+
function normalizeFetchRequestConfig(config) {
|
|
272
|
+
return {
|
|
273
|
+
...DEFAULT_FETCH_REQUEST_CONFIG,
|
|
274
|
+
...config,
|
|
275
|
+
headers: {
|
|
276
|
+
...DEFAULT_FETCH_REQUEST_CONFIG.headers,
|
|
277
|
+
...config?.headers
|
|
278
|
+
},
|
|
279
|
+
headersJson: config?.headersJson,
|
|
280
|
+
swaggerEndpoints: config?.swaggerEndpoints
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function joinFetchUrl(base, path) {
|
|
284
|
+
const normalizedBase = base.replace(/\/+$/, "");
|
|
285
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
286
|
+
return `${normalizedBase}${normalizedPath}`;
|
|
287
|
+
}
|
|
288
|
+
function getUrlAuthorityPart(url) {
|
|
289
|
+
const trimmed = url.trim();
|
|
290
|
+
if (!trimmed || trimmed.startsWith("/")) return null;
|
|
291
|
+
const slashIndex = trimmed.indexOf("/");
|
|
292
|
+
return slashIndex === -1 ? trimmed : trimmed.slice(0, slashIndex);
|
|
293
|
+
}
|
|
294
|
+
function isAbsoluteHostAuthority(authority) {
|
|
295
|
+
if (/^localhost$/i.test(authority)) return true;
|
|
296
|
+
if (/^localhost:\d+$/i.test(authority)) return true;
|
|
297
|
+
if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(authority)) return true;
|
|
298
|
+
if (/^\d{1,3}(?:\.\d{1,3}){3}:\d+$/.test(authority)) return true;
|
|
299
|
+
if (/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(authority) && authority.includes(".")) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
if (/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?\.[a-z]{2,}(?::\d+)?$/i.test(authority)) {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
if (/^[a-z0-9-]+:\d+$/i.test(authority)) return true;
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
function hasExplicitUrlScheme(url) {
|
|
309
|
+
return /^[a-z][a-z0-9+.-]*:\/\//i.test(url) || url.startsWith("//");
|
|
310
|
+
}
|
|
311
|
+
function resolveFetchRequestUrl(config) {
|
|
312
|
+
const rawUrl = config.url?.trim() ?? "";
|
|
313
|
+
if (!rawUrl) {
|
|
314
|
+
throw new Error("\u8BF7\u6C42 URL \u672A\u914D\u7F6E");
|
|
315
|
+
}
|
|
316
|
+
if (hasExplicitUrlScheme(rawUrl)) {
|
|
317
|
+
return rawUrl;
|
|
318
|
+
}
|
|
319
|
+
const authority = getUrlAuthorityPart(rawUrl);
|
|
320
|
+
if (authority && isAbsoluteHostAuthority(authority)) {
|
|
321
|
+
return `http://${rawUrl}`;
|
|
322
|
+
}
|
|
323
|
+
const apiBaseUrl = config.apiBaseUrl?.trim();
|
|
324
|
+
if (!apiBaseUrl) {
|
|
325
|
+
return rawUrl;
|
|
326
|
+
}
|
|
327
|
+
return joinFetchUrl(apiBaseUrl, rawUrl);
|
|
328
|
+
}
|
|
329
|
+
function linkAbortSignal(controller, external) {
|
|
330
|
+
if (!external) return () => {
|
|
331
|
+
};
|
|
332
|
+
if (external.aborted) {
|
|
333
|
+
controller.abort();
|
|
334
|
+
return () => {
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const onAbort = () => controller.abort();
|
|
338
|
+
external.addEventListener("abort", onAbort);
|
|
339
|
+
return () => external.removeEventListener("abort", onAbort);
|
|
340
|
+
}
|
|
341
|
+
async function executeFetch(config, options) {
|
|
342
|
+
const rawUrl = config.url?.trim();
|
|
343
|
+
if (!rawUrl) {
|
|
344
|
+
throw new Error("\u8BF7\u6C42 URL \u672A\u914D\u7F6E");
|
|
345
|
+
}
|
|
346
|
+
const url = resolveFetchRequestUrl(config);
|
|
347
|
+
const method = config.method ?? "GET";
|
|
348
|
+
const hasBody = method !== "GET" && method !== "HEAD";
|
|
349
|
+
const body = hasBody && config.body?.trim() ? config.body : void 0;
|
|
350
|
+
if (body && looksLikeJsonText(body)) {
|
|
351
|
+
try {
|
|
352
|
+
JSON.parse(body);
|
|
353
|
+
} catch (error) {
|
|
354
|
+
throw new Error(
|
|
355
|
+
`\u8BF7\u6C42\u4F53\u4E0D\u662F\u6709\u6548 JSON\uFF1A${error instanceof Error ? error.message : "\u683C\u5F0F\u65E0\u6548"}`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const headers = { ...config.headers ?? {} };
|
|
360
|
+
const hasContentType = Object.keys(headers).some(
|
|
361
|
+
(key) => key.toLowerCase() === "content-type"
|
|
362
|
+
);
|
|
363
|
+
if (body && looksLikeJsonText(body) && !hasContentType) {
|
|
364
|
+
headers["Content-Type"] = "application/json";
|
|
365
|
+
}
|
|
366
|
+
const timeoutMs = config.timeoutMs ?? 3e4;
|
|
367
|
+
const controller = new AbortController();
|
|
368
|
+
const unlinkExternal = linkAbortSignal(controller, options?.signal);
|
|
369
|
+
const timer = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
|
|
370
|
+
try {
|
|
371
|
+
const response = await fetch(url, {
|
|
372
|
+
method,
|
|
373
|
+
headers: Object.keys(headers).length > 0 ? headers : void 0,
|
|
374
|
+
body,
|
|
375
|
+
credentials: config.credentials,
|
|
376
|
+
mode: config.mode,
|
|
377
|
+
cache: config.cache,
|
|
378
|
+
redirect: config.redirect,
|
|
379
|
+
signal: controller.signal
|
|
380
|
+
});
|
|
381
|
+
const responseType = config.responseType ?? "json";
|
|
382
|
+
let data;
|
|
383
|
+
if (responseType === "text") {
|
|
384
|
+
data = await response.text();
|
|
385
|
+
} else {
|
|
386
|
+
const text = await response.text();
|
|
387
|
+
if (!text) {
|
|
388
|
+
data = null;
|
|
389
|
+
} else {
|
|
390
|
+
try {
|
|
391
|
+
data = JSON.parse(text);
|
|
392
|
+
} catch {
|
|
393
|
+
if (options?.allowHttpError) {
|
|
394
|
+
data = text;
|
|
395
|
+
} else {
|
|
396
|
+
throw new Error("\u54CD\u5E94\u4E0D\u662F\u6709\u6548\u7684 JSON");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (!response.ok && !options?.allowHttpError) {
|
|
402
|
+
const detail = typeof data === "string" ? data.slice(0, 200) : JSON.stringify(data).slice(0, 200);
|
|
403
|
+
throw new Error(
|
|
404
|
+
`HTTP ${response.status} ${response.statusText}${detail ? `: ${detail}` : ""}`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
status: response.status,
|
|
409
|
+
statusText: response.statusText,
|
|
410
|
+
url: response.url,
|
|
411
|
+
data
|
|
412
|
+
};
|
|
413
|
+
} catch (error) {
|
|
414
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
415
|
+
if (options?.signal?.aborted) {
|
|
416
|
+
throw new Error("\u8BF7\u6C42\u5DF2\u4E2D\u6B62");
|
|
417
|
+
}
|
|
418
|
+
throw new Error(`\u8BF7\u6C42\u8D85\u65F6\uFF08${timeoutMs}ms\uFF09`);
|
|
419
|
+
}
|
|
420
|
+
throw error;
|
|
421
|
+
} finally {
|
|
422
|
+
unlinkExternal();
|
|
423
|
+
if (timer) clearTimeout(timer);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// src/scope-autocomplete.ts
|
|
428
|
+
function getValueAtPath(scope, path) {
|
|
429
|
+
let current = scope;
|
|
430
|
+
for (const part of path) {
|
|
431
|
+
if (current === null || typeof current !== "object") return void 0;
|
|
432
|
+
current = current[part];
|
|
433
|
+
}
|
|
434
|
+
return current;
|
|
435
|
+
}
|
|
436
|
+
function listObjectKeys(value) {
|
|
437
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
438
|
+
return [];
|
|
439
|
+
}
|
|
440
|
+
return Object.keys(value);
|
|
441
|
+
}
|
|
442
|
+
function parseScopeAutocomplete(text, cursor, scope) {
|
|
443
|
+
const before = text.slice(0, cursor);
|
|
444
|
+
const templateStart = before.lastIndexOf("{");
|
|
445
|
+
if (templateStart < 0) return null;
|
|
446
|
+
const inner = before.slice(templateStart + 1);
|
|
447
|
+
if (inner.includes("}")) return null;
|
|
448
|
+
if (!inner.startsWith("scope")) return null;
|
|
449
|
+
let body = inner.slice("scope".length);
|
|
450
|
+
if (body === "" || body === "?") {
|
|
451
|
+
return { templateStart, cursor, path: [], partialKey: "" };
|
|
452
|
+
}
|
|
453
|
+
if (!body.startsWith("?.")) return null;
|
|
454
|
+
body = body.slice(2);
|
|
455
|
+
if (body === "") {
|
|
456
|
+
return { templateStart, cursor, path: [], partialKey: "" };
|
|
457
|
+
}
|
|
458
|
+
const segments = body.split("?.");
|
|
459
|
+
const endsWithSeparator = inner.endsWith("?.");
|
|
460
|
+
if (endsWithSeparator) {
|
|
461
|
+
const path = segments.filter((segment) => segment.length > 0);
|
|
462
|
+
return { templateStart, cursor, path, partialKey: "" };
|
|
463
|
+
}
|
|
464
|
+
const lastSegment = segments[segments.length - 1] ?? "";
|
|
465
|
+
const prefixSegments = segments.slice(0, -1).filter((segment) => segment.length > 0);
|
|
466
|
+
const parent = getValueAtPath(scope, prefixSegments);
|
|
467
|
+
const keys = listObjectKeys(parent);
|
|
468
|
+
if (lastSegment.length === 0) {
|
|
469
|
+
return { templateStart, cursor, path: prefixSegments, partialKey: "" };
|
|
470
|
+
}
|
|
471
|
+
if (keys.includes(lastSegment)) {
|
|
472
|
+
return {
|
|
473
|
+
templateStart,
|
|
474
|
+
cursor,
|
|
475
|
+
path: [...prefixSegments, lastSegment],
|
|
476
|
+
partialKey: ""
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
templateStart,
|
|
481
|
+
cursor,
|
|
482
|
+
path: prefixSegments,
|
|
483
|
+
partialKey: lastSegment
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function getScopeAutocompleteSuggestions(scope, state) {
|
|
487
|
+
const parent = state.partialKey.length > 0 ? getValueAtPath(scope, state.path) : state.path.length > 0 ? getValueAtPath(scope, state.path) : scope;
|
|
488
|
+
const keys = listObjectKeys(parent);
|
|
489
|
+
if (state.partialKey.length === 0) return keys;
|
|
490
|
+
return keys.filter((key) => key.startsWith(state.partialKey));
|
|
491
|
+
}
|
|
492
|
+
function buildScopeExpression(path, selectedKey) {
|
|
493
|
+
return `scope?.${[...path, selectedKey].join("?.")}`;
|
|
494
|
+
}
|
|
495
|
+
function applyScopeAutocompleteSelection(text, state, selectedKey) {
|
|
496
|
+
const expr = buildScopeExpression(state.path, selectedKey);
|
|
497
|
+
const before = text.slice(0, state.templateStart + 1);
|
|
498
|
+
const after = text.slice(state.cursor);
|
|
499
|
+
const value = `${before}${expr}${after}`;
|
|
500
|
+
const cursor = before.length + expr.length;
|
|
501
|
+
return { value, cursor };
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/incoming-node-scope.ts
|
|
505
|
+
var FETCH_SCOPE_AUTOCOMPLETE_FALLBACK = {
|
|
506
|
+
id: "",
|
|
507
|
+
name: "",
|
|
508
|
+
type: "",
|
|
509
|
+
role: "",
|
|
510
|
+
port: "out",
|
|
511
|
+
kind: "pending",
|
|
512
|
+
value: {},
|
|
513
|
+
error: "",
|
|
514
|
+
timestamp: 0,
|
|
515
|
+
isoTime: ""
|
|
516
|
+
};
|
|
517
|
+
function resolveFetchScopeAutocompleteRoot(scope) {
|
|
518
|
+
return scope === void 0 ? FETCH_SCOPE_AUTOCOMPLETE_FALLBACK : scope;
|
|
519
|
+
}
|
|
520
|
+
function readOutputSignal(output) {
|
|
521
|
+
if (output === void 0) return { kind: "pending" };
|
|
522
|
+
if (isTrueSignal(output)) {
|
|
523
|
+
return {
|
|
524
|
+
kind: "true",
|
|
525
|
+
value: output.value,
|
|
526
|
+
timestamp: output.timestamp,
|
|
527
|
+
isoTime: output.isoTime
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
if (isFalseSignal(output)) {
|
|
531
|
+
return {
|
|
532
|
+
kind: "false",
|
|
533
|
+
error: output.error,
|
|
534
|
+
timestamp: output.timestamp,
|
|
535
|
+
isoTime: output.isoTime
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
if (output && typeof output === "object" && "kind" in output) {
|
|
539
|
+
const rec = output;
|
|
540
|
+
if (rec.kind === "true") {
|
|
541
|
+
return {
|
|
542
|
+
kind: "true",
|
|
543
|
+
value: rec.value,
|
|
544
|
+
timestamp: rec.timestamp,
|
|
545
|
+
isoTime: rec.isoTime
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
if (rec.kind === "false") {
|
|
549
|
+
return {
|
|
550
|
+
kind: "false",
|
|
551
|
+
error: rec.error,
|
|
552
|
+
timestamp: rec.timestamp,
|
|
553
|
+
isoTime: rec.isoTime
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return { kind: "true", value: output };
|
|
558
|
+
}
|
|
559
|
+
function createIncomingNodeScopeEntry(node, port, output) {
|
|
560
|
+
const id = node?.id ?? "in";
|
|
561
|
+
const signal = readOutputSignal(output);
|
|
562
|
+
return {
|
|
563
|
+
id,
|
|
564
|
+
name: node?.label?.trim() || node?.name?.trim() || id,
|
|
565
|
+
type: node?.nodeType || node?.type || "unknown",
|
|
566
|
+
role: node?.role,
|
|
567
|
+
port,
|
|
568
|
+
...signal
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
function buildIncomingNodeScope(entries) {
|
|
572
|
+
if (entries.length === 0) return void 0;
|
|
573
|
+
if (entries.length === 1) return entries[0];
|
|
574
|
+
const scoped = {};
|
|
575
|
+
for (const entry of entries) {
|
|
576
|
+
scoped[entry.id] = entry;
|
|
577
|
+
}
|
|
578
|
+
return scoped;
|
|
579
|
+
}
|
|
580
|
+
function collectIncomingNodeScopeEntries(options) {
|
|
581
|
+
const targetPort = options.targetPort ?? "in";
|
|
582
|
+
const nodeById = new Map(options.nodes.map((node) => [node.id, node]));
|
|
583
|
+
const inbound = options.edges.filter(
|
|
584
|
+
(edge) => edge.target === options.targetNodeId && (edge.targetHandle ?? "in") === targetPort
|
|
585
|
+
);
|
|
586
|
+
const seen = /* @__PURE__ */ new Set();
|
|
587
|
+
const entries = [];
|
|
588
|
+
for (const edge of inbound) {
|
|
589
|
+
const port = edge.sourceHandle ?? "out";
|
|
590
|
+
const key = `${edge.source}:${port}`;
|
|
591
|
+
if (seen.has(key)) continue;
|
|
592
|
+
seen.add(key);
|
|
593
|
+
const output = options.getOutput?.(edge.source, port);
|
|
594
|
+
entries.push(
|
|
595
|
+
createIncomingNodeScopeEntry(nodeById.get(edge.source), port, output)
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
return entries;
|
|
599
|
+
}
|
|
600
|
+
function resolveFetchIncomingScope(options) {
|
|
601
|
+
const entries = collectIncomingNodeScopeEntries({
|
|
602
|
+
targetNodeId: options.fetchNodeId,
|
|
603
|
+
targetPort: options.inputPort,
|
|
604
|
+
nodes: options.nodes,
|
|
605
|
+
edges: options.edges,
|
|
606
|
+
getOutput: options.getOutput
|
|
607
|
+
});
|
|
608
|
+
if (entries.length > 0) return buildIncomingNodeScope(entries);
|
|
609
|
+
if (options.fallbackInput === void 0) return void 0;
|
|
610
|
+
return createIncomingNodeScopeEntry(
|
|
611
|
+
{ id: "in", label: "in", nodeType: "input" },
|
|
612
|
+
options.inputPort ?? "in",
|
|
613
|
+
options.fallbackInput
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
function latestTraceOutputsByNode(entries) {
|
|
617
|
+
const map = {};
|
|
618
|
+
for (const entry of entries) {
|
|
619
|
+
map[entry.nodeId] = entry.outputs ?? {};
|
|
620
|
+
}
|
|
621
|
+
return map;
|
|
622
|
+
}
|
|
623
|
+
function resolveTemplateString(value, scope) {
|
|
624
|
+
if (value === void 0) return void 0;
|
|
625
|
+
if (!hasScopeTemplate(value)) return value;
|
|
626
|
+
return evaluateScopeTemplate(value, scope);
|
|
627
|
+
}
|
|
628
|
+
function parseJsonText(text) {
|
|
629
|
+
try {
|
|
630
|
+
return { ok: true, value: JSON.parse(text) };
|
|
631
|
+
} catch (error) {
|
|
632
|
+
return {
|
|
633
|
+
ok: false,
|
|
634
|
+
error: error instanceof Error ? error.message : "JSON \u683C\u5F0F\u65E0\u6548"
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
function validateFetchJsonText(text, options) {
|
|
639
|
+
const trimmed = text.trim();
|
|
640
|
+
if (!trimmed) {
|
|
641
|
+
if (options?.allowEmpty === false) {
|
|
642
|
+
return { ok: false, error: "\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A" };
|
|
643
|
+
}
|
|
644
|
+
return { ok: true };
|
|
645
|
+
}
|
|
646
|
+
if (isWholeScopeExpression(trimmed)) {
|
|
647
|
+
return { ok: true };
|
|
648
|
+
}
|
|
649
|
+
if (!looksLikeJsonText(trimmed)) {
|
|
650
|
+
return { ok: true };
|
|
651
|
+
}
|
|
652
|
+
const parsed = parseJsonText(trimmed);
|
|
653
|
+
return parsed.ok ? { ok: true } : parsed;
|
|
654
|
+
}
|
|
655
|
+
function resolveFetchBody(body, scope) {
|
|
656
|
+
if (body === void 0) return void 0;
|
|
657
|
+
const trimmed = body.trim();
|
|
658
|
+
if (!trimmed) return body;
|
|
659
|
+
if (scope !== void 0 && isWholeScopeExpression(trimmed)) {
|
|
660
|
+
const value = evaluateScopeExpression(trimmed.slice(1, -1), scope);
|
|
661
|
+
if (value === void 0) return "";
|
|
662
|
+
if (typeof value === "string") return value;
|
|
663
|
+
return stringifyScopeValue(value);
|
|
664
|
+
}
|
|
665
|
+
if (scope === void 0 || !hasScopeTemplate(body)) return body;
|
|
666
|
+
if (looksLikeJsonText(trimmed)) {
|
|
667
|
+
return evaluateScopeTemplateInJson(body, scope);
|
|
668
|
+
}
|
|
669
|
+
return evaluateScopeTemplate(body, scope);
|
|
670
|
+
}
|
|
671
|
+
function getFetchBodyValidationError(body, resolvedBody) {
|
|
672
|
+
const source = (resolvedBody ?? body ?? "").trim();
|
|
673
|
+
if (!source) return null;
|
|
674
|
+
if (isWholeScopeExpression(source)) return null;
|
|
675
|
+
if (!looksLikeJsonText(source)) return null;
|
|
676
|
+
const parsed = parseJsonText(source);
|
|
677
|
+
if (parsed.ok) return null;
|
|
678
|
+
if (hasScopeTemplate(source)) return null;
|
|
679
|
+
return parsed.error;
|
|
680
|
+
}
|
|
681
|
+
function getFetchHeadersValidationError(config, scope) {
|
|
682
|
+
const raw = (config.headersJson ?? "").trim();
|
|
683
|
+
if (!raw) return null;
|
|
684
|
+
if (isWholeScopeExpression(raw) || hasScopeTemplate(raw)) {
|
|
685
|
+
if (scope === void 0) return null;
|
|
686
|
+
const parsed2 = parseFetchHeadersJson(raw, scope);
|
|
687
|
+
if (!parsed2) return "\u8BF7\u6C42\u5934\u6A21\u677F\u89E3\u6790\u540E\u4E0D\u662F\u6709\u6548\u7684 JSON \u5BF9\u8C61";
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
const result = validateFetchJsonText(raw);
|
|
691
|
+
if (!result.ok) return result.error;
|
|
692
|
+
const parsed = parseFetchHeadersJson(raw, scope);
|
|
693
|
+
if (!parsed) return "\u8BF7\u6C42\u5934\u4E0D\u662F\u6709\u6548\u7684 JSON \u5BF9\u8C61";
|
|
694
|
+
return null;
|
|
695
|
+
}
|
|
696
|
+
function isWholeScopeExpression(text) {
|
|
697
|
+
const trimmed = text.trim();
|
|
698
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return false;
|
|
699
|
+
return trimmed.slice(1, -1).trim().startsWith("scope");
|
|
700
|
+
}
|
|
701
|
+
function asHeaderRecord(value) {
|
|
702
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
703
|
+
const headers = {};
|
|
704
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
705
|
+
if (raw === void 0 || raw === null) continue;
|
|
706
|
+
headers[key] = typeof raw === "string" ? raw : stringifyScopeValue(raw);
|
|
707
|
+
}
|
|
708
|
+
return headers;
|
|
709
|
+
}
|
|
710
|
+
function applyScopeToHeaderRecord(headers, scope) {
|
|
711
|
+
if (scope === void 0) return headers;
|
|
712
|
+
return Object.fromEntries(
|
|
713
|
+
Object.entries(headers).map(([key, value]) => [
|
|
714
|
+
evaluateScopeTemplate(String(key), scope),
|
|
715
|
+
evaluateScopeTemplate(value == null ? "" : String(value), scope)
|
|
716
|
+
])
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
function parseFetchHeadersJson(text, scope) {
|
|
720
|
+
const trimmed = text.trim();
|
|
721
|
+
if (!trimmed) return {};
|
|
722
|
+
if (isWholeScopeExpression(trimmed)) {
|
|
723
|
+
if (scope === void 0) return void 0;
|
|
724
|
+
const inner = trimmed.slice(1, -1);
|
|
725
|
+
return asHeaderRecord(evaluateScopeExpression(inner, scope));
|
|
726
|
+
}
|
|
727
|
+
let jsonText = trimmed;
|
|
728
|
+
if (scope !== void 0 && hasScopeTemplate(trimmed) && looksLikeJsonText(trimmed)) {
|
|
729
|
+
jsonText = evaluateScopeTemplateInJson(trimmed, scope);
|
|
730
|
+
}
|
|
731
|
+
try {
|
|
732
|
+
const parsed = asHeaderRecord(JSON.parse(jsonText));
|
|
733
|
+
if (!parsed) return void 0;
|
|
734
|
+
if (jsonText === trimmed) {
|
|
735
|
+
return applyScopeToHeaderRecord(parsed, scope);
|
|
736
|
+
}
|
|
737
|
+
return parsed;
|
|
738
|
+
} catch {
|
|
739
|
+
return void 0;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
function draftFetchHeadersText(config) {
|
|
743
|
+
if (config.headersJson !== void 0) return config.headersJson;
|
|
744
|
+
try {
|
|
745
|
+
return JSON.stringify(config.headers ?? {}, null, 2);
|
|
746
|
+
} catch {
|
|
747
|
+
return "{}";
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function resolveFetchHeaders(config, scope) {
|
|
751
|
+
const rawJson = config.headersJson;
|
|
752
|
+
if (rawJson !== void 0 && rawJson.trim() !== "") {
|
|
753
|
+
const parsed = parseFetchHeadersJson(rawJson, scope);
|
|
754
|
+
if (parsed) return parsed;
|
|
755
|
+
}
|
|
756
|
+
if (!config.headers) return config.headers;
|
|
757
|
+
return applyScopeToHeaderRecord(config.headers, scope);
|
|
758
|
+
}
|
|
759
|
+
function applyFetchConfigScope(config, scope) {
|
|
760
|
+
const headers = resolveFetchHeaders(config, scope);
|
|
761
|
+
const body = resolveFetchBody(config.body, scope);
|
|
762
|
+
if (scope === void 0) {
|
|
763
|
+
if (headers === config.headers && body === config.body) return config;
|
|
764
|
+
return { ...config, headers, body };
|
|
765
|
+
}
|
|
766
|
+
return {
|
|
767
|
+
...config,
|
|
768
|
+
url: resolveTemplateString(config.url, scope) ?? "",
|
|
769
|
+
apiBaseUrl: resolveTemplateString(config.apiBaseUrl, scope),
|
|
770
|
+
body,
|
|
771
|
+
headers
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
function fetchConfigHasScopeTemplate(config) {
|
|
775
|
+
if (hasScopeTemplate(config.url ?? "")) return true;
|
|
776
|
+
if (hasScopeTemplate(config.apiBaseUrl ?? "")) return true;
|
|
777
|
+
if (hasScopeTemplate(config.body ?? "")) return true;
|
|
778
|
+
if (hasScopeTemplate(config.headersJson ?? "")) return true;
|
|
779
|
+
const headers = config.headers ?? {};
|
|
780
|
+
return Object.entries(headers).some(
|
|
781
|
+
([key, value]) => hasScopeTemplate(key) || hasScopeTemplate(String(value ?? ""))
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/json-config.ts
|
|
786
|
+
var DEFAULT_JSON_NODE_CONFIG = {
|
|
787
|
+
jsonString: "{}"
|
|
788
|
+
};
|
|
789
|
+
function validateJsonString(jsonString) {
|
|
790
|
+
const raw = jsonString?.trim();
|
|
791
|
+
if (!raw) {
|
|
792
|
+
return { ok: false, error: "JSON \u4E0D\u80FD\u4E3A\u7A7A" };
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
const value = JSON.parse(raw);
|
|
796
|
+
if (value === null || typeof value !== "object") {
|
|
797
|
+
return { ok: false, error: "JSON \u6839\u8282\u70B9\u5FC5\u987B\u662F object \u6216 array" };
|
|
798
|
+
}
|
|
799
|
+
return { ok: true, value };
|
|
800
|
+
} catch (error) {
|
|
801
|
+
return {
|
|
802
|
+
ok: false,
|
|
803
|
+
error: error instanceof Error ? error.message : "JSON \u683C\u5F0F\u65E0\u6548"
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function parseJsonConfig(config) {
|
|
808
|
+
const result = validateJsonString(config.jsonString ?? "");
|
|
809
|
+
if (!result.ok) {
|
|
810
|
+
throw new Error(result.error);
|
|
811
|
+
}
|
|
812
|
+
return result.value;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// src/storage-config.ts
|
|
816
|
+
var STORAGE_KINDS = ["session", "local"];
|
|
817
|
+
var DEFAULT_STORAGE_NODE_CONFIG = {
|
|
818
|
+
read: { storage: "local", key: "" },
|
|
819
|
+
set: { storages: [], key: "", value: "" }
|
|
820
|
+
};
|
|
821
|
+
function isStorageKind(value) {
|
|
822
|
+
return value === "session" || value === "local";
|
|
823
|
+
}
|
|
824
|
+
function uniqueStorageKinds(kinds) {
|
|
825
|
+
const next = /* @__PURE__ */ new Set();
|
|
826
|
+
for (const kind of kinds ?? []) {
|
|
827
|
+
if (isStorageKind(kind)) next.add(kind);
|
|
828
|
+
}
|
|
829
|
+
return STORAGE_KINDS.filter((kind) => next.has(kind));
|
|
830
|
+
}
|
|
831
|
+
function normalizeStorageConfig(config) {
|
|
832
|
+
const read = config?.read;
|
|
833
|
+
const set = config?.set;
|
|
834
|
+
return {
|
|
835
|
+
read: {
|
|
836
|
+
storage: read?.storage === "session" ? "session" : "local",
|
|
837
|
+
key: typeof read?.key === "string" ? read.key : ""
|
|
838
|
+
},
|
|
839
|
+
set: {
|
|
840
|
+
storages: uniqueStorageKinds(set?.storages),
|
|
841
|
+
key: typeof set?.key === "string" ? set.key : "",
|
|
842
|
+
value: typeof set?.value === "string" ? set.value : ""
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
function isStorageReadConfigured(config) {
|
|
847
|
+
return Boolean(config.read?.key?.trim());
|
|
848
|
+
}
|
|
849
|
+
function isStorageSetConfigured(config) {
|
|
850
|
+
return Boolean(config.set?.key?.trim()) && (config.set?.storages?.length ?? 0) > 0;
|
|
851
|
+
}
|
|
852
|
+
function resolveStorageWriteValue(template, scope) {
|
|
853
|
+
const raw = template ?? "";
|
|
854
|
+
const trimmed = raw.trim();
|
|
855
|
+
if (!trimmed) return "";
|
|
856
|
+
if (isWholeScopeExpression(trimmed)) {
|
|
857
|
+
const value = evaluateScopeExpression(trimmed.slice(1, -1), scope);
|
|
858
|
+
return value === void 0 ? "" : value;
|
|
859
|
+
}
|
|
860
|
+
if (hasScopeTemplate(raw)) {
|
|
861
|
+
return evaluateScopeTemplate(raw, scope);
|
|
862
|
+
}
|
|
863
|
+
return raw;
|
|
864
|
+
}
|
|
865
|
+
function serializeStorageValue(value) {
|
|
866
|
+
if (value === void 0 || value === null) return "";
|
|
867
|
+
if (typeof value === "string") return value;
|
|
868
|
+
try {
|
|
869
|
+
return JSON.stringify(value);
|
|
870
|
+
} catch {
|
|
871
|
+
return String(value);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function deserializeStorageValue(raw) {
|
|
875
|
+
if (raw === null) return null;
|
|
876
|
+
const trimmed = raw.trim();
|
|
877
|
+
if (!trimmed) return raw;
|
|
878
|
+
if (!looksLikeJsonText(trimmed)) return raw;
|
|
879
|
+
try {
|
|
880
|
+
return JSON.parse(trimmed);
|
|
881
|
+
} catch {
|
|
882
|
+
return raw;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
function getDefaultStorageAccessors() {
|
|
886
|
+
if (typeof window === "undefined") return null;
|
|
887
|
+
try {
|
|
888
|
+
return {
|
|
889
|
+
session: window.sessionStorage,
|
|
890
|
+
local: window.localStorage
|
|
891
|
+
};
|
|
892
|
+
} catch {
|
|
893
|
+
return null;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function requireStorage(accessors, kind) {
|
|
897
|
+
const target = kind === "session" ? accessors?.session : accessors?.local;
|
|
898
|
+
if (!target) {
|
|
899
|
+
throw new Error(
|
|
900
|
+
kind === "session" ? "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 sessionStorage" : "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 localStorage"
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
return target;
|
|
904
|
+
}
|
|
905
|
+
function executeStorageConfig(config, incomingScope, accessors) {
|
|
906
|
+
const normalized = normalizeStorageConfig(config);
|
|
907
|
+
const store = accessors === void 0 ? getDefaultStorageAccessors() : accessors;
|
|
908
|
+
if (isStorageSetConfigured(normalized)) {
|
|
909
|
+
const value = resolveStorageWriteValue(normalized.set.value, incomingScope);
|
|
910
|
+
const serialized = serializeStorageValue(value);
|
|
911
|
+
const key = normalized.set.key.trim();
|
|
912
|
+
for (const kind of normalized.set.storages) {
|
|
913
|
+
requireStorage(store, kind).setItem(key, serialized);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
if (!isStorageReadConfigured(normalized)) {
|
|
917
|
+
return null;
|
|
918
|
+
}
|
|
919
|
+
return deserializeStorageValue(
|
|
920
|
+
requireStorage(store, normalized.read.storage).getItem(
|
|
921
|
+
normalized.read.key.trim()
|
|
922
|
+
)
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// src/logic-config.ts
|
|
927
|
+
var DEFAULT_LOGIC_NODE_CONFIG = {
|
|
928
|
+
sourceCode: `function update(input) {
|
|
929
|
+
return input;
|
|
930
|
+
}`
|
|
931
|
+
};
|
|
932
|
+
function compileLogicRunner(sourceCode) {
|
|
933
|
+
return new Function(
|
|
934
|
+
"input",
|
|
935
|
+
`"use strict";
|
|
936
|
+
${sourceCode}
|
|
937
|
+
if (typeof update !== "function") {
|
|
938
|
+
throw new TypeError("\u9700\u8981\u5B9A\u4E49 update(input) \u51FD\u6570");
|
|
939
|
+
}
|
|
940
|
+
return update(input);`
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
function validateLogicSourceCode(sourceCode) {
|
|
944
|
+
const raw = sourceCode?.trim();
|
|
945
|
+
if (!raw) {
|
|
946
|
+
return { ok: false, error: "\u4EE3\u7801\u4E0D\u80FD\u4E3A\u7A7A" };
|
|
947
|
+
}
|
|
948
|
+
try {
|
|
949
|
+
compileLogicRunner(raw);
|
|
950
|
+
return { ok: true };
|
|
951
|
+
} catch (error) {
|
|
952
|
+
return {
|
|
953
|
+
ok: false,
|
|
954
|
+
error: error instanceof Error ? error.message : "JavaScript \u8BED\u6CD5\u9519\u8BEF"
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
function executeLogicConfig(config, input) {
|
|
959
|
+
const validation = validateLogicSourceCode(config.sourceCode ?? "");
|
|
960
|
+
if (!validation.ok) {
|
|
961
|
+
throw new Error(validation.error);
|
|
962
|
+
}
|
|
963
|
+
const run = compileLogicRunner(config.sourceCode);
|
|
964
|
+
return run(input);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/clock-config.ts
|
|
968
|
+
var DEFAULT_CLOCK_NODE_CONFIG = {
|
|
969
|
+
intervalSeconds: 0,
|
|
970
|
+
timeFormat: "YYYY-MM-DD HH:mm:ss",
|
|
971
|
+
outputCount: 1,
|
|
972
|
+
emitImmediately: true
|
|
973
|
+
};
|
|
974
|
+
function normalizeClockConfig(config) {
|
|
975
|
+
const intervalRaw = Number(config?.intervalSeconds);
|
|
976
|
+
const intervalSeconds = Number.isFinite(intervalRaw) && intervalRaw > 0 ? Math.floor(intervalRaw) : 0;
|
|
977
|
+
const outputCountRaw = Number(config?.outputCount);
|
|
978
|
+
const outputCount = Number.isFinite(outputCountRaw) && outputCountRaw > 0 ? Math.floor(outputCountRaw) : DEFAULT_CLOCK_NODE_CONFIG.outputCount;
|
|
979
|
+
const timeFormat = config?.timeFormat?.trim() || DEFAULT_CLOCK_NODE_CONFIG.timeFormat;
|
|
980
|
+
return {
|
|
981
|
+
intervalSeconds,
|
|
982
|
+
timeFormat,
|
|
983
|
+
outputCount,
|
|
984
|
+
emitImmediately: config?.emitImmediately !== false
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
function validateClockScheduleConfig(config) {
|
|
988
|
+
const normalized = normalizeClockConfig(config);
|
|
989
|
+
if (normalized.outputCount <= 0) {
|
|
990
|
+
return { ok: false, error: "\u8F93\u51FA\u6B21\u6570\u987B\u5927\u4E8E 0" };
|
|
991
|
+
}
|
|
992
|
+
const needsInterval = normalized.outputCount > 1 || normalized.outputCount === 1 && !normalized.emitImmediately;
|
|
993
|
+
if (needsInterval && normalized.intervalSeconds <= 0) {
|
|
994
|
+
return { ok: false, error: "\u5F53\u524D\u914D\u7F6E\u4E0B\u65F6\u949F\u4FE1\u53F7\u95F4\u9694\u987B\u5927\u4E8E 0 \u79D2" };
|
|
995
|
+
}
|
|
996
|
+
return { ok: true };
|
|
997
|
+
}
|
|
998
|
+
var pad2 = (value) => String(value).padStart(2, "0");
|
|
999
|
+
function formatClockTime(date, pattern) {
|
|
1000
|
+
const tokens = {
|
|
1001
|
+
YYYY: String(date.getFullYear()).padStart(4, "0"),
|
|
1002
|
+
MM: pad2(date.getMonth() + 1),
|
|
1003
|
+
DD: pad2(date.getDate()),
|
|
1004
|
+
HH: pad2(date.getHours()),
|
|
1005
|
+
mm: pad2(date.getMinutes()),
|
|
1006
|
+
ss: pad2(date.getSeconds())
|
|
1007
|
+
};
|
|
1008
|
+
return pattern.replace(/YYYY|MM|DD|HH|mm|ss/g, (token) => tokens[token] ?? token);
|
|
1009
|
+
}
|
|
1010
|
+
function buildClockSignalValue(config, now = /* @__PURE__ */ new Date()) {
|
|
1011
|
+
const normalized = normalizeClockConfig(config);
|
|
1012
|
+
return {
|
|
1013
|
+
formatted: formatClockTime(now, normalized.timeFormat),
|
|
1014
|
+
timestamp: now.getTime(),
|
|
1015
|
+
isoTime: now.toISOString()
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
function sleep(ms, abort, sessionKey) {
|
|
1019
|
+
if (ms <= 0 || abort.aborted) return Promise.resolve();
|
|
1020
|
+
return new Promise((resolve) => {
|
|
1021
|
+
const timerId = setTimeout(() => {
|
|
1022
|
+
clearInterval(pollId);
|
|
1023
|
+
resolve();
|
|
1024
|
+
}, ms);
|
|
1025
|
+
const pollId = setInterval(() => {
|
|
1026
|
+
if (abort.aborted || sessionKey !== void 0 && isClockSessionAborted(sessionKey)) {
|
|
1027
|
+
clearTimeout(timerId);
|
|
1028
|
+
clearInterval(pollId);
|
|
1029
|
+
resolve();
|
|
1030
|
+
}
|
|
1031
|
+
}, 50);
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
function getClockTickDelayOffsetMs(config, tickIndex) {
|
|
1035
|
+
const normalized = normalizeClockConfig(config);
|
|
1036
|
+
const intervalMs = normalized.intervalSeconds * 1e3;
|
|
1037
|
+
if (tickIndex <= 0) {
|
|
1038
|
+
return normalized.emitImmediately ? 0 : intervalMs;
|
|
1039
|
+
}
|
|
1040
|
+
if (normalized.emitImmediately) {
|
|
1041
|
+
return tickIndex * intervalMs;
|
|
1042
|
+
}
|
|
1043
|
+
return (tickIndex + 1) * intervalMs;
|
|
1044
|
+
}
|
|
1045
|
+
function getClockTickWaitMs(config, tickIndex, scheduleStartMs, nowMs = Date.now()) {
|
|
1046
|
+
const targetMs = scheduleStartMs + getClockTickDelayOffsetMs(config, tickIndex);
|
|
1047
|
+
return Math.max(0, targetMs - nowMs);
|
|
1048
|
+
}
|
|
1049
|
+
var activeSessions = /* @__PURE__ */ new Map();
|
|
1050
|
+
var abortedClockSessions = /* @__PURE__ */ new Set();
|
|
1051
|
+
function stopClockSchedule(sessionKey) {
|
|
1052
|
+
const session = activeSessions.get(sessionKey);
|
|
1053
|
+
if (!session) return;
|
|
1054
|
+
session.aborted = true;
|
|
1055
|
+
activeSessions.delete(sessionKey);
|
|
1056
|
+
}
|
|
1057
|
+
function isClockScheduleActive(sessionKey) {
|
|
1058
|
+
return activeSessions.has(sessionKey);
|
|
1059
|
+
}
|
|
1060
|
+
function abortClockSession(sessionKey) {
|
|
1061
|
+
stopClockSchedule(sessionKey);
|
|
1062
|
+
abortedClockSessions.add(sessionKey);
|
|
1063
|
+
}
|
|
1064
|
+
function isClockSessionAborted(sessionKey) {
|
|
1065
|
+
return abortedClockSessions.has(sessionKey);
|
|
1066
|
+
}
|
|
1067
|
+
function clearClockSessionAbort(sessionKey) {
|
|
1068
|
+
abortedClockSessions.delete(sessionKey);
|
|
1069
|
+
}
|
|
1070
|
+
function startClockSchedule(options) {
|
|
1071
|
+
stopClockSchedule(options.sessionKey);
|
|
1072
|
+
clearClockSessionAbort(options.sessionKey);
|
|
1073
|
+
const abort = { aborted: false };
|
|
1074
|
+
activeSessions.set(options.sessionKey, abort);
|
|
1075
|
+
void (async () => {
|
|
1076
|
+
try {
|
|
1077
|
+
const config = normalizeClockConfig(options.config);
|
|
1078
|
+
const total = config.outputCount;
|
|
1079
|
+
const scheduleStartMs = Date.now();
|
|
1080
|
+
for (let tickIndex = 0; tickIndex < total; tickIndex++) {
|
|
1081
|
+
if (abort.aborted || isClockSessionAborted(options.sessionKey)) return;
|
|
1082
|
+
const waitMs = getClockTickWaitMs(config, tickIndex, scheduleStartMs);
|
|
1083
|
+
if (waitMs > 0) {
|
|
1084
|
+
await sleep(waitMs, abort, options.sessionKey);
|
|
1085
|
+
}
|
|
1086
|
+
if (abort.aborted || isClockSessionAborted(options.sessionKey)) return;
|
|
1087
|
+
await options.onTick();
|
|
1088
|
+
}
|
|
1089
|
+
} finally {
|
|
1090
|
+
activeSessions.delete(options.sessionKey);
|
|
1091
|
+
options.onSettled?.();
|
|
1092
|
+
}
|
|
1093
|
+
})();
|
|
1094
|
+
return () => stopClockSchedule(options.sessionKey);
|
|
1095
|
+
}
|
|
1096
|
+
function stopAllClockSchedules() {
|
|
1097
|
+
for (const key of [...activeSessions.keys()]) {
|
|
1098
|
+
abortClockSession(key);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// src/event-config.ts
|
|
1103
|
+
var VIEW_EVENT_TYPES = [
|
|
1104
|
+
"click",
|
|
1105
|
+
"dblclick",
|
|
1106
|
+
"contextmenu",
|
|
1107
|
+
"mouseenter",
|
|
1108
|
+
"mouseleave"
|
|
1109
|
+
];
|
|
1110
|
+
var DEFAULT_VIEW_EVENT_NODE_CONFIG = {
|
|
1111
|
+
eventTypes: ["click"]
|
|
1112
|
+
};
|
|
1113
|
+
var VIEW_EVENT_TYPE_SET = new Set(VIEW_EVENT_TYPES);
|
|
1114
|
+
function isViewEventType(value) {
|
|
1115
|
+
return typeof value === "string" && VIEW_EVENT_TYPE_SET.has(value);
|
|
1116
|
+
}
|
|
1117
|
+
function normalizeViewEventConfig(config) {
|
|
1118
|
+
const raw = Array.isArray(config?.eventTypes) ? config.eventTypes : [];
|
|
1119
|
+
const eventTypes = [
|
|
1120
|
+
...new Set(raw.filter(isViewEventType))
|
|
1121
|
+
];
|
|
1122
|
+
return {
|
|
1123
|
+
eventTypes: eventTypes.length > 0 ? eventTypes : [...DEFAULT_VIEW_EVENT_NODE_CONFIG.eventTypes]
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
function snapshotDomEvent(event) {
|
|
1127
|
+
return {
|
|
1128
|
+
type: event.type,
|
|
1129
|
+
timeStamp: Number(event.timeStamp) || Date.now(),
|
|
1130
|
+
clientX: event.clientX,
|
|
1131
|
+
clientY: event.clientY,
|
|
1132
|
+
pageX: event.pageX,
|
|
1133
|
+
pageY: event.pageY,
|
|
1134
|
+
button: event.button,
|
|
1135
|
+
altKey: event.altKey,
|
|
1136
|
+
ctrlKey: event.ctrlKey,
|
|
1137
|
+
metaKey: event.metaKey,
|
|
1138
|
+
shiftKey: event.shiftKey
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
function snapshotViewEventNode(node) {
|
|
1142
|
+
return {
|
|
1143
|
+
id: node.id,
|
|
1144
|
+
name: node.name,
|
|
1145
|
+
materialType: node.materialType,
|
|
1146
|
+
x: node.x,
|
|
1147
|
+
y: node.y,
|
|
1148
|
+
width: node.width,
|
|
1149
|
+
height: node.height,
|
|
1150
|
+
layerId: node.layerId
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
function createViewEventSignal(input) {
|
|
1154
|
+
return {
|
|
1155
|
+
event: input.event,
|
|
1156
|
+
node: input.node,
|
|
1157
|
+
eventType: input.eventType
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
function collectArmedViewEventNodeIds(nodes, edges, eventNodeType, lifecycleNodeType, firedPhases) {
|
|
1161
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
1162
|
+
const armed = /* @__PURE__ */ new Set();
|
|
1163
|
+
for (const node of nodes) {
|
|
1164
|
+
if (node.nodeType !== eventNodeType) continue;
|
|
1165
|
+
const registered = edges.some((edge) => {
|
|
1166
|
+
if (edge.target !== node.id) return false;
|
|
1167
|
+
const source = byId.get(edge.source);
|
|
1168
|
+
if (!source || source.nodeType !== lifecycleNodeType) return false;
|
|
1169
|
+
const phase = source.lifecyclePhase || "mounted";
|
|
1170
|
+
return firedPhases.has(phase);
|
|
1171
|
+
});
|
|
1172
|
+
if (registered) armed.add(node.id);
|
|
1173
|
+
}
|
|
1174
|
+
return armed;
|
|
1175
|
+
}
|
|
1176
|
+
function collectArmedViewEventBindings(nodes, edges, eventNodeType, lifecycleNodeType, firedPhases) {
|
|
1177
|
+
const armed = collectArmedViewEventNodeIds(
|
|
1178
|
+
nodes,
|
|
1179
|
+
edges,
|
|
1180
|
+
eventNodeType,
|
|
1181
|
+
lifecycleNodeType,
|
|
1182
|
+
firedPhases
|
|
1183
|
+
);
|
|
1184
|
+
return collectViewEventBindings(nodes, eventNodeType, armed);
|
|
1185
|
+
}
|
|
1186
|
+
function collectViewEventBindings(nodes, eventNodeType, armedNodeIds) {
|
|
1187
|
+
const map = /* @__PURE__ */ new Map();
|
|
1188
|
+
for (const node of nodes) {
|
|
1189
|
+
if (node.nodeType !== eventNodeType) continue;
|
|
1190
|
+
if (armedNodeIds && (!node.id || !armedNodeIds.has(node.id))) continue;
|
|
1191
|
+
const types = normalizeViewEventConfig(node.eventConfig).eventTypes;
|
|
1192
|
+
for (const id of node.viewElementIds ?? []) {
|
|
1193
|
+
if (!id) continue;
|
|
1194
|
+
let set = map.get(id);
|
|
1195
|
+
if (!set) {
|
|
1196
|
+
set = /* @__PURE__ */ new Set();
|
|
1197
|
+
map.set(id, set);
|
|
1198
|
+
}
|
|
1199
|
+
for (const type of types) set.add(type);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
return map;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// src/swagger.ts
|
|
1206
|
+
var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
1207
|
+
"get",
|
|
1208
|
+
"post",
|
|
1209
|
+
"put",
|
|
1210
|
+
"patch",
|
|
1211
|
+
"delete",
|
|
1212
|
+
"head",
|
|
1213
|
+
"options"
|
|
1214
|
+
]);
|
|
1215
|
+
function normalizeBaseUrl(url) {
|
|
1216
|
+
return url.replace(/\/+$/, "");
|
|
1217
|
+
}
|
|
1218
|
+
function joinBaseAndPath(base, path) {
|
|
1219
|
+
const normalizedBase = normalizeBaseUrl(base);
|
|
1220
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
1221
|
+
return `${normalizedBase}${normalizedPath}`;
|
|
1222
|
+
}
|
|
1223
|
+
function resolveAgainstDocsUrl(relativeOrAbsolute, docsUrl) {
|
|
1224
|
+
const trimmed = relativeOrAbsolute.trim();
|
|
1225
|
+
if (!trimmed) return "";
|
|
1226
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
1227
|
+
return normalizeBaseUrl(trimmed);
|
|
1228
|
+
}
|
|
1229
|
+
try {
|
|
1230
|
+
const docs = new URL(docsUrl);
|
|
1231
|
+
if (trimmed.startsWith("/")) {
|
|
1232
|
+
return normalizeBaseUrl(`${docs.origin}${trimmed}`);
|
|
1233
|
+
}
|
|
1234
|
+
return normalizeBaseUrl(new URL(trimmed, `${docs.origin}/`).href);
|
|
1235
|
+
} catch {
|
|
1236
|
+
return normalizeBaseUrl(trimmed);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
function extractEndpointsFromPaths(paths) {
|
|
1240
|
+
if (!paths || typeof paths !== "object") return [];
|
|
1241
|
+
const endpoints = [];
|
|
1242
|
+
for (const [path, item] of Object.entries(paths)) {
|
|
1243
|
+
if (!item || typeof item !== "object") continue;
|
|
1244
|
+
for (const [method, operation] of Object.entries(item)) {
|
|
1245
|
+
if (!HTTP_METHODS.has(method.toLowerCase())) continue;
|
|
1246
|
+
if (!operation || typeof operation !== "object") continue;
|
|
1247
|
+
const op = operation;
|
|
1248
|
+
endpoints.push({
|
|
1249
|
+
method: method.toUpperCase(),
|
|
1250
|
+
path,
|
|
1251
|
+
summary: typeof op.summary === "string" ? op.summary : void 0,
|
|
1252
|
+
operationId: typeof op.operationId === "string" ? op.operationId : void 0
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
return endpoints.sort(
|
|
1257
|
+
(a, b) => `${a.path}:${a.method}`.localeCompare(`${b.path}:${b.method}`)
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
function parseOpenApiV3(spec, docsUrl) {
|
|
1261
|
+
const servers = Array.isArray(spec.servers) ? spec.servers : [];
|
|
1262
|
+
const firstServer = servers.find((item) => item && typeof item === "object");
|
|
1263
|
+
const serverUrl = typeof firstServer?.url === "string" ? firstServer.url : "";
|
|
1264
|
+
const apiBaseUrl = serverUrl ? resolveAgainstDocsUrl(serverUrl, docsUrl) : resolveAgainstDocsUrl(new URL(docsUrl).origin, docsUrl);
|
|
1265
|
+
return {
|
|
1266
|
+
apiBaseUrl,
|
|
1267
|
+
endpoints: extractEndpointsFromPaths(spec.paths)
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
function parseSwaggerV2(spec, docsUrl) {
|
|
1271
|
+
const schemes = Array.isArray(spec.schemes) ? spec.schemes : ["https"];
|
|
1272
|
+
const scheme = typeof schemes[0] === "string" ? schemes[0] : "https";
|
|
1273
|
+
const host = typeof spec.host === "string" ? spec.host : new URL(docsUrl).host;
|
|
1274
|
+
const basePath = typeof spec.basePath === "string" ? spec.basePath : "";
|
|
1275
|
+
const apiBaseUrl = normalizeBaseUrl(`${scheme}://${host}${basePath}`);
|
|
1276
|
+
return {
|
|
1277
|
+
apiBaseUrl,
|
|
1278
|
+
endpoints: extractEndpointsFromPaths(spec.paths)
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
function parseSwaggerDocument(spec, docsUrl) {
|
|
1282
|
+
if (!spec || typeof spec !== "object") {
|
|
1283
|
+
throw new Error("Swagger \u6587\u6863\u683C\u5F0F\u65E0\u6548");
|
|
1284
|
+
}
|
|
1285
|
+
const document = spec;
|
|
1286
|
+
if (typeof document.openapi === "string") {
|
|
1287
|
+
const parsed = parseOpenApiV3(document, docsUrl);
|
|
1288
|
+
if (parsed.endpoints.length === 0) {
|
|
1289
|
+
throw new Error("\u672A\u5728 OpenAPI \u6587\u6863\u4E2D\u627E\u5230\u63A5\u53E3");
|
|
1290
|
+
}
|
|
1291
|
+
return parsed;
|
|
1292
|
+
}
|
|
1293
|
+
if (document.swagger === "2.0" || document.swagger === 2) {
|
|
1294
|
+
const parsed = parseSwaggerV2(document, docsUrl);
|
|
1295
|
+
if (parsed.endpoints.length === 0) {
|
|
1296
|
+
throw new Error("\u672A\u5728 Swagger 2.0 \u6587\u6863\u4E2D\u627E\u5230\u63A5\u53E3");
|
|
1297
|
+
}
|
|
1298
|
+
return parsed;
|
|
1299
|
+
}
|
|
1300
|
+
throw new Error("\u4EC5\u652F\u6301 OpenAPI 3.x \u4E0E Swagger 2.0 \u6587\u6863");
|
|
1301
|
+
}
|
|
1302
|
+
function buildEndpointFullUrl(apiBaseUrl, pathOrEndpoint) {
|
|
1303
|
+
const path = typeof pathOrEndpoint === "string" ? pathOrEndpoint : pathOrEndpoint.path;
|
|
1304
|
+
return joinBaseAndPath(apiBaseUrl, path);
|
|
1305
|
+
}
|
|
1306
|
+
function buildEndpointSuggestions(apiBaseUrl, endpoints) {
|
|
1307
|
+
return endpoints.map((endpoint) => {
|
|
1308
|
+
const fullUrl = buildEndpointFullUrl(apiBaseUrl, endpoint);
|
|
1309
|
+
const labelParts = [
|
|
1310
|
+
endpoint.method,
|
|
1311
|
+
endpoint.path,
|
|
1312
|
+
endpoint.summary ? `\xB7 ${endpoint.summary}` : ""
|
|
1313
|
+
].filter(Boolean);
|
|
1314
|
+
return {
|
|
1315
|
+
...endpoint,
|
|
1316
|
+
fullUrl,
|
|
1317
|
+
label: labelParts.join(" ")
|
|
1318
|
+
};
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
function filterEndpointSuggestions(suggestions, query) {
|
|
1322
|
+
const keyword = query.trim().toLowerCase();
|
|
1323
|
+
if (!keyword) return suggestions;
|
|
1324
|
+
return suggestions.filter(
|
|
1325
|
+
(item) => item.fullUrl.toLowerCase().includes(keyword) || item.path.toLowerCase().includes(keyword) || item.method.toLowerCase().includes(keyword) || item.summary?.toLowerCase().includes(keyword) || item.operationId?.toLowerCase().includes(keyword)
|
|
1326
|
+
);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// src/runtime/execution-trace.ts
|
|
1330
|
+
function serializeTraceValue(value) {
|
|
1331
|
+
if (value === void 0) return void 0;
|
|
1332
|
+
if (isTrueSignal(value)) {
|
|
1333
|
+
return {
|
|
1334
|
+
kind: "true",
|
|
1335
|
+
value: value.value,
|
|
1336
|
+
isoTime: value.isoTime
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
if (isFalseSignal(value)) {
|
|
1340
|
+
return {
|
|
1341
|
+
kind: "false",
|
|
1342
|
+
error: value.error,
|
|
1343
|
+
isoTime: value.isoTime
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
return value;
|
|
1347
|
+
}
|
|
1348
|
+
function createTraceEntryId() {
|
|
1349
|
+
return `trace_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// src/nodes/definitions.ts
|
|
1353
|
+
var BLUEPRINT_NODE_TYPE = "Blueprint";
|
|
1354
|
+
var DEFAULT_LOGIC_NODE_TYPE = "Logic";
|
|
1355
|
+
var LIFECYCLE_NODE_TYPE = "Lifecycle";
|
|
1356
|
+
var FETCH_NODE_TYPE = "DataFetch";
|
|
1357
|
+
var JSON_NODE_TYPE = "JsonNode";
|
|
1358
|
+
var STORAGE_NODE_TYPE = "StorageNode";
|
|
1359
|
+
var CLOCK_NODE_TYPE = "Clock";
|
|
1360
|
+
var AND_NODE_TYPE = "AndLogic";
|
|
1361
|
+
var VIEW_NODE_TYPE = "ViewBind";
|
|
1362
|
+
var EVENT_NODE_TYPE = "ViewEvent";
|
|
1363
|
+
var blueprintNodeDefinition = {
|
|
1364
|
+
type: BLUEPRINT_NODE_TYPE,
|
|
1365
|
+
inputs: [{ name: "in", kind: "data" }],
|
|
1366
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1367
|
+
behavior: { kind: "js", ref: "blueprint-ref-run" }
|
|
1368
|
+
};
|
|
1369
|
+
var defaultLogicNodeDefinition = {
|
|
1370
|
+
type: DEFAULT_LOGIC_NODE_TYPE,
|
|
1371
|
+
inputs: [{ name: "in", kind: "data", optional: true }],
|
|
1372
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1373
|
+
behavior: { kind: "js", ref: "logic-run" }
|
|
1374
|
+
};
|
|
1375
|
+
var lifecycleNodeDefinition = {
|
|
1376
|
+
type: LIFECYCLE_NODE_TYPE,
|
|
1377
|
+
inputs: [],
|
|
1378
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1379
|
+
behavior: { kind: "js", ref: "lifecycle-emit" }
|
|
1380
|
+
};
|
|
1381
|
+
var fetchNodeDefinition = {
|
|
1382
|
+
type: FETCH_NODE_TYPE,
|
|
1383
|
+
inputs: [{ name: "in", kind: "data" }],
|
|
1384
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1385
|
+
behavior: { kind: "js", ref: "fetch-run" }
|
|
1386
|
+
};
|
|
1387
|
+
var jsonNodeDefinition = {
|
|
1388
|
+
type: JSON_NODE_TYPE,
|
|
1389
|
+
inputs: [{ name: "in", kind: "data" }],
|
|
1390
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1391
|
+
behavior: { kind: "js", ref: "json-parse-run" }
|
|
1392
|
+
};
|
|
1393
|
+
var storageNodeDefinition = {
|
|
1394
|
+
type: STORAGE_NODE_TYPE,
|
|
1395
|
+
inputs: [{ name: "in", kind: "data" }],
|
|
1396
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1397
|
+
behavior: { kind: "js", ref: "storage-run" }
|
|
1398
|
+
};
|
|
1399
|
+
var clockNodeDefinition = {
|
|
1400
|
+
type: CLOCK_NODE_TYPE,
|
|
1401
|
+
inputs: [{ name: "in", kind: "data" }],
|
|
1402
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1403
|
+
behavior: { kind: "js", ref: "clock-run" }
|
|
1404
|
+
};
|
|
1405
|
+
var andLogicNodeDefinition = {
|
|
1406
|
+
type: AND_NODE_TYPE,
|
|
1407
|
+
inputs: [
|
|
1408
|
+
{ name: "inA", kind: "data" },
|
|
1409
|
+
{ name: "inB", kind: "data" }
|
|
1410
|
+
],
|
|
1411
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1412
|
+
behavior: { kind: "js", ref: "and-run" }
|
|
1413
|
+
};
|
|
1414
|
+
var viewBindNodeDefinition = {
|
|
1415
|
+
type: VIEW_NODE_TYPE,
|
|
1416
|
+
inputs: [{ name: "in", kind: "data" }],
|
|
1417
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1418
|
+
behavior: { kind: "js", ref: "view-bind-run" }
|
|
1419
|
+
};
|
|
1420
|
+
var viewEventNodeDefinition = {
|
|
1421
|
+
type: EVENT_NODE_TYPE,
|
|
1422
|
+
inputs: [{ name: "in", kind: "data" }],
|
|
1423
|
+
outputs: [{ name: "out", kind: "data" }],
|
|
1424
|
+
behavior: { kind: "js", ref: "event-emit" }
|
|
1425
|
+
};
|
|
1426
|
+
var nodeDefinitionRegistry = {
|
|
1427
|
+
[BLUEPRINT_NODE_TYPE]: blueprintNodeDefinition,
|
|
1428
|
+
[DEFAULT_LOGIC_NODE_TYPE]: defaultLogicNodeDefinition,
|
|
1429
|
+
[LIFECYCLE_NODE_TYPE]: lifecycleNodeDefinition,
|
|
1430
|
+
[FETCH_NODE_TYPE]: fetchNodeDefinition,
|
|
1431
|
+
[JSON_NODE_TYPE]: jsonNodeDefinition,
|
|
1432
|
+
[STORAGE_NODE_TYPE]: storageNodeDefinition,
|
|
1433
|
+
[CLOCK_NODE_TYPE]: clockNodeDefinition,
|
|
1434
|
+
[AND_NODE_TYPE]: andLogicNodeDefinition,
|
|
1435
|
+
[VIEW_NODE_TYPE]: viewBindNodeDefinition,
|
|
1436
|
+
[EVENT_NODE_TYPE]: viewEventNodeDefinition
|
|
1437
|
+
};
|
|
1438
|
+
function getNodeDefinition(type) {
|
|
1439
|
+
const def = nodeDefinitionRegistry[type];
|
|
1440
|
+
if (!def) {
|
|
1441
|
+
throw new Error(`NodeDefinition not found: ${type}`);
|
|
1442
|
+
}
|
|
1443
|
+
return def;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// src/runtime/blueprint-cycle.ts
|
|
1447
|
+
var BLUEPRINT_CALL_STACK_KEY = "__blueprintCallStack";
|
|
1448
|
+
var BlueprintCycleError = class extends Error {
|
|
1449
|
+
cycleIds;
|
|
1450
|
+
constructor(cycleIds, message) {
|
|
1451
|
+
super(message);
|
|
1452
|
+
this.name = "BlueprintCycleError";
|
|
1453
|
+
this.cycleIds = cycleIds;
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
function collectBlueprintLibraryRefs(graph) {
|
|
1457
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1458
|
+
for (const node of graph.nodes) {
|
|
1459
|
+
if (node.nodeType === BLUEPRINT_NODE_TYPE && node.libraryBlueprintId) {
|
|
1460
|
+
ids.add(node.libraryBlueprintId);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
return [...ids];
|
|
1464
|
+
}
|
|
1465
|
+
function formatBlueprintCycleMessage(cycleIds, resolveName) {
|
|
1466
|
+
const labels = cycleIds.map((id) => resolveName?.(id) ?? id);
|
|
1467
|
+
return `\u84DD\u56FE\u5F15\u7528\u5B58\u5728\u6B7B\u5FAA\u73AF\uFF1A${labels.join(" \u2192 ")}`;
|
|
1468
|
+
}
|
|
1469
|
+
async function detectBlueprintReferenceCycle(options) {
|
|
1470
|
+
const {
|
|
1471
|
+
rootGraph,
|
|
1472
|
+
rootLibraryBlueprintId,
|
|
1473
|
+
resolveLibraryBlueprint,
|
|
1474
|
+
resolveBlueprintName
|
|
1475
|
+
} = options;
|
|
1476
|
+
const graphCache = /* @__PURE__ */ new Map();
|
|
1477
|
+
const loadGraph = async (libraryBlueprintId) => {
|
|
1478
|
+
if (!graphCache.has(libraryBlueprintId)) {
|
|
1479
|
+
graphCache.set(
|
|
1480
|
+
libraryBlueprintId,
|
|
1481
|
+
await resolveLibraryBlueprint(libraryBlueprintId)
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
return graphCache.get(libraryBlueprintId) ?? null;
|
|
1485
|
+
};
|
|
1486
|
+
const visit = async (path, graph) => {
|
|
1487
|
+
for (const refId of collectBlueprintLibraryRefs(graph)) {
|
|
1488
|
+
const cycleIndex = path.indexOf(refId);
|
|
1489
|
+
if (cycleIndex !== -1) {
|
|
1490
|
+
return [...path.slice(cycleIndex), refId];
|
|
1491
|
+
}
|
|
1492
|
+
const nested = await loadGraph(refId);
|
|
1493
|
+
if (!nested) continue;
|
|
1494
|
+
const cycle = await visit([...path, refId], nested);
|
|
1495
|
+
if (cycle) return cycle;
|
|
1496
|
+
}
|
|
1497
|
+
return null;
|
|
1498
|
+
};
|
|
1499
|
+
const initialPath = rootLibraryBlueprintId ? [rootLibraryBlueprintId] : [];
|
|
1500
|
+
const cycleIds = await visit(initialPath, rootGraph);
|
|
1501
|
+
if (!cycleIds) {
|
|
1502
|
+
return { ok: true };
|
|
1503
|
+
}
|
|
1504
|
+
return {
|
|
1505
|
+
ok: false,
|
|
1506
|
+
cycleIds,
|
|
1507
|
+
message: formatBlueprintCycleMessage(cycleIds, resolveBlueprintName)
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
async function assertNoBlueprintReferenceCycle(options) {
|
|
1511
|
+
const result = await detectBlueprintReferenceCycle(options);
|
|
1512
|
+
if (!result.ok) {
|
|
1513
|
+
throw new BlueprintCycleError(result.cycleIds, result.message);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
function resolveBlueprintCallStack(scopeStack, rootLibraryBlueprintId) {
|
|
1517
|
+
if (scopeStack) return scopeStack;
|
|
1518
|
+
return rootLibraryBlueprintId ? [rootLibraryBlueprintId] : [];
|
|
1519
|
+
}
|
|
1520
|
+
function detectRuntimeBlueprintCycle(callStack, targetLibraryBlueprintId, resolveName) {
|
|
1521
|
+
const cycleIndex = callStack.indexOf(targetLibraryBlueprintId);
|
|
1522
|
+
if (cycleIndex === -1) {
|
|
1523
|
+
return { ok: true };
|
|
1524
|
+
}
|
|
1525
|
+
const cycleIds = [
|
|
1526
|
+
...callStack.slice(cycleIndex),
|
|
1527
|
+
targetLibraryBlueprintId
|
|
1528
|
+
];
|
|
1529
|
+
return {
|
|
1530
|
+
ok: false,
|
|
1531
|
+
cycleIds,
|
|
1532
|
+
message: formatBlueprintCycleMessage(cycleIds, resolveName)
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// src/runtime/clock-active-registry.ts
|
|
1537
|
+
var activeClockNodeIds = /* @__PURE__ */ new Set();
|
|
1538
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
1539
|
+
function emit() {
|
|
1540
|
+
listeners.forEach((listener) => listener());
|
|
1541
|
+
}
|
|
1542
|
+
function markClockNodeActive(nodeId) {
|
|
1543
|
+
if (activeClockNodeIds.has(nodeId)) return;
|
|
1544
|
+
activeClockNodeIds.add(nodeId);
|
|
1545
|
+
emit();
|
|
1546
|
+
}
|
|
1547
|
+
function markClockNodeInactive(nodeId) {
|
|
1548
|
+
if (!activeClockNodeIds.delete(nodeId)) return;
|
|
1549
|
+
emit();
|
|
1550
|
+
}
|
|
1551
|
+
function isClockNodeActive(nodeId) {
|
|
1552
|
+
return activeClockNodeIds.has(nodeId);
|
|
1553
|
+
}
|
|
1554
|
+
function getActiveClockNodeIds() {
|
|
1555
|
+
return [...activeClockNodeIds];
|
|
1556
|
+
}
|
|
1557
|
+
function subscribeActiveClockNodes(listener) {
|
|
1558
|
+
listeners.add(listener);
|
|
1559
|
+
return () => listeners.delete(listener);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// src/runtime/clock-scheduler.ts
|
|
1563
|
+
function buildClockSessionKey(scopeId, nodeId) {
|
|
1564
|
+
return `${scopeId}:${nodeId}`;
|
|
1565
|
+
}
|
|
1566
|
+
function abortClockNode(scopeId, nodeId) {
|
|
1567
|
+
abortClockSession(buildClockSessionKey(scopeId, nodeId));
|
|
1568
|
+
markClockNodeInactive(nodeId);
|
|
1569
|
+
}
|
|
1570
|
+
function scheduleClockOutputs(options) {
|
|
1571
|
+
return startClockSchedule(options);
|
|
1572
|
+
}
|
|
1573
|
+
function createClockOutputValue(config) {
|
|
1574
|
+
return buildClockSignalValue(normalizeClockConfig(config));
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
// src/runtime/graph-runner.ts
|
|
1578
|
+
function createTokenId() {
|
|
1579
|
+
return `token_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
1580
|
+
}
|
|
1581
|
+
function cloneScope(scope) {
|
|
1582
|
+
return {
|
|
1583
|
+
parent: scope?.parent,
|
|
1584
|
+
vars: new Map(scope?.vars ?? [])
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
function cloneOutputs(outputs) {
|
|
1588
|
+
const next = /* @__PURE__ */ new Map();
|
|
1589
|
+
for (const [nodeId, ports] of outputs.entries()) {
|
|
1590
|
+
next.set(nodeId, new Map(ports));
|
|
1591
|
+
}
|
|
1592
|
+
return next;
|
|
1593
|
+
}
|
|
1594
|
+
function cloneToken(token) {
|
|
1595
|
+
return {
|
|
1596
|
+
tokenId: token.tokenId,
|
|
1597
|
+
nodeId: token.nodeId,
|
|
1598
|
+
nodeType: token.nodeType,
|
|
1599
|
+
inPort: token.inPort,
|
|
1600
|
+
scope: cloneScope(token.scope),
|
|
1601
|
+
correlationId: token.correlationId
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
function cloneQueue(queue) {
|
|
1605
|
+
return queue.map(cloneToken);
|
|
1606
|
+
}
|
|
1607
|
+
var BlueprintGraphRunner = class _BlueprintGraphRunner {
|
|
1608
|
+
constructor(graph, options) {
|
|
1609
|
+
this.graph = graph;
|
|
1610
|
+
this.resolveLibraryBlueprint = options?.resolveLibraryBlueprint;
|
|
1611
|
+
this.rootLibraryBlueprintId = options?.rootLibraryBlueprintId ?? null;
|
|
1612
|
+
this.resolveBlueprintName = options?.resolveBlueprintName;
|
|
1613
|
+
this.onViewScopeUpdate = options?.onViewScopeUpdate;
|
|
1614
|
+
this.behaviors = new BehaviorRegistry();
|
|
1615
|
+
registerDefaultBehaviors(this.behaviors);
|
|
1616
|
+
this.registerBlueprintRefBehavior();
|
|
1617
|
+
this.registerFetchBehavior();
|
|
1618
|
+
this.registerJsonBehavior();
|
|
1619
|
+
this.registerStorageBehavior();
|
|
1620
|
+
this.registerLogicBehavior();
|
|
1621
|
+
this.registerClockBehavior();
|
|
1622
|
+
this.registerAndBehavior();
|
|
1623
|
+
this.registerViewBindBehavior();
|
|
1624
|
+
}
|
|
1625
|
+
graph;
|
|
1626
|
+
behaviors;
|
|
1627
|
+
outputs = /* @__PURE__ */ new Map();
|
|
1628
|
+
resolveLibraryBlueprint;
|
|
1629
|
+
debugQueue = null;
|
|
1630
|
+
debugExecutor = null;
|
|
1631
|
+
traceEntries = [];
|
|
1632
|
+
debugHistory = [];
|
|
1633
|
+
rootLibraryBlueprintId;
|
|
1634
|
+
resolveBlueprintName;
|
|
1635
|
+
cycleValidated = false;
|
|
1636
|
+
debugProgressCallback = null;
|
|
1637
|
+
onViewScopeUpdate;
|
|
1638
|
+
async ensureNoBlueprintCycle() {
|
|
1639
|
+
if (this.cycleValidated || !this.resolveLibraryBlueprint) {
|
|
1640
|
+
return;
|
|
1641
|
+
}
|
|
1642
|
+
await assertNoBlueprintReferenceCycle({
|
|
1643
|
+
rootGraph: this.graph,
|
|
1644
|
+
rootLibraryBlueprintId: this.rootLibraryBlueprintId,
|
|
1645
|
+
resolveLibraryBlueprint: this.resolveLibraryBlueprint,
|
|
1646
|
+
resolveBlueprintName: this.resolveBlueprintName
|
|
1647
|
+
});
|
|
1648
|
+
this.cycleValidated = true;
|
|
1649
|
+
}
|
|
1650
|
+
injectedInputs = /* @__PURE__ */ new Map();
|
|
1651
|
+
/**
|
|
1652
|
+
* 从视图交互触发指定蓝图节点:向该节点 in 口注入真信号并执行下游。
|
|
1653
|
+
* payload 写入 scope(UI_EVENT_PAYLOAD_KEY)供 Logic 等节点读取。
|
|
1654
|
+
*/
|
|
1655
|
+
async triggerNode(nodeId, inputValue) {
|
|
1656
|
+
await this.ensureNoBlueprintCycle();
|
|
1657
|
+
this.requireNode(nodeId);
|
|
1658
|
+
const key = `${nodeId}:in`;
|
|
1659
|
+
this.injectedInputs.set(key, createTrueSignal(inputValue ?? true));
|
|
1660
|
+
try {
|
|
1661
|
+
await this.runFromNodeWithUiPayload(nodeId, inputValue);
|
|
1662
|
+
} finally {
|
|
1663
|
+
this.injectedInputs.delete(key);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
async runFromNodeWithUiPayload(nodeId, inputValue) {
|
|
1667
|
+
const queue = [
|
|
1668
|
+
{
|
|
1669
|
+
tokenId: createTokenId(),
|
|
1670
|
+
nodeId,
|
|
1671
|
+
nodeType: this.requireNode(nodeId).nodeType,
|
|
1672
|
+
inPort: "in",
|
|
1673
|
+
scope: cloneScope()
|
|
1674
|
+
}
|
|
1675
|
+
];
|
|
1676
|
+
queue[0].scope.vars.set(UI_EVENT_PAYLOAD_KEY, inputValue);
|
|
1677
|
+
const executor = this.createExecutor(queue);
|
|
1678
|
+
while (queue.length > 0) {
|
|
1679
|
+
const token = queue.shift();
|
|
1680
|
+
if (!this.syncTokenFromGraph(token)) continue;
|
|
1681
|
+
try {
|
|
1682
|
+
await executor.executeToken(token);
|
|
1683
|
+
} catch (error) {
|
|
1684
|
+
this.setNodeOutput(
|
|
1685
|
+
token.nodeId,
|
|
1686
|
+
"out",
|
|
1687
|
+
createFalseSignal(
|
|
1688
|
+
error instanceof Error ? error.message : String(error)
|
|
1689
|
+
)
|
|
1690
|
+
);
|
|
1691
|
+
const nextNodes = this.findSignalTargets(token.nodeId, "out");
|
|
1692
|
+
for (const target of nextNodes) {
|
|
1693
|
+
queue.push({
|
|
1694
|
+
tokenId: createTokenId(),
|
|
1695
|
+
nodeId: target.nodeId,
|
|
1696
|
+
nodeType: target.nodeType,
|
|
1697
|
+
inPort: target.inPort,
|
|
1698
|
+
scope: token.scope,
|
|
1699
|
+
correlationId: token.correlationId ?? token.tokenId
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
async emitLifecycle(phase) {
|
|
1706
|
+
await this.ensureNoBlueprintCycle();
|
|
1707
|
+
const signal = createLifecycleSignal(phase);
|
|
1708
|
+
const targets = this.graph.nodes.filter(
|
|
1709
|
+
(node) => node.nodeType === LIFECYCLE_NODE_TYPE && node.lifecyclePhase === phase
|
|
1710
|
+
);
|
|
1711
|
+
for (const node of targets) {
|
|
1712
|
+
await this.runFromNode(node.id, signal);
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* 嵌套蓝图被引用且父级传入真信号时,触发 blueprintActivated 生命周期节点,
|
|
1717
|
+
* 并将父级输入值写入 scope 供节点输出。
|
|
1718
|
+
*/
|
|
1719
|
+
async emitBlueprintActivated(inputValue, parentScope) {
|
|
1720
|
+
const signal = createLifecycleSignal("blueprintActivated");
|
|
1721
|
+
const targets = this.graph.nodes.filter(
|
|
1722
|
+
(node) => node.nodeType === LIFECYCLE_NODE_TYPE && node.lifecyclePhase === "blueprintActivated"
|
|
1723
|
+
);
|
|
1724
|
+
for (const node of targets) {
|
|
1725
|
+
await this.runFromNode(node.id, signal, parentScope, inputValue);
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* 视图节点触发事件时,匹配已注册(上游生命周期已触发)且绑定了该元素、事件类型的事件节点,发出真信号。
|
|
1730
|
+
*/
|
|
1731
|
+
async emitViewEvent(payload, armedNodeIds) {
|
|
1732
|
+
await this.ensureNoBlueprintCycle();
|
|
1733
|
+
const targets = this.graph.nodes.filter((node) => {
|
|
1734
|
+
if (node.nodeType !== EVENT_NODE_TYPE) return false;
|
|
1735
|
+
if (armedNodeIds && !armedNodeIds.has(node.id)) return false;
|
|
1736
|
+
if (!(node.viewElementIds ?? []).includes(payload.node.id)) return false;
|
|
1737
|
+
return normalizeViewEventConfig(node.eventConfig).eventTypes.includes(
|
|
1738
|
+
payload.eventType
|
|
1739
|
+
);
|
|
1740
|
+
});
|
|
1741
|
+
for (const node of targets) {
|
|
1742
|
+
await this.runFromNode(node.id, void 0, void 0, void 0, payload);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
/** 时钟节点单次输出:向下游传播含当前时间的真信号 */
|
|
1746
|
+
async propagateClockOutput(nodeId, parentScope, sessionKey) {
|
|
1747
|
+
const resolvedSessionKey = sessionKey ?? buildClockSessionKey(this.clockScopeId(), nodeId);
|
|
1748
|
+
if (isClockSessionAborted(resolvedSessionKey)) return;
|
|
1749
|
+
await this.ensureNoBlueprintCycle();
|
|
1750
|
+
const node = this.requireNode(nodeId);
|
|
1751
|
+
if (node.nodeType !== CLOCK_NODE_TYPE) return;
|
|
1752
|
+
const config = normalizeClockConfig({
|
|
1753
|
+
...DEFAULT_CLOCK_NODE_CONFIG,
|
|
1754
|
+
...node.clockConfig
|
|
1755
|
+
});
|
|
1756
|
+
const value = buildClockSignalValue(config);
|
|
1757
|
+
this.setNodeOutput(nodeId, "out", createTrueSignal(value));
|
|
1758
|
+
const queue = [];
|
|
1759
|
+
for (const target of this.findSignalTargets(nodeId, "out")) {
|
|
1760
|
+
queue.push({
|
|
1761
|
+
tokenId: createTokenId(),
|
|
1762
|
+
nodeId: target.nodeId,
|
|
1763
|
+
nodeType: target.nodeType,
|
|
1764
|
+
inPort: target.inPort,
|
|
1765
|
+
scope: cloneScope(parentScope)
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
const executor = this.createExecutor(queue);
|
|
1769
|
+
while (queue.length > 0) {
|
|
1770
|
+
if (isClockSessionAborted(resolvedSessionKey)) {
|
|
1771
|
+
queue.length = 0;
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
const token = queue.shift();
|
|
1775
|
+
if (!this.syncTokenFromGraph(token)) continue;
|
|
1776
|
+
try {
|
|
1777
|
+
await executor.executeToken(token);
|
|
1778
|
+
} catch (error) {
|
|
1779
|
+
this.setNodeOutput(
|
|
1780
|
+
token.nodeId,
|
|
1781
|
+
"out",
|
|
1782
|
+
createFalseSignal(
|
|
1783
|
+
error instanceof Error ? error.message : String(error)
|
|
1784
|
+
)
|
|
1785
|
+
);
|
|
1786
|
+
const nextNodes = this.findSignalTargets(token.nodeId, "out");
|
|
1787
|
+
for (const target of nextNodes) {
|
|
1788
|
+
queue.push({
|
|
1789
|
+
tokenId: createTokenId(),
|
|
1790
|
+
nodeId: target.nodeId,
|
|
1791
|
+
nodeType: target.nodeType,
|
|
1792
|
+
inPort: target.inPort,
|
|
1793
|
+
scope: token.scope,
|
|
1794
|
+
correlationId: token.correlationId ?? token.tokenId
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
clockScopeId() {
|
|
1801
|
+
return this.rootLibraryBlueprintId ?? "local";
|
|
1802
|
+
}
|
|
1803
|
+
startClockSchedule(nodeId, config, scope) {
|
|
1804
|
+
const sessionKey = buildClockSessionKey(this.clockScopeId(), nodeId);
|
|
1805
|
+
markClockNodeActive(nodeId);
|
|
1806
|
+
scheduleClockOutputs({
|
|
1807
|
+
sessionKey,
|
|
1808
|
+
config,
|
|
1809
|
+
onTick: async () => {
|
|
1810
|
+
if (isClockSessionAborted(sessionKey)) return;
|
|
1811
|
+
await this.propagateClockOutput(nodeId, scope, sessionKey);
|
|
1812
|
+
},
|
|
1813
|
+
onSettled: () => markClockNodeInactive(nodeId)
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
/** 中止指定时钟节点:停止剩余 tick 与正在执行的下游任务 */
|
|
1817
|
+
abortClockNode(nodeId) {
|
|
1818
|
+
abortClockNode(this.clockScopeId(), nodeId);
|
|
1819
|
+
}
|
|
1820
|
+
/** 从所有无入流 signal 的节点开始执行(嵌套蓝图调用) */
|
|
1821
|
+
async runFromFlowEntries(parentScope, options) {
|
|
1822
|
+
if (!options?.preserveOutputs) {
|
|
1823
|
+
this.outputs.clear();
|
|
1824
|
+
}
|
|
1825
|
+
const entries = this.findSignalEntryNodes();
|
|
1826
|
+
for (const node of entries) {
|
|
1827
|
+
await this.runFromNode(node.id, void 0, parentScope);
|
|
1828
|
+
}
|
|
1829
|
+
return this.collectOutputs();
|
|
1830
|
+
}
|
|
1831
|
+
getNodeOutputs() {
|
|
1832
|
+
return this.collectOutputs();
|
|
1833
|
+
}
|
|
1834
|
+
getTraceEntries() {
|
|
1835
|
+
return [...this.traceEntries];
|
|
1836
|
+
}
|
|
1837
|
+
isDebugSessionActive() {
|
|
1838
|
+
return this.debugQueue !== null;
|
|
1839
|
+
}
|
|
1840
|
+
isDebugQueueEmpty() {
|
|
1841
|
+
return !this.debugQueue || this.debugQueue.length === 0;
|
|
1842
|
+
}
|
|
1843
|
+
/** 调试过程中同步最新蓝图拓扑与节点配置 */
|
|
1844
|
+
updateGraph(graph) {
|
|
1845
|
+
this.graph = graph;
|
|
1846
|
+
this.syncDebugQueueWithLatestGraph();
|
|
1847
|
+
}
|
|
1848
|
+
/**
|
|
1849
|
+
* 按当前图结构重建待执行队列。
|
|
1850
|
+
* 已有 trace 时,从最后执行的节点按最新出边重新入队;便于编辑连线后继续单步调试。
|
|
1851
|
+
*/
|
|
1852
|
+
refreshPendingQueueFromLatestGraph() {
|
|
1853
|
+
if (!this.debugQueue) return;
|
|
1854
|
+
if (this.traceEntries.length === 0) {
|
|
1855
|
+
this.syncDebugQueueWithLatestGraph();
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
const lastEntry = this.traceEntries[this.traceEntries.length - 1];
|
|
1859
|
+
const lastOutput = this.getNodeOutput(lastEntry.nodeId, "out");
|
|
1860
|
+
if (lastOutput !== void 0 && isFalseSignal(lastOutput) && !this.graph.allowFalseSignalPropagation) {
|
|
1861
|
+
this.debugQueue = [];
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
const scope = this.debugQueue[0]?.scope ?? this.debugHistory[0]?.queue[0]?.scope ?? cloneScope();
|
|
1865
|
+
const node = this.graph.nodes.find((n) => n.id === lastEntry.nodeId);
|
|
1866
|
+
if (!node) {
|
|
1867
|
+
this.debugQueue = [];
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
let def;
|
|
1871
|
+
try {
|
|
1872
|
+
def = getNodeDefinition(node.nodeType);
|
|
1873
|
+
} catch {
|
|
1874
|
+
this.debugQueue = [];
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1877
|
+
const newQueue = [];
|
|
1878
|
+
for (const port of def.outputs) {
|
|
1879
|
+
if (this.getNodeOutput(lastEntry.nodeId, port.name) === void 0) {
|
|
1880
|
+
continue;
|
|
1881
|
+
}
|
|
1882
|
+
for (const target of this.findSignalTargets(lastEntry.nodeId, port.name)) {
|
|
1883
|
+
newQueue.push({
|
|
1884
|
+
tokenId: createTokenId(),
|
|
1885
|
+
nodeId: target.nodeId,
|
|
1886
|
+
nodeType: target.nodeType,
|
|
1887
|
+
inPort: target.inPort,
|
|
1888
|
+
scope: cloneScope(scope)
|
|
1889
|
+
});
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
if (newQueue.length > 0 || this.debugQueue.length === 0) {
|
|
1893
|
+
this.debugQueue = newQueue;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
canDebugStepBack() {
|
|
1897
|
+
return this.debugHistory.length > 1;
|
|
1898
|
+
}
|
|
1899
|
+
debugStepBack() {
|
|
1900
|
+
if (!this.debugQueue || this.debugHistory.length <= 1) {
|
|
1901
|
+
return false;
|
|
1902
|
+
}
|
|
1903
|
+
this.debugHistory.pop();
|
|
1904
|
+
const snapshot = this.debugHistory[this.debugHistory.length - 1];
|
|
1905
|
+
this.restoreDebugSnapshot(snapshot);
|
|
1906
|
+
return true;
|
|
1907
|
+
}
|
|
1908
|
+
captureDebugSnapshot() {
|
|
1909
|
+
return {
|
|
1910
|
+
outputs: cloneOutputs(this.outputs),
|
|
1911
|
+
queue: cloneQueue(this.debugQueue ?? []),
|
|
1912
|
+
traceEntries: [...this.traceEntries]
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
restoreDebugSnapshot(snapshot) {
|
|
1916
|
+
this.outputs = cloneOutputs(snapshot.outputs);
|
|
1917
|
+
this.debugQueue = cloneQueue(snapshot.queue);
|
|
1918
|
+
this.traceEntries = [...snapshot.traceEntries];
|
|
1919
|
+
}
|
|
1920
|
+
pushDebugSnapshot() {
|
|
1921
|
+
this.debugHistory.push(this.captureDebugSnapshot());
|
|
1922
|
+
}
|
|
1923
|
+
beginDebugSession(lifecycleNodeId) {
|
|
1924
|
+
stopAllClockSchedules();
|
|
1925
|
+
const node = this.requireNode(lifecycleNodeId);
|
|
1926
|
+
if (node.nodeType !== LIFECYCLE_NODE_TYPE) {
|
|
1927
|
+
throw new Error("\u8C03\u8BD5\u4F1A\u8BDD\u53EA\u80FD\u4ECE\u751F\u547D\u5468\u671F\u8282\u70B9\u5F00\u59CB");
|
|
1928
|
+
}
|
|
1929
|
+
this.outputs.clear();
|
|
1930
|
+
this.traceEntries = [];
|
|
1931
|
+
this.debugQueue = [
|
|
1932
|
+
{
|
|
1933
|
+
tokenId: createTokenId(),
|
|
1934
|
+
nodeId: lifecycleNodeId,
|
|
1935
|
+
nodeType: node.nodeType,
|
|
1936
|
+
inPort: "in",
|
|
1937
|
+
scope: cloneScope()
|
|
1938
|
+
}
|
|
1939
|
+
];
|
|
1940
|
+
this.applyLifecycleScopeForNode(lifecycleNodeId);
|
|
1941
|
+
this.debugExecutor = this.createExecutor(this.debugQueue, {
|
|
1942
|
+
emitToActiveDebugQueue: true
|
|
1943
|
+
});
|
|
1944
|
+
this.debugHistory = [this.captureDebugSnapshot()];
|
|
1945
|
+
}
|
|
1946
|
+
/** 调试中修改生命周期阶段后,同步队列头部的 scope 信号 */
|
|
1947
|
+
refreshDebugLifecycleScope(lifecycleNodeId) {
|
|
1948
|
+
const head = this.debugQueue?.[0];
|
|
1949
|
+
if (!head || head.nodeId !== lifecycleNodeId) return;
|
|
1950
|
+
this.applyLifecycleScopeForNode(lifecycleNodeId);
|
|
1951
|
+
}
|
|
1952
|
+
applyLifecycleScopeForNode(lifecycleNodeId) {
|
|
1953
|
+
const head = this.debugQueue?.[0];
|
|
1954
|
+
if (!head || head.nodeId !== lifecycleNodeId) return;
|
|
1955
|
+
const node = this.graph.nodes.find((n) => n.id === lifecycleNodeId);
|
|
1956
|
+
if (!node?.lifecyclePhase) {
|
|
1957
|
+
head.scope.vars.delete(LIFECYCLE_SIGNAL_KEY);
|
|
1958
|
+
head.scope.vars.delete(BLUEPRINT_ACTIVATION_INPUT_KEY);
|
|
1959
|
+
return;
|
|
1960
|
+
}
|
|
1961
|
+
head.scope.vars.set(
|
|
1962
|
+
LIFECYCLE_SIGNAL_KEY,
|
|
1963
|
+
createLifecycleSignal(node.lifecyclePhase)
|
|
1964
|
+
);
|
|
1965
|
+
if (node.lifecyclePhase === "blueprintActivated") {
|
|
1966
|
+
head.scope.vars.set(BLUEPRINT_ACTIVATION_INPUT_KEY, void 0);
|
|
1967
|
+
} else {
|
|
1968
|
+
head.scope.vars.delete(BLUEPRINT_ACTIVATION_INPUT_KEY);
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
clearDebugSession() {
|
|
1972
|
+
stopAllClockSchedules();
|
|
1973
|
+
this.debugQueue = null;
|
|
1974
|
+
this.debugExecutor = null;
|
|
1975
|
+
this.traceEntries = [];
|
|
1976
|
+
this.outputs.clear();
|
|
1977
|
+
this.debugHistory = [];
|
|
1978
|
+
}
|
|
1979
|
+
async debugStep(nodeLabelById, onProgress) {
|
|
1980
|
+
if (!this.debugQueue || !this.debugExecutor) {
|
|
1981
|
+
return { done: true };
|
|
1982
|
+
}
|
|
1983
|
+
if (this.debugQueue.length === 0) {
|
|
1984
|
+
return { done: true };
|
|
1985
|
+
}
|
|
1986
|
+
const prevCallback = this.debugProgressCallback;
|
|
1987
|
+
this.debugProgressCallback = onProgress ?? null;
|
|
1988
|
+
try {
|
|
1989
|
+
this.pushDebugSnapshot();
|
|
1990
|
+
const token = this.debugQueue.shift();
|
|
1991
|
+
if (!this.syncTokenFromGraph(token)) {
|
|
1992
|
+
this.pushDebugSnapshot();
|
|
1993
|
+
return {
|
|
1994
|
+
done: this.debugQueue.length === 0,
|
|
1995
|
+
haltedByFalseSignal: false
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
if (token.nodeType === CLOCK_NODE_TYPE) {
|
|
1999
|
+
const node = this.requireNode(token.nodeId);
|
|
2000
|
+
const config = normalizeClockConfig({
|
|
2001
|
+
...DEFAULT_CLOCK_NODE_CONFIG,
|
|
2002
|
+
...node.clockConfig
|
|
2003
|
+
});
|
|
2004
|
+
const halted = await this.executeClockScheduleForDebug(
|
|
2005
|
+
token,
|
|
2006
|
+
config,
|
|
2007
|
+
nodeLabelById
|
|
2008
|
+
);
|
|
2009
|
+
this.haltDebugQueueOnFalseOutput(token.nodeId);
|
|
2010
|
+
this.pushDebugSnapshot();
|
|
2011
|
+
return {
|
|
2012
|
+
done: this.debugQueue.length === 0,
|
|
2013
|
+
entry: this.traceEntries[this.traceEntries.length - 1],
|
|
2014
|
+
haltedByFalseSignal: halted || this.isDebugHaltedByFalseOutput(token.nodeId)
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
const entry = await this.executeDebugToken(token, nodeLabelById);
|
|
2018
|
+
this.haltDebugQueueOnFalseOutput(token.nodeId);
|
|
2019
|
+
this.pushDebugSnapshot();
|
|
2020
|
+
return {
|
|
2021
|
+
done: this.debugQueue.length === 0,
|
|
2022
|
+
entry,
|
|
2023
|
+
haltedByFalseSignal: this.isDebugHaltedByFalseOutput(token.nodeId)
|
|
2024
|
+
};
|
|
2025
|
+
} finally {
|
|
2026
|
+
this.debugProgressCallback = prevCallback;
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
notifyDebugProgress() {
|
|
2030
|
+
this.debugProgressCallback?.([...this.traceEntries]);
|
|
2031
|
+
}
|
|
2032
|
+
async awaitClockDelay(ms, sessionKey) {
|
|
2033
|
+
if (ms <= 0) return;
|
|
2034
|
+
const step = 50;
|
|
2035
|
+
let elapsed = 0;
|
|
2036
|
+
while (elapsed < ms) {
|
|
2037
|
+
if (sessionKey && isClockSessionAborted(sessionKey)) return;
|
|
2038
|
+
const chunk = Math.min(step, ms - elapsed);
|
|
2039
|
+
await new Promise((resolve) => setTimeout(resolve, chunk));
|
|
2040
|
+
elapsed += chunk;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
buildTraceInputsForNode(nodeId, nodeType) {
|
|
2044
|
+
const def = getNodeDefinition(nodeType);
|
|
2045
|
+
const inputs = {};
|
|
2046
|
+
for (const port of def.inputs) {
|
|
2047
|
+
inputs[port.name] = serializeTraceValue(
|
|
2048
|
+
this.resolvePortInputValue(nodeId, port.name)
|
|
2049
|
+
);
|
|
2050
|
+
}
|
|
2051
|
+
return inputs;
|
|
2052
|
+
}
|
|
2053
|
+
appendDebugTraceEntry(token, nodeLabelById, startedAt, options) {
|
|
2054
|
+
const def = getNodeDefinition(token.nodeType);
|
|
2055
|
+
const outputs = {};
|
|
2056
|
+
for (const port of def.outputs) {
|
|
2057
|
+
outputs[port.name] = serializeTraceValue(
|
|
2058
|
+
this.getNodeOutput(token.nodeId, port.name)
|
|
2059
|
+
);
|
|
2060
|
+
}
|
|
2061
|
+
const entry = {
|
|
2062
|
+
id: createTraceEntryId(),
|
|
2063
|
+
nodeId: token.nodeId,
|
|
2064
|
+
nodeLabel: options?.tickLabel ?? nodeLabelById?.[token.nodeId],
|
|
2065
|
+
nodeType: token.nodeType,
|
|
2066
|
+
startedAt,
|
|
2067
|
+
finishedAt: Date.now(),
|
|
2068
|
+
isoTime: new Date(startedAt).toISOString(),
|
|
2069
|
+
inputs: options?.inputs ?? this.buildTraceInputsForNode(token.nodeId, token.nodeType),
|
|
2070
|
+
outputs,
|
|
2071
|
+
error: options?.error,
|
|
2072
|
+
clockTickIndex: options?.clockTickIndex,
|
|
2073
|
+
clockTickTotal: options?.clockTickTotal
|
|
2074
|
+
};
|
|
2075
|
+
this.traceEntries.push(entry);
|
|
2076
|
+
this.notifyDebugProgress();
|
|
2077
|
+
return entry;
|
|
2078
|
+
}
|
|
2079
|
+
enqueueDebugTargets(sourceNodeId, outPort, scope) {
|
|
2080
|
+
return this.findSignalTargets(sourceNodeId, outPort).map((target) => ({
|
|
2081
|
+
tokenId: createTokenId(),
|
|
2082
|
+
nodeId: target.nodeId,
|
|
2083
|
+
nodeType: target.nodeType,
|
|
2084
|
+
inPort: target.inPort,
|
|
2085
|
+
scope: cloneScope(scope)
|
|
2086
|
+
}));
|
|
2087
|
+
}
|
|
2088
|
+
async runDebugTokenSubqueue(queue, nodeLabelById, abortSessionKey) {
|
|
2089
|
+
const executor = this.createExecutor(queue);
|
|
2090
|
+
while (queue.length > 0) {
|
|
2091
|
+
if (abortSessionKey && isClockSessionAborted(abortSessionKey)) {
|
|
2092
|
+
queue.length = 0;
|
|
2093
|
+
return false;
|
|
2094
|
+
}
|
|
2095
|
+
const token = queue.shift();
|
|
2096
|
+
if (token.nodeType === CLOCK_NODE_TYPE) {
|
|
2097
|
+
const node = this.requireNode(token.nodeId);
|
|
2098
|
+
const config = normalizeClockConfig({
|
|
2099
|
+
...DEFAULT_CLOCK_NODE_CONFIG,
|
|
2100
|
+
...node.clockConfig
|
|
2101
|
+
});
|
|
2102
|
+
const halted = await this.executeClockScheduleForDebug(
|
|
2103
|
+
token,
|
|
2104
|
+
config,
|
|
2105
|
+
nodeLabelById
|
|
2106
|
+
);
|
|
2107
|
+
if (halted) return true;
|
|
2108
|
+
continue;
|
|
2109
|
+
}
|
|
2110
|
+
await this.executeDebugToken(token, nodeLabelById, executor, queue);
|
|
2111
|
+
if (abortSessionKey && isClockSessionAborted(abortSessionKey)) {
|
|
2112
|
+
queue.length = 0;
|
|
2113
|
+
return false;
|
|
2114
|
+
}
|
|
2115
|
+
if (this.isDebugHaltedByFalseOutput(token.nodeId)) {
|
|
2116
|
+
return true;
|
|
2117
|
+
}
|
|
2118
|
+
this.pushDebugSnapshot();
|
|
2119
|
+
}
|
|
2120
|
+
return false;
|
|
2121
|
+
}
|
|
2122
|
+
async executeDebugToken(token, nodeLabelById, executor, emitQueue) {
|
|
2123
|
+
const startedAt = Date.now();
|
|
2124
|
+
let error;
|
|
2125
|
+
const runExecutor = executor ?? this.debugExecutor ?? this.createExecutor(this.debugQueue ?? []);
|
|
2126
|
+
if (!this.syncTokenFromGraph(token)) {
|
|
2127
|
+
return this.appendDebugTraceEntry(token, nodeLabelById, startedAt, {
|
|
2128
|
+
error: "\u8282\u70B9\u5DF2\u4ECE\u84DD\u56FE\u4E2D\u79FB\u9664"
|
|
2129
|
+
});
|
|
2130
|
+
}
|
|
2131
|
+
try {
|
|
2132
|
+
await runExecutor.executeToken(token);
|
|
2133
|
+
} catch (err) {
|
|
2134
|
+
error = err instanceof Error ? err.message : String(err);
|
|
2135
|
+
this.setNodeOutput(
|
|
2136
|
+
token.nodeId,
|
|
2137
|
+
"out",
|
|
2138
|
+
createFalseSignal(error)
|
|
2139
|
+
);
|
|
2140
|
+
const targets = emitQueue ?? this.debugQueue;
|
|
2141
|
+
if (targets) {
|
|
2142
|
+
for (const next of this.enqueueDebugTargets(
|
|
2143
|
+
token.nodeId,
|
|
2144
|
+
"out",
|
|
2145
|
+
token.scope
|
|
2146
|
+
)) {
|
|
2147
|
+
targets.push(next);
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
return this.appendDebugTraceEntry(token, nodeLabelById, startedAt, {
|
|
2152
|
+
error
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
/**
|
|
2156
|
+
* 调试模式下执行完整时钟序列:等待 n 次输出(含间隔),
|
|
2157
|
+
* 每次更新 trace / 画布高亮,并同步跑完当次下游链。
|
|
2158
|
+
*/
|
|
2159
|
+
async executeClockScheduleForDebug(token, config, nodeLabelById) {
|
|
2160
|
+
const sessionKey = buildClockSessionKey(this.clockScopeId(), token.nodeId);
|
|
2161
|
+
clearClockSessionAbort(sessionKey);
|
|
2162
|
+
markClockNodeActive(token.nodeId);
|
|
2163
|
+
try {
|
|
2164
|
+
const normalized = normalizeClockConfig(config);
|
|
2165
|
+
const baseInputs = this.buildTraceInputsForNode(
|
|
2166
|
+
token.nodeId,
|
|
2167
|
+
token.nodeType
|
|
2168
|
+
);
|
|
2169
|
+
const input = this.resolvePortInputValue(token.nodeId, "in");
|
|
2170
|
+
const finishWithOutput = async (output, tickLabel) => {
|
|
2171
|
+
this.setNodeOutput(token.nodeId, "out", output);
|
|
2172
|
+
this.appendDebugTraceEntry(token, nodeLabelById, Date.now(), {
|
|
2173
|
+
tickLabel,
|
|
2174
|
+
inputs: baseInputs
|
|
2175
|
+
});
|
|
2176
|
+
this.pushDebugSnapshot();
|
|
2177
|
+
const subQueue = this.enqueueDebugTargets(
|
|
2178
|
+
token.nodeId,
|
|
2179
|
+
"out",
|
|
2180
|
+
token.scope
|
|
2181
|
+
);
|
|
2182
|
+
return this.runDebugTokenSubqueue(subQueue, nodeLabelById, sessionKey);
|
|
2183
|
+
};
|
|
2184
|
+
if (isFalseSignal(input)) {
|
|
2185
|
+
return finishWithOutput(input);
|
|
2186
|
+
}
|
|
2187
|
+
if (!isTrueSignal(input)) {
|
|
2188
|
+
return finishWithOutput(
|
|
2189
|
+
createFalseSignal("\u65F6\u949F\u8282\u70B9\u9700\u8981\u6536\u5230\u771F\u4FE1\u53F7\u540E\u624D\u4F1A\u542F\u52A8")
|
|
2190
|
+
);
|
|
2191
|
+
}
|
|
2192
|
+
const validation = validateClockScheduleConfig(normalized);
|
|
2193
|
+
if (!validation.ok) {
|
|
2194
|
+
return finishWithOutput(createFalseSignal(validation.error));
|
|
2195
|
+
}
|
|
2196
|
+
const baseLabel = nodeLabelById?.[token.nodeId] ?? token.nodeId;
|
|
2197
|
+
const scheduleStartMs = Date.now();
|
|
2198
|
+
for (let i = 0; i < normalized.outputCount; i++) {
|
|
2199
|
+
if (isClockSessionAborted(sessionKey)) return false;
|
|
2200
|
+
const waitMs = getClockTickWaitMs(normalized, i, scheduleStartMs);
|
|
2201
|
+
if (waitMs > 0) {
|
|
2202
|
+
await this.awaitClockDelay(waitMs, sessionKey);
|
|
2203
|
+
}
|
|
2204
|
+
if (isClockSessionAborted(sessionKey)) return false;
|
|
2205
|
+
const tickStarted = Date.now();
|
|
2206
|
+
const value = buildClockSignalValue(normalized);
|
|
2207
|
+
this.setNodeOutput(token.nodeId, "out", createTrueSignal(value));
|
|
2208
|
+
const tickLabel = normalized.outputCount > 1 ? `${baseLabel} (${i + 1}/${normalized.outputCount})` : baseLabel;
|
|
2209
|
+
this.appendDebugTraceEntry(token, nodeLabelById, tickStarted, {
|
|
2210
|
+
tickLabel,
|
|
2211
|
+
inputs: baseInputs,
|
|
2212
|
+
clockTickIndex: i + 1,
|
|
2213
|
+
clockTickTotal: normalized.outputCount
|
|
2214
|
+
});
|
|
2215
|
+
this.pushDebugSnapshot();
|
|
2216
|
+
const subQueue = this.enqueueDebugTargets(
|
|
2217
|
+
token.nodeId,
|
|
2218
|
+
"out",
|
|
2219
|
+
token.scope
|
|
2220
|
+
);
|
|
2221
|
+
const halted = await this.runDebugTokenSubqueue(
|
|
2222
|
+
subQueue,
|
|
2223
|
+
nodeLabelById,
|
|
2224
|
+
sessionKey
|
|
2225
|
+
);
|
|
2226
|
+
if (halted || isClockSessionAborted(sessionKey)) return halted;
|
|
2227
|
+
}
|
|
2228
|
+
return false;
|
|
2229
|
+
} finally {
|
|
2230
|
+
markClockNodeInactive(token.nodeId);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
isDebugHaltedByFalseOutput(nodeId) {
|
|
2234
|
+
if (this.graph.allowFalseSignalPropagation) return false;
|
|
2235
|
+
const targetId = nodeId ?? this.traceEntries[this.traceEntries.length - 1]?.nodeId;
|
|
2236
|
+
if (!targetId) return false;
|
|
2237
|
+
return this.isFalseOutputNode(targetId);
|
|
2238
|
+
}
|
|
2239
|
+
isFalseOutputNode(nodeId) {
|
|
2240
|
+
const out = this.getNodeOutput(nodeId, "out");
|
|
2241
|
+
return out !== void 0 && isFalseSignal(out);
|
|
2242
|
+
}
|
|
2243
|
+
haltDebugQueueOnFalseOutput(nodeId) {
|
|
2244
|
+
if (!this.debugQueue || this.graph.allowFalseSignalPropagation) return;
|
|
2245
|
+
if (this.isFalseOutputNode(nodeId)) {
|
|
2246
|
+
this.debugQueue = [];
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
async debugRunAll(nodeLabelById, onProgress) {
|
|
2250
|
+
while (this.debugQueue && this.debugQueue.length > 0) {
|
|
2251
|
+
await this.debugStep(nodeLabelById, onProgress);
|
|
2252
|
+
}
|
|
2253
|
+
return this.getTraceEntries();
|
|
2254
|
+
}
|
|
2255
|
+
registerBlueprintRefBehavior() {
|
|
2256
|
+
const runner = this;
|
|
2257
|
+
this.behaviors.registerJS("blueprint-ref-run", async ({ token, io }) => {
|
|
2258
|
+
const node = runner.requireNode(token.nodeId);
|
|
2259
|
+
try {
|
|
2260
|
+
const input = await io.getInput("in");
|
|
2261
|
+
if (!isTrueSignal(input)) {
|
|
2262
|
+
io.setOutput(
|
|
2263
|
+
"out",
|
|
2264
|
+
createFalseSignal("\u84DD\u56FE\u8282\u70B9\u9700\u8981\u6536\u5230\u771F\u4FE1\u53F7\u540E\u624D\u4F1A\u6267\u884C")
|
|
2265
|
+
);
|
|
2266
|
+
io.emitFlow("out");
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
const libraryId = node.libraryBlueprintId;
|
|
2270
|
+
if (!libraryId) {
|
|
2271
|
+
io.setOutput("out", createFalseSignal("\u672A\u9009\u62E9\u84DD\u56FE\u5E93\u4E2D\u7684\u84DD\u56FE"));
|
|
2272
|
+
io.emitFlow("out");
|
|
2273
|
+
return;
|
|
2274
|
+
}
|
|
2275
|
+
if (!runner.resolveLibraryBlueprint) {
|
|
2276
|
+
io.setOutput("out", createFalseSignal("\u84DD\u56FE\u5E93\u89E3\u6790\u5668\u672A\u914D\u7F6E"));
|
|
2277
|
+
io.emitFlow("out");
|
|
2278
|
+
return;
|
|
2279
|
+
}
|
|
2280
|
+
const scopeStack = token.scope.vars.get(BLUEPRINT_CALL_STACK_KEY);
|
|
2281
|
+
const callStack = resolveBlueprintCallStack(
|
|
2282
|
+
scopeStack,
|
|
2283
|
+
runner.rootLibraryBlueprintId
|
|
2284
|
+
);
|
|
2285
|
+
const runtimeCycle = detectRuntimeBlueprintCycle(
|
|
2286
|
+
callStack,
|
|
2287
|
+
libraryId,
|
|
2288
|
+
runner.resolveBlueprintName
|
|
2289
|
+
);
|
|
2290
|
+
if (!runtimeCycle.ok) {
|
|
2291
|
+
io.setOutput("out", createFalseSignal(runtimeCycle.message));
|
|
2292
|
+
io.emitFlow("out");
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
const nestedGraph = await runner.resolveLibraryBlueprint(libraryId);
|
|
2296
|
+
if (!nestedGraph) {
|
|
2297
|
+
io.setOutput(
|
|
2298
|
+
"out",
|
|
2299
|
+
createFalseSignal(`\u84DD\u56FE\u5E93\u8BB0\u5F55\u4E0D\u5B58\u5728: ${libraryId}`)
|
|
2300
|
+
);
|
|
2301
|
+
io.emitFlow("out");
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
const nestedScope = cloneScope(token.scope);
|
|
2305
|
+
nestedScope.vars.set(BLUEPRINT_CALL_STACK_KEY, [...callStack, libraryId]);
|
|
2306
|
+
const subRunner = new _BlueprintGraphRunner(nestedGraph, {
|
|
2307
|
+
resolveLibraryBlueprint: runner.resolveLibraryBlueprint,
|
|
2308
|
+
rootLibraryBlueprintId: libraryId,
|
|
2309
|
+
resolveBlueprintName: runner.resolveBlueprintName,
|
|
2310
|
+
onViewScopeUpdate: runner.onViewScopeUpdate
|
|
2311
|
+
});
|
|
2312
|
+
await subRunner.emitBlueprintActivated(input.value, nestedScope);
|
|
2313
|
+
const nestedOutputs = await subRunner.runFromFlowEntries(nestedScope, {
|
|
2314
|
+
preserveOutputs: true
|
|
2315
|
+
});
|
|
2316
|
+
const payload = {
|
|
2317
|
+
nodeId: token.nodeId,
|
|
2318
|
+
nodeType: node.nodeType,
|
|
2319
|
+
libraryBlueprintId: libraryId,
|
|
2320
|
+
blueprintName: node.blueprintName ?? nestedGraph.nodes[0]?.blueprintName,
|
|
2321
|
+
nestedOutputs
|
|
2322
|
+
};
|
|
2323
|
+
io.setOutput("out", createTrueSignal(payload));
|
|
2324
|
+
} catch (error) {
|
|
2325
|
+
io.setOutput(
|
|
2326
|
+
"out",
|
|
2327
|
+
createFalseSignal(
|
|
2328
|
+
error instanceof Error ? error.message : String(error)
|
|
2329
|
+
)
|
|
2330
|
+
);
|
|
2331
|
+
}
|
|
2332
|
+
io.emitFlow("out");
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2335
|
+
registerFetchBehavior() {
|
|
2336
|
+
const runner = this;
|
|
2337
|
+
this.behaviors.registerJS("fetch-run", async ({ token, io }) => {
|
|
2338
|
+
const node = runner.requireNode(token.nodeId);
|
|
2339
|
+
try {
|
|
2340
|
+
const inputPort = token.inPort || "in";
|
|
2341
|
+
const input = await io.getInput(inputPort);
|
|
2342
|
+
if (isFalseSignal(input)) {
|
|
2343
|
+
io.setOutput("out", input);
|
|
2344
|
+
io.emitFlow("out");
|
|
2345
|
+
return;
|
|
2346
|
+
}
|
|
2347
|
+
if (!isTrueSignal(input)) {
|
|
2348
|
+
io.setOutput(
|
|
2349
|
+
"out",
|
|
2350
|
+
createFalseSignal(
|
|
2351
|
+
input === void 0 ? "\u6570\u636E\u6E90\u8282\u70B9\u672A\u6536\u5230\u4E0A\u6E38\u8F93\u51FA\uFF0C\u8BF7\u786E\u8BA4\u8FDE\u7EBF\u4E0E\u4E0A\u6E38\u8282\u70B9\u5DF2\u6267\u884C" : "\u6570\u636E\u6E90\u8282\u70B9\u9700\u8981\u6536\u5230\u771F\u4FE1\u53F7\u540E\u624D\u4F1A\u53D1\u8D77\u8BF7\u6C42"
|
|
2352
|
+
)
|
|
2353
|
+
);
|
|
2354
|
+
io.emitFlow("out");
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
const incomingScope = runner.buildFetchIncomingScope(
|
|
2358
|
+
token.nodeId,
|
|
2359
|
+
inputPort,
|
|
2360
|
+
input
|
|
2361
|
+
);
|
|
2362
|
+
const config = applyFetchConfigScope(
|
|
2363
|
+
normalizeFetchRequestConfig(node.fetchConfig),
|
|
2364
|
+
incomingScope
|
|
2365
|
+
);
|
|
2366
|
+
const headersError = getFetchHeadersValidationError(config, incomingScope);
|
|
2367
|
+
if (headersError) {
|
|
2368
|
+
throw new Error(headersError);
|
|
2369
|
+
}
|
|
2370
|
+
const bodyError = getFetchBodyValidationError(config.body, config.body);
|
|
2371
|
+
if (bodyError) {
|
|
2372
|
+
throw new Error(`\u8BF7\u6C42\u4F53\u4E0D\u662F\u6709\u6548 JSON\uFF1A${bodyError}`);
|
|
2373
|
+
}
|
|
2374
|
+
resolveFetchRequestUrl(config);
|
|
2375
|
+
const result = await executeFetch(config, {
|
|
2376
|
+
allowHttpError: runner.isDebugSessionActive()
|
|
2377
|
+
});
|
|
2378
|
+
io.setOutput("out", createTrueSignal(result));
|
|
2379
|
+
} catch (error) {
|
|
2380
|
+
io.setOutput(
|
|
2381
|
+
"out",
|
|
2382
|
+
createFalseSignal(
|
|
2383
|
+
error instanceof Error ? error.message : String(error)
|
|
2384
|
+
)
|
|
2385
|
+
);
|
|
2386
|
+
}
|
|
2387
|
+
io.emitFlow("out");
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
registerLogicBehavior() {
|
|
2391
|
+
const runner = this;
|
|
2392
|
+
this.behaviors.registerJS("logic-run", async ({ token, io }) => {
|
|
2393
|
+
const node = runner.requireNode(token.nodeId);
|
|
2394
|
+
try {
|
|
2395
|
+
const input = await io.getInput("in");
|
|
2396
|
+
if (isFalseSignal(input)) {
|
|
2397
|
+
io.setOutput("out", input);
|
|
2398
|
+
io.emitFlow("out");
|
|
2399
|
+
return;
|
|
2400
|
+
}
|
|
2401
|
+
const inputValue = isTrueSignal(input) ? input.value : void 0;
|
|
2402
|
+
const config = {
|
|
2403
|
+
...DEFAULT_LOGIC_NODE_CONFIG,
|
|
2404
|
+
...node.logicConfig
|
|
2405
|
+
};
|
|
2406
|
+
const result = executeLogicConfig(config, inputValue);
|
|
2407
|
+
io.setOutput("out", createTrueSignal(result));
|
|
2408
|
+
} catch (error) {
|
|
2409
|
+
io.setOutput(
|
|
2410
|
+
"out",
|
|
2411
|
+
createFalseSignal(
|
|
2412
|
+
error instanceof Error ? error.message : String(error)
|
|
2413
|
+
)
|
|
2414
|
+
);
|
|
2415
|
+
}
|
|
2416
|
+
io.emitFlow("out");
|
|
2417
|
+
});
|
|
2418
|
+
}
|
|
2419
|
+
registerJsonBehavior() {
|
|
2420
|
+
const runner = this;
|
|
2421
|
+
this.behaviors.registerJS("json-parse-run", async ({ token, io }) => {
|
|
2422
|
+
const node = runner.requireNode(token.nodeId);
|
|
2423
|
+
try {
|
|
2424
|
+
const input = await io.getInput("in");
|
|
2425
|
+
if (!isTrueSignal(input)) {
|
|
2426
|
+
io.setOutput(
|
|
2427
|
+
"out",
|
|
2428
|
+
createFalseSignal("JSON \u8282\u70B9\u9700\u8981\u6536\u5230\u771F\u4FE1\u53F7\u540E\u624D\u4F1A\u89E3\u6790")
|
|
2429
|
+
);
|
|
2430
|
+
io.emitFlow("out");
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
const config = {
|
|
2434
|
+
...DEFAULT_JSON_NODE_CONFIG,
|
|
2435
|
+
...node.jsonConfig
|
|
2436
|
+
};
|
|
2437
|
+
const value = parseJsonConfig(config);
|
|
2438
|
+
io.setOutput("out", createTrueSignal(value));
|
|
2439
|
+
} catch (error) {
|
|
2440
|
+
io.setOutput(
|
|
2441
|
+
"out",
|
|
2442
|
+
createFalseSignal(
|
|
2443
|
+
error instanceof Error ? error.message : String(error)
|
|
2444
|
+
)
|
|
2445
|
+
);
|
|
2446
|
+
}
|
|
2447
|
+
io.emitFlow("out");
|
|
2448
|
+
});
|
|
2449
|
+
}
|
|
2450
|
+
registerStorageBehavior() {
|
|
2451
|
+
const runner = this;
|
|
2452
|
+
this.behaviors.registerJS("storage-run", async ({ token, io }) => {
|
|
2453
|
+
const node = runner.requireNode(token.nodeId);
|
|
2454
|
+
try {
|
|
2455
|
+
const inputPort = token.inPort || "in";
|
|
2456
|
+
const input = await io.getInput(inputPort);
|
|
2457
|
+
if (isFalseSignal(input)) {
|
|
2458
|
+
io.setOutput("out", input);
|
|
2459
|
+
io.emitFlow("out");
|
|
2460
|
+
return;
|
|
2461
|
+
}
|
|
2462
|
+
if (!isTrueSignal(input)) {
|
|
2463
|
+
io.setOutput(
|
|
2464
|
+
"out",
|
|
2465
|
+
createFalseSignal("\u5B58\u50A8\u8282\u70B9\u9700\u8981\u6536\u5230\u771F\u4FE1\u53F7\u540E\u624D\u4F1A\u8BFB\u5199\u7F13\u5B58")
|
|
2466
|
+
);
|
|
2467
|
+
io.emitFlow("out");
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
const incomingScope = runner.buildFetchIncomingScope(
|
|
2471
|
+
token.nodeId,
|
|
2472
|
+
inputPort,
|
|
2473
|
+
input
|
|
2474
|
+
);
|
|
2475
|
+
const config = normalizeStorageConfig({
|
|
2476
|
+
...DEFAULT_STORAGE_NODE_CONFIG,
|
|
2477
|
+
...node.storageConfig
|
|
2478
|
+
});
|
|
2479
|
+
const value = executeStorageConfig(config, incomingScope);
|
|
2480
|
+
io.setOutput("out", createTrueSignal(value));
|
|
2481
|
+
} catch (error) {
|
|
2482
|
+
io.setOutput(
|
|
2483
|
+
"out",
|
|
2484
|
+
createFalseSignal(
|
|
2485
|
+
error instanceof Error ? error.message : String(error)
|
|
2486
|
+
)
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2489
|
+
io.emitFlow("out");
|
|
2490
|
+
});
|
|
2491
|
+
}
|
|
2492
|
+
registerClockBehavior() {
|
|
2493
|
+
const runner = this;
|
|
2494
|
+
this.behaviors.registerJS("clock-run", async ({ token, io }) => {
|
|
2495
|
+
const node = runner.requireNode(token.nodeId);
|
|
2496
|
+
const config = normalizeClockConfig({
|
|
2497
|
+
...DEFAULT_CLOCK_NODE_CONFIG,
|
|
2498
|
+
...node.clockConfig
|
|
2499
|
+
});
|
|
2500
|
+
try {
|
|
2501
|
+
const input = await io.getInput("in");
|
|
2502
|
+
if (isFalseSignal(input)) {
|
|
2503
|
+
io.setOutput("out", input);
|
|
2504
|
+
io.emitFlow("out");
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2507
|
+
if (!isTrueSignal(input)) {
|
|
2508
|
+
io.setOutput(
|
|
2509
|
+
"out",
|
|
2510
|
+
createFalseSignal("\u65F6\u949F\u8282\u70B9\u9700\u8981\u6536\u5230\u771F\u4FE1\u53F7\u540E\u624D\u4F1A\u542F\u52A8")
|
|
2511
|
+
);
|
|
2512
|
+
io.emitFlow("out");
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2515
|
+
const validation = validateClockScheduleConfig(config);
|
|
2516
|
+
if (!validation.ok) {
|
|
2517
|
+
io.setOutput("out", createFalseSignal(validation.error));
|
|
2518
|
+
io.emitFlow("out");
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
if (runner.isDebugSessionActive()) {
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
runner.startClockSchedule(token.nodeId, config, token.scope);
|
|
2525
|
+
} catch (error) {
|
|
2526
|
+
io.setOutput(
|
|
2527
|
+
"out",
|
|
2528
|
+
createFalseSignal(
|
|
2529
|
+
error instanceof Error ? error.message : String(error)
|
|
2530
|
+
)
|
|
2531
|
+
);
|
|
2532
|
+
io.emitFlow("out");
|
|
2533
|
+
}
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
registerAndBehavior() {
|
|
2537
|
+
this.behaviors.registerJS("and-run", async ({ io }) => {
|
|
2538
|
+
const inA = await io.getInput("inA");
|
|
2539
|
+
const inB = await io.getInput("inB");
|
|
2540
|
+
if (isTrueSignal(inA) && isTrueSignal(inB)) {
|
|
2541
|
+
io.setOutput(
|
|
2542
|
+
"out",
|
|
2543
|
+
createTrueSignal({ inA: inA.value, inB: inB.value })
|
|
2544
|
+
);
|
|
2545
|
+
} else {
|
|
2546
|
+
io.setOutput(
|
|
2547
|
+
"out",
|
|
2548
|
+
createFalseSignal("\u5E76\u8FD0\u7B97\uFF1A\u4E24\u4E2A\u8F93\u5165\u987B\u5747\u4E3A\u771F\u4FE1\u53F7")
|
|
2549
|
+
);
|
|
2550
|
+
}
|
|
2551
|
+
io.emitFlow("out");
|
|
2552
|
+
});
|
|
2553
|
+
}
|
|
2554
|
+
registerViewBindBehavior() {
|
|
2555
|
+
const runner = this;
|
|
2556
|
+
this.behaviors.registerJS("view-bind-run", async ({ token, io }) => {
|
|
2557
|
+
const node = runner.requireNode(token.nodeId);
|
|
2558
|
+
const input = await io.getInput("in");
|
|
2559
|
+
if (isTrueSignal(input) && node.viewElementIds?.length) {
|
|
2560
|
+
runner.onViewScopeUpdate?.(node.viewElementIds, input.value);
|
|
2561
|
+
}
|
|
2562
|
+
if (isFalseSignal(input)) {
|
|
2563
|
+
io.setOutput("out", input);
|
|
2564
|
+
} else if (isTrueSignal(input)) {
|
|
2565
|
+
io.setOutput("out", createTrueSignal(input.value));
|
|
2566
|
+
} else {
|
|
2567
|
+
io.setOutput("out", createTrueSignal(void 0));
|
|
2568
|
+
}
|
|
2569
|
+
io.emitFlow("out");
|
|
2570
|
+
});
|
|
2571
|
+
}
|
|
2572
|
+
async runFromNode(nodeId, lifecycleSignal, parentScope, activationInput, viewEvent) {
|
|
2573
|
+
const queue = [
|
|
2574
|
+
{
|
|
2575
|
+
tokenId: createTokenId(),
|
|
2576
|
+
nodeId,
|
|
2577
|
+
nodeType: this.requireNode(nodeId).nodeType,
|
|
2578
|
+
inPort: "in",
|
|
2579
|
+
scope: cloneScope(parentScope)
|
|
2580
|
+
}
|
|
2581
|
+
];
|
|
2582
|
+
if (lifecycleSignal) {
|
|
2583
|
+
queue[0].scope.vars.set(LIFECYCLE_SIGNAL_KEY, lifecycleSignal);
|
|
2584
|
+
}
|
|
2585
|
+
if (lifecycleSignal?.phase === "blueprintActivated") {
|
|
2586
|
+
queue[0].scope.vars.set(
|
|
2587
|
+
BLUEPRINT_ACTIVATION_INPUT_KEY,
|
|
2588
|
+
activationInput
|
|
2589
|
+
);
|
|
2590
|
+
}
|
|
2591
|
+
if (viewEvent) {
|
|
2592
|
+
queue[0].scope.vars.set(VIEW_EVENT_SIGNAL_KEY, viewEvent);
|
|
2593
|
+
queue[0].scope.vars.set(UI_EVENT_PAYLOAD_KEY, viewEvent);
|
|
2594
|
+
}
|
|
2595
|
+
const executor = this.createExecutor(queue);
|
|
2596
|
+
while (queue.length > 0) {
|
|
2597
|
+
const token = queue.shift();
|
|
2598
|
+
if (!this.syncTokenFromGraph(token)) continue;
|
|
2599
|
+
try {
|
|
2600
|
+
await executor.executeToken(token);
|
|
2601
|
+
} catch (error) {
|
|
2602
|
+
this.setNodeOutput(
|
|
2603
|
+
token.nodeId,
|
|
2604
|
+
"out",
|
|
2605
|
+
createFalseSignal(
|
|
2606
|
+
error instanceof Error ? error.message : String(error)
|
|
2607
|
+
)
|
|
2608
|
+
);
|
|
2609
|
+
const nextNodes = this.findSignalTargets(token.nodeId, "out");
|
|
2610
|
+
for (const target of nextNodes) {
|
|
2611
|
+
queue.push({
|
|
2612
|
+
tokenId: createTokenId(),
|
|
2613
|
+
nodeId: target.nodeId,
|
|
2614
|
+
nodeType: target.nodeType,
|
|
2615
|
+
inPort: target.inPort,
|
|
2616
|
+
scope: token.scope,
|
|
2617
|
+
correlationId: token.correlationId ?? token.tokenId
|
|
2618
|
+
});
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
createExecutor(queue, options) {
|
|
2624
|
+
return new Executor({
|
|
2625
|
+
getNodeDefinition,
|
|
2626
|
+
behaviors: this.behaviors,
|
|
2627
|
+
runBlueprint: async () => {
|
|
2628
|
+
},
|
|
2629
|
+
getInputValue: async (token, port) => {
|
|
2630
|
+
const resolvedPort = port || token.inPort || "in";
|
|
2631
|
+
return this.resolvePortInputValue(token.nodeId, resolvedPort);
|
|
2632
|
+
},
|
|
2633
|
+
setNodeOutput: (token, port, value) => {
|
|
2634
|
+
this.setNodeOutput(token.nodeId, port, value);
|
|
2635
|
+
},
|
|
2636
|
+
emitFlow: (token, outPort) => {
|
|
2637
|
+
const targetQueue = options?.emitToActiveDebugQueue && this.debugQueue ? this.debugQueue : queue;
|
|
2638
|
+
const nextNodes = this.findSignalTargets(token.nodeId, outPort);
|
|
2639
|
+
for (const target of nextNodes) {
|
|
2640
|
+
targetQueue.push({
|
|
2641
|
+
tokenId: createTokenId(),
|
|
2642
|
+
nodeId: target.nodeId,
|
|
2643
|
+
nodeType: target.nodeType,
|
|
2644
|
+
inPort: target.inPort,
|
|
2645
|
+
scope: token.scope,
|
|
2646
|
+
correlationId: token.correlationId ?? token.tokenId
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
});
|
|
2651
|
+
}
|
|
2652
|
+
findSignalEntryNodes() {
|
|
2653
|
+
const hasIncoming = /* @__PURE__ */ new Set();
|
|
2654
|
+
for (const edge of this.graph.edges) {
|
|
2655
|
+
hasIncoming.add(edge.target);
|
|
2656
|
+
}
|
|
2657
|
+
return this.graph.nodes.filter(
|
|
2658
|
+
(node) => node.nodeType !== LIFECYCLE_NODE_TYPE && node.nodeType !== EVENT_NODE_TYPE && !hasIncoming.has(node.id)
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2661
|
+
collectOutputs() {
|
|
2662
|
+
const result = {};
|
|
2663
|
+
for (const [nodeId, ports] of this.outputs.entries()) {
|
|
2664
|
+
result[nodeId] = Object.fromEntries(ports.entries());
|
|
2665
|
+
}
|
|
2666
|
+
return result;
|
|
2667
|
+
}
|
|
2668
|
+
requireNode(nodeId) {
|
|
2669
|
+
const node = this.graph.nodes.find((n) => n.id === nodeId);
|
|
2670
|
+
if (!node) {
|
|
2671
|
+
throw new Error(`Graph node not found: ${nodeId}`);
|
|
2672
|
+
}
|
|
2673
|
+
return node;
|
|
2674
|
+
}
|
|
2675
|
+
/** 队列中的 token 可能是在节点改类型(如视图绑定)之前入队的,执行前与最新图对齐 */
|
|
2676
|
+
syncTokenFromGraph(token) {
|
|
2677
|
+
const node = this.graph.nodes.find((n) => n.id === token.nodeId);
|
|
2678
|
+
if (!node) return false;
|
|
2679
|
+
token.nodeType = node.nodeType;
|
|
2680
|
+
return true;
|
|
2681
|
+
}
|
|
2682
|
+
syncDebugQueueWithLatestGraph() {
|
|
2683
|
+
if (!this.debugQueue) return;
|
|
2684
|
+
this.debugQueue = this.debugQueue.filter(
|
|
2685
|
+
(token) => this.syncTokenFromGraph(token)
|
|
2686
|
+
);
|
|
2687
|
+
}
|
|
2688
|
+
findSignalTargets(nodeId, outPort) {
|
|
2689
|
+
return this.graph.edges.filter(
|
|
2690
|
+
(edge) => edge.source === nodeId && (edge.sourceHandle ?? "out") === outPort
|
|
2691
|
+
).map((edge) => {
|
|
2692
|
+
const target = this.requireNode(edge.target);
|
|
2693
|
+
return {
|
|
2694
|
+
nodeId: target.id,
|
|
2695
|
+
nodeType: target.nodeType,
|
|
2696
|
+
inPort: edge.targetHandle ?? "in"
|
|
2697
|
+
};
|
|
2698
|
+
});
|
|
2699
|
+
}
|
|
2700
|
+
findInboundSignalEdges(nodeId, port) {
|
|
2701
|
+
return this.graph.edges.filter(
|
|
2702
|
+
(edge) => edge.target === nodeId && (edge.targetHandle ?? "in") === port
|
|
2703
|
+
);
|
|
2704
|
+
}
|
|
2705
|
+
buildFetchIncomingScope(nodeId, port, fallbackInput) {
|
|
2706
|
+
return resolveFetchIncomingScope({
|
|
2707
|
+
fetchNodeId: nodeId,
|
|
2708
|
+
inputPort: port,
|
|
2709
|
+
nodes: this.graph.nodes.map((node) => ({
|
|
2710
|
+
id: node.id,
|
|
2711
|
+
label: node.label,
|
|
2712
|
+
nodeType: node.nodeType,
|
|
2713
|
+
role: node.role
|
|
2714
|
+
})),
|
|
2715
|
+
edges: this.graph.edges,
|
|
2716
|
+
getOutput: (sourceId, sourcePort) => this.getNodeOutput(sourceId, sourcePort),
|
|
2717
|
+
fallbackInput
|
|
2718
|
+
});
|
|
2719
|
+
}
|
|
2720
|
+
/** 单端口多连线:任一为真则视为真(或语义);支持 triggerNode 注入的入口信号 */
|
|
2721
|
+
resolvePortInputValue(nodeId, port) {
|
|
2722
|
+
const injected = this.injectedInputs.get(`${nodeId}:${port}`);
|
|
2723
|
+
if (injected !== void 0) return injected;
|
|
2724
|
+
const inboundEdges = this.findInboundSignalEdges(nodeId, port);
|
|
2725
|
+
if (inboundEdges.length === 0) return void 0;
|
|
2726
|
+
const values = inboundEdges.map(
|
|
2727
|
+
(edge) => this.getNodeOutput(edge.source, edge.sourceHandle ?? "out")
|
|
2728
|
+
);
|
|
2729
|
+
return combinePortSignalsOr(values);
|
|
2730
|
+
}
|
|
2731
|
+
findInboundSignalEdge(nodeId, port) {
|
|
2732
|
+
return this.findInboundSignalEdges(nodeId, port)[0];
|
|
2733
|
+
}
|
|
2734
|
+
getNodeOutput(nodeId, port) {
|
|
2735
|
+
return this.outputs.get(nodeId)?.get(port);
|
|
2736
|
+
}
|
|
2737
|
+
setNodeOutput(nodeId, port, value) {
|
|
2738
|
+
let nodeOutputs = this.outputs.get(nodeId);
|
|
2739
|
+
if (!nodeOutputs) {
|
|
2740
|
+
nodeOutputs = /* @__PURE__ */ new Map();
|
|
2741
|
+
this.outputs.set(nodeId, nodeOutputs);
|
|
2742
|
+
}
|
|
2743
|
+
nodeOutputs.set(port, value);
|
|
2744
|
+
}
|
|
2745
|
+
};
|
|
2746
|
+
|
|
2747
|
+
exports.AND_NODE_TYPE = AND_NODE_TYPE;
|
|
2748
|
+
exports.BLUEPRINT_ACTIVATION_INPUT_KEY = BLUEPRINT_ACTIVATION_INPUT_KEY;
|
|
2749
|
+
exports.BLUEPRINT_CALL_STACK_KEY = BLUEPRINT_CALL_STACK_KEY;
|
|
2750
|
+
exports.BLUEPRINT_NODE_TYPE = BLUEPRINT_NODE_TYPE;
|
|
2751
|
+
exports.BehaviorRegistry = BehaviorRegistry;
|
|
2752
|
+
exports.BlueprintCycleError = BlueprintCycleError;
|
|
2753
|
+
exports.BlueprintGraphRunner = BlueprintGraphRunner;
|
|
2754
|
+
exports.CLOCK_NODE_TYPE = CLOCK_NODE_TYPE;
|
|
2755
|
+
exports.DEFAULT_CLOCK_NODE_CONFIG = DEFAULT_CLOCK_NODE_CONFIG;
|
|
2756
|
+
exports.DEFAULT_FETCH_REQUEST_CONFIG = DEFAULT_FETCH_REQUEST_CONFIG;
|
|
2757
|
+
exports.DEFAULT_JSON_NODE_CONFIG = DEFAULT_JSON_NODE_CONFIG;
|
|
2758
|
+
exports.DEFAULT_LOGIC_NODE_CONFIG = DEFAULT_LOGIC_NODE_CONFIG;
|
|
2759
|
+
exports.DEFAULT_LOGIC_NODE_TYPE = DEFAULT_LOGIC_NODE_TYPE;
|
|
2760
|
+
exports.DEFAULT_STORAGE_NODE_CONFIG = DEFAULT_STORAGE_NODE_CONFIG;
|
|
2761
|
+
exports.DEFAULT_VIEW_EVENT_NODE_CONFIG = DEFAULT_VIEW_EVENT_NODE_CONFIG;
|
|
2762
|
+
exports.EVENT_NODE_TYPE = EVENT_NODE_TYPE;
|
|
2763
|
+
exports.Executor = Executor;
|
|
2764
|
+
exports.FETCH_CACHES = FETCH_CACHES;
|
|
2765
|
+
exports.FETCH_CREDENTIALS = FETCH_CREDENTIALS;
|
|
2766
|
+
exports.FETCH_HTTP_METHODS = FETCH_HTTP_METHODS;
|
|
2767
|
+
exports.FETCH_MODES = FETCH_MODES;
|
|
2768
|
+
exports.FETCH_NODE_TYPE = FETCH_NODE_TYPE;
|
|
2769
|
+
exports.FETCH_REDIRECTS = FETCH_REDIRECTS;
|
|
2770
|
+
exports.FETCH_RESPONSE_TYPES = FETCH_RESPONSE_TYPES;
|
|
2771
|
+
exports.FETCH_SCOPE_AUTOCOMPLETE_FALLBACK = FETCH_SCOPE_AUTOCOMPLETE_FALLBACK;
|
|
2772
|
+
exports.JSON_NODE_TYPE = JSON_NODE_TYPE;
|
|
2773
|
+
exports.LIFECYCLE_NODE_TYPE = LIFECYCLE_NODE_TYPE;
|
|
2774
|
+
exports.LIFECYCLE_SIGNAL_KEY = LIFECYCLE_SIGNAL_KEY;
|
|
2775
|
+
exports.PAGE_LIFECYCLE_LABELS = PAGE_LIFECYCLE_LABELS;
|
|
2776
|
+
exports.PAGE_LIFECYCLE_PHASES = PAGE_LIFECYCLE_PHASES;
|
|
2777
|
+
exports.STORAGE_KINDS = STORAGE_KINDS;
|
|
2778
|
+
exports.STORAGE_NODE_TYPE = STORAGE_NODE_TYPE;
|
|
2779
|
+
exports.UI_EVENT_PAYLOAD_KEY = UI_EVENT_PAYLOAD_KEY;
|
|
2780
|
+
exports.VIEW_EVENT_SIGNAL_KEY = VIEW_EVENT_SIGNAL_KEY;
|
|
2781
|
+
exports.VIEW_EVENT_TYPES = VIEW_EVENT_TYPES;
|
|
2782
|
+
exports.VIEW_NODE_TYPE = VIEW_NODE_TYPE;
|
|
2783
|
+
exports.abortClockNode = abortClockNode;
|
|
2784
|
+
exports.abortClockSession = abortClockSession;
|
|
2785
|
+
exports.andLogicNodeDefinition = andLogicNodeDefinition;
|
|
2786
|
+
exports.applyFetchConfigScope = applyFetchConfigScope;
|
|
2787
|
+
exports.applyScopeAutocompleteSelection = applyScopeAutocompleteSelection;
|
|
2788
|
+
exports.assertNoBlueprintReferenceCycle = assertNoBlueprintReferenceCycle;
|
|
2789
|
+
exports.blueprintNodeDefinition = blueprintNodeDefinition;
|
|
2790
|
+
exports.buildClockSessionKey = buildClockSessionKey;
|
|
2791
|
+
exports.buildClockSignalValue = buildClockSignalValue;
|
|
2792
|
+
exports.buildEndpointFullUrl = buildEndpointFullUrl;
|
|
2793
|
+
exports.buildEndpointSuggestions = buildEndpointSuggestions;
|
|
2794
|
+
exports.buildIncomingNodeScope = buildIncomingNodeScope;
|
|
2795
|
+
exports.buildScopeExpression = buildScopeExpression;
|
|
2796
|
+
exports.clearClockSessionAbort = clearClockSessionAbort;
|
|
2797
|
+
exports.clockNodeDefinition = clockNodeDefinition;
|
|
2798
|
+
exports.collectArmedViewEventBindings = collectArmedViewEventBindings;
|
|
2799
|
+
exports.collectArmedViewEventNodeIds = collectArmedViewEventNodeIds;
|
|
2800
|
+
exports.collectBlueprintLibraryRefs = collectBlueprintLibraryRefs;
|
|
2801
|
+
exports.collectIncomingNodeScopeEntries = collectIncomingNodeScopeEntries;
|
|
2802
|
+
exports.collectViewEventBindings = collectViewEventBindings;
|
|
2803
|
+
exports.combinePortSignalsOr = combinePortSignalsOr;
|
|
2804
|
+
exports.createClockOutputValue = createClockOutputValue;
|
|
2805
|
+
exports.createFalseSignal = createFalseSignal;
|
|
2806
|
+
exports.createIncomingNodeScopeEntry = createIncomingNodeScopeEntry;
|
|
2807
|
+
exports.createLifecycleSignal = createLifecycleSignal;
|
|
2808
|
+
exports.createTraceEntryId = createTraceEntryId;
|
|
2809
|
+
exports.createTrueSignal = createTrueSignal;
|
|
2810
|
+
exports.createViewEventSignal = createViewEventSignal;
|
|
2811
|
+
exports.defaultLogicNodeDefinition = defaultLogicNodeDefinition;
|
|
2812
|
+
exports.deserializeStorageValue = deserializeStorageValue;
|
|
2813
|
+
exports.detectBlueprintReferenceCycle = detectBlueprintReferenceCycle;
|
|
2814
|
+
exports.detectRuntimeBlueprintCycle = detectRuntimeBlueprintCycle;
|
|
2815
|
+
exports.draftFetchHeadersText = draftFetchHeadersText;
|
|
2816
|
+
exports.evaluateScopeExpression = evaluateScopeExpression;
|
|
2817
|
+
exports.evaluateScopeTemplate = evaluateScopeTemplate;
|
|
2818
|
+
exports.evaluateScopeTemplateInJson = evaluateScopeTemplateInJson;
|
|
2819
|
+
exports.executeFetch = executeFetch;
|
|
2820
|
+
exports.executeLogicConfig = executeLogicConfig;
|
|
2821
|
+
exports.executeStorageConfig = executeStorageConfig;
|
|
2822
|
+
exports.fetchConfigHasScopeTemplate = fetchConfigHasScopeTemplate;
|
|
2823
|
+
exports.fetchNodeDefinition = fetchNodeDefinition;
|
|
2824
|
+
exports.filterEndpointSuggestions = filterEndpointSuggestions;
|
|
2825
|
+
exports.formatBlueprintCycleMessage = formatBlueprintCycleMessage;
|
|
2826
|
+
exports.formatClockTime = formatClockTime;
|
|
2827
|
+
exports.getActiveClockNodeIds = getActiveClockNodeIds;
|
|
2828
|
+
exports.getClockTickDelayOffsetMs = getClockTickDelayOffsetMs;
|
|
2829
|
+
exports.getClockTickWaitMs = getClockTickWaitMs;
|
|
2830
|
+
exports.getFetchBodyValidationError = getFetchBodyValidationError;
|
|
2831
|
+
exports.getFetchHeadersValidationError = getFetchHeadersValidationError;
|
|
2832
|
+
exports.getNodeDefinition = getNodeDefinition;
|
|
2833
|
+
exports.getScopeAutocompleteSuggestions = getScopeAutocompleteSuggestions;
|
|
2834
|
+
exports.hasScopeTemplate = hasScopeTemplate;
|
|
2835
|
+
exports.isClockNodeActive = isClockNodeActive;
|
|
2836
|
+
exports.isClockScheduleActive = isClockScheduleActive;
|
|
2837
|
+
exports.isClockSessionAborted = isClockSessionAborted;
|
|
2838
|
+
exports.isFalseSignal = isFalseSignal;
|
|
2839
|
+
exports.isStorageReadConfigured = isStorageReadConfigured;
|
|
2840
|
+
exports.isStorageSetConfigured = isStorageSetConfigured;
|
|
2841
|
+
exports.isTrueSignal = isTrueSignal;
|
|
2842
|
+
exports.isViewEventType = isViewEventType;
|
|
2843
|
+
exports.isWholeScopeExpression = isWholeScopeExpression;
|
|
2844
|
+
exports.jsonNodeDefinition = jsonNodeDefinition;
|
|
2845
|
+
exports.latestTraceOutputsByNode = latestTraceOutputsByNode;
|
|
2846
|
+
exports.lifecycleNodeDefinition = lifecycleNodeDefinition;
|
|
2847
|
+
exports.looksLikeJsonText = looksLikeJsonText;
|
|
2848
|
+
exports.nodeDefinitionRegistry = nodeDefinitionRegistry;
|
|
2849
|
+
exports.normalizeClockConfig = normalizeClockConfig;
|
|
2850
|
+
exports.normalizeFetchRequestConfig = normalizeFetchRequestConfig;
|
|
2851
|
+
exports.normalizeStorageConfig = normalizeStorageConfig;
|
|
2852
|
+
exports.normalizeViewEventConfig = normalizeViewEventConfig;
|
|
2853
|
+
exports.parseFetchHeadersJson = parseFetchHeadersJson;
|
|
2854
|
+
exports.parseJsonConfig = parseJsonConfig;
|
|
2855
|
+
exports.parseJsonText = parseJsonText;
|
|
2856
|
+
exports.parseScopeAutocomplete = parseScopeAutocomplete;
|
|
2857
|
+
exports.parseSwaggerDocument = parseSwaggerDocument;
|
|
2858
|
+
exports.registerDefaultBehaviors = registerDefaultBehaviors;
|
|
2859
|
+
exports.resolveBlueprintCallStack = resolveBlueprintCallStack;
|
|
2860
|
+
exports.resolveFetchBody = resolveFetchBody;
|
|
2861
|
+
exports.resolveFetchHeaders = resolveFetchHeaders;
|
|
2862
|
+
exports.resolveFetchIncomingScope = resolveFetchIncomingScope;
|
|
2863
|
+
exports.resolveFetchRequestUrl = resolveFetchRequestUrl;
|
|
2864
|
+
exports.resolveFetchScopeAutocompleteRoot = resolveFetchScopeAutocompleteRoot;
|
|
2865
|
+
exports.resolveStorageWriteValue = resolveStorageWriteValue;
|
|
2866
|
+
exports.scheduleClockOutputs = scheduleClockOutputs;
|
|
2867
|
+
exports.serializeStorageValue = serializeStorageValue;
|
|
2868
|
+
exports.serializeTraceValue = serializeTraceValue;
|
|
2869
|
+
exports.snapshotDomEvent = snapshotDomEvent;
|
|
2870
|
+
exports.snapshotViewEventNode = snapshotViewEventNode;
|
|
2871
|
+
exports.startClockSchedule = startClockSchedule;
|
|
2872
|
+
exports.stopAllClockSchedules = stopAllClockSchedules;
|
|
2873
|
+
exports.stopClockSchedule = stopClockSchedule;
|
|
2874
|
+
exports.storageNodeDefinition = storageNodeDefinition;
|
|
2875
|
+
exports.stringifyScopeValue = stringifyScopeValue;
|
|
2876
|
+
exports.subscribeActiveClockNodes = subscribeActiveClockNodes;
|
|
2877
|
+
exports.uniqueStorageKinds = uniqueStorageKinds;
|
|
2878
|
+
exports.validateClockScheduleConfig = validateClockScheduleConfig;
|
|
2879
|
+
exports.validateFetchJsonText = validateFetchJsonText;
|
|
2880
|
+
exports.validateJsonString = validateJsonString;
|
|
2881
|
+
exports.validateLogicSourceCode = validateLogicSourceCode;
|
|
2882
|
+
exports.viewBindNodeDefinition = viewBindNodeDefinition;
|
|
2883
|
+
exports.viewEventNodeDefinition = viewEventNodeDefinition;
|
|
2884
|
+
//# sourceMappingURL=index.cjs.map
|
|
2885
|
+
//# sourceMappingURL=index.cjs.map
|