@renderify/runtime 0.1.0

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.
@@ -0,0 +1,3701 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ BabelRuntimeSourceTranspiler: () => BabelRuntimeSourceTranspiler,
24
+ DefaultRuntimeManager: () => DefaultRuntimeManager,
25
+ DefaultUIRenderer: () => DefaultUIRenderer,
26
+ JspmModuleLoader: () => JspmModuleLoader,
27
+ RuntimeSecurityViolationError: () => RuntimeSecurityViolationError,
28
+ renderPlanInBrowser: () => renderPlanInBrowser
29
+ });
30
+ module.exports = __toCommonJS(src_exports);
31
+
32
+ // src/embed.ts
33
+ var import_security = require("@renderify/security");
34
+
35
+ // src/jspm-module-loader.ts
36
+ var import_ir = require("@renderify/ir");
37
+ var NODE_BUILTIN_MODULE_NAMES = /* @__PURE__ */ new Set([
38
+ "assert",
39
+ "buffer",
40
+ "child_process",
41
+ "cluster",
42
+ "console",
43
+ "constants",
44
+ "crypto",
45
+ "dgram",
46
+ "diagnostics_channel",
47
+ "dns",
48
+ "domain",
49
+ "events",
50
+ "fs",
51
+ "http",
52
+ "http2",
53
+ "https",
54
+ "inspector",
55
+ "module",
56
+ "net",
57
+ "os",
58
+ "path",
59
+ "perf_hooks",
60
+ "process",
61
+ "punycode",
62
+ "querystring",
63
+ "readline",
64
+ "repl",
65
+ "stream",
66
+ "string_decoder",
67
+ "sys",
68
+ "timers",
69
+ "tls",
70
+ "tty",
71
+ "url",
72
+ "util",
73
+ "v8",
74
+ "vm",
75
+ "wasi",
76
+ "worker_threads",
77
+ "zlib"
78
+ ]);
79
+ function hasSystemImport(value) {
80
+ if (typeof value !== "object" || value === null) {
81
+ return false;
82
+ }
83
+ const maybeSystem = value;
84
+ return typeof maybeSystem.import === "function";
85
+ }
86
+ var JspmModuleLoader = class {
87
+ cdnBaseUrl;
88
+ importMap;
89
+ cache = /* @__PURE__ */ new Map();
90
+ constructor(options = {}) {
91
+ this.cdnBaseUrl = this.normalizeCdnBaseUrl(options.cdnBaseUrl);
92
+ this.importMap = options.importMap ?? {};
93
+ }
94
+ async load(specifier) {
95
+ const resolved = this.resolveSpecifier(specifier);
96
+ if (this.cache.has(resolved)) {
97
+ return this.cache.get(resolved);
98
+ }
99
+ const loaded = await this.importWithBestEffort(resolved);
100
+ this.cache.set(resolved, loaded);
101
+ return loaded;
102
+ }
103
+ async unload(specifier) {
104
+ const resolved = this.resolveSpecifier(specifier);
105
+ this.cache.delete(resolved);
106
+ }
107
+ resolveSpecifier(specifier) {
108
+ const normalized = specifier.trim();
109
+ if (normalized.length === 0) {
110
+ throw new Error("Empty module specifier is not supported");
111
+ }
112
+ const mapped = this.importMap[normalized];
113
+ if (mapped) {
114
+ return mapped;
115
+ }
116
+ if (this.isUrl(normalized)) {
117
+ return normalized;
118
+ }
119
+ if (this.isNodeBuiltinSpecifier(normalized)) {
120
+ throw new Error(
121
+ `Node.js builtin modules are not supported in JSPM runtime: ${normalized}`
122
+ );
123
+ }
124
+ if (this.hasUnsupportedScheme(normalized)) {
125
+ const scheme = normalized.slice(0, normalized.indexOf(":"));
126
+ throw new Error(
127
+ `Unsupported module scheme "${scheme}" in specifier: ${normalized}`
128
+ );
129
+ }
130
+ if (normalized.startsWith("npm:")) {
131
+ return this.resolveNpmSpecifier(normalized.slice(4));
132
+ }
133
+ if (this.isBareNpmSpecifier(normalized)) {
134
+ return this.resolveNpmSpecifier(normalized);
135
+ }
136
+ throw new Error(`Unsupported JSPM specifier: ${normalized}`);
137
+ }
138
+ async importWithBestEffort(resolved) {
139
+ const globalValue = globalThis;
140
+ const maybeSystem = typeof globalValue === "object" && globalValue !== null ? globalValue.System : void 0;
141
+ if (hasSystemImport(maybeSystem)) {
142
+ return maybeSystem.import(resolved);
143
+ }
144
+ return import(
145
+ /* webpackIgnore: true */
146
+ resolved
147
+ );
148
+ }
149
+ isUrl(value) {
150
+ try {
151
+ const parsed = new URL(value);
152
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
153
+ } catch {
154
+ return false;
155
+ }
156
+ }
157
+ hasUnsupportedScheme(specifier) {
158
+ const schemeMatch = /^([a-zA-Z][a-zA-Z\d+\-.]*):/.exec(specifier);
159
+ if (!schemeMatch) {
160
+ return false;
161
+ }
162
+ const scheme = schemeMatch[1].toLowerCase();
163
+ return scheme !== "http" && scheme !== "https" && scheme !== "npm";
164
+ }
165
+ isBareNpmSpecifier(specifier) {
166
+ if (specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/")) {
167
+ return false;
168
+ }
169
+ if (/\s/.test(specifier)) {
170
+ return false;
171
+ }
172
+ return /^[@a-zA-Z0-9][@a-zA-Z0-9._/-]*(?:@[a-zA-Z0-9._-]+)?$/.test(
173
+ specifier
174
+ );
175
+ }
176
+ isNodeBuiltinSpecifier(specifier) {
177
+ if (specifier.startsWith("node:")) {
178
+ const name = specifier.slice(5).split("/")[0];
179
+ return name.length > 0;
180
+ }
181
+ const target = specifier.startsWith("npm:") ? specifier.slice(4) : specifier;
182
+ const topLevel = this.extractTopLevelPackageName(target);
183
+ return NODE_BUILTIN_MODULE_NAMES.has(topLevel);
184
+ }
185
+ extractTopLevelPackageName(specifier) {
186
+ if (specifier.startsWith("@")) {
187
+ const segments = specifier.split("/");
188
+ if (segments.length < 2) {
189
+ return specifier;
190
+ }
191
+ const scopedName = segments[1].split("@")[0];
192
+ return `${segments[0]}/${scopedName}`;
193
+ }
194
+ const firstSegment = specifier.split("/")[0];
195
+ return firstSegment.split("@")[0];
196
+ }
197
+ resolveNpmSpecifier(specifier) {
198
+ const normalized = specifier.trim();
199
+ if (normalized.length === 0) {
200
+ throw new Error("Empty npm specifier is not supported");
201
+ }
202
+ const override = import_ir.DEFAULT_JSPM_SPECIFIER_OVERRIDES[normalized];
203
+ if (override) {
204
+ return override;
205
+ }
206
+ return `${this.cdnBaseUrl}/npm:${normalized}`;
207
+ }
208
+ normalizeCdnBaseUrl(input) {
209
+ const raw = input?.trim() || "https://ga.jspm.io";
210
+ const normalized = raw.replace(/\/$/, "");
211
+ return normalized.endsWith("/npm") ? normalized.slice(0, normalized.length - 4) : normalized;
212
+ }
213
+ };
214
+
215
+ // src/manager.ts
216
+ var import_ir9 = require("@renderify/ir");
217
+
218
+ // src/module-fetch.ts
219
+ var import_ir2 = require("@renderify/ir");
220
+ var DEFAULT_ESM_CDN_BASE = "https://esm.sh";
221
+ function buildRemoteModuleAttemptUrls(url, fallbackCdnBases) {
222
+ const candidates = /* @__PURE__ */ new Set();
223
+ candidates.add(url);
224
+ for (const fallbackBase of fallbackCdnBases) {
225
+ const fallback = toConfiguredFallbackUrl(url, fallbackBase);
226
+ if (fallback) {
227
+ candidates.add(fallback);
228
+ }
229
+ }
230
+ return [...candidates];
231
+ }
232
+ function toConfiguredFallbackUrl(url, cdnBase) {
233
+ const normalizedBase = cdnBase.trim().replace(/\/$/, "");
234
+ const specifier = extractJspmNpmSpecifier(url);
235
+ if (!specifier || normalizedBase.length === 0) {
236
+ return void 0;
237
+ }
238
+ if (normalizedBase.includes("esm.sh")) {
239
+ return toEsmFallbackUrl(url, normalizedBase);
240
+ }
241
+ if (normalizedBase.includes("jsdelivr.net")) {
242
+ return `${normalizedBase}/npm/${specifier}`;
243
+ }
244
+ if (normalizedBase.includes("unpkg.com")) {
245
+ const separator = specifier.includes("?") ? "&" : "?";
246
+ return `${normalizedBase}/${specifier}${separator}module`;
247
+ }
248
+ if (normalizedBase.includes("jspm.io")) {
249
+ const root = normalizedBase.endsWith("/npm") ? normalizedBase.slice(0, normalizedBase.length - 4) : normalizedBase;
250
+ return `${root}/npm:${specifier}`;
251
+ }
252
+ return void 0;
253
+ }
254
+ function toEsmFallbackUrl(url, cdnBase = DEFAULT_ESM_CDN_BASE) {
255
+ const specifier = extractJspmNpmSpecifier(url);
256
+ if (!specifier) {
257
+ return void 0;
258
+ }
259
+ const normalizedBase = cdnBase.trim().replace(/\/$/, "");
260
+ if (normalizedBase.length === 0) {
261
+ return void 0;
262
+ }
263
+ const aliasQuery = [
264
+ "alias=react:preact/compat,react-dom:preact/compat,react-dom/client:preact/compat,react/jsx-runtime:preact/jsx-runtime,react/jsx-dev-runtime:preact/jsx-runtime",
265
+ "target=es2022"
266
+ ].join("&");
267
+ const separator = specifier.includes("?") ? "&" : "?";
268
+ return `${normalizedBase}/${specifier}${separator}${aliasQuery}`;
269
+ }
270
+ function extractJspmNpmSpecifier(url) {
271
+ const prefix = "https://ga.jspm.io/npm:";
272
+ if (!url.startsWith(prefix)) {
273
+ return void 0;
274
+ }
275
+ const specifier = url.slice(prefix.length).trim();
276
+ if (specifier.length === 0) {
277
+ return void 0;
278
+ }
279
+ return specifier;
280
+ }
281
+ function isCssModuleResponse(fetched) {
282
+ return fetched.contentType.includes("text/css") || isCssUrl(fetched.url);
283
+ }
284
+ function isJsonModuleResponse(fetched) {
285
+ return fetched.contentType.includes("application/json") || fetched.contentType.includes("text/json") || isJsonUrl(fetched.url);
286
+ }
287
+ function isJavaScriptModuleResponse(fetched) {
288
+ if (isJavaScriptLikeContentType(fetched.contentType)) {
289
+ return true;
290
+ }
291
+ return isJavaScriptUrl(fetched.url);
292
+ }
293
+ function isJavaScriptLikeContentType(contentType) {
294
+ return contentType.includes("javascript") || contentType.includes("ecmascript") || contentType.includes("typescript") || contentType.includes("module");
295
+ }
296
+ function isBinaryLikeContentType(contentType) {
297
+ return contentType.includes("application/wasm") || contentType.includes("image/") || contentType.includes("font/");
298
+ }
299
+ function isJavaScriptUrl(url) {
300
+ const pathname = toUrlPathname(url);
301
+ return /\.(?:m?js|cjs|jsx|ts|tsx)$/i.test(pathname);
302
+ }
303
+ function isCssUrl(url) {
304
+ const pathname = toUrlPathname(url);
305
+ return /\.css$/i.test(pathname);
306
+ }
307
+ function isJsonUrl(url) {
308
+ const pathname = toUrlPathname(url);
309
+ return /\.json$/i.test(pathname);
310
+ }
311
+ function createCssProxyModuleSource(cssText, sourceUrl) {
312
+ const styleId = `renderify-css-${(0, import_ir2.hashStringFNV1a32Base36)(sourceUrl)}`;
313
+ const cssLiteral = JSON.stringify(cssText);
314
+ const styleIdLiteral = JSON.stringify(styleId);
315
+ return [
316
+ "const __css = " + cssLiteral + ";",
317
+ "const __styleId = " + styleIdLiteral + ";",
318
+ 'if (typeof document !== "undefined") {',
319
+ " let __style = null;",
320
+ ' const __styles = document.querySelectorAll("style[data-renderify-style-id]");',
321
+ " for (const __candidate of __styles) {",
322
+ ' if (__candidate.getAttribute("data-renderify-style-id") === __styleId) {',
323
+ " __style = __candidate;",
324
+ " break;",
325
+ " }",
326
+ " }",
327
+ " if (!__style) {",
328
+ ' __style = document.createElement("style");',
329
+ ' __style.setAttribute("data-renderify-style-id", __styleId);',
330
+ " __style.textContent = __css;",
331
+ " document.head.appendChild(__style);",
332
+ " }",
333
+ "}",
334
+ "export default __css;",
335
+ "export const cssText = __css;"
336
+ ].join("\n");
337
+ }
338
+ function createJsonProxyModuleSource(value) {
339
+ return [
340
+ `const __json = ${JSON.stringify(value)};`,
341
+ "export default __json;"
342
+ ].join("\n");
343
+ }
344
+ function createTextProxyModuleSource(text) {
345
+ return [
346
+ `const __text = ${JSON.stringify(text)};`,
347
+ "export default __text;",
348
+ "export const text = __text;"
349
+ ].join("\n");
350
+ }
351
+ function createUrlProxyModuleSource(url) {
352
+ return [
353
+ `const __assetUrl = ${JSON.stringify(url)};`,
354
+ "export default __assetUrl;",
355
+ "export const assetUrl = __assetUrl;"
356
+ ].join("\n");
357
+ }
358
+ async function fetchWithTimeout(url, timeoutMs) {
359
+ if (typeof AbortController === "undefined") {
360
+ return fetch(url);
361
+ }
362
+ const controller = new AbortController();
363
+ const timer = setTimeout(() => {
364
+ controller.abort();
365
+ }, timeoutMs);
366
+ try {
367
+ return await fetch(url, {
368
+ signal: controller.signal
369
+ });
370
+ } finally {
371
+ clearTimeout(timer);
372
+ }
373
+ }
374
+ async function delay(ms) {
375
+ if (ms <= 0) {
376
+ return;
377
+ }
378
+ await new Promise((resolve) => {
379
+ setTimeout(resolve, ms);
380
+ });
381
+ }
382
+ function toUrlPathname(url) {
383
+ try {
384
+ return new URL(url).pathname;
385
+ } catch {
386
+ return url;
387
+ }
388
+ }
389
+
390
+ // src/runtime-environment.ts
391
+ function nowMs() {
392
+ if (typeof performance !== "undefined" && typeof performance.now === "function") {
393
+ return performance.now();
394
+ }
395
+ return Date.now();
396
+ }
397
+ function isBrowserRuntime() {
398
+ return typeof window !== "undefined" && typeof document !== "undefined" && typeof navigator !== "undefined";
399
+ }
400
+ function hasVmScript(value) {
401
+ if (typeof value !== "object" || value === null) {
402
+ return false;
403
+ }
404
+ const candidate = value;
405
+ return typeof candidate.Script === "function";
406
+ }
407
+ function hasPreactFactory(value) {
408
+ if (typeof value !== "object" || value === null) {
409
+ return false;
410
+ }
411
+ const candidate = value;
412
+ return typeof candidate.h === "function";
413
+ }
414
+ function getVmSpecifier() {
415
+ return "node:vm";
416
+ }
417
+ function getPreactSpecifier() {
418
+ return "preact";
419
+ }
420
+
421
+ // src/runtime-budget.ts
422
+ function hasExceededBudget(frame) {
423
+ return nowMs() - frame.startedAt > frame.maxExecutionMs;
424
+ }
425
+ function isAborted(signal) {
426
+ return Boolean(signal?.aborted);
427
+ }
428
+ function createAbortError(message) {
429
+ const error = new Error(message);
430
+ error.name = "AbortError";
431
+ return error;
432
+ }
433
+ function throwIfAborted(signal) {
434
+ if (isAborted(signal)) {
435
+ throw createAbortError("Runtime execution aborted");
436
+ }
437
+ }
438
+ function isAbortError(error) {
439
+ return error instanceof Error && error.name === "AbortError";
440
+ }
441
+ async function withRemainingBudget(operation, frame, timeoutMessage) {
442
+ throwIfAborted(frame.signal);
443
+ const remainingMs = frame.maxExecutionMs - (nowMs() - frame.startedAt);
444
+ if (remainingMs <= 0) {
445
+ throw new Error(timeoutMessage);
446
+ }
447
+ let timer;
448
+ let onAbort;
449
+ const timeoutPromise = new Promise((_resolve, reject) => {
450
+ timer = setTimeout(() => {
451
+ reject(new Error(timeoutMessage));
452
+ }, remainingMs);
453
+ });
454
+ const signal = frame.signal;
455
+ const abortPromise = signal && new Promise((_resolve, reject) => {
456
+ onAbort = () => {
457
+ reject(createAbortError("Runtime execution aborted"));
458
+ };
459
+ signal.addEventListener("abort", onAbort, { once: true });
460
+ });
461
+ try {
462
+ const pending = abortPromise ? [operation(), timeoutPromise, abortPromise] : [operation(), timeoutPromise];
463
+ return await Promise.race(pending);
464
+ } finally {
465
+ if (timer !== void 0) {
466
+ clearTimeout(timer);
467
+ }
468
+ if (signal && onAbort) {
469
+ signal.removeEventListener("abort", onAbort);
470
+ }
471
+ }
472
+ }
473
+
474
+ // src/runtime-component-runtime.ts
475
+ var import_ir3 = require("@renderify/ir");
476
+ async function createPreactRenderArtifact(input) {
477
+ const preact = await loadPreactModule();
478
+ if (!preact) {
479
+ input.diagnostics.push({
480
+ level: "error",
481
+ code: "RUNTIME_PREACT_UNAVAILABLE",
482
+ message: "source.runtime=preact requested but preact runtime is unavailable"
483
+ });
484
+ return void 0;
485
+ }
486
+ if (isPreactLikeVNode(input.sourceExport)) {
487
+ return {
488
+ mode: "preact-vnode",
489
+ payload: input.sourceExport
490
+ };
491
+ }
492
+ if (typeof input.sourceExport !== "function") {
493
+ input.diagnostics.push({
494
+ level: "error",
495
+ code: "RUNTIME_PREACT_EXPORT_INVALID",
496
+ message: "source.runtime=preact requires a component export function"
497
+ });
498
+ return void 0;
499
+ }
500
+ try {
501
+ const vnode = preact.h(
502
+ input.sourceExport,
503
+ input.runtimeInput
504
+ );
505
+ return {
506
+ mode: "preact-vnode",
507
+ payload: vnode
508
+ };
509
+ } catch (error) {
510
+ input.diagnostics.push({
511
+ level: "error",
512
+ code: "RUNTIME_PREACT_VNODE_FAILED",
513
+ message: errorToMessage(error)
514
+ });
515
+ return void 0;
516
+ }
517
+ }
518
+ async function executeComponentFactory(input) {
519
+ if (input.executionProfile !== "isolated-vm") {
520
+ return input.withRemainingBudget(
521
+ async () => input.componentFactory(input.props, input.context, input.children),
522
+ input.timeoutMessage
523
+ );
524
+ }
525
+ const isolated = await executeComponentInVm(input);
526
+ if (isolated.mode === "isolation-unavailable") {
527
+ if (!input.allowIsolationFallback) {
528
+ throw new Error(
529
+ "isolated-vm profile requested but node:vm is unavailable; fallback is disabled"
530
+ );
531
+ }
532
+ input.diagnostics.push({
533
+ level: "warning",
534
+ code: "RUNTIME_SANDBOX_UNAVAILABLE",
535
+ message: "isolated-vm profile requested but node:vm is unavailable; falling back to standard execution"
536
+ });
537
+ return input.withRemainingBudget(
538
+ async () => input.componentFactory(input.props, input.context, input.children),
539
+ input.timeoutMessage
540
+ );
541
+ }
542
+ return isolated.value;
543
+ }
544
+ async function executeComponentInVm(input) {
545
+ const vmModule = await loadVmModule();
546
+ if (!vmModule) {
547
+ return { mode: "isolation-unavailable" };
548
+ }
549
+ const remainingMs = input.maxExecutionMs - (nowMs() - input.startedAt);
550
+ if (remainingMs <= 0) {
551
+ throw new Error("Component execution timed out before sandbox start");
552
+ }
553
+ const serializedFactory = input.componentFactory.toString();
554
+ const sandboxData = {
555
+ props: (0, import_ir3.cloneJsonValue)(input.props),
556
+ context: (0, import_ir3.cloneJsonValue)((0, import_ir3.asJsonValue)(input.context)),
557
+ children: (0, import_ir3.cloneJsonValue)((0, import_ir3.asJsonValue)(input.children))
558
+ };
559
+ const script = new vmModule.Script(
560
+ `'use strict';
561
+ const __component = (${serializedFactory});
562
+ const __result = __component(__input.props, __input.context, __input.children);
563
+ if (__result && typeof __result.then === "function") {
564
+ throw new Error("Async component is not supported in isolated-vm profile");
565
+ }
566
+ __result;`
567
+ );
568
+ const output = script.runInNewContext(
569
+ {
570
+ __input: sandboxData
571
+ },
572
+ {
573
+ timeout: Math.max(1, Math.floor(remainingMs))
574
+ }
575
+ );
576
+ if (typeof output === "string") {
577
+ return {
578
+ mode: "isolated",
579
+ value: output
580
+ };
581
+ }
582
+ if ((0, import_ir3.isRuntimeNode)(output)) {
583
+ return {
584
+ mode: "isolated",
585
+ value: output
586
+ };
587
+ }
588
+ throw new Error("Sandboxed component returned unsupported output");
589
+ }
590
+ function isPreactLikeVNode(value) {
591
+ if (typeof value !== "object" || value === null) {
592
+ return false;
593
+ }
594
+ const record = value;
595
+ return "type" in record && "props" in record;
596
+ }
597
+ async function loadPreactModule() {
598
+ try {
599
+ const maybePreact = await import(getPreactSpecifier());
600
+ if (!hasPreactFactory(maybePreact)) {
601
+ return void 0;
602
+ }
603
+ return maybePreact;
604
+ } catch {
605
+ return void 0;
606
+ }
607
+ }
608
+ async function loadVmModule() {
609
+ if (typeof process === "undefined" || typeof process.versions !== "object" || process.versions === null || typeof process.versions.node !== "string") {
610
+ return void 0;
611
+ }
612
+ try {
613
+ const maybeVm = await import(getVmSpecifier());
614
+ if (!hasVmScript(maybeVm)) {
615
+ return void 0;
616
+ }
617
+ return maybeVm;
618
+ } catch {
619
+ return void 0;
620
+ }
621
+ }
622
+ function errorToMessage(error) {
623
+ if (error instanceof Error) {
624
+ return error.message;
625
+ }
626
+ return String(error);
627
+ }
628
+
629
+ // src/runtime-defaults.ts
630
+ var import_ir4 = require("@renderify/ir");
631
+ var FALLBACK_MAX_IMPORTS = 50;
632
+ var FALLBACK_MAX_COMPONENT_INVOCATIONS = 200;
633
+ var FALLBACK_MAX_EXECUTION_MS = 1500;
634
+ var FALLBACK_EXECUTION_PROFILE = "standard";
635
+ var FALLBACK_JSPM_CDN_BASE = "https://ga.jspm.io/npm";
636
+ var FALLBACK_ESM_CDN_BASE = DEFAULT_ESM_CDN_BASE;
637
+ var FALLBACK_ENABLE_DEPENDENCY_PREFLIGHT = true;
638
+ var FALLBACK_FAIL_ON_DEPENDENCY_PREFLIGHT_ERROR = false;
639
+ var FALLBACK_REMOTE_FETCH_TIMEOUT_MS = 12e3;
640
+ var FALLBACK_REMOTE_FETCH_RETRIES = 2;
641
+ var FALLBACK_REMOTE_FETCH_BACKOFF_MS = 150;
642
+ var FALLBACK_REMOTE_FALLBACK_CDN_BASES = [FALLBACK_ESM_CDN_BASE];
643
+ var FALLBACK_SUPPORTED_SPEC_VERSIONS = [
644
+ import_ir4.DEFAULT_RUNTIME_PLAN_SPEC_VERSION
645
+ ];
646
+ var FALLBACK_ENFORCE_MODULE_MANIFEST = true;
647
+ var FALLBACK_ALLOW_ISOLATION_FALLBACK = false;
648
+ var FALLBACK_BROWSER_SOURCE_SANDBOX_TIMEOUT_MS = 4e3;
649
+ var FALLBACK_BROWSER_SOURCE_SANDBOX_FAIL_CLOSED = true;
650
+ function normalizeSupportedSpecVersions(versions) {
651
+ const normalized = /* @__PURE__ */ new Set();
652
+ const input = versions && versions.length > 0 ? versions : FALLBACK_SUPPORTED_SPEC_VERSIONS;
653
+ for (const entry of input) {
654
+ if (typeof entry !== "string") {
655
+ continue;
656
+ }
657
+ const trimmed = entry.trim();
658
+ if (trimmed.length > 0) {
659
+ normalized.add(trimmed);
660
+ }
661
+ }
662
+ if (normalized.size === 0) {
663
+ normalized.add(import_ir4.DEFAULT_RUNTIME_PLAN_SPEC_VERSION);
664
+ }
665
+ return normalized;
666
+ }
667
+ function normalizeSourceSandboxMode(mode) {
668
+ if (mode === "none" || mode === "worker" || mode === "iframe") {
669
+ return mode;
670
+ }
671
+ return isBrowserRuntime() ? "worker" : "none";
672
+ }
673
+ function normalizeFallbackCdnBases(input) {
674
+ const explicitInput = input !== void 0;
675
+ const candidates = explicitInput ? input : FALLBACK_REMOTE_FALLBACK_CDN_BASES;
676
+ const normalized = /* @__PURE__ */ new Set();
677
+ for (const entry of candidates) {
678
+ if (typeof entry !== "string") {
679
+ continue;
680
+ }
681
+ const trimmed = entry.trim().replace(/\/$/, "");
682
+ if (trimmed.length > 0) {
683
+ normalized.add(trimmed);
684
+ }
685
+ }
686
+ if (normalized.size === 0) {
687
+ return explicitInput ? [] : [FALLBACK_ESM_CDN_BASE];
688
+ }
689
+ return [...normalized];
690
+ }
691
+ function normalizePositiveInteger(value, fallback) {
692
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
693
+ return fallback;
694
+ }
695
+ return value;
696
+ }
697
+ function normalizeNonNegativeInteger(value, fallback) {
698
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value < 0) {
699
+ return fallback;
700
+ }
701
+ return value;
702
+ }
703
+
704
+ // src/runtime-node-resolver.ts
705
+ var import_ir6 = require("@renderify/ir");
706
+
707
+ // src/template.ts
708
+ var import_ir5 = require("@renderify/ir");
709
+ var TEMPLATE_STRINGIFY_MAX_DEPTH = 8;
710
+ var TEMPLATE_STRINGIFY_MAX_NODES = 256;
711
+ var TEMPLATE_STRINGIFY_MAX_LENGTH = 4096;
712
+ var TEMPLATE_TRUNCATED_MARKER = "[Truncated]";
713
+ var TEMPLATE_CIRCULAR = /* @__PURE__ */ Symbol("renderify-template-circular");
714
+ function resolveProps(props, context, state, event) {
715
+ if (!props) {
716
+ return void 0;
717
+ }
718
+ const resolved = {};
719
+ for (const [key, value] of Object.entries(props)) {
720
+ resolved[key] = resolveJsonValue(value, context, state, event);
721
+ }
722
+ return resolved;
723
+ }
724
+ function resolveJsonValue(value, context, state, event) {
725
+ return resolveJsonValueInternal(value, context, state, event, /* @__PURE__ */ new WeakSet());
726
+ }
727
+ function resolveJsonValueInternal(value, context, state, event, seen) {
728
+ if (typeof value === "string") {
729
+ return interpolateTemplate(value, context, state, event);
730
+ }
731
+ if (Array.isArray(value)) {
732
+ if (seen.has(value)) {
733
+ return null;
734
+ }
735
+ seen.add(value);
736
+ const resolved = value.map(
737
+ (item) => resolveJsonValueInternal(item, context, state, event, seen)
738
+ );
739
+ seen.delete(value);
740
+ return resolved;
741
+ }
742
+ if (value !== null && typeof value === "object") {
743
+ if (seen.has(value)) {
744
+ return null;
745
+ }
746
+ seen.add(value);
747
+ const resolved = {};
748
+ for (const [key, item] of Object.entries(value)) {
749
+ resolved[key] = resolveJsonValueInternal(
750
+ item,
751
+ context,
752
+ state,
753
+ event,
754
+ seen
755
+ );
756
+ }
757
+ seen.delete(value);
758
+ return resolved;
759
+ }
760
+ return value;
761
+ }
762
+ function interpolateTemplate(template, context, state, event) {
763
+ return template.replace(/{{\s*([^}]+)\s*}}/g, (_match, expression) => {
764
+ const resolved = resolveExpression(expression, context, state, event);
765
+ if (resolved === void 0 || resolved === null) {
766
+ return "";
767
+ }
768
+ if (typeof resolved === "object") {
769
+ return serializeTemplateObject(resolved);
770
+ }
771
+ return String(resolved);
772
+ });
773
+ }
774
+ function serializeTemplateObject(value) {
775
+ const normalized = toTemplateSerializable(value, 0, /* @__PURE__ */ new WeakSet(), {
776
+ nodes: 0
777
+ });
778
+ if (normalized === TEMPLATE_CIRCULAR || normalized === void 0) {
779
+ return "";
780
+ }
781
+ try {
782
+ const serialized = JSON.stringify(normalized);
783
+ if (typeof serialized !== "string") {
784
+ return "";
785
+ }
786
+ if (serialized.length > TEMPLATE_STRINGIFY_MAX_LENGTH) {
787
+ return `${serialized.slice(0, TEMPLATE_STRINGIFY_MAX_LENGTH)}...`;
788
+ }
789
+ return serialized;
790
+ } catch {
791
+ return "";
792
+ }
793
+ }
794
+ function toTemplateSerializable(value, depth, seen, budget) {
795
+ if (value === void 0) {
796
+ return void 0;
797
+ }
798
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
799
+ return value;
800
+ }
801
+ if (typeof value === "number") {
802
+ return Number.isFinite(value) ? value : null;
803
+ }
804
+ if (typeof value === "bigint") {
805
+ return value.toString();
806
+ }
807
+ if (typeof value === "function" || typeof value === "symbol") {
808
+ return String(value);
809
+ }
810
+ if (typeof value !== "object") {
811
+ return String(value);
812
+ }
813
+ if (seen.has(value)) {
814
+ return TEMPLATE_CIRCULAR;
815
+ }
816
+ if (depth >= TEMPLATE_STRINGIFY_MAX_DEPTH || budget.nodes >= TEMPLATE_STRINGIFY_MAX_NODES) {
817
+ return TEMPLATE_TRUNCATED_MARKER;
818
+ }
819
+ seen.add(value);
820
+ budget.nodes += 1;
821
+ if (Array.isArray(value)) {
822
+ const normalizedArray = [];
823
+ for (const entry of value) {
824
+ const normalized = toTemplateSerializable(entry, depth + 1, seen, budget);
825
+ if (normalized === TEMPLATE_CIRCULAR) {
826
+ seen.delete(value);
827
+ return TEMPLATE_CIRCULAR;
828
+ }
829
+ normalizedArray.push(normalized === void 0 ? null : normalized);
830
+ }
831
+ seen.delete(value);
832
+ return normalizedArray;
833
+ }
834
+ const normalizedRecord = {};
835
+ for (const [key, entry] of Object.entries(value)) {
836
+ const normalized = toTemplateSerializable(entry, depth + 1, seen, budget);
837
+ if (normalized === TEMPLATE_CIRCULAR) {
838
+ seen.delete(value);
839
+ return TEMPLATE_CIRCULAR;
840
+ }
841
+ if (normalized !== void 0) {
842
+ normalizedRecord[key] = normalized;
843
+ }
844
+ }
845
+ seen.delete(value);
846
+ return normalizedRecord;
847
+ }
848
+ function resolveExpression(expression, context, state, event) {
849
+ const path = expression.trim();
850
+ if (path.startsWith("state.")) {
851
+ return (0, import_ir5.getValueByPath)(state, path.slice(6));
852
+ }
853
+ if (path.startsWith("event.")) {
854
+ return (0, import_ir5.getValueByPath)(event, path.slice(6));
855
+ }
856
+ if (path.startsWith("context.")) {
857
+ return (0, import_ir5.getValueByPath)(context, path.slice(8));
858
+ }
859
+ if (path.startsWith("vars.")) {
860
+ return (0, import_ir5.getValueByPath)(context.variables, path.slice(5));
861
+ }
862
+ return (0, import_ir5.getValueByPath)(state, path);
863
+ }
864
+
865
+ // src/runtime-node-resolver.ts
866
+ async function resolveRuntimeNode(input) {
867
+ const {
868
+ node,
869
+ moduleManifest,
870
+ context,
871
+ state,
872
+ event,
873
+ diagnostics,
874
+ frame,
875
+ resolver
876
+ } = input;
877
+ if (node.type === "text") {
878
+ return (0, import_ir6.createTextNode)(
879
+ interpolateTemplate(node.value, context, state, event)
880
+ );
881
+ }
882
+ const resolvedChildren = await resolveChildren(
883
+ node.children ?? [],
884
+ resolver.resolveNode
885
+ );
886
+ if (node.type === "element") {
887
+ return {
888
+ ...node,
889
+ props: resolveProps(node.props, context, state, event),
890
+ children: resolvedChildren
891
+ };
892
+ }
893
+ if (frame.componentInvocations >= frame.maxComponentInvocations) {
894
+ diagnostics.push({
895
+ level: "error",
896
+ code: "RUNTIME_COMPONENT_LIMIT_EXCEEDED",
897
+ message: `Component invocation limit exceeded: ${frame.maxComponentInvocations}`
898
+ });
899
+ return (0, import_ir6.createElementNode)(
900
+ "div",
901
+ { "data-renderify-component-limit": node.module },
902
+ [(0, import_ir6.createTextNode)("Component invocation limit exceeded")]
903
+ );
904
+ }
905
+ frame.componentInvocations += 1;
906
+ const resolvedComponentSpecifier = resolver.resolveRuntimeSpecifier(
907
+ node.module,
908
+ moduleManifest,
909
+ diagnostics,
910
+ "component"
911
+ );
912
+ if (!resolvedComponentSpecifier) {
913
+ return (0, import_ir6.createElementNode)(
914
+ "div",
915
+ { "data-renderify-component-error": node.module },
916
+ [(0, import_ir6.createTextNode)("Missing module manifest entry for component")]
917
+ );
918
+ }
919
+ if (!resolver.moduleLoader) {
920
+ diagnostics.push({
921
+ level: "warning",
922
+ code: "RUNTIME_COMPONENT_SKIPPED",
923
+ message: `Component ${resolvedComponentSpecifier} skipped because module loader is missing`
924
+ });
925
+ return (0, import_ir6.createElementNode)(
926
+ "div",
927
+ { "data-renderify-missing-module": node.module },
928
+ resolvedChildren
929
+ );
930
+ }
931
+ try {
932
+ const loaded = await resolver.withRemainingBudget(
933
+ () => resolver.moduleLoader.load(resolvedComponentSpecifier),
934
+ `Component module timed out: ${resolvedComponentSpecifier}`
935
+ );
936
+ const exportName = node.exportName ?? "default";
937
+ const target = selectExportFromNamespace(loaded, exportName);
938
+ if (typeof target !== "function") {
939
+ diagnostics.push({
940
+ level: "error",
941
+ code: "RUNTIME_COMPONENT_INVALID",
942
+ message: `Export ${exportName} from ${resolvedComponentSpecifier} is not callable`
943
+ });
944
+ return (0, import_ir6.createElementNode)(
945
+ "div",
946
+ { "data-renderify-component-error": `${node.module}:${exportName}` },
947
+ [(0, import_ir6.createTextNode)("Component export is not callable")]
948
+ );
949
+ }
950
+ const runtimeContext = {
951
+ ...context,
952
+ variables: {
953
+ ...context.variables ?? {},
954
+ state,
955
+ event: event ? (0, import_ir6.asJsonValue)(event) : null
956
+ }
957
+ };
958
+ const produced = await executeComponentFactory({
959
+ componentFactory: target,
960
+ props: resolveProps(node.props, context, state, event) ?? {},
961
+ context: runtimeContext,
962
+ children: resolvedChildren,
963
+ executionProfile: frame.executionProfile,
964
+ maxExecutionMs: frame.maxExecutionMs,
965
+ startedAt: frame.startedAt,
966
+ timeoutMessage: `Component execution timed out: ${node.module}`,
967
+ allowIsolationFallback: resolver.allowIsolationFallback,
968
+ diagnostics,
969
+ withRemainingBudget: resolver.withRemainingBudget
970
+ });
971
+ if (typeof produced === "string") {
972
+ return (0, import_ir6.createTextNode)(
973
+ interpolateTemplate(produced, context, state, event)
974
+ );
975
+ }
976
+ if ((0, import_ir6.isRuntimeNode)(produced)) {
977
+ return resolver.resolveNode(produced);
978
+ }
979
+ diagnostics.push({
980
+ level: "error",
981
+ code: "RUNTIME_COMPONENT_OUTPUT_INVALID",
982
+ message: `Component ${resolvedComponentSpecifier} produced unsupported output`
983
+ });
984
+ return (0, import_ir6.createElementNode)(
985
+ "div",
986
+ { "data-renderify-component-error": node.module },
987
+ [(0, import_ir6.createTextNode)("Unsupported component output")]
988
+ );
989
+ } catch (error) {
990
+ diagnostics.push({
991
+ level: "error",
992
+ code: "RUNTIME_COMPONENT_EXEC_FAILED",
993
+ message: `${resolvedComponentSpecifier}: ${resolver.errorToMessage(error)}`
994
+ });
995
+ return (0, import_ir6.createElementNode)(
996
+ "div",
997
+ { "data-renderify-component-error": node.module },
998
+ [(0, import_ir6.createTextNode)("Component execution failed")]
999
+ );
1000
+ }
1001
+ }
1002
+ async function resolveChildren(nodes, resolveNode) {
1003
+ const resolved = [];
1004
+ for (const child of nodes) {
1005
+ resolved.push(await resolveNode(child));
1006
+ }
1007
+ return resolved;
1008
+ }
1009
+ function selectExportFromNamespace(moduleNamespace, exportName) {
1010
+ if (typeof moduleNamespace !== "object" || moduleNamespace === null) {
1011
+ return void 0;
1012
+ }
1013
+ const record = moduleNamespace;
1014
+ return record[exportName];
1015
+ }
1016
+
1017
+ // src/runtime-plan-imports.ts
1018
+ async function resolveRuntimePlanImports(input) {
1019
+ const { imports, maxImports, moduleManifest, diagnostics } = input;
1020
+ for (let i = 0; i < imports.length; i += 1) {
1021
+ if (input.isAborted()) {
1022
+ diagnostics.push({
1023
+ level: "error",
1024
+ code: "RUNTIME_ABORTED",
1025
+ message: "Execution aborted before import resolution"
1026
+ });
1027
+ break;
1028
+ }
1029
+ const specifier = imports[i];
1030
+ const resolvedSpecifier = input.resolveRuntimeSpecifier(
1031
+ specifier,
1032
+ moduleManifest,
1033
+ diagnostics
1034
+ );
1035
+ if (!resolvedSpecifier) {
1036
+ continue;
1037
+ }
1038
+ if (i >= maxImports) {
1039
+ diagnostics.push({
1040
+ level: "warning",
1041
+ code: "RUNTIME_IMPORT_LIMIT_EXCEEDED",
1042
+ message: `Import skipped because maxImports=${maxImports}: ${specifier}`
1043
+ });
1044
+ continue;
1045
+ }
1046
+ if (!input.moduleLoader) {
1047
+ diagnostics.push({
1048
+ level: "warning",
1049
+ code: "RUNTIME_LOADER_MISSING",
1050
+ message: `Import skipped because no module loader is configured: ${resolvedSpecifier}`
1051
+ });
1052
+ continue;
1053
+ }
1054
+ if (input.hasExceededBudget()) {
1055
+ diagnostics.push({
1056
+ level: "error",
1057
+ code: "RUNTIME_TIMEOUT",
1058
+ message: `Execution time budget exceeded before importing: ${specifier}`
1059
+ });
1060
+ break;
1061
+ }
1062
+ try {
1063
+ await input.withRemainingBudget(
1064
+ () => input.moduleLoader.load(resolvedSpecifier),
1065
+ `Import timed out: ${resolvedSpecifier}`
1066
+ );
1067
+ } catch (error) {
1068
+ if (input.isAbortError(error)) {
1069
+ diagnostics.push({
1070
+ level: "error",
1071
+ code: "RUNTIME_ABORTED",
1072
+ message: `Execution aborted during import: ${resolvedSpecifier}`
1073
+ });
1074
+ break;
1075
+ }
1076
+ diagnostics.push({
1077
+ level: "error",
1078
+ code: "RUNTIME_IMPORT_FAILED",
1079
+ message: `${resolvedSpecifier}: ${input.errorToMessage(error)}`
1080
+ });
1081
+ }
1082
+ }
1083
+ }
1084
+
1085
+ // src/runtime-preflight.ts
1086
+ var import_ir7 = require("@renderify/ir");
1087
+ async function collectDependencyProbes(plan, parseSourceImportSpecifiers2) {
1088
+ const probes = [];
1089
+ const seen = /* @__PURE__ */ new Set();
1090
+ const pushProbe = (usage, specifier) => {
1091
+ const trimmed = specifier.trim();
1092
+ if (trimmed.length === 0) {
1093
+ return;
1094
+ }
1095
+ const key = `${usage}:${trimmed}`;
1096
+ if (seen.has(key)) {
1097
+ return;
1098
+ }
1099
+ seen.add(key);
1100
+ probes.push({
1101
+ usage,
1102
+ specifier: trimmed
1103
+ });
1104
+ };
1105
+ for (const specifier of plan.imports ?? []) {
1106
+ pushProbe("import", specifier);
1107
+ }
1108
+ for (const specifier of (0, import_ir7.collectComponentModules)(plan.root)) {
1109
+ pushProbe("component", specifier);
1110
+ }
1111
+ if (plan.source) {
1112
+ const sourceImports = await parseSourceImportSpecifiers2(plan.source.code);
1113
+ for (const specifier of sourceImports) {
1114
+ pushProbe("source-import", specifier);
1115
+ }
1116
+ }
1117
+ return probes;
1118
+ }
1119
+ async function runDependencyPreflight(probes, diagnostics, probeExecutor, options) {
1120
+ const statuses = [];
1121
+ for (const probe of probes) {
1122
+ if (options.isAborted()) {
1123
+ diagnostics.push({
1124
+ level: "error",
1125
+ code: "RUNTIME_ABORTED",
1126
+ message: `Execution aborted during dependency preflight (${probe.usage}:${probe.specifier})`
1127
+ });
1128
+ statuses.push({
1129
+ usage: probe.usage,
1130
+ specifier: probe.specifier,
1131
+ ok: false,
1132
+ message: "Dependency preflight aborted"
1133
+ });
1134
+ return statuses;
1135
+ }
1136
+ if (options.hasExceededBudget()) {
1137
+ diagnostics.push({
1138
+ level: "error",
1139
+ code: "RUNTIME_TIMEOUT",
1140
+ message: `Execution time budget exceeded during dependency preflight (${probe.usage}:${probe.specifier})`
1141
+ });
1142
+ statuses.push({
1143
+ usage: probe.usage,
1144
+ specifier: probe.specifier,
1145
+ ok: false,
1146
+ message: "Dependency preflight timed out"
1147
+ });
1148
+ return statuses;
1149
+ }
1150
+ statuses.push(await probeExecutor(probe));
1151
+ }
1152
+ return statuses;
1153
+ }
1154
+ async function executeDependencyProbe(probe, moduleManifest, diagnostics, executor) {
1155
+ if (probe.usage === "source-import") {
1156
+ const resolved2 = executor.resolveRuntimeSourceSpecifier(
1157
+ probe.specifier,
1158
+ moduleManifest,
1159
+ diagnostics,
1160
+ false
1161
+ );
1162
+ if (resolved2.startsWith("./") || resolved2.startsWith("../") || resolved2.startsWith("/")) {
1163
+ diagnostics.push({
1164
+ level: "error",
1165
+ code: "RUNTIME_PREFLIGHT_SOURCE_IMPORT_RELATIVE_UNRESOLVED",
1166
+ message: `Runtime source entry import must resolve to URL or bare package alias: ${probe.specifier}`
1167
+ });
1168
+ return {
1169
+ usage: probe.usage,
1170
+ specifier: probe.specifier,
1171
+ resolvedSpecifier: resolved2,
1172
+ ok: false,
1173
+ message: "Relative source import could not be resolved"
1174
+ };
1175
+ }
1176
+ const timeoutMessage = `Dependency preflight timed out: ${probe.specifier}`;
1177
+ const loaderCandidate = executor.resolveSourceImportLoaderCandidate(
1178
+ probe.specifier,
1179
+ moduleManifest
1180
+ );
1181
+ try {
1182
+ if (executor.moduleLoader && loaderCandidate) {
1183
+ await executor.withRemainingBudget(
1184
+ () => executor.moduleLoader.load(loaderCandidate),
1185
+ timeoutMessage
1186
+ );
1187
+ return {
1188
+ usage: probe.usage,
1189
+ specifier: probe.specifier,
1190
+ resolvedSpecifier: loaderCandidate,
1191
+ ok: true
1192
+ };
1193
+ }
1194
+ if (executor.isHttpUrl(resolved2)) {
1195
+ await executor.withRemainingBudget(async () => {
1196
+ if (executor.canMaterializeBrowserModules()) {
1197
+ await executor.materializeBrowserRemoteModule(
1198
+ resolved2,
1199
+ moduleManifest,
1200
+ diagnostics
1201
+ );
1202
+ } else {
1203
+ await executor.fetchRemoteModuleCodeWithFallback(
1204
+ resolved2,
1205
+ diagnostics
1206
+ );
1207
+ }
1208
+ }, timeoutMessage);
1209
+ return {
1210
+ usage: probe.usage,
1211
+ specifier: probe.specifier,
1212
+ resolvedSpecifier: resolved2,
1213
+ ok: true
1214
+ };
1215
+ }
1216
+ if (!executor.moduleLoader) {
1217
+ diagnostics.push({
1218
+ level: "warning",
1219
+ code: "RUNTIME_PREFLIGHT_SKIPPED",
1220
+ message: `Dependency preflight skipped (no module loader): ${probe.usage}:${resolved2}`
1221
+ });
1222
+ return {
1223
+ usage: probe.usage,
1224
+ specifier: probe.specifier,
1225
+ resolvedSpecifier: resolved2,
1226
+ ok: false,
1227
+ message: "Dependency preflight skipped because source import is not loadable without module loader"
1228
+ };
1229
+ }
1230
+ await executor.withRemainingBudget(
1231
+ () => executor.moduleLoader.load(resolved2),
1232
+ timeoutMessage
1233
+ );
1234
+ return {
1235
+ usage: probe.usage,
1236
+ specifier: probe.specifier,
1237
+ resolvedSpecifier: resolved2,
1238
+ ok: true
1239
+ };
1240
+ } catch (error) {
1241
+ if (executor.isAbortError(error)) {
1242
+ diagnostics.push({
1243
+ level: "error",
1244
+ code: "RUNTIME_ABORTED",
1245
+ message: `${probe.specifier}: dependency preflight aborted`
1246
+ });
1247
+ return {
1248
+ usage: probe.usage,
1249
+ specifier: probe.specifier,
1250
+ resolvedSpecifier: resolved2,
1251
+ ok: false,
1252
+ message: "Dependency preflight aborted"
1253
+ };
1254
+ }
1255
+ diagnostics.push({
1256
+ level: "error",
1257
+ code: "RUNTIME_PREFLIGHT_SOURCE_IMPORT_FAILED",
1258
+ message: `${probe.specifier}: ${executor.errorToMessage(error)}`
1259
+ });
1260
+ return {
1261
+ usage: probe.usage,
1262
+ specifier: probe.specifier,
1263
+ resolvedSpecifier: resolved2,
1264
+ ok: false,
1265
+ message: executor.errorToMessage(error)
1266
+ };
1267
+ }
1268
+ }
1269
+ const resolved = executor.resolveRuntimeSpecifier(
1270
+ probe.specifier,
1271
+ moduleManifest,
1272
+ diagnostics,
1273
+ probe.usage
1274
+ );
1275
+ if (!resolved) {
1276
+ return {
1277
+ usage: probe.usage,
1278
+ specifier: probe.specifier,
1279
+ ok: false,
1280
+ message: "Module manifest resolution failed"
1281
+ };
1282
+ }
1283
+ if (!executor.moduleLoader) {
1284
+ diagnostics.push({
1285
+ level: "warning",
1286
+ code: "RUNTIME_PREFLIGHT_SKIPPED",
1287
+ message: `Dependency preflight skipped (no module loader): ${probe.usage}:${resolved}`
1288
+ });
1289
+ return {
1290
+ usage: probe.usage,
1291
+ specifier: probe.specifier,
1292
+ resolvedSpecifier: resolved,
1293
+ ok: false,
1294
+ message: "Dependency preflight skipped because module loader is missing"
1295
+ };
1296
+ }
1297
+ try {
1298
+ await executor.withRemainingBudget(
1299
+ () => executor.moduleLoader.load(resolved),
1300
+ `Dependency preflight timed out: ${resolved}`
1301
+ );
1302
+ return {
1303
+ usage: probe.usage,
1304
+ specifier: probe.specifier,
1305
+ resolvedSpecifier: resolved,
1306
+ ok: true
1307
+ };
1308
+ } catch (error) {
1309
+ if (executor.isAbortError(error)) {
1310
+ diagnostics.push({
1311
+ level: "error",
1312
+ code: "RUNTIME_ABORTED",
1313
+ message: `${resolved}: dependency preflight aborted`
1314
+ });
1315
+ return {
1316
+ usage: probe.usage,
1317
+ specifier: probe.specifier,
1318
+ resolvedSpecifier: resolved,
1319
+ ok: false,
1320
+ message: "Dependency preflight aborted"
1321
+ };
1322
+ }
1323
+ diagnostics.push({
1324
+ level: "error",
1325
+ code: probe.usage === "component" ? "RUNTIME_PREFLIGHT_COMPONENT_FAILED" : "RUNTIME_PREFLIGHT_IMPORT_FAILED",
1326
+ message: `${resolved}: ${executor.errorToMessage(error)}`
1327
+ });
1328
+ return {
1329
+ usage: probe.usage,
1330
+ specifier: probe.specifier,
1331
+ resolvedSpecifier: resolved,
1332
+ ok: false,
1333
+ message: executor.errorToMessage(error)
1334
+ };
1335
+ }
1336
+ }
1337
+
1338
+ // src/runtime-source-utils.ts
1339
+ var import_ir8 = require("@renderify/ir");
1340
+ function canMaterializeBrowserModules() {
1341
+ return typeof URL !== "undefined" && typeof URL.createObjectURL === "function" && typeof Blob !== "undefined" && typeof fetch === "function";
1342
+ }
1343
+ async function rewriteImportsAsync(code, resolver) {
1344
+ const imports = await parseImportSpecifiersFromSource(code);
1345
+ if (imports.length === 0) {
1346
+ return code;
1347
+ }
1348
+ let rewritten = "";
1349
+ let cursor = 0;
1350
+ for (const item of imports) {
1351
+ rewritten += code.slice(cursor, item.start);
1352
+ rewritten += await resolver(item.specifier);
1353
+ cursor = item.end;
1354
+ }
1355
+ rewritten += code.slice(cursor);
1356
+ return rewritten;
1357
+ }
1358
+ async function parseImportSpecifiersFromSource(source) {
1359
+ return (0, import_ir8.parseRuntimeSourceImportRanges)(source);
1360
+ }
1361
+ function createBrowserBlobModuleUrl(code, browserBlobUrls) {
1362
+ const blobUrl = URL.createObjectURL(
1363
+ new Blob([code], { type: "text/javascript" })
1364
+ );
1365
+ browserBlobUrls.add(blobUrl);
1366
+ return blobUrl;
1367
+ }
1368
+ function revokeBrowserBlobUrls(browserBlobUrls) {
1369
+ if (typeof URL === "undefined" || typeof URL.revokeObjectURL !== "function") {
1370
+ browserBlobUrls.clear();
1371
+ return;
1372
+ }
1373
+ for (const blobUrl of browserBlobUrls) {
1374
+ URL.revokeObjectURL(blobUrl);
1375
+ }
1376
+ browserBlobUrls.clear();
1377
+ }
1378
+ function normalizeRuntimeSourceOutput(output) {
1379
+ if ((0, import_ir8.isRuntimeNode)(output)) {
1380
+ return output;
1381
+ }
1382
+ if (typeof output === "string" || typeof output === "number") {
1383
+ return (0, import_ir8.createTextNode)(String(output));
1384
+ }
1385
+ if (Array.isArray(output)) {
1386
+ const normalizedChildren = output.map((entry) => normalizeRuntimeSourceOutput(entry)).filter((entry) => entry !== void 0);
1387
+ return (0, import_ir8.createElementNode)(
1388
+ "div",
1389
+ { "data-renderify-fragment": "true" },
1390
+ normalizedChildren
1391
+ );
1392
+ }
1393
+ return void 0;
1394
+ }
1395
+
1396
+ // src/runtime-specifier.ts
1397
+ function resolveRuntimeSourceSpecifier(input) {
1398
+ const trimmed = input.specifier.trim();
1399
+ const manifestResolved = resolveOptionalManifestSpecifier(
1400
+ trimmed,
1401
+ input.moduleManifest
1402
+ );
1403
+ if (manifestResolved && manifestResolved !== trimmed) {
1404
+ return resolveSourceSpecifierWithLoader(
1405
+ manifestResolved,
1406
+ input.moduleLoader
1407
+ );
1408
+ }
1409
+ if (!shouldRewriteSpecifier(trimmed)) {
1410
+ return manifestResolved ?? trimmed;
1411
+ }
1412
+ const resolvedFromPolicy = input.requireManifest !== false ? resolveRuntimeSpecifier({
1413
+ specifier: trimmed,
1414
+ moduleManifest: input.moduleManifest,
1415
+ diagnostics: input.diagnostics,
1416
+ usage: "source-import",
1417
+ enforceModuleManifest: input.enforceModuleManifest
1418
+ }) : manifestResolved;
1419
+ if (!resolvedFromPolicy) {
1420
+ return trimmed;
1421
+ }
1422
+ const loaderResolved = resolveSourceSpecifierWithLoader(
1423
+ resolvedFromPolicy,
1424
+ input.moduleLoader
1425
+ );
1426
+ if (loaderResolved !== resolvedFromPolicy) {
1427
+ return loaderResolved;
1428
+ }
1429
+ const jspmBase = (input.jspmCdnBase ?? FALLBACK_JSPM_CDN_BASE).replace(
1430
+ /\/$/,
1431
+ ""
1432
+ );
1433
+ if (resolvedFromPolicy.startsWith("npm:")) {
1434
+ return `${jspmBase}/${resolvedFromPolicy.slice(4)}`;
1435
+ }
1436
+ if (isDirectSpecifier(resolvedFromPolicy)) {
1437
+ return resolvedFromPolicy;
1438
+ }
1439
+ if (isBareSpecifier(resolvedFromPolicy)) {
1440
+ return `${jspmBase}/npm:${resolvedFromPolicy}`;
1441
+ }
1442
+ return `${jspmBase}/${resolvedFromPolicy}`;
1443
+ }
1444
+ function resolveRuntimeSpecifier(input) {
1445
+ const trimmed = input.specifier.trim();
1446
+ if (trimmed.length === 0) {
1447
+ input.diagnostics.push({
1448
+ level: "error",
1449
+ code: "RUNTIME_MANIFEST_INVALID",
1450
+ message: `Empty ${input.usage} specifier`
1451
+ });
1452
+ return void 0;
1453
+ }
1454
+ const descriptor = input.moduleManifest?.[trimmed];
1455
+ if (descriptor) {
1456
+ const resolved = descriptor.resolvedUrl.trim();
1457
+ if (resolved.length === 0) {
1458
+ input.diagnostics.push({
1459
+ level: "error",
1460
+ code: "RUNTIME_MANIFEST_INVALID",
1461
+ message: `Manifest entry has empty resolvedUrl for ${trimmed}`
1462
+ });
1463
+ return void 0;
1464
+ }
1465
+ return resolved;
1466
+ }
1467
+ if (!input.enforceModuleManifest || isDirectSpecifier(trimmed)) {
1468
+ return trimmed;
1469
+ }
1470
+ input.diagnostics.push({
1471
+ level: "error",
1472
+ code: "RUNTIME_MANIFEST_MISSING",
1473
+ message: `Missing moduleManifest entry for ${input.usage}: ${trimmed}`
1474
+ });
1475
+ return void 0;
1476
+ }
1477
+ function resolveSourceImportLoaderCandidate(specifier, moduleManifest, moduleLoader) {
1478
+ const manifestResolved = resolveOptionalManifestSpecifier(
1479
+ specifier,
1480
+ moduleManifest
1481
+ );
1482
+ const candidate = (manifestResolved ?? specifier).trim();
1483
+ if (candidate.length === 0) {
1484
+ return void 0;
1485
+ }
1486
+ if (candidate.startsWith("./") || candidate.startsWith("../") || candidate.startsWith("/")) {
1487
+ return void 0;
1488
+ }
1489
+ return resolveSourceSpecifierWithLoader(candidate, moduleLoader);
1490
+ }
1491
+ function resolveOptionalManifestSpecifier(specifier, moduleManifest) {
1492
+ const descriptor = moduleManifest?.[specifier];
1493
+ if (!descriptor) {
1494
+ return specifier;
1495
+ }
1496
+ const resolved = descriptor.resolvedUrl.trim();
1497
+ if (resolved.length === 0) {
1498
+ return void 0;
1499
+ }
1500
+ return resolved;
1501
+ }
1502
+ function resolveSourceSpecifierWithLoader(specifier, loader) {
1503
+ if (loader && hasResolveSpecifier(loader)) {
1504
+ try {
1505
+ return loader.resolveSpecifier(specifier);
1506
+ } catch {
1507
+ return specifier;
1508
+ }
1509
+ }
1510
+ return specifier;
1511
+ }
1512
+ function shouldRewriteSpecifier(specifier) {
1513
+ return !isDirectSpecifier(specifier);
1514
+ }
1515
+ function isDirectSpecifier(specifier) {
1516
+ return specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("/") || specifier.startsWith("http://") || specifier.startsWith("https://") || specifier.startsWith("blob:") || specifier.startsWith("data:");
1517
+ }
1518
+ function isHttpUrl(specifier) {
1519
+ return specifier.startsWith("http://") || specifier.startsWith("https://");
1520
+ }
1521
+ function isBareSpecifier(specifier) {
1522
+ return !isDirectSpecifier(specifier) && !specifier.startsWith("npm:");
1523
+ }
1524
+ function hasResolveSpecifier(loader) {
1525
+ if (typeof loader !== "object" || loader === null) {
1526
+ return false;
1527
+ }
1528
+ return "resolveSpecifier" in loader && typeof loader.resolveSpecifier === "function";
1529
+ }
1530
+
1531
+ // src/runtime-plan-preflight.ts
1532
+ async function preflightRuntimePlanDependencies(input) {
1533
+ const probes = await collectDependencyProbes(
1534
+ input.plan,
1535
+ parseSourceImportSpecifiers
1536
+ );
1537
+ return runDependencyPreflight(
1538
+ probes,
1539
+ input.diagnostics,
1540
+ (probe) => executeDependencyProbe(
1541
+ probe,
1542
+ input.plan.moduleManifest,
1543
+ input.diagnostics,
1544
+ {
1545
+ moduleLoader: input.moduleLoader,
1546
+ withRemainingBudget: (operation, timeoutMessage) => input.withRemainingBudget(operation, timeoutMessage),
1547
+ resolveRuntimeSourceSpecifier: (specifier, manifest, diagnostics, requireManifest) => input.resolveRuntimeSourceSpecifier(
1548
+ specifier,
1549
+ manifest,
1550
+ diagnostics,
1551
+ requireManifest
1552
+ ),
1553
+ resolveSourceImportLoaderCandidate: (specifier, manifest) => input.resolveSourceImportLoaderCandidate(specifier, manifest),
1554
+ resolveRuntimeSpecifier: (specifier, manifest, diagnostics, usage) => input.resolveRuntimeSpecifier(
1555
+ specifier,
1556
+ manifest,
1557
+ diagnostics,
1558
+ usage
1559
+ ),
1560
+ isHttpUrl,
1561
+ canMaterializeBrowserModules: () => canMaterializeBrowserModules(),
1562
+ materializeBrowserRemoteModule: (url, manifest, diagnostics) => input.materializeBrowserRemoteModule(url, manifest, diagnostics),
1563
+ fetchRemoteModuleCodeWithFallback: (url, diagnostics) => input.fetchRemoteModuleCodeWithFallback(url, diagnostics),
1564
+ isAbortError: (error) => input.isAbortError(error),
1565
+ errorToMessage: (error) => input.errorToMessage(error)
1566
+ }
1567
+ ),
1568
+ {
1569
+ isAborted: () => input.isAborted(),
1570
+ hasExceededBudget: () => input.hasExceededBudget()
1571
+ }
1572
+ );
1573
+ }
1574
+ async function parseSourceImportSpecifiers(code) {
1575
+ if (code.trim().length === 0) {
1576
+ return [];
1577
+ }
1578
+ const imports = /* @__PURE__ */ new Set();
1579
+ const parsedSpecifiers = await parseImportSpecifiersFromSource(code);
1580
+ for (const entry of parsedSpecifiers) {
1581
+ imports.add(entry.specifier);
1582
+ }
1583
+ return [...imports];
1584
+ }
1585
+
1586
+ // src/sandbox.ts
1587
+ async function executeSourceInBrowserSandbox(options) {
1588
+ throwIfAborted2(options.signal);
1589
+ if (options.mode === "worker") {
1590
+ return executeSourceInWorkerSandbox(options);
1591
+ }
1592
+ if (options.mode === "iframe") {
1593
+ return executeSourceInIframeSandbox(options);
1594
+ }
1595
+ throw new Error(`Unsupported runtime source sandbox mode: ${options.mode}`);
1596
+ }
1597
+ async function executeSourceInWorkerSandbox(options) {
1598
+ if (typeof Worker === "undefined" || typeof Blob === "undefined" || typeof URL === "undefined" || typeof URL.createObjectURL !== "function" || typeof URL.revokeObjectURL !== "function") {
1599
+ throw new Error("Worker sandbox is unavailable in this runtime");
1600
+ }
1601
+ const workerSource = [
1602
+ "const CHANNEL = 'runtime-source';",
1603
+ "self.onmessage = async (event) => {",
1604
+ " const request = event.data;",
1605
+ " if (!request || request.renderifySandbox !== CHANNEL) {",
1606
+ " return;",
1607
+ " }",
1608
+ " const safeSend = (payload) => {",
1609
+ " try {",
1610
+ " self.postMessage({ renderifySandbox: CHANNEL, id: request.id, ...payload });",
1611
+ " return true;",
1612
+ " } catch (postError) {",
1613
+ " try {",
1614
+ " const postMessageError = postError && typeof postError === 'object' && 'message' in postError",
1615
+ " ? String(postError.message)",
1616
+ " : String(postError);",
1617
+ " self.postMessage({",
1618
+ " renderifySandbox: CHANNEL,",
1619
+ " id: request.id,",
1620
+ " ok: false,",
1621
+ " error: `Sandbox response is not serializable: ${postMessageError}`,",
1622
+ " });",
1623
+ " } catch {",
1624
+ " // Ignore terminal postMessage failures.",
1625
+ " }",
1626
+ " return false;",
1627
+ " }",
1628
+ " };",
1629
+ " try {",
1630
+ " const moduleUrl = URL.createObjectURL(new Blob([String(request.code ?? '')], { type: 'text/javascript' }));",
1631
+ " try {",
1632
+ " const namespace = await import(moduleUrl);",
1633
+ " const exportName = typeof request.exportName === 'string' && request.exportName.trim().length > 0",
1634
+ " ? request.exportName.trim()",
1635
+ " : 'default';",
1636
+ " const selected = namespace[exportName];",
1637
+ " if (selected === undefined) {",
1638
+ ' throw new Error(`Runtime source export "${exportName}" is missing`);',
1639
+ " }",
1640
+ " const output = typeof selected === 'function'",
1641
+ " ? await selected(request.runtimeInput ?? {})",
1642
+ " : selected;",
1643
+ " safeSend({ ok: true, output });",
1644
+ " } finally {",
1645
+ " URL.revokeObjectURL(moduleUrl);",
1646
+ " }",
1647
+ " } catch (error) {",
1648
+ " const message = error && typeof error === 'object' && 'message' in error",
1649
+ " ? String(error.message)",
1650
+ " : String(error);",
1651
+ " safeSend({ ok: false, error: message });",
1652
+ " }",
1653
+ "};"
1654
+ ].join("\n");
1655
+ const workerUrl = URL.createObjectURL(
1656
+ new Blob([workerSource], {
1657
+ type: "text/javascript"
1658
+ })
1659
+ );
1660
+ const worker = new Worker(workerUrl, {
1661
+ type: "module",
1662
+ name: "renderify-runtime-source-sandbox"
1663
+ });
1664
+ URL.revokeObjectURL(workerUrl);
1665
+ return new Promise((resolve, reject) => {
1666
+ let settled = false;
1667
+ let onAbort;
1668
+ const cleanup = () => {
1669
+ if (settled) {
1670
+ return;
1671
+ }
1672
+ settled = true;
1673
+ clearTimeout(timer);
1674
+ if (options.signal && onAbort) {
1675
+ options.signal.removeEventListener("abort", onAbort);
1676
+ }
1677
+ worker.removeEventListener("message", onMessage);
1678
+ worker.removeEventListener("error", onError);
1679
+ };
1680
+ const timer = setTimeout(() => {
1681
+ cleanup();
1682
+ worker.terminate();
1683
+ reject(new Error("Worker sandbox timed out"));
1684
+ }, options.timeoutMs);
1685
+ const onMessage = (event) => {
1686
+ const payload = event.data;
1687
+ if (!isRuntimeSandboxResponse(payload, options.request.id)) {
1688
+ return;
1689
+ }
1690
+ cleanup();
1691
+ worker.terminate();
1692
+ if (!payload.ok) {
1693
+ reject(new Error(payload.error ?? "Worker sandbox execution failed"));
1694
+ return;
1695
+ }
1696
+ resolve({
1697
+ output: payload.output
1698
+ });
1699
+ };
1700
+ const onError = (event) => {
1701
+ cleanup();
1702
+ worker.terminate();
1703
+ reject(
1704
+ new Error(
1705
+ event.message || "Worker sandbox terminated with an unknown error"
1706
+ )
1707
+ );
1708
+ };
1709
+ worker.addEventListener("message", onMessage);
1710
+ worker.addEventListener("error", onError);
1711
+ if (options.signal) {
1712
+ if (options.signal.aborted) {
1713
+ cleanup();
1714
+ worker.terminate();
1715
+ reject(createAbortError2("Worker sandbox execution aborted"));
1716
+ return;
1717
+ }
1718
+ onAbort = () => {
1719
+ cleanup();
1720
+ worker.terminate();
1721
+ reject(createAbortError2("Worker sandbox execution aborted"));
1722
+ };
1723
+ options.signal.addEventListener("abort", onAbort, { once: true });
1724
+ }
1725
+ worker.postMessage(options.request);
1726
+ });
1727
+ }
1728
+ async function executeSourceInIframeSandbox(options) {
1729
+ if (typeof document === "undefined" || typeof window === "undefined" || typeof Blob === "undefined" || typeof URL === "undefined" || typeof URL.createObjectURL !== "function" || typeof URL.revokeObjectURL !== "function") {
1730
+ throw new Error("Iframe sandbox is unavailable in this runtime");
1731
+ }
1732
+ const iframe = document.createElement("iframe");
1733
+ iframe.setAttribute("sandbox", "allow-scripts");
1734
+ iframe.style.display = "none";
1735
+ const channel = `renderify-runtime-source-${options.request.id}`;
1736
+ const channelLiteral = JSON.stringify(channel);
1737
+ iframe.srcdoc = [
1738
+ "<!doctype html><html><body><script>",
1739
+ `const CHANNEL = ${channelLiteral};`,
1740
+ "window.addEventListener('message', async (event) => {",
1741
+ " const data = event.data;",
1742
+ " if (!data || data.channel !== CHANNEL) {",
1743
+ " return;",
1744
+ " }",
1745
+ " const request = data.request || {};",
1746
+ " const safeSend = (payload) => {",
1747
+ " try {",
1748
+ " parent.postMessage({ channel: CHANNEL, ...payload }, '*');",
1749
+ " return true;",
1750
+ " } catch (postError) {",
1751
+ " try {",
1752
+ " const postMessageError = postError && typeof postError === 'object' && 'message' in postError",
1753
+ " ? String(postError.message)",
1754
+ " : String(postError);",
1755
+ " parent.postMessage({",
1756
+ " channel: CHANNEL,",
1757
+ " ok: false,",
1758
+ " error: `Sandbox response is not serializable: ${postMessageError}`,",
1759
+ " }, '*');",
1760
+ " } catch {",
1761
+ " // Ignore terminal postMessage failures.",
1762
+ " }",
1763
+ " return false;",
1764
+ " }",
1765
+ " };",
1766
+ " try {",
1767
+ " const moduleUrl = URL.createObjectURL(new Blob([String(request.code ?? '')], { type: 'text/javascript' }));",
1768
+ " try {",
1769
+ " const namespace = await import(moduleUrl);",
1770
+ " const exportName = typeof request.exportName === 'string' && request.exportName.trim().length > 0",
1771
+ " ? request.exportName.trim()",
1772
+ " : 'default';",
1773
+ " const selected = namespace[exportName];",
1774
+ " if (selected === undefined) {",
1775
+ ' throw new Error(`Runtime source export "${exportName}" is missing`);',
1776
+ " }",
1777
+ " const output = typeof selected === 'function'",
1778
+ " ? await selected(request.runtimeInput ?? {})",
1779
+ " : selected;",
1780
+ " safeSend({ ok: true, output });",
1781
+ " } finally {",
1782
+ " URL.revokeObjectURL(moduleUrl);",
1783
+ " }",
1784
+ " } catch (error) {",
1785
+ " const message = error && typeof error === 'object' && 'message' in error",
1786
+ " ? String(error.message)",
1787
+ " : String(error);",
1788
+ " safeSend({ ok: false, error: message });",
1789
+ " }",
1790
+ "});",
1791
+ "</script></body></html>"
1792
+ ].join("");
1793
+ document.body.appendChild(iframe);
1794
+ return new Promise((resolve, reject) => {
1795
+ let settled = false;
1796
+ let onAbort;
1797
+ const cleanup = () => {
1798
+ if (settled) {
1799
+ return;
1800
+ }
1801
+ settled = true;
1802
+ clearTimeout(timer);
1803
+ if (options.signal && onAbort) {
1804
+ options.signal.removeEventListener("abort", onAbort);
1805
+ }
1806
+ window.removeEventListener("message", onMessage);
1807
+ iframe.removeEventListener("load", onLoad);
1808
+ iframe.remove();
1809
+ };
1810
+ const timer = setTimeout(() => {
1811
+ cleanup();
1812
+ reject(new Error("Iframe sandbox timed out"));
1813
+ }, options.timeoutMs);
1814
+ const onMessage = (event) => {
1815
+ if (event.source !== iframe.contentWindow) {
1816
+ return;
1817
+ }
1818
+ const data = event.data;
1819
+ if (!data || data.channel !== channel) {
1820
+ return;
1821
+ }
1822
+ cleanup();
1823
+ if (!data.ok) {
1824
+ reject(new Error(data.error ?? "Iframe sandbox execution failed"));
1825
+ return;
1826
+ }
1827
+ resolve({
1828
+ output: data.output
1829
+ });
1830
+ };
1831
+ const onLoad = () => {
1832
+ iframe.contentWindow?.postMessage(
1833
+ { channel, request: options.request },
1834
+ "*"
1835
+ );
1836
+ };
1837
+ window.addEventListener("message", onMessage);
1838
+ iframe.addEventListener("load", onLoad, { once: true });
1839
+ if (options.signal) {
1840
+ if (options.signal.aborted) {
1841
+ cleanup();
1842
+ reject(createAbortError2("Iframe sandbox execution aborted"));
1843
+ return;
1844
+ }
1845
+ onAbort = () => {
1846
+ cleanup();
1847
+ reject(createAbortError2("Iframe sandbox execution aborted"));
1848
+ };
1849
+ options.signal.addEventListener("abort", onAbort, { once: true });
1850
+ }
1851
+ });
1852
+ }
1853
+ function isRuntimeSandboxResponse(value, expectedId) {
1854
+ if (typeof value !== "object" || value === null) {
1855
+ return false;
1856
+ }
1857
+ const candidate = value;
1858
+ return candidate.renderifySandbox === "runtime-source" && candidate.id === expectedId && typeof candidate.ok === "boolean";
1859
+ }
1860
+ function throwIfAborted2(signal) {
1861
+ if (!signal?.aborted) {
1862
+ return;
1863
+ }
1864
+ throw createAbortError2("Runtime sandbox execution aborted");
1865
+ }
1866
+ function createAbortError2(message) {
1867
+ const error = new Error(message);
1868
+ error.name = "AbortError";
1869
+ return error;
1870
+ }
1871
+
1872
+ // src/runtime-source-execution.ts
1873
+ async function executeRuntimeSourceRoot(input) {
1874
+ const {
1875
+ plan,
1876
+ source,
1877
+ context,
1878
+ state,
1879
+ event,
1880
+ diagnostics,
1881
+ frame,
1882
+ browserSourceSandboxTimeoutMs,
1883
+ browserSourceSandboxFailClosed
1884
+ } = input;
1885
+ try {
1886
+ const exportName = source.exportName ?? "default";
1887
+ const runtimeInput = {
1888
+ context: input.cloneJsonValue(input.asJsonValue(context)),
1889
+ state: input.cloneJsonValue(state),
1890
+ event: event ? input.cloneJsonValue(input.asJsonValue(event)) : null
1891
+ };
1892
+ const transpiled = await input.withRemainingBudget(
1893
+ () => input.transpileRuntimeSource(source),
1894
+ "Runtime source transpilation timed out"
1895
+ );
1896
+ const rewritten = await input.rewriteSourceImports(
1897
+ transpiled,
1898
+ plan.moduleManifest,
1899
+ diagnostics
1900
+ );
1901
+ const sandboxMode = input.resolveSourceSandboxMode(
1902
+ source,
1903
+ frame.executionProfile
1904
+ );
1905
+ if (sandboxMode !== "none") {
1906
+ try {
1907
+ const sandboxResult = await input.withRemainingBudget(
1908
+ () => executeSourceInBrowserSandbox({
1909
+ mode: sandboxMode,
1910
+ timeoutMs: browserSourceSandboxTimeoutMs,
1911
+ signal: frame.signal,
1912
+ request: {
1913
+ renderifySandbox: "runtime-source",
1914
+ id: `sandbox_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`,
1915
+ code: rewritten,
1916
+ exportName,
1917
+ runtimeInput
1918
+ }
1919
+ }),
1920
+ `Runtime source sandbox (${sandboxMode}) timed out`
1921
+ );
1922
+ const normalized2 = input.normalizeSourceOutput(sandboxResult.output);
1923
+ if (!normalized2) {
1924
+ diagnostics.push({
1925
+ level: "error",
1926
+ code: "RUNTIME_SOURCE_OUTPUT_INVALID",
1927
+ message: "Runtime source output from sandbox is not a supported RuntimeNode payload"
1928
+ });
1929
+ return void 0;
1930
+ }
1931
+ diagnostics.push({
1932
+ level: "info",
1933
+ code: "RUNTIME_SOURCE_SANDBOX_EXECUTED",
1934
+ message: `Runtime source executed in ${sandboxMode} sandbox`
1935
+ });
1936
+ return {
1937
+ root: normalized2
1938
+ };
1939
+ } catch (error) {
1940
+ if (input.isAbortError(error)) {
1941
+ throw error;
1942
+ }
1943
+ const message = input.errorToMessage(error);
1944
+ diagnostics.push({
1945
+ level: browserSourceSandboxFailClosed ? "error" : "warning",
1946
+ code: browserSourceSandboxFailClosed ? "RUNTIME_SOURCE_SANDBOX_FAILED" : "RUNTIME_SOURCE_SANDBOX_FALLBACK",
1947
+ message
1948
+ });
1949
+ if (browserSourceSandboxFailClosed) {
1950
+ throw new Error(
1951
+ `Runtime source sandbox (${sandboxMode}) failed: ${message}`
1952
+ );
1953
+ }
1954
+ }
1955
+ }
1956
+ const namespace = await input.withRemainingBudget(
1957
+ () => input.importSourceModuleFromCode(
1958
+ rewritten,
1959
+ plan.moduleManifest,
1960
+ diagnostics
1961
+ ),
1962
+ "Runtime source module loading timed out"
1963
+ );
1964
+ const selected = selectExportFromNamespace(namespace, exportName);
1965
+ if (selected === void 0) {
1966
+ diagnostics.push({
1967
+ level: "error",
1968
+ code: "RUNTIME_SOURCE_EXPORT_MISSING",
1969
+ message: `Runtime source export "${exportName}" is missing`
1970
+ });
1971
+ return void 0;
1972
+ }
1973
+ if (input.shouldUsePreactSourceRuntime(source)) {
1974
+ const preactArtifact = await input.createPreactRenderArtifact({
1975
+ sourceExport: selected,
1976
+ runtimeInput,
1977
+ diagnostics
1978
+ });
1979
+ if (preactArtifact) {
1980
+ return {
1981
+ renderArtifact: preactArtifact
1982
+ };
1983
+ }
1984
+ }
1985
+ const produced = typeof selected === "function" ? await input.withRemainingBudget(
1986
+ async () => selected(runtimeInput),
1987
+ "Runtime source export execution timed out"
1988
+ ) : selected;
1989
+ const normalized = input.normalizeSourceOutput(produced);
1990
+ if (!normalized) {
1991
+ diagnostics.push({
1992
+ level: "error",
1993
+ code: "RUNTIME_SOURCE_OUTPUT_INVALID",
1994
+ message: "Runtime source output is not a supported RuntimeNode payload"
1995
+ });
1996
+ return void 0;
1997
+ }
1998
+ return {
1999
+ root: normalized
2000
+ };
2001
+ } catch (error) {
2002
+ if (input.isAbortError(error)) {
2003
+ throw error;
2004
+ }
2005
+ diagnostics.push({
2006
+ level: "error",
2007
+ code: "RUNTIME_SOURCE_EXEC_FAILED",
2008
+ message: input.errorToMessage(error)
2009
+ });
2010
+ return void 0;
2011
+ }
2012
+ }
2013
+
2014
+ // src/runtime-source-module-loader.ts
2015
+ var RuntimeSourceModuleLoader = class {
2016
+ moduleManifest;
2017
+ diagnostics;
2018
+ browserModuleUrlCache;
2019
+ browserModuleInflight;
2020
+ remoteFallbackCdnBases;
2021
+ remoteFetchTimeoutMs;
2022
+ remoteFetchRetries;
2023
+ remoteFetchBackoffMs;
2024
+ canMaterializeBrowserModulesFn;
2025
+ rewriteImportsAsyncFn;
2026
+ createBrowserBlobModuleUrlFn;
2027
+ resolveRuntimeSourceSpecifierFn;
2028
+ constructor(options) {
2029
+ this.moduleManifest = options.moduleManifest;
2030
+ this.diagnostics = options.diagnostics;
2031
+ this.browserModuleUrlCache = options.browserModuleUrlCache;
2032
+ this.browserModuleInflight = options.browserModuleInflight;
2033
+ this.remoteFallbackCdnBases = options.remoteFallbackCdnBases;
2034
+ this.remoteFetchTimeoutMs = options.remoteFetchTimeoutMs;
2035
+ this.remoteFetchRetries = options.remoteFetchRetries;
2036
+ this.remoteFetchBackoffMs = options.remoteFetchBackoffMs;
2037
+ this.canMaterializeBrowserModulesFn = options.canMaterializeBrowserModules;
2038
+ this.rewriteImportsAsyncFn = options.rewriteImportsAsync;
2039
+ this.createBrowserBlobModuleUrlFn = options.createBrowserBlobModuleUrl;
2040
+ this.resolveRuntimeSourceSpecifierFn = options.resolveRuntimeSourceSpecifier;
2041
+ }
2042
+ async importSourceModuleFromCode(code) {
2043
+ const isNodeRuntime = typeof process !== "undefined" && process !== null && typeof process.versions === "object" && process.versions !== null && typeof process.versions.node === "string";
2044
+ if (isNodeRuntime && typeof Buffer !== "undefined") {
2045
+ const encoded = Buffer.from(code, "utf8").toString("base64");
2046
+ const dataUrl = `data:text/javascript;base64,${encoded}`;
2047
+ return import(
2048
+ /* webpackIgnore: true */
2049
+ dataUrl
2050
+ );
2051
+ }
2052
+ if (this.canMaterializeBrowserModulesFn()) {
2053
+ const rewrittenEntry = await this.rewriteImportsAsyncFn(
2054
+ code,
2055
+ async (specifier) => this.resolveBrowserImportSpecifier(specifier, void 0)
2056
+ );
2057
+ const entryUrl = this.createBrowserBlobModuleUrlFn(rewrittenEntry);
2058
+ return import(
2059
+ /* webpackIgnore: true */
2060
+ entryUrl
2061
+ );
2062
+ }
2063
+ if (typeof Buffer !== "undefined") {
2064
+ const encoded = Buffer.from(code, "utf8").toString("base64");
2065
+ const dataUrl = `data:text/javascript;base64,${encoded}`;
2066
+ return import(
2067
+ /* webpackIgnore: true */
2068
+ dataUrl
2069
+ );
2070
+ }
2071
+ throw new Error("No runtime module import strategy is available");
2072
+ }
2073
+ async resolveBrowserImportSpecifier(specifier, parentUrl) {
2074
+ const trimmed = specifier.trim();
2075
+ if (trimmed.length === 0) {
2076
+ return trimmed;
2077
+ }
2078
+ if (trimmed.startsWith("data:") || trimmed.startsWith("blob:")) {
2079
+ return trimmed;
2080
+ }
2081
+ if (isHttpUrl(trimmed)) {
2082
+ return this.materializeBrowserRemoteModule(trimmed);
2083
+ }
2084
+ if (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith("/")) {
2085
+ if (!parentUrl || !isHttpUrl(parentUrl)) {
2086
+ this.diagnostics.push({
2087
+ level: "warning",
2088
+ code: "RUNTIME_SOURCE_IMPORT_UNRESOLVED",
2089
+ message: `Cannot resolve relative source import without parent URL: ${trimmed}`
2090
+ });
2091
+ return trimmed;
2092
+ }
2093
+ const absolute = new URL(trimmed, parentUrl).toString();
2094
+ if (!isHttpUrl(absolute)) {
2095
+ return absolute;
2096
+ }
2097
+ return this.materializeBrowserRemoteModule(absolute);
2098
+ }
2099
+ const resolved = this.resolveRuntimeSourceSpecifierFn(
2100
+ trimmed,
2101
+ this.moduleManifest,
2102
+ this.diagnostics,
2103
+ false
2104
+ );
2105
+ if (isHttpUrl(resolved)) {
2106
+ return this.materializeBrowserRemoteModule(resolved);
2107
+ }
2108
+ if ((resolved.startsWith("./") || resolved.startsWith("../") || resolved.startsWith("/")) && parentUrl && isHttpUrl(parentUrl)) {
2109
+ const absolute = new URL(resolved, parentUrl).toString();
2110
+ if (!isHttpUrl(absolute)) {
2111
+ return absolute;
2112
+ }
2113
+ return this.materializeBrowserRemoteModule(absolute);
2114
+ }
2115
+ return resolved;
2116
+ }
2117
+ async materializeBrowserRemoteModule(url) {
2118
+ const normalizedUrl = url.trim();
2119
+ if (normalizedUrl.length === 0) {
2120
+ return normalizedUrl;
2121
+ }
2122
+ const cachedUrl = this.browserModuleUrlCache.get(normalizedUrl);
2123
+ if (cachedUrl) {
2124
+ return cachedUrl;
2125
+ }
2126
+ const inflight = this.browserModuleInflight.get(normalizedUrl);
2127
+ if (inflight) {
2128
+ return inflight;
2129
+ }
2130
+ const loading = (async () => {
2131
+ const fetched = await this.fetchRemoteModuleCodeWithFallback(normalizedUrl);
2132
+ const rewritten = await this.materializeFetchedModuleSource(fetched);
2133
+ const blobUrl = this.createBrowserBlobModuleUrlFn(rewritten);
2134
+ this.browserModuleUrlCache.set(normalizedUrl, blobUrl);
2135
+ this.browserModuleUrlCache.set(fetched.url, blobUrl);
2136
+ return blobUrl;
2137
+ })();
2138
+ this.browserModuleInflight.set(normalizedUrl, loading);
2139
+ try {
2140
+ return await loading;
2141
+ } finally {
2142
+ this.browserModuleInflight.delete(normalizedUrl);
2143
+ }
2144
+ }
2145
+ async materializeFetchedModuleSource(fetched) {
2146
+ if (isCssModuleResponse(fetched)) {
2147
+ return createCssProxyModuleSource(fetched.code, fetched.url);
2148
+ }
2149
+ if (isJsonModuleResponse(fetched)) {
2150
+ return this.createJsonProxyModuleSource(fetched);
2151
+ }
2152
+ if (!isJavaScriptModuleResponse(fetched)) {
2153
+ this.diagnostics.push({
2154
+ level: "warning",
2155
+ code: "RUNTIME_SOURCE_ASSET_PROXY",
2156
+ message: `Treating non-JS module as proxied asset: ${fetched.url} (${fetched.contentType || "unknown"})`
2157
+ });
2158
+ if (isBinaryLikeContentType(fetched.contentType)) {
2159
+ return createUrlProxyModuleSource(fetched.url);
2160
+ }
2161
+ return createTextProxyModuleSource(fetched.code);
2162
+ }
2163
+ return this.rewriteImportsAsyncFn(
2164
+ fetched.code,
2165
+ async (childSpecifier) => this.resolveBrowserImportSpecifier(childSpecifier, fetched.url)
2166
+ );
2167
+ }
2168
+ async fetchRemoteModuleCodeWithFallback(url) {
2169
+ const attempts = buildRemoteModuleAttemptUrls(
2170
+ url,
2171
+ this.remoteFallbackCdnBases
2172
+ );
2173
+ if (attempts.length === 0) {
2174
+ throw new Error(`Failed to load module: ${url}`);
2175
+ }
2176
+ const hedgeDelayMs = Math.max(
2177
+ 50,
2178
+ Math.min(300, this.remoteFetchBackoffMs || 100)
2179
+ );
2180
+ const fetchTasks = attempts.map(
2181
+ (attempt, index) => this.fetchRemoteModuleAttemptWithRetries(
2182
+ attempt,
2183
+ url,
2184
+ index === 0 ? 0 : hedgeDelayMs * index
2185
+ )
2186
+ );
2187
+ try {
2188
+ return await Promise.any(fetchTasks);
2189
+ } catch (error) {
2190
+ if (error instanceof AggregateError && error.errors.length > 0) {
2191
+ throw error.errors[error.errors.length - 1];
2192
+ }
2193
+ throw error;
2194
+ }
2195
+ }
2196
+ async fetchRemoteModuleAttemptWithRetries(attempt, originalUrl, startDelayMs) {
2197
+ if (startDelayMs > 0) {
2198
+ await delay(startDelayMs);
2199
+ }
2200
+ let lastError;
2201
+ for (let retry = 0; retry <= this.remoteFetchRetries; retry += 1) {
2202
+ try {
2203
+ const response = await fetchWithTimeout(
2204
+ attempt,
2205
+ this.remoteFetchTimeoutMs
2206
+ );
2207
+ if (!response.ok) {
2208
+ throw new Error(
2209
+ `Failed to load module ${attempt}: HTTP ${response.status}`
2210
+ );
2211
+ }
2212
+ if (attempt !== originalUrl) {
2213
+ this.diagnostics.push({
2214
+ level: "warning",
2215
+ code: "RUNTIME_SOURCE_IMPORT_FALLBACK_USED",
2216
+ message: `Loaded module via fallback URL: ${originalUrl} -> ${attempt}`
2217
+ });
2218
+ }
2219
+ if (retry > 0) {
2220
+ this.diagnostics.push({
2221
+ level: "warning",
2222
+ code: "RUNTIME_SOURCE_IMPORT_RETRY_SUCCEEDED",
2223
+ message: `Recovered remote module after retry ${retry}: ${attempt}`
2224
+ });
2225
+ }
2226
+ return {
2227
+ url: response.url || attempt,
2228
+ code: await response.text(),
2229
+ contentType: response.headers.get("content-type")?.toLowerCase() ?? "",
2230
+ requestUrl: attempt
2231
+ };
2232
+ } catch (error) {
2233
+ lastError = error;
2234
+ if (retry >= this.remoteFetchRetries) {
2235
+ break;
2236
+ }
2237
+ await delay(this.remoteFetchBackoffMs * Math.max(1, retry + 1));
2238
+ }
2239
+ }
2240
+ throw lastError ?? new Error(`Failed to load module: ${attempt}`);
2241
+ }
2242
+ createJsonProxyModuleSource(fetched) {
2243
+ try {
2244
+ const parsed = JSON.parse(fetched.code);
2245
+ return createJsonProxyModuleSource(parsed);
2246
+ } catch (error) {
2247
+ this.diagnostics.push({
2248
+ level: "warning",
2249
+ code: "RUNTIME_SOURCE_JSON_PARSE_FAILED",
2250
+ message: `${fetched.requestUrl}: ${this.errorToMessage(error)}`
2251
+ });
2252
+ return createTextProxyModuleSource(fetched.code);
2253
+ }
2254
+ }
2255
+ errorToMessage(error) {
2256
+ if (error instanceof Error) {
2257
+ return error.message;
2258
+ }
2259
+ return String(error);
2260
+ }
2261
+ };
2262
+
2263
+ // src/transpiler.ts
2264
+ var RUNTIME_JSX_HELPERS = `
2265
+ function __renderify_runtime_to_nodes(value) {
2266
+ if (value === null || value === undefined || value === false || value === true) {
2267
+ return [];
2268
+ }
2269
+ if (Array.isArray(value)) {
2270
+ const flattened = [];
2271
+ for (const entry of value) {
2272
+ flattened.push(...__renderify_runtime_to_nodes(entry));
2273
+ }
2274
+ return flattened;
2275
+ }
2276
+ if (typeof value === "string" || typeof value === "number") {
2277
+ return [{ type: "text", value: String(value) }];
2278
+ }
2279
+ if (
2280
+ typeof value === "object" &&
2281
+ value !== null &&
2282
+ typeof value.type === "string"
2283
+ ) {
2284
+ return [value];
2285
+ }
2286
+ return [{ type: "text", value: String(value) }];
2287
+ }
2288
+
2289
+ function __renderify_runtime_h(type, props, ...children) {
2290
+ const normalizedChildren = __renderify_runtime_to_nodes(children);
2291
+ if (typeof type === "function") {
2292
+ const output = type({ ...(props || {}), children: normalizedChildren });
2293
+ const functionNodes = __renderify_runtime_to_nodes(output);
2294
+ if (functionNodes.length === 1) {
2295
+ return functionNodes[0];
2296
+ }
2297
+ return { type: "element", tag: "div", children: functionNodes };
2298
+ }
2299
+ if (typeof type === "string") {
2300
+ return {
2301
+ type: "element",
2302
+ tag: type,
2303
+ props: props || undefined,
2304
+ children: normalizedChildren,
2305
+ };
2306
+ }
2307
+ return { type: "text", value: "Unsupported JSX node type" };
2308
+ }
2309
+
2310
+ function __renderify_runtime_fragment(...children) {
2311
+ return __renderify_runtime_to_nodes(children);
2312
+ }
2313
+ `.trim();
2314
+ var BabelRuntimeSourceTranspiler = class {
2315
+ async transpile(input) {
2316
+ if (input.language === "js") {
2317
+ return input.code;
2318
+ }
2319
+ const babel = this.resolveBabel();
2320
+ const presets = [];
2321
+ if (input.language === "ts" || input.language === "tsx") {
2322
+ presets.push("typescript");
2323
+ }
2324
+ if (input.language === "jsx" || input.language === "tsx") {
2325
+ if (input.runtime === "preact") {
2326
+ presets.push([
2327
+ "react",
2328
+ {
2329
+ runtime: "automatic",
2330
+ importSource: "preact"
2331
+ }
2332
+ ]);
2333
+ } else {
2334
+ presets.push([
2335
+ "react",
2336
+ {
2337
+ runtime: "classic",
2338
+ pragma: "__renderify_runtime_h",
2339
+ pragmaFrag: "__renderify_runtime_fragment"
2340
+ }
2341
+ ]);
2342
+ }
2343
+ }
2344
+ const transformed = babel.transform(input.code, {
2345
+ sourceType: "module",
2346
+ presets,
2347
+ filename: input.filename,
2348
+ babelrc: false,
2349
+ configFile: false,
2350
+ comments: false
2351
+ });
2352
+ if (!transformed.code) {
2353
+ throw new Error("Babel returned empty output");
2354
+ }
2355
+ return transformed.code;
2356
+ }
2357
+ resolveBabel() {
2358
+ const root = globalThis;
2359
+ if (root.Babel && typeof root.Babel.transform === "function") {
2360
+ return root.Babel;
2361
+ }
2362
+ throw new Error(
2363
+ "Babel standalone is not available. Load @babel/standalone in browser or provide sourceTranspiler."
2364
+ );
2365
+ }
2366
+ static mergeRuntimeHelpers(source, runtime) {
2367
+ if (runtime === "preact") {
2368
+ return source;
2369
+ }
2370
+ return `${source}
2371
+
2372
+ ${RUNTIME_JSX_HELPERS}`;
2373
+ }
2374
+ };
2375
+
2376
+ // src/runtime-source-runtime.ts
2377
+ function shouldUsePreactSourceRuntime(source) {
2378
+ return source.runtime === "preact";
2379
+ }
2380
+ function executionProfileToSourceSandboxMode(executionProfile) {
2381
+ if (executionProfile === "sandbox-worker") {
2382
+ return "worker";
2383
+ }
2384
+ if (executionProfile === "sandbox-iframe") {
2385
+ return "iframe";
2386
+ }
2387
+ return void 0;
2388
+ }
2389
+ function resolveSourceSandboxMode(input) {
2390
+ const requested = executionProfileToSourceSandboxMode(input.executionProfile);
2391
+ const mode = requested ?? input.defaultMode;
2392
+ if (mode === "none") {
2393
+ return "none";
2394
+ }
2395
+ if (!input.isBrowserRuntime) {
2396
+ return "none";
2397
+ }
2398
+ if (shouldUsePreactSourceRuntime(input.source)) {
2399
+ if (requested) {
2400
+ throw new Error(
2401
+ `${requested} executionProfile is not supported with source.runtime=preact`
2402
+ );
2403
+ }
2404
+ return "none";
2405
+ }
2406
+ return mode;
2407
+ }
2408
+ async function transpileRuntimeSource(source, sourceTranspiler) {
2409
+ const mergedSource = BabelRuntimeSourceTranspiler.mergeRuntimeHelpers(
2410
+ source.code,
2411
+ source.runtime
2412
+ );
2413
+ return sourceTranspiler.transpile({
2414
+ code: mergedSource,
2415
+ language: source.language,
2416
+ filename: `renderify-runtime-source.${source.language}`,
2417
+ runtime: source.runtime
2418
+ });
2419
+ }
2420
+
2421
+ // src/manager.ts
2422
+ var DefaultRuntimeManager = class {
2423
+ moduleLoader;
2424
+ sourceTranspiler;
2425
+ states = /* @__PURE__ */ new Map();
2426
+ defaultMaxImports;
2427
+ defaultMaxComponentInvocations;
2428
+ defaultMaxExecutionMs;
2429
+ defaultExecutionProfile;
2430
+ supportedPlanSpecVersions;
2431
+ enforceModuleManifest;
2432
+ allowIsolationFallback;
2433
+ browserSourceSandboxMode;
2434
+ browserSourceSandboxTimeoutMs;
2435
+ browserSourceSandboxFailClosed;
2436
+ enableDependencyPreflight;
2437
+ failOnDependencyPreflightError;
2438
+ remoteFetchTimeoutMs;
2439
+ remoteFetchRetries;
2440
+ remoteFetchBackoffMs;
2441
+ remoteFallbackCdnBases;
2442
+ browserModuleUrlCache = /* @__PURE__ */ new Map();
2443
+ browserModuleInflight = /* @__PURE__ */ new Map();
2444
+ browserBlobUrls = /* @__PURE__ */ new Set();
2445
+ initialized = false;
2446
+ constructor(options = {}) {
2447
+ this.moduleLoader = options.moduleLoader;
2448
+ this.sourceTranspiler = options.sourceTranspiler ?? new BabelRuntimeSourceTranspiler();
2449
+ this.defaultMaxImports = options.defaultMaxImports ?? FALLBACK_MAX_IMPORTS;
2450
+ this.defaultMaxComponentInvocations = options.defaultMaxComponentInvocations ?? FALLBACK_MAX_COMPONENT_INVOCATIONS;
2451
+ this.defaultMaxExecutionMs = options.defaultMaxExecutionMs ?? FALLBACK_MAX_EXECUTION_MS;
2452
+ this.defaultExecutionProfile = options.defaultExecutionProfile ?? FALLBACK_EXECUTION_PROFILE;
2453
+ this.supportedPlanSpecVersions = normalizeSupportedSpecVersions(
2454
+ options.supportedPlanSpecVersions
2455
+ );
2456
+ this.enforceModuleManifest = options.enforceModuleManifest ?? FALLBACK_ENFORCE_MODULE_MANIFEST;
2457
+ this.allowIsolationFallback = options.allowIsolationFallback ?? FALLBACK_ALLOW_ISOLATION_FALLBACK;
2458
+ this.browserSourceSandboxMode = normalizeSourceSandboxMode(
2459
+ options.browserSourceSandboxMode
2460
+ );
2461
+ this.browserSourceSandboxTimeoutMs = normalizePositiveInteger(
2462
+ options.browserSourceSandboxTimeoutMs,
2463
+ FALLBACK_BROWSER_SOURCE_SANDBOX_TIMEOUT_MS
2464
+ );
2465
+ this.browserSourceSandboxFailClosed = options.browserSourceSandboxFailClosed ?? FALLBACK_BROWSER_SOURCE_SANDBOX_FAIL_CLOSED;
2466
+ this.enableDependencyPreflight = options.enableDependencyPreflight ?? FALLBACK_ENABLE_DEPENDENCY_PREFLIGHT;
2467
+ this.failOnDependencyPreflightError = options.failOnDependencyPreflightError ?? FALLBACK_FAIL_ON_DEPENDENCY_PREFLIGHT_ERROR;
2468
+ this.remoteFetchTimeoutMs = normalizePositiveInteger(
2469
+ options.remoteFetchTimeoutMs,
2470
+ FALLBACK_REMOTE_FETCH_TIMEOUT_MS
2471
+ );
2472
+ this.remoteFetchRetries = normalizeNonNegativeInteger(
2473
+ options.remoteFetchRetries,
2474
+ FALLBACK_REMOTE_FETCH_RETRIES
2475
+ );
2476
+ this.remoteFetchBackoffMs = normalizeNonNegativeInteger(
2477
+ options.remoteFetchBackoffMs,
2478
+ FALLBACK_REMOTE_FETCH_BACKOFF_MS
2479
+ );
2480
+ this.remoteFallbackCdnBases = normalizeFallbackCdnBases(
2481
+ options.remoteFallbackCdnBases
2482
+ );
2483
+ }
2484
+ async initialize() {
2485
+ if (this.initialized) {
2486
+ return;
2487
+ }
2488
+ this.initialized = true;
2489
+ }
2490
+ async terminate() {
2491
+ this.initialized = false;
2492
+ this.states.clear();
2493
+ this.browserModuleUrlCache.clear();
2494
+ this.browserModuleInflight.clear();
2495
+ this.revokeBrowserBlobUrls();
2496
+ }
2497
+ async execute(input) {
2498
+ return this.executePlan(
2499
+ input.plan,
2500
+ input.context,
2501
+ input.event,
2502
+ input.stateOverride,
2503
+ input.signal
2504
+ );
2505
+ }
2506
+ async probePlan(plan) {
2507
+ this.ensureInitialized();
2508
+ const diagnostics = [];
2509
+ const specVersion = (0, import_ir9.resolveRuntimePlanSpecVersion)(plan.specVersion);
2510
+ if (!this.supportedPlanSpecVersions.has(specVersion)) {
2511
+ diagnostics.push({
2512
+ level: "error",
2513
+ code: "RUNTIME_SPEC_VERSION_UNSUPPORTED",
2514
+ message: `Unsupported plan specVersion "${specVersion}". Supported: ${[
2515
+ ...this.supportedPlanSpecVersions
2516
+ ].join(", ")}`
2517
+ });
2518
+ return {
2519
+ planId: plan.id,
2520
+ diagnostics,
2521
+ dependencies: []
2522
+ };
2523
+ }
2524
+ const frame = {
2525
+ startedAt: nowMs(),
2526
+ maxExecutionMs: plan.capabilities.maxExecutionMs ?? this.defaultMaxExecutionMs,
2527
+ maxComponentInvocations: plan.capabilities.maxComponentInvocations ?? this.defaultMaxComponentInvocations,
2528
+ componentInvocations: 0,
2529
+ executionProfile: plan.capabilities.executionProfile ?? this.defaultExecutionProfile
2530
+ };
2531
+ const dependencies = await this.preflightPlanDependencies(
2532
+ plan,
2533
+ diagnostics,
2534
+ frame
2535
+ );
2536
+ return {
2537
+ planId: plan.id,
2538
+ diagnostics,
2539
+ dependencies
2540
+ };
2541
+ }
2542
+ async executePlan(plan, context = {}, event, stateOverride, signal) {
2543
+ this.ensureInitialized();
2544
+ throwIfAborted(signal);
2545
+ const specVersion = (0, import_ir9.resolveRuntimePlanSpecVersion)(plan.specVersion);
2546
+ const diagnostics = [];
2547
+ if (!this.supportedPlanSpecVersions.has(specVersion)) {
2548
+ diagnostics.push({
2549
+ level: "error",
2550
+ code: "RUNTIME_SPEC_VERSION_UNSUPPORTED",
2551
+ message: `Unsupported plan specVersion "${specVersion}". Supported: ${[
2552
+ ...this.supportedPlanSpecVersions
2553
+ ].join(", ")}`
2554
+ });
2555
+ return {
2556
+ planId: plan.id,
2557
+ root: plan.root,
2558
+ diagnostics,
2559
+ state: (0, import_ir9.cloneJsonValue)(this.resolveState(plan, stateOverride)),
2560
+ handledEvent: event,
2561
+ appliedActions: []
2562
+ };
2563
+ }
2564
+ const state = this.resolveState(plan, stateOverride);
2565
+ const appliedActions = [];
2566
+ const frame = {
2567
+ startedAt: nowMs(),
2568
+ maxExecutionMs: plan.capabilities.maxExecutionMs ?? this.defaultMaxExecutionMs,
2569
+ maxComponentInvocations: plan.capabilities.maxComponentInvocations ?? this.defaultMaxComponentInvocations,
2570
+ componentInvocations: 0,
2571
+ executionProfile: plan.capabilities.executionProfile ?? this.defaultExecutionProfile,
2572
+ signal
2573
+ };
2574
+ const maxImports = plan.capabilities.maxImports ?? this.defaultMaxImports;
2575
+ const imports = plan.imports ?? [];
2576
+ if (this.enableDependencyPreflight) {
2577
+ await this.preflightPlanDependencies(plan, diagnostics, frame);
2578
+ if (this.failOnDependencyPreflightError && diagnostics.some(
2579
+ (item) => item.level === "error" && item.code.startsWith("RUNTIME_PREFLIGHT_")
2580
+ )) {
2581
+ return {
2582
+ planId: plan.id,
2583
+ root: plan.root,
2584
+ diagnostics,
2585
+ state: (0, import_ir9.cloneJsonValue)(state),
2586
+ handledEvent: event,
2587
+ appliedActions
2588
+ };
2589
+ }
2590
+ }
2591
+ await resolveRuntimePlanImports({
2592
+ imports,
2593
+ maxImports,
2594
+ moduleManifest: plan.moduleManifest,
2595
+ diagnostics,
2596
+ moduleLoader: this.moduleLoader,
2597
+ resolveRuntimeSpecifier: (specifier, moduleManifest, runtimeDiagnostics) => this.resolveRuntimeSpecifier(
2598
+ specifier,
2599
+ moduleManifest,
2600
+ runtimeDiagnostics,
2601
+ "import"
2602
+ ),
2603
+ isAborted: () => isAborted(frame.signal),
2604
+ hasExceededBudget: () => hasExceededBudget(frame),
2605
+ withRemainingBudget: (operation, timeoutMessage) => withRemainingBudget(operation, frame, timeoutMessage),
2606
+ isAbortError: (error) => isAbortError(error),
2607
+ errorToMessage: (error) => this.errorToMessage(error)
2608
+ });
2609
+ const sourceRoot = plan.source ? await this.resolveSourceRoot(
2610
+ plan,
2611
+ plan.source,
2612
+ context,
2613
+ state,
2614
+ event,
2615
+ diagnostics,
2616
+ frame
2617
+ ) : void 0;
2618
+ const sourceRenderArtifact = sourceRoot?.renderArtifact;
2619
+ const resolvedRoot = sourceRoot?.root ? await this.resolveNode(
2620
+ sourceRoot.root,
2621
+ plan.moduleManifest,
2622
+ context,
2623
+ state,
2624
+ event,
2625
+ diagnostics,
2626
+ frame
2627
+ ) : await this.resolveNode(
2628
+ plan.root,
2629
+ plan.moduleManifest,
2630
+ context,
2631
+ state,
2632
+ event,
2633
+ diagnostics,
2634
+ frame
2635
+ );
2636
+ return {
2637
+ planId: plan.id,
2638
+ root: resolvedRoot,
2639
+ diagnostics,
2640
+ state: (0, import_ir9.cloneJsonValue)(state),
2641
+ handledEvent: event,
2642
+ appliedActions,
2643
+ ...sourceRenderArtifact ? { renderArtifact: sourceRenderArtifact } : {}
2644
+ };
2645
+ }
2646
+ async compile(plan, options = {}) {
2647
+ const indent = options.pretty ? 2 : 0;
2648
+ return JSON.stringify(plan, null, indent);
2649
+ }
2650
+ getPlanState(planId) {
2651
+ const snapshot = this.states.get(planId);
2652
+ if (!snapshot) {
2653
+ return void 0;
2654
+ }
2655
+ return (0, import_ir9.cloneJsonValue)(snapshot);
2656
+ }
2657
+ setPlanState(planId, snapshot) {
2658
+ this.states.set(planId, (0, import_ir9.cloneJsonValue)(snapshot));
2659
+ }
2660
+ clearPlanState(planId) {
2661
+ this.states.delete(planId);
2662
+ }
2663
+ resolveState(plan, stateOverride) {
2664
+ if (stateOverride) {
2665
+ return (0, import_ir9.cloneJsonValue)(stateOverride);
2666
+ }
2667
+ if (plan.state?.initial) {
2668
+ return (0, import_ir9.cloneJsonValue)(plan.state.initial);
2669
+ }
2670
+ return {};
2671
+ }
2672
+ async preflightPlanDependencies(plan, diagnostics, frame) {
2673
+ return preflightRuntimePlanDependencies({
2674
+ plan,
2675
+ diagnostics,
2676
+ moduleLoader: this.moduleLoader,
2677
+ withRemainingBudget: (operation, timeoutMessage) => withRemainingBudget(operation, frame, timeoutMessage),
2678
+ resolveRuntimeSourceSpecifier: (specifier, manifest, runtimeDiagnostics, requireManifest) => this.resolveRuntimeSourceSpecifier(
2679
+ specifier,
2680
+ manifest,
2681
+ runtimeDiagnostics,
2682
+ requireManifest
2683
+ ),
2684
+ resolveSourceImportLoaderCandidate: (specifier, manifest) => this.resolveSourceImportLoaderCandidate(specifier, manifest),
2685
+ resolveRuntimeSpecifier: (specifier, manifest, runtimeDiagnostics, usage) => this.resolveRuntimeSpecifier(
2686
+ specifier,
2687
+ manifest,
2688
+ runtimeDiagnostics,
2689
+ usage
2690
+ ),
2691
+ materializeBrowserRemoteModule: (url, manifest, runtimeDiagnostics) => this.createSourceModuleLoader(
2692
+ manifest,
2693
+ runtimeDiagnostics
2694
+ ).materializeBrowserRemoteModule(url),
2695
+ fetchRemoteModuleCodeWithFallback: (url, runtimeDiagnostics) => this.createSourceModuleLoader(
2696
+ void 0,
2697
+ runtimeDiagnostics
2698
+ ).fetchRemoteModuleCodeWithFallback(url),
2699
+ isAbortError: (error) => isAbortError(error),
2700
+ errorToMessage: (error) => this.errorToMessage(error),
2701
+ isAborted: () => isAborted(frame.signal),
2702
+ hasExceededBudget: () => hasExceededBudget(frame)
2703
+ });
2704
+ }
2705
+ async resolveSourceRoot(plan, source, context, state, event, diagnostics, frame) {
2706
+ return executeRuntimeSourceRoot({
2707
+ plan,
2708
+ source,
2709
+ context,
2710
+ state,
2711
+ event,
2712
+ diagnostics,
2713
+ frame: {
2714
+ executionProfile: frame.executionProfile,
2715
+ signal: frame.signal
2716
+ },
2717
+ browserSourceSandboxTimeoutMs: this.browserSourceSandboxTimeoutMs,
2718
+ browserSourceSandboxFailClosed: this.browserSourceSandboxFailClosed,
2719
+ withRemainingBudget: (operation, timeoutMessage) => withRemainingBudget(operation, frame, timeoutMessage),
2720
+ transpileRuntimeSource: (runtimeSource) => transpileRuntimeSource(runtimeSource, this.sourceTranspiler),
2721
+ rewriteSourceImports: async (code, manifest, runtimeDiagnostics) => this.rewriteImportsAsync(
2722
+ code,
2723
+ async (specifier) => this.resolveRuntimeSourceSpecifier(
2724
+ specifier,
2725
+ manifest,
2726
+ runtimeDiagnostics
2727
+ )
2728
+ ),
2729
+ resolveSourceSandboxMode: (runtimeSource, executionProfile) => resolveSourceSandboxMode({
2730
+ source: runtimeSource,
2731
+ executionProfile,
2732
+ defaultMode: this.browserSourceSandboxMode,
2733
+ isBrowserRuntime: isBrowserRuntime()
2734
+ }),
2735
+ importSourceModuleFromCode: (code, manifest, runtimeDiagnostics) => this.createSourceModuleLoader(
2736
+ manifest,
2737
+ runtimeDiagnostics
2738
+ ).importSourceModuleFromCode(code),
2739
+ normalizeSourceOutput: (output) => this.normalizeSourceOutput(output),
2740
+ shouldUsePreactSourceRuntime,
2741
+ createPreactRenderArtifact: ({
2742
+ sourceExport,
2743
+ runtimeInput,
2744
+ diagnostics: diagnostics2
2745
+ }) => createPreactRenderArtifact({
2746
+ sourceExport,
2747
+ runtimeInput,
2748
+ diagnostics: diagnostics2
2749
+ }),
2750
+ isAbortError: (error) => isAbortError(error),
2751
+ errorToMessage: (error) => this.errorToMessage(error),
2752
+ cloneJsonValue: import_ir9.cloneJsonValue,
2753
+ asJsonValue: import_ir9.asJsonValue
2754
+ });
2755
+ }
2756
+ resolveRuntimeSourceSpecifier(specifier, moduleManifest, diagnostics, requireManifest = true) {
2757
+ return resolveRuntimeSourceSpecifier({
2758
+ specifier,
2759
+ moduleManifest,
2760
+ diagnostics,
2761
+ requireManifest,
2762
+ enforceModuleManifest: this.enforceModuleManifest,
2763
+ moduleLoader: this.moduleLoader,
2764
+ jspmCdnBase: FALLBACK_JSPM_CDN_BASE
2765
+ });
2766
+ }
2767
+ resolveSourceImportLoaderCandidate(specifier, moduleManifest) {
2768
+ return resolveSourceImportLoaderCandidate(
2769
+ specifier,
2770
+ moduleManifest,
2771
+ this.moduleLoader
2772
+ );
2773
+ }
2774
+ resolveRuntimeSpecifier(specifier, moduleManifest, diagnostics, usage) {
2775
+ return resolveRuntimeSpecifier({
2776
+ specifier,
2777
+ moduleManifest,
2778
+ diagnostics,
2779
+ usage,
2780
+ enforceModuleManifest: this.enforceModuleManifest
2781
+ });
2782
+ }
2783
+ createSourceModuleLoader(moduleManifest, diagnostics) {
2784
+ return new RuntimeSourceModuleLoader({
2785
+ moduleManifest,
2786
+ diagnostics,
2787
+ browserModuleUrlCache: this.browserModuleUrlCache,
2788
+ browserModuleInflight: this.browserModuleInflight,
2789
+ remoteFallbackCdnBases: this.remoteFallbackCdnBases,
2790
+ remoteFetchTimeoutMs: this.remoteFetchTimeoutMs,
2791
+ remoteFetchRetries: this.remoteFetchRetries,
2792
+ remoteFetchBackoffMs: this.remoteFetchBackoffMs,
2793
+ canMaterializeBrowserModules: () => canMaterializeBrowserModules(),
2794
+ rewriteImportsAsync: (code, resolver) => this.rewriteImportsAsync(code, resolver),
2795
+ createBrowserBlobModuleUrl: (code) => this.createBrowserBlobModuleUrl(code),
2796
+ resolveRuntimeSourceSpecifier: (specifier, manifest, runtimeDiagnostics, requireManifest) => this.resolveRuntimeSourceSpecifier(
2797
+ specifier,
2798
+ manifest,
2799
+ runtimeDiagnostics,
2800
+ requireManifest
2801
+ )
2802
+ });
2803
+ }
2804
+ async materializeFetchedModuleSource(fetched, moduleManifest, diagnostics) {
2805
+ return this.createSourceModuleLoader(
2806
+ moduleManifest,
2807
+ diagnostics
2808
+ ).materializeFetchedModuleSource(fetched);
2809
+ }
2810
+ toConfiguredFallbackUrl(url, cdnBase) {
2811
+ return toConfiguredFallbackUrl(url, cdnBase);
2812
+ }
2813
+ toEsmFallbackUrl(url, cdnBase = FALLBACK_ESM_CDN_BASE) {
2814
+ return toEsmFallbackUrl(url, cdnBase);
2815
+ }
2816
+ async rewriteImportsAsync(code, resolver) {
2817
+ return rewriteImportsAsync(code, resolver);
2818
+ }
2819
+ createBrowserBlobModuleUrl(code) {
2820
+ return createBrowserBlobModuleUrl(code, this.browserBlobUrls);
2821
+ }
2822
+ revokeBrowserBlobUrls() {
2823
+ revokeBrowserBlobUrls(this.browserBlobUrls);
2824
+ }
2825
+ normalizeSourceOutput(output) {
2826
+ return normalizeRuntimeSourceOutput(output);
2827
+ }
2828
+ async resolveNode(node, moduleManifest, context, state, event, diagnostics, frame) {
2829
+ throwIfAborted(frame.signal);
2830
+ if (hasExceededBudget(frame)) {
2831
+ diagnostics.push({
2832
+ level: "error",
2833
+ code: "RUNTIME_TIMEOUT",
2834
+ message: "Execution time budget exceeded during node resolution"
2835
+ });
2836
+ return (0, import_ir9.createElementNode)("div", { "data-renderify-timeout": "true" }, [
2837
+ (0, import_ir9.createTextNode)("Runtime execution timed out")
2838
+ ]);
2839
+ }
2840
+ return resolveRuntimeNode({
2841
+ node,
2842
+ moduleManifest,
2843
+ context,
2844
+ state,
2845
+ event,
2846
+ diagnostics,
2847
+ frame,
2848
+ resolver: {
2849
+ moduleLoader: this.moduleLoader,
2850
+ allowIsolationFallback: this.allowIsolationFallback,
2851
+ resolveRuntimeSpecifier: (specifier, manifest, runtimeDiagnostics, usage) => this.resolveRuntimeSpecifier(
2852
+ specifier,
2853
+ manifest,
2854
+ runtimeDiagnostics,
2855
+ usage
2856
+ ),
2857
+ withRemainingBudget: (operation, timeoutMessage) => withRemainingBudget(operation, frame, timeoutMessage),
2858
+ resolveNode: (nextNode) => this.resolveNode(
2859
+ nextNode,
2860
+ moduleManifest,
2861
+ context,
2862
+ state,
2863
+ event,
2864
+ diagnostics,
2865
+ frame
2866
+ ),
2867
+ errorToMessage: (error) => this.errorToMessage(error)
2868
+ }
2869
+ });
2870
+ }
2871
+ ensureInitialized() {
2872
+ if (!this.initialized) {
2873
+ throw new Error("RuntimeManager is not initialized");
2874
+ }
2875
+ }
2876
+ errorToMessage(error) {
2877
+ if (error instanceof Error) {
2878
+ return error.message;
2879
+ }
2880
+ return String(error);
2881
+ }
2882
+ };
2883
+
2884
+ // src/runtime-manager.types.ts
2885
+ var RuntimeSecurityViolationError = class extends Error {
2886
+ result;
2887
+ constructor(result) {
2888
+ super(`Security policy rejected runtime plan: ${result.issues.join("; ")}`);
2889
+ this.name = "RuntimeSecurityViolationError";
2890
+ this.result = result;
2891
+ }
2892
+ };
2893
+
2894
+ // src/ui-renderer.ts
2895
+ var DefaultUIRenderer = class {
2896
+ mountSessions = /* @__PURE__ */ new WeakMap();
2897
+ async render(result, target) {
2898
+ if (result.renderArtifact?.mode === "preact-vnode") {
2899
+ return this.renderPreactArtifact(result.renderArtifact.payload, target);
2900
+ }
2901
+ const serialized = this.renderNodeWithBindings(result.root);
2902
+ if (typeof document === "undefined") {
2903
+ return serialized.html;
2904
+ }
2905
+ if (!target) {
2906
+ return serialized.html;
2907
+ }
2908
+ const resolvedTarget = this.resolveRenderTarget(target);
2909
+ if (!resolvedTarget) {
2910
+ throw new Error(
2911
+ `Render target not found: ${this.stringifyTarget(target)}`
2912
+ );
2913
+ }
2914
+ const { mountPoint, onRuntimeEvent } = resolvedTarget;
2915
+ this.patchMountPoint(mountPoint, serialized.html);
2916
+ this.syncMountSession(
2917
+ mountPoint,
2918
+ result.planId,
2919
+ serialized.eventBindings,
2920
+ onRuntimeEvent
2921
+ );
2922
+ return mountPoint.innerHTML;
2923
+ }
2924
+ async renderPreactArtifact(payload, target) {
2925
+ if (typeof document !== "undefined" && target) {
2926
+ const resolvedTarget = this.resolveRenderTarget(target);
2927
+ if (!resolvedTarget) {
2928
+ throw new Error(
2929
+ `Render target not found: ${this.stringifyTarget(target)}`
2930
+ );
2931
+ }
2932
+ const preact = await this.loadPreactRenderer();
2933
+ preact.render(payload, resolvedTarget.mountPoint);
2934
+ return resolvedTarget.mountPoint.innerHTML;
2935
+ }
2936
+ const renderToString = await this.loadPreactRenderToString();
2937
+ return renderToString(payload);
2938
+ }
2939
+ renderNode(node) {
2940
+ return this.renderNodeWithBindings(node).html;
2941
+ }
2942
+ renderNodeWithBindings(node) {
2943
+ const context = {
2944
+ nextBindingId: 0,
2945
+ eventBindings: []
2946
+ };
2947
+ return {
2948
+ html: this.renderNodeInternal(node, context),
2949
+ eventBindings: context.eventBindings
2950
+ };
2951
+ }
2952
+ renderNodeInternal(node, context) {
2953
+ if (node.type === "text") {
2954
+ return escapeHtml(node.value);
2955
+ }
2956
+ if (node.type === "component") {
2957
+ return `<div data-renderify-unresolved-component="${escapeHtml(node.module)}"></div>`;
2958
+ }
2959
+ const children = (node.children ?? []).map((child) => this.renderNodeInternal(child, context)).join("");
2960
+ const normalizedTag = normalizeTagName(node.tag);
2961
+ if (!normalizedTag) {
2962
+ return `<div data-renderify-sanitized-tag="${escapeHtml(node.tag)}">${children}</div>`;
2963
+ }
2964
+ if (BLOCKED_TAG_NAMES.has(normalizedTag)) {
2965
+ return `<div data-renderify-sanitized-tag="${escapeHtml(node.tag)}"></div>`;
2966
+ }
2967
+ const attributes = serializeProps(node.props, context);
2968
+ return `<${normalizedTag}${attributes}>${children}</${normalizedTag}>`;
2969
+ }
2970
+ resolveRenderTarget(target) {
2971
+ if (isInteractiveRenderTarget(target)) {
2972
+ const mountPoint2 = this.resolveTargetElement(target.element);
2973
+ if (!mountPoint2) {
2974
+ return null;
2975
+ }
2976
+ return {
2977
+ mountPoint: mountPoint2,
2978
+ onRuntimeEvent: target.onRuntimeEvent
2979
+ };
2980
+ }
2981
+ const mountPoint = this.resolveTargetElement(target);
2982
+ if (!mountPoint) {
2983
+ return null;
2984
+ }
2985
+ return {
2986
+ mountPoint
2987
+ };
2988
+ }
2989
+ resolveTargetElement(target) {
2990
+ if (typeof target !== "string") {
2991
+ return target;
2992
+ }
2993
+ return document.querySelector(target);
2994
+ }
2995
+ patchMountPoint(mountPoint, nextHtml) {
2996
+ const sanitizedHtml = this.sanitizeHtmlForMount(nextHtml);
2997
+ const session = this.mountSessions.get(mountPoint);
2998
+ if (!session) {
2999
+ mountPoint.innerHTML = sanitizedHtml;
3000
+ return;
3001
+ }
3002
+ if (session.html === sanitizedHtml) {
3003
+ return;
3004
+ }
3005
+ const scrollTop = mountPoint.scrollTop;
3006
+ const scrollLeft = mountPoint.scrollLeft;
3007
+ const template = document.createElement("template");
3008
+ template.innerHTML = sanitizedHtml;
3009
+ this.reconcileChildren(mountPoint, template.content);
3010
+ mountPoint.scrollTop = scrollTop;
3011
+ mountPoint.scrollLeft = scrollLeft;
3012
+ }
3013
+ sanitizeHtmlForMount(html) {
3014
+ const template = document.createElement("template");
3015
+ template.innerHTML = html;
3016
+ sanitizeRenderedFragment(template.content);
3017
+ return template.innerHTML;
3018
+ }
3019
+ reconcileChildren(currentParent, nextParent) {
3020
+ const currentChildren = Array.from(currentParent.childNodes);
3021
+ const nextChildren = Array.from(nextParent.childNodes);
3022
+ if (this.shouldUseKeyedReconcile(currentChildren, nextChildren)) {
3023
+ this.reconcileKeyedChildren(currentParent, currentChildren, nextChildren);
3024
+ return;
3025
+ }
3026
+ const commonLength = Math.min(currentChildren.length, nextChildren.length);
3027
+ for (let i = 0; i < commonLength; i += 1) {
3028
+ this.reconcileNode(currentChildren[i], nextChildren[i]);
3029
+ }
3030
+ for (let i = currentChildren.length - 1; i >= nextChildren.length; i -= 1) {
3031
+ currentChildren[i].remove();
3032
+ }
3033
+ for (let i = commonLength; i < nextChildren.length; i += 1) {
3034
+ currentParent.appendChild(nextChildren[i].cloneNode(true));
3035
+ }
3036
+ }
3037
+ shouldUseKeyedReconcile(currentChildren, nextChildren) {
3038
+ return currentChildren.some((node) => this.getNodeKey(node) !== null) || nextChildren.some((node) => this.getNodeKey(node) !== null);
3039
+ }
3040
+ reconcileKeyedChildren(currentParent, currentChildren, nextChildren) {
3041
+ const currentByKey = /* @__PURE__ */ new Map();
3042
+ for (const node of currentChildren) {
3043
+ const key = this.getNodeKey(node);
3044
+ if (!key || currentByKey.has(key)) {
3045
+ continue;
3046
+ }
3047
+ currentByKey.set(key, node);
3048
+ }
3049
+ const consumed = /* @__PURE__ */ new Set();
3050
+ const desiredNodes = [];
3051
+ for (let index = 0; index < nextChildren.length; index += 1) {
3052
+ const nextChild = nextChildren[index];
3053
+ const nextKey = this.getNodeKey(nextChild);
3054
+ let candidate;
3055
+ if (nextKey) {
3056
+ const keyed = currentByKey.get(nextKey);
3057
+ if (keyed && !consumed.has(keyed) && this.areNodesCompatible(keyed, nextChild)) {
3058
+ candidate = keyed;
3059
+ }
3060
+ } else {
3061
+ const positional = currentChildren[index];
3062
+ if (positional && !consumed.has(positional) && this.getNodeKey(positional) === null && this.areNodesCompatible(positional, nextChild)) {
3063
+ candidate = positional;
3064
+ }
3065
+ }
3066
+ if (candidate) {
3067
+ this.reconcileNode(candidate, nextChild);
3068
+ consumed.add(candidate);
3069
+ desiredNodes.push(candidate);
3070
+ continue;
3071
+ }
3072
+ desiredNodes.push(nextChild.cloneNode(true));
3073
+ }
3074
+ this.applyDesiredChildren(currentParent, desiredNodes);
3075
+ }
3076
+ applyDesiredChildren(currentParent, desiredNodes) {
3077
+ const desiredSet = new Set(desiredNodes);
3078
+ for (const child of Array.from(currentParent.childNodes)) {
3079
+ if (!desiredSet.has(child)) {
3080
+ child.remove();
3081
+ }
3082
+ }
3083
+ for (let index = 0; index < desiredNodes.length; index += 1) {
3084
+ const desiredNode = desiredNodes[index];
3085
+ const nodeAtIndex = currentParent.childNodes[index] ?? null;
3086
+ if (desiredNode.parentNode !== currentParent) {
3087
+ currentParent.insertBefore(desiredNode, nodeAtIndex);
3088
+ continue;
3089
+ }
3090
+ if (nodeAtIndex !== desiredNode) {
3091
+ currentParent.insertBefore(desiredNode, nodeAtIndex);
3092
+ }
3093
+ }
3094
+ }
3095
+ getNodeKey(node) {
3096
+ if (typeof Element === "undefined" || !(node instanceof Element)) {
3097
+ return null;
3098
+ }
3099
+ const key = node.getAttribute("data-renderify-key") ?? node.getAttribute("key");
3100
+ if (!key || key.trim().length === 0) {
3101
+ return null;
3102
+ }
3103
+ return key;
3104
+ }
3105
+ areNodesCompatible(currentNode, nextNode) {
3106
+ if (currentNode.nodeType !== nextNode.nodeType) {
3107
+ return false;
3108
+ }
3109
+ if (typeof Element === "undefined" || !(currentNode instanceof Element) || !(nextNode instanceof Element)) {
3110
+ return true;
3111
+ }
3112
+ return currentNode.tagName === nextNode.tagName;
3113
+ }
3114
+ reconcileNode(currentNode, nextNode) {
3115
+ if (currentNode.nodeType !== nextNode.nodeType) {
3116
+ currentNode.replaceWith(nextNode.cloneNode(true));
3117
+ return;
3118
+ }
3119
+ if (currentNode.nodeType === Node.TEXT_NODE) {
3120
+ if (currentNode.textContent !== nextNode.textContent) {
3121
+ currentNode.textContent = nextNode.textContent;
3122
+ }
3123
+ return;
3124
+ }
3125
+ if (!(currentNode instanceof Element) || !(nextNode instanceof Element)) {
3126
+ if (currentNode.textContent !== nextNode.textContent) {
3127
+ currentNode.textContent = nextNode.textContent;
3128
+ }
3129
+ return;
3130
+ }
3131
+ if (currentNode.tagName !== nextNode.tagName) {
3132
+ currentNode.replaceWith(nextNode.cloneNode(true));
3133
+ return;
3134
+ }
3135
+ this.reconcileAttributes(currentNode, nextNode);
3136
+ this.reconcileChildren(currentNode, nextNode);
3137
+ }
3138
+ reconcileAttributes(currentElement, nextElement) {
3139
+ const activeElement = typeof document !== "undefined" ? document.activeElement : void 0;
3140
+ for (const attribute of Array.from(currentElement.attributes)) {
3141
+ if (!nextElement.hasAttribute(attribute.name)) {
3142
+ currentElement.removeAttribute(attribute.name);
3143
+ }
3144
+ }
3145
+ for (const attribute of Array.from(nextElement.attributes)) {
3146
+ if (this.shouldSkipInteractivePropertySync(
3147
+ currentElement,
3148
+ activeElement,
3149
+ attribute.name
3150
+ )) {
3151
+ continue;
3152
+ }
3153
+ if (currentElement.getAttribute(attribute.name) !== attribute.value) {
3154
+ currentElement.setAttribute(attribute.name, attribute.value);
3155
+ }
3156
+ }
3157
+ }
3158
+ shouldSkipInteractivePropertySync(element, activeElement, attributeName) {
3159
+ if (!activeElement || element !== activeElement) {
3160
+ return false;
3161
+ }
3162
+ if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement)) {
3163
+ return false;
3164
+ }
3165
+ return attributeName === "value" || attributeName === "checked";
3166
+ }
3167
+ syncMountSession(mountPoint, planId, eventBindings, onRuntimeEvent) {
3168
+ const existing = this.mountSessions.get(mountPoint);
3169
+ const runtimeEvents = /* @__PURE__ */ new Map();
3170
+ const delegatedEventTypes = /* @__PURE__ */ new Set();
3171
+ for (const binding of eventBindings) {
3172
+ runtimeEvents.set(binding.bindingId, binding.runtimeEvent);
3173
+ delegatedEventTypes.add(binding.domEvent);
3174
+ }
3175
+ const session = existing ?? {
3176
+ html: "",
3177
+ planId,
3178
+ runtimeEvents,
3179
+ listeners: /* @__PURE__ */ new Map(),
3180
+ onRuntimeEvent
3181
+ };
3182
+ session.html = mountPoint.innerHTML;
3183
+ session.planId = planId;
3184
+ session.runtimeEvents = runtimeEvents;
3185
+ session.onRuntimeEvent = onRuntimeEvent;
3186
+ this.syncDelegatedListeners(mountPoint, session, delegatedEventTypes);
3187
+ this.mountSessions.set(mountPoint, session);
3188
+ }
3189
+ syncDelegatedListeners(mountPoint, session, delegatedEventTypes) {
3190
+ for (const [eventType, listener] of session.listeners.entries()) {
3191
+ if (!delegatedEventTypes.has(eventType)) {
3192
+ mountPoint.removeEventListener(eventType, listener);
3193
+ session.listeners.delete(eventType);
3194
+ }
3195
+ }
3196
+ for (const eventType of delegatedEventTypes) {
3197
+ if (session.listeners.has(eventType)) {
3198
+ continue;
3199
+ }
3200
+ const listener = (event) => {
3201
+ this.handleDelegatedRuntimeEvent(mountPoint, session, eventType, event);
3202
+ };
3203
+ mountPoint.addEventListener(eventType, listener);
3204
+ session.listeners.set(eventType, listener);
3205
+ }
3206
+ }
3207
+ handleDelegatedRuntimeEvent(mountPoint, session, domEvent, event) {
3208
+ const eventTarget = event.target;
3209
+ if (!eventTarget || !(eventTarget instanceof Element)) {
3210
+ return;
3211
+ }
3212
+ const bindingAttribute = getBindingAttributeName(domEvent);
3213
+ const matched = eventTarget.closest(`[${bindingAttribute}]`);
3214
+ if (!matched || !(matched instanceof Element) || !mountPoint.contains(matched)) {
3215
+ return;
3216
+ }
3217
+ const bindingId = matched.getAttribute(bindingAttribute);
3218
+ if (!bindingId) {
3219
+ return;
3220
+ }
3221
+ const runtimeEvent = session.runtimeEvents.get(bindingId);
3222
+ if (!runtimeEvent) {
3223
+ return;
3224
+ }
3225
+ const dispatchRequest = {
3226
+ planId: session.planId,
3227
+ event: runtimeEvent
3228
+ };
3229
+ if (typeof CustomEvent === "function") {
3230
+ mountPoint.dispatchEvent(
3231
+ new CustomEvent(
3232
+ "renderify:runtime-event",
3233
+ {
3234
+ bubbles: true,
3235
+ composed: true,
3236
+ detail: dispatchRequest
3237
+ }
3238
+ )
3239
+ );
3240
+ }
3241
+ if (session.onRuntimeEvent) {
3242
+ void Promise.resolve(session.onRuntimeEvent(dispatchRequest)).catch(
3243
+ () => {
3244
+ }
3245
+ );
3246
+ }
3247
+ }
3248
+ async loadPreactRenderer() {
3249
+ const loaded = await import(getPreactSpecifier2());
3250
+ if (!isPreactRendererLike(loaded)) {
3251
+ throw new Error("Failed to load preact renderer from `preact` package");
3252
+ }
3253
+ return loaded;
3254
+ }
3255
+ async loadPreactRenderToString() {
3256
+ const loaded = await import(getPreactRenderToStringSpecifier());
3257
+ if (!isPreactRenderToStringLike(loaded)) {
3258
+ throw new Error(
3259
+ "Failed to load preact-render-to-string from `preact-render-to-string` package"
3260
+ );
3261
+ }
3262
+ if (typeof loaded === "function") {
3263
+ return loaded;
3264
+ }
3265
+ if (typeof loaded.default === "function") {
3266
+ return loaded.default;
3267
+ }
3268
+ return loaded.render;
3269
+ }
3270
+ stringifyTarget(target) {
3271
+ if (typeof target === "string") {
3272
+ return target;
3273
+ }
3274
+ if (isInteractiveRenderTarget(target)) {
3275
+ if (typeof target.element === "string") {
3276
+ return target.element;
3277
+ }
3278
+ return "[interactive-target-element]";
3279
+ }
3280
+ return "[target-element]";
3281
+ }
3282
+ };
3283
+ function isPreactRendererLike(value) {
3284
+ if (typeof value !== "object" || value === null) {
3285
+ return false;
3286
+ }
3287
+ const candidate = value;
3288
+ return typeof candidate.render === "function";
3289
+ }
3290
+ function isPreactRenderToStringLike(value) {
3291
+ if (typeof value === "function") {
3292
+ return true;
3293
+ }
3294
+ if (typeof value !== "object" || value === null) {
3295
+ return false;
3296
+ }
3297
+ const candidate = value;
3298
+ return typeof candidate.default === "function" || typeof candidate.render === "function";
3299
+ }
3300
+ function isInteractiveRenderTarget(value) {
3301
+ if (typeof value === "string") {
3302
+ return false;
3303
+ }
3304
+ if (typeof HTMLElement !== "undefined" && value instanceof HTMLElement) {
3305
+ return false;
3306
+ }
3307
+ return typeof value === "object" && value !== null && "element" in value && (typeof value.element === "string" || typeof HTMLElement !== "undefined" && value.element instanceof HTMLElement);
3308
+ }
3309
+ function getPreactSpecifier2() {
3310
+ return "preact";
3311
+ }
3312
+ function getPreactRenderToStringSpecifier() {
3313
+ return "preact-render-to-string";
3314
+ }
3315
+ function getBindingAttributeName(domEvent) {
3316
+ return `data-renderify-event-${domEvent}`;
3317
+ }
3318
+ var BLOCKED_TAG_NAMES = /* @__PURE__ */ new Set([
3319
+ "script",
3320
+ "style",
3321
+ "iframe",
3322
+ "object",
3323
+ "embed",
3324
+ "link",
3325
+ "meta",
3326
+ "base",
3327
+ "form"
3328
+ ]);
3329
+ var BLOCKED_ATTRIBUTE_NAMES = /* @__PURE__ */ new Set([
3330
+ "srcdoc",
3331
+ "innerhtml",
3332
+ "dangerouslysetinnerhtml"
3333
+ ]);
3334
+ var URL_ATTRIBUTE_NAMES = /* @__PURE__ */ new Set([
3335
+ "href",
3336
+ "src",
3337
+ "xlink:href",
3338
+ "action",
3339
+ "formaction",
3340
+ "poster"
3341
+ ]);
3342
+ var SAFE_URL_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:", "mailto:", "tel:"]);
3343
+ var UNSAFE_STYLE_PATTERNS = [
3344
+ /\bexpression\s*\(/i,
3345
+ /\burl\s*\(/i,
3346
+ /\bjavascript\s*:/i,
3347
+ /\bdata\s*:/i,
3348
+ /@import/i,
3349
+ /\bbehavior\s*:/i,
3350
+ /-moz-binding/i
3351
+ ];
3352
+ function sanitizeTagName(tag) {
3353
+ const normalized = normalizeTagName(tag);
3354
+ if (!normalized) {
3355
+ return void 0;
3356
+ }
3357
+ if (BLOCKED_TAG_NAMES.has(normalized)) {
3358
+ return void 0;
3359
+ }
3360
+ return normalized;
3361
+ }
3362
+ function normalizeTagName(tag) {
3363
+ const normalized = tag.trim().toLowerCase();
3364
+ if (!/^[a-z][a-z0-9-]*$/.test(normalized)) {
3365
+ return void 0;
3366
+ }
3367
+ return normalized;
3368
+ }
3369
+ function isSafeAttributeName(attributeName) {
3370
+ return /^[A-Za-z_:][A-Za-z0-9:._-]*$/.test(attributeName);
3371
+ }
3372
+ function isSafeAttributeUrl(value) {
3373
+ const trimmed = value.trim();
3374
+ if (trimmed.length === 0) {
3375
+ return false;
3376
+ }
3377
+ if (trimmed.startsWith("#") || trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("../")) {
3378
+ return true;
3379
+ }
3380
+ const lowered = trimmed.toLowerCase();
3381
+ if (lowered.startsWith("javascript:") || lowered.startsWith("vbscript:") || lowered.startsWith("data:")) {
3382
+ return false;
3383
+ }
3384
+ if (/^[a-z][a-z0-9+.-]*:/.test(lowered)) {
3385
+ try {
3386
+ const parsed = new URL(trimmed);
3387
+ return SAFE_URL_PROTOCOLS.has(parsed.protocol);
3388
+ } catch {
3389
+ return false;
3390
+ }
3391
+ }
3392
+ return true;
3393
+ }
3394
+ function serializeProps(props, context) {
3395
+ if (!props) {
3396
+ return "";
3397
+ }
3398
+ const attributes = [];
3399
+ let targetIsBlank = false;
3400
+ let relProvided = false;
3401
+ for (const [key, rawValue] of Object.entries(props)) {
3402
+ if (!isSafeAttributeName(key)) {
3403
+ continue;
3404
+ }
3405
+ const normalizedKey = key.toLowerCase();
3406
+ if (BLOCKED_ATTRIBUTE_NAMES.has(normalizedKey)) {
3407
+ continue;
3408
+ }
3409
+ if (key === "key") {
3410
+ if (typeof rawValue === "string" || typeof rawValue === "number") {
3411
+ attributes.push(
3412
+ ` data-renderify-key="${escapeHtml(String(rawValue))}"`
3413
+ );
3414
+ }
3415
+ continue;
3416
+ }
3417
+ const eventSpec = parseRuntimeEventProp(key, rawValue);
3418
+ if (eventSpec) {
3419
+ const bindingId = `evt_${String(++context.nextBindingId)}`;
3420
+ context.eventBindings.push({
3421
+ bindingId,
3422
+ domEvent: eventSpec.domEvent,
3423
+ runtimeEvent: eventSpec.runtimeEvent
3424
+ });
3425
+ attributes.push(
3426
+ ` ${getBindingAttributeName(eventSpec.domEvent)}="${escapeHtml(bindingId)}"`
3427
+ );
3428
+ continue;
3429
+ }
3430
+ if (URL_ATTRIBUTE_NAMES.has(normalizedKey)) {
3431
+ if (typeof rawValue !== "string" || !isSafeAttributeUrl(rawValue)) {
3432
+ continue;
3433
+ }
3434
+ }
3435
+ if (normalizedKey === "style") {
3436
+ if (typeof rawValue !== "string") {
3437
+ continue;
3438
+ }
3439
+ const sanitizedStyle = sanitizeInlineStyle(rawValue);
3440
+ if (!sanitizedStyle) {
3441
+ continue;
3442
+ }
3443
+ attributes.push(` style="${escapeHtml(sanitizedStyle)}"`);
3444
+ continue;
3445
+ }
3446
+ if (key.startsWith("on")) {
3447
+ continue;
3448
+ }
3449
+ if (normalizedKey === "target" && String(rawValue).trim() === "_blank") {
3450
+ targetIsBlank = true;
3451
+ }
3452
+ if (normalizedKey === "rel") {
3453
+ relProvided = true;
3454
+ }
3455
+ if (typeof rawValue === "boolean") {
3456
+ if (rawValue) {
3457
+ attributes.push(` ${key}`);
3458
+ }
3459
+ continue;
3460
+ }
3461
+ if (rawValue === null || typeof rawValue === "object") {
3462
+ attributes.push(` ${key}='${escapeHtml(JSON.stringify(rawValue))}'`);
3463
+ continue;
3464
+ }
3465
+ attributes.push(` ${key}="${escapeHtml(String(rawValue))}"`);
3466
+ }
3467
+ if (targetIsBlank && !relProvided) {
3468
+ attributes.push(' rel="noopener noreferrer"');
3469
+ }
3470
+ return attributes.join("");
3471
+ }
3472
+ function sanitizeInlineStyle(style) {
3473
+ const normalized = style.trim();
3474
+ if (normalized.length === 0) {
3475
+ return void 0;
3476
+ }
3477
+ const inspected = normalizeStyleForSecurityInspection(normalized);
3478
+ if (inspected.length === 0) {
3479
+ return void 0;
3480
+ }
3481
+ for (const pattern of UNSAFE_STYLE_PATTERNS) {
3482
+ if (pattern.test(inspected)) {
3483
+ return void 0;
3484
+ }
3485
+ }
3486
+ return normalized;
3487
+ }
3488
+ function normalizeStyleForSecurityInspection(style) {
3489
+ const withoutComments = style.replace(/\/\*[\s\S]*?\*\//g, "");
3490
+ const decodedEscapes = decodeCssEscapes(withoutComments).replace(/\0/g, "");
3491
+ return decodedEscapes.replace(/\s+/g, " ").trim().toLowerCase();
3492
+ }
3493
+ function decodeCssEscapes(input) {
3494
+ return input.replace(
3495
+ /\\(?:([0-9a-fA-F]{1,6})(?:\r\n|[ \t\r\n\f])?|(.))/g,
3496
+ (_match, hexCodePoint, escapedChar) => {
3497
+ if (hexCodePoint) {
3498
+ const parsed = Number.parseInt(hexCodePoint, 16);
3499
+ if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1114111) {
3500
+ return "";
3501
+ }
3502
+ return String.fromCodePoint(parsed);
3503
+ }
3504
+ return escapedChar;
3505
+ }
3506
+ );
3507
+ }
3508
+ function sanitizeRenderedFragment(fragment) {
3509
+ sanitizeRenderedSubtree(fragment);
3510
+ }
3511
+ function sanitizeRenderedSubtree(root) {
3512
+ const elements = Array.from(root.querySelectorAll("*"));
3513
+ for (const element of elements) {
3514
+ if (!element.isConnected) {
3515
+ continue;
3516
+ }
3517
+ const tagName = element.tagName.toLowerCase();
3518
+ if (!sanitizeTagName(tagName)) {
3519
+ replaceBlockedElement(element, tagName);
3520
+ continue;
3521
+ }
3522
+ sanitizeElementAttributes(element);
3523
+ const shadowRoot = element.shadowRoot;
3524
+ if (shadowRoot) {
3525
+ sanitizeRenderedSubtree(shadowRoot);
3526
+ }
3527
+ }
3528
+ }
3529
+ function replaceBlockedElement(element, tagName) {
3530
+ const replacement = element.ownerDocument.createElement("div");
3531
+ replacement.setAttribute("data-renderify-sanitized-tag", tagName);
3532
+ element.replaceWith(replacement);
3533
+ }
3534
+ function sanitizeElementAttributes(element) {
3535
+ let targetIsBlank = false;
3536
+ let relProvided = false;
3537
+ for (const attribute of Array.from(element.attributes)) {
3538
+ const key = attribute.name;
3539
+ const value = attribute.value;
3540
+ const normalizedKey = key.toLowerCase();
3541
+ if (!isSafeAttributeName(key) || BLOCKED_ATTRIBUTE_NAMES.has(normalizedKey)) {
3542
+ element.removeAttribute(key);
3543
+ continue;
3544
+ }
3545
+ if (normalizedKey.startsWith("on")) {
3546
+ element.removeAttribute(key);
3547
+ continue;
3548
+ }
3549
+ if (URL_ATTRIBUTE_NAMES.has(normalizedKey) && !isSafeAttributeUrl(value)) {
3550
+ element.removeAttribute(key);
3551
+ continue;
3552
+ }
3553
+ if (normalizedKey === "style") {
3554
+ const sanitizedStyle = sanitizeInlineStyle(value);
3555
+ if (!sanitizedStyle) {
3556
+ element.removeAttribute(key);
3557
+ continue;
3558
+ }
3559
+ if (sanitizedStyle !== value) {
3560
+ element.setAttribute(key, sanitizedStyle);
3561
+ }
3562
+ }
3563
+ if (normalizedKey === "target" && value.trim() === "_blank") {
3564
+ targetIsBlank = true;
3565
+ }
3566
+ if (normalizedKey === "rel") {
3567
+ relProvided = true;
3568
+ }
3569
+ }
3570
+ if (targetIsBlank && !relProvided) {
3571
+ element.setAttribute("rel", "noopener noreferrer");
3572
+ }
3573
+ }
3574
+ function parseRuntimeEventProp(propName, value) {
3575
+ if (!/^on[A-Z]/.test(propName)) {
3576
+ return void 0;
3577
+ }
3578
+ const domEvent = propName.slice(2).toLowerCase();
3579
+ if (!/^[a-z][a-z0-9_-]*$/.test(domEvent)) {
3580
+ return void 0;
3581
+ }
3582
+ if (typeof value === "string" && value.trim().length > 0) {
3583
+ return {
3584
+ domEvent,
3585
+ runtimeEvent: {
3586
+ type: value.trim()
3587
+ }
3588
+ };
3589
+ }
3590
+ if (!isJsonObject(value)) {
3591
+ return void 0;
3592
+ }
3593
+ const eventType = value.type;
3594
+ if (typeof eventType !== "string" || eventType.trim().length === 0) {
3595
+ return void 0;
3596
+ }
3597
+ const payload = value.payload;
3598
+ const runtimeEvent = {
3599
+ type: eventType.trim()
3600
+ };
3601
+ if (isJsonObject(payload)) {
3602
+ runtimeEvent.payload = payload;
3603
+ }
3604
+ return {
3605
+ domEvent,
3606
+ runtimeEvent
3607
+ };
3608
+ }
3609
+ function isJsonObject(value) {
3610
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3611
+ }
3612
+ function escapeHtml(value) {
3613
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
3614
+ }
3615
+
3616
+ // src/embed.ts
3617
+ var EMBED_TARGET_RENDER_LOCKS = /* @__PURE__ */ new WeakMap();
3618
+ async function renderPlanInBrowser(plan, options = {}) {
3619
+ const renderOperation = async () => {
3620
+ const ui = options.ui ?? new DefaultUIRenderer();
3621
+ const runtime = options.runtime ?? new DefaultRuntimeManager({
3622
+ moduleLoader: new JspmModuleLoader(),
3623
+ ...options.runtimeOptions ?? {}
3624
+ });
3625
+ const security = options.security ?? new import_security.DefaultSecurityChecker();
3626
+ const shouldInitializeRuntime = options.autoInitializeRuntime !== false || options.runtime === void 0;
3627
+ const shouldTerminateRuntime = options.autoTerminateRuntime !== false && options.runtime === void 0;
3628
+ security.initialize(options.securityInitialization);
3629
+ if (shouldInitializeRuntime) {
3630
+ await runtime.initialize();
3631
+ }
3632
+ try {
3633
+ const securityResult = await security.checkPlan(plan);
3634
+ if (!securityResult.safe) {
3635
+ throw new RuntimeSecurityViolationError(securityResult);
3636
+ }
3637
+ const execution = await runtime.execute({
3638
+ plan,
3639
+ context: options.context,
3640
+ signal: options.signal
3641
+ });
3642
+ const html = await ui.render(execution, options.target);
3643
+ return {
3644
+ html,
3645
+ execution,
3646
+ security: securityResult,
3647
+ runtime
3648
+ };
3649
+ } finally {
3650
+ if (shouldTerminateRuntime) {
3651
+ await runtime.terminate();
3652
+ }
3653
+ }
3654
+ };
3655
+ const shouldSerialize = options.serializeTargetRenders !== false;
3656
+ const targetElement = shouldSerialize ? resolveEmbedRenderTargetElement(options.target) : void 0;
3657
+ if (targetElement) {
3658
+ return withEmbedTargetRenderLock(targetElement, renderOperation);
3659
+ }
3660
+ return renderOperation();
3661
+ }
3662
+ async function withEmbedTargetRenderLock(target, operation) {
3663
+ const previousLock = EMBED_TARGET_RENDER_LOCKS.get(target) ?? Promise.resolve();
3664
+ let releaseCurrentLock;
3665
+ const currentLock = new Promise((resolve) => {
3666
+ releaseCurrentLock = resolve;
3667
+ });
3668
+ const queuedLock = previousLock.catch(() => void 0).then(() => currentLock);
3669
+ EMBED_TARGET_RENDER_LOCKS.set(target, queuedLock);
3670
+ await previousLock.catch(() => void 0);
3671
+ try {
3672
+ return await operation();
3673
+ } finally {
3674
+ releaseCurrentLock?.();
3675
+ if (EMBED_TARGET_RENDER_LOCKS.get(target) === queuedLock) {
3676
+ EMBED_TARGET_RENDER_LOCKS.delete(target);
3677
+ }
3678
+ }
3679
+ }
3680
+ function resolveEmbedRenderTargetElement(target) {
3681
+ if (typeof document === "undefined" || !target) {
3682
+ return void 0;
3683
+ }
3684
+ if (typeof target === "string") {
3685
+ return document.querySelector(target) ?? void 0;
3686
+ }
3687
+ if (typeof HTMLElement !== "undefined" && target instanceof HTMLElement) {
3688
+ return target;
3689
+ }
3690
+ if (isInteractiveRenderTargetValue(target)) {
3691
+ if (typeof target.element === "string") {
3692
+ return document.querySelector(target.element) ?? void 0;
3693
+ }
3694
+ return target.element;
3695
+ }
3696
+ return void 0;
3697
+ }
3698
+ function isInteractiveRenderTargetValue(target) {
3699
+ return typeof target === "object" && target !== null && "element" in target && (typeof target.element === "string" || typeof HTMLElement !== "undefined" && target.element instanceof HTMLElement);
3700
+ }
3701
+ //# sourceMappingURL=runtime.cjs.js.map