@absolutejs/absolute 0.19.0-beta.365 → 0.19.0-beta.366
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/browser.js +8 -12
- package/dist/angular/browser.js.map +4 -4
- package/dist/angular/index.js +4420 -4465
- package/dist/angular/index.js.map +8 -8
- package/dist/build.js +575 -23
- package/dist/build.js.map +10 -4
- package/dist/client/index.js +44 -45
- package/dist/client/index.js.map +4 -4
- package/dist/index.js +4337 -4363
- package/dist/index.js.map +15 -14
- package/dist/react/components/browser/index.js +18 -6
- package/dist/react/components/index.js +35 -16
- package/dist/react/components/index.js.map +6 -5
- package/dist/react/index.js +1762 -1794
- package/dist/react/index.js.map +12 -12
- package/dist/react/server.js +571 -3
- package/dist/react/server.js.map +11 -4
- package/dist/src/core/pageHandlers.d.ts +0 -1
- package/dist/src/react/index.d.ts +1 -1
- package/dist/src/react/streamingSlotCollection.d.ts +9 -0
- package/dist/svelte/index.js +1881 -1926
- package/dist/svelte/index.js.map +8 -8
- package/dist/vue/components/index.js +8 -12
- package/dist/vue/components/index.js.map +5 -5
- package/dist/vue/index.js +1929 -1976
- package/dist/vue/index.js.map +8 -8
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -78,24 +78,8 @@ var __legacyMetadataTS = (k, v) => {
|
|
|
78
78
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
79
79
|
var __require = import.meta.require;
|
|
80
80
|
|
|
81
|
-
// src/utils/escapeScriptContent.ts
|
|
82
|
-
var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
|
|
83
|
-
const escaped = ESCAPE_LOOKUP[char];
|
|
84
|
-
return escaped !== undefined ? escaped : char;
|
|
85
|
-
});
|
|
86
|
-
var init_escapeScriptContent = __esm(() => {
|
|
87
|
-
ESCAPE_LOOKUP = {
|
|
88
|
-
"\u2028": "\\u2028",
|
|
89
|
-
"\u2029": "\\u2029",
|
|
90
|
-
"&": "\\u0026",
|
|
91
|
-
"<": "\\u003C",
|
|
92
|
-
">": "\\u003E"
|
|
93
|
-
};
|
|
94
|
-
ESCAPE_REGEX = /[&><\u2028\u2029]/g;
|
|
95
|
-
});
|
|
96
|
-
|
|
97
81
|
// src/core/islandPageContext.ts
|
|
98
|
-
var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST__", ISLAND_STATE_MARKER = "__ABS_ISLAND_STATE__",
|
|
82
|
+
var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST__", ISLAND_STATE_MARKER = "__ABS_ISLAND_STATE__", CLOSING_HEAD_TAG = "</head>", buildIslandsHeadMarkup = (manifest) => {
|
|
99
83
|
const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
|
|
100
84
|
const islandStateScript = `<script>window.__ABS_ISLAND_STATE__ = ${JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {})}</script>`;
|
|
101
85
|
const bootstrapPath = manifest[BOOTSTRAP_MANIFEST_KEY];
|
|
@@ -114,10 +98,10 @@ var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="tr
|
|
|
114
98
|
}
|
|
115
99
|
}
|
|
116
100
|
return `<!DOCTYPE html><html><head>${markup}</head><body>${html}</body></html>`;
|
|
117
|
-
},
|
|
101
|
+
}, streamChunkToString = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true }), pipeStreamWithHeadInjection = (stream, markup) => {
|
|
118
102
|
const encoder = new TextEncoder;
|
|
119
103
|
const decoder = new TextDecoder;
|
|
120
|
-
const lookbehind =
|
|
104
|
+
const lookbehind = CLOSING_HEAD_TAG.length - 1;
|
|
121
105
|
return new ReadableStream({
|
|
122
106
|
async start(controller) {
|
|
123
107
|
const reader = stream.getReader();
|
|
@@ -130,13 +114,13 @@ var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="tr
|
|
|
130
114
|
break;
|
|
131
115
|
if (!value)
|
|
132
116
|
continue;
|
|
133
|
-
pending +=
|
|
117
|
+
pending += streamChunkToString(value, decoder);
|
|
134
118
|
if (injected) {
|
|
135
119
|
controller.enqueue(encoder.encode(pending));
|
|
136
120
|
pending = "";
|
|
137
121
|
continue;
|
|
138
122
|
}
|
|
139
|
-
const headIndex = pending.indexOf(
|
|
123
|
+
const headIndex = pending.indexOf(CLOSING_HEAD_TAG);
|
|
140
124
|
if (headIndex >= 0) {
|
|
141
125
|
const next = `${pending.slice(0, headIndex)}${markup}${pending.slice(headIndex)}`;
|
|
142
126
|
controller.enqueue(encoder.encode(next));
|
|
@@ -179,7 +163,7 @@ var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="tr
|
|
|
179
163
|
break;
|
|
180
164
|
if (!value)
|
|
181
165
|
continue;
|
|
182
|
-
pending +=
|
|
166
|
+
pending += streamChunkToString(value, decoder);
|
|
183
167
|
if (injected) {
|
|
184
168
|
controller.enqueue(encoder.encode(pending));
|
|
185
169
|
pending = "";
|
|
@@ -237,1870 +221,1857 @@ var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="tr
|
|
|
237
221
|
globalThis.__absoluteManifest = manifest;
|
|
238
222
|
};
|
|
239
223
|
|
|
240
|
-
// src/
|
|
241
|
-
var
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
224
|
+
// src/client/streamSwap.ts
|
|
225
|
+
var streamSwapRuntime = () => {
|
|
226
|
+
if (window.__ABS_SLOT_RUNTIME__ === true)
|
|
227
|
+
return;
|
|
228
|
+
window.__ABS_SLOT_RUNTIME__ = true;
|
|
229
|
+
window.__ABS_SLOT_PENDING__ = window.__ABS_SLOT_PENDING__ ?? {};
|
|
230
|
+
const pending = window.__ABS_SLOT_PENDING__;
|
|
231
|
+
const apply = (id, html) => {
|
|
232
|
+
const node = document.getElementById(`slot-${id}`);
|
|
233
|
+
if (!node) {
|
|
234
|
+
pending[id] = html;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
node.innerHTML = html;
|
|
238
|
+
delete pending[id];
|
|
249
239
|
};
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
.
|
|
264
|
-
.brand{font-weight:700;font-size:20px;color:#fff;letter-spacing:-0.02em}
|
|
265
|
-
.badge{padding:5px 10px;border-radius:8px;font-size:12px;font-weight:600;background:${accent};color:#fff;opacity:0.95;box-shadow:0 2px 4px rgba(0,0,0,0.2)}
|
|
266
|
-
.kind{color:#94a3b8;font-size:13px;font-weight:500}
|
|
267
|
-
.content{padding:24px}
|
|
268
|
-
.label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin-bottom:8px}
|
|
269
|
-
.message{margin:0;padding:16px 20px;background:rgba(239,68,68,0.12);border:1px solid rgba(239,68,68,0.25);border-radius:10px;overflow-x:auto;white-space:pre-wrap;word-break:break-word;color:#fca5a5;font-size:13px;line-height:1.5}
|
|
270
|
-
.hint{margin-top:20px;padding:12px 20px;background:rgba(71,85,105,0.3);border-radius:10px;border:1px solid rgba(71,85,105,0.4);color:#cbd5e1;font-size:13px}
|
|
271
|
-
</style>
|
|
272
|
-
</head>
|
|
273
|
-
<body>
|
|
274
|
-
<div class="card">
|
|
275
|
-
<div class="header">
|
|
276
|
-
<div style="display:flex;align-items:center;gap:12px">
|
|
277
|
-
<span class="brand">AbsoluteJS</span>
|
|
278
|
-
<span class="badge">${label}</span>
|
|
279
|
-
</div>
|
|
280
|
-
<span class="kind">Server Render Error</span>
|
|
281
|
-
</div>
|
|
282
|
-
<div class="content">
|
|
283
|
-
<div class="label">What went wrong</div>
|
|
284
|
-
<pre class="message">${message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</pre>
|
|
285
|
-
<div class="hint">A component threw during server-side rendering. Check the terminal for the full stack trace.</div>
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
</body>
|
|
289
|
-
</html>`;
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
// src/utils/stringModifiers.ts
|
|
293
|
-
var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9\-_]+/g, "").replace(/[-_]{2,}/g, "-"), toKebab = (str) => normalizeSlug(str).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), toPascal = (str) => {
|
|
294
|
-
if (!str.includes("-") && !str.includes("_")) {
|
|
295
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
240
|
+
const flush = () => {
|
|
241
|
+
for (const id in pending) {
|
|
242
|
+
if (!Object.prototype.hasOwnProperty.call(pending, id))
|
|
243
|
+
continue;
|
|
244
|
+
apply(id, pending[id] ?? "");
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
window.__ABS_SLOT_ENQUEUE__ = (id, html) => {
|
|
248
|
+
apply(id, html);
|
|
249
|
+
};
|
|
250
|
+
if (typeof MutationObserver === "function") {
|
|
251
|
+
const observer = new MutationObserver(flush);
|
|
252
|
+
const root = document.documentElement ?? document.body ?? document;
|
|
253
|
+
observer.observe(root, { childList: true, subtree: true });
|
|
296
254
|
}
|
|
297
|
-
|
|
298
|
-
|
|
255
|
+
if (document.readyState === "loading") {
|
|
256
|
+
document.addEventListener("DOMContentLoaded", flush, { once: true });
|
|
257
|
+
}
|
|
258
|
+
flush();
|
|
259
|
+
}, stripFunctionWrapper = (value) => {
|
|
260
|
+
const start = value.indexOf("{");
|
|
261
|
+
const end = value.lastIndexOf("}");
|
|
262
|
+
if (start < 0 || end <= start)
|
|
263
|
+
return "";
|
|
264
|
+
return value.slice(start + 1, end);
|
|
265
|
+
}, getStreamSwapRuntimeScript = () => `(function(){${stripFunctionWrapper(streamSwapRuntime.toString())}})();`;
|
|
299
266
|
|
|
300
|
-
// src/utils/
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
267
|
+
// src/utils/escapeScriptContent.ts
|
|
268
|
+
var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
|
|
269
|
+
const escaped = ESCAPE_LOOKUP[char];
|
|
270
|
+
return escaped !== undefined ? escaped : char;
|
|
271
|
+
});
|
|
272
|
+
var init_escapeScriptContent = __esm(() => {
|
|
273
|
+
ESCAPE_LOOKUP = {
|
|
274
|
+
"\u2028": "\\u2028",
|
|
275
|
+
"\u2029": "\\u2029",
|
|
276
|
+
"&": "\\u0026",
|
|
277
|
+
"<": "\\u003C",
|
|
278
|
+
">": "\\u003E"
|
|
279
|
+
};
|
|
280
|
+
ESCAPE_REGEX = /[&><\u2028\u2029]/g;
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// src/utils/streamingSlots.ts
|
|
284
|
+
var SLOT_ID_PREFIX = "abs-slot-", SLOT_PLACEHOLDER_PREFIX = "slot-", CLOSING_HEAD_TAG2 = "</head>", CLOSING_HEAD_TAG_LENGTH, CLOSING_PAGE_TAG_REGEX, STREAMING_RUNTIME_GLOBAL = "__ABS_SLOT_ENQUEUE__", STREAMING_PENDING_GLOBAL = "__ABS_SLOT_PENDING__", STREAM_TAIL_LOOKBEHIND = 128, STREAMING_SLOT_TIMEOUT_MS = 5000, STREAMING_SLOT_MAX_PER_RESPONSE = 128, STREAMING_SLOT_MAX_HTML_BYTES = 64000, createSlotPlaceholderId = (id) => `${SLOT_PLACEHOLDER_PREFIX}${id}`, createSlotPatchStatement = (id, html) => `(window.${STREAMING_RUNTIME_GLOBAL}||function(i,h){window.${STREAMING_PENDING_GLOBAL}=window.${STREAMING_PENDING_GLOBAL}||{};window.${STREAMING_PENDING_GLOBAL}[i]=h;})(${JSON.stringify(id)},${JSON.stringify(html)});`, createNonceAttr = (nonce) => nonce ? ` nonce="${nonce}"` : "", createStreamingSlotId = () => `${SLOT_ID_PREFIX}${Math.random().toString(36).slice(2, 10)}`, getStreamingSlotsRuntimeScript = () => getStreamSwapRuntimeScript(), renderStreamingSlotsRuntimeTag = (nonce) => `<script${createNonceAttr(nonce)}>${escapeScriptContent(getStreamingSlotsRuntimeScript())}</script>`, renderStreamingSlotPlaceholder = (id, fallbackHtml = "") => `<div id="${createSlotPlaceholderId(id)}" data-absolute-slot="true">${fallbackHtml}</div>`, renderStreamingSlotPatchTag = (id, html, nonce) => `<script${createNonceAttr(nonce)}>${escapeScriptContent(createSlotPatchStatement(id, html))}</script>`, injectHtmlIntoHead = (html, injection) => {
|
|
285
|
+
const closingHeadIndex = html.indexOf(CLOSING_HEAD_TAG2);
|
|
286
|
+
if (closingHeadIndex >= 0) {
|
|
287
|
+
return `${html.slice(0, closingHeadIndex)}${injection}${html.slice(closingHeadIndex)}`;
|
|
288
|
+
}
|
|
289
|
+
return `${html}${injection}`;
|
|
290
|
+
}, toUint8 = (value, encoder) => encoder.encode(value), currentStreamingSlotPolicy, clonePolicy = (policy) => ({
|
|
291
|
+
...policy
|
|
292
|
+
}), normalizeSlotBytes = (value, fallback) => {
|
|
293
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
294
|
+
return Math.floor(value);
|
|
295
|
+
}
|
|
296
|
+
return fallback;
|
|
297
|
+
}, normalizeSlotText = (value, fallback) => typeof value === "string" ? value : fallback, normalizeSlotError = (value, fallback) => typeof value === "string" ? value : fallback, hasPolicyValue = (policy, key) => Object.prototype.hasOwnProperty.call(policy, key), applyStreamingSlotPolicyOverrides = (base, overridePolicy = {}) => ({
|
|
298
|
+
timeoutMs: hasPolicyValue(overridePolicy, "timeoutMs") ? normalizeSlotBytes(overridePolicy.timeoutMs, base.timeoutMs) : base.timeoutMs,
|
|
299
|
+
fallbackHtml: hasPolicyValue(overridePolicy, "fallbackHtml") ? normalizeSlotText(overridePolicy.fallbackHtml, "") : base.fallbackHtml,
|
|
300
|
+
errorHtml: hasPolicyValue(overridePolicy, "errorHtml") ? normalizeSlotError(overridePolicy.errorHtml) : base.errorHtml,
|
|
301
|
+
maxSlotsPerResponse: hasPolicyValue(overridePolicy, "maxSlotsPerResponse") ? normalizeSlotBytes(overridePolicy.maxSlotsPerResponse, base.maxSlotsPerResponse) : base.maxSlotsPerResponse,
|
|
302
|
+
maxSlotHtmlSizeBytes: hasPolicyValue(overridePolicy, "maxSlotHtmlSizeBytes") ? normalizeSlotBytes(overridePolicy.maxSlotHtmlSizeBytes, base.maxSlotHtmlSizeBytes) : base.maxSlotHtmlSizeBytes,
|
|
303
|
+
onError: hasPolicyValue(overridePolicy, "onError") ? overridePolicy.onError : base.onError,
|
|
304
|
+
onSlotMetric: hasPolicyValue(overridePolicy, "onSlotMetric") ? overridePolicy.onSlotMetric : base.onSlotMetric
|
|
305
|
+
}), createCombinedSlotErrorHandler = (policyOnError, enhancerOnError) => {
|
|
306
|
+
if (!policyOnError && !enhancerOnError)
|
|
316
307
|
return;
|
|
317
|
-
return
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
return { error: { message, stack } };
|
|
324
|
-
}, renderReactError = async (conventionPath, errorProps) => {
|
|
325
|
-
const { createElement } = await import("react");
|
|
326
|
-
const { renderToReadableStream } = await import("react-dom/server");
|
|
327
|
-
const mod = await import(conventionPath);
|
|
328
|
-
const [firstKey] = Object.keys(mod);
|
|
329
|
-
const ErrorComponent = mod.default ?? (firstKey ? mod[firstKey] : undefined);
|
|
330
|
-
const element = createElement(ErrorComponent, errorProps);
|
|
331
|
-
const stream = await renderToReadableStream(element);
|
|
332
|
-
return new Response(stream, {
|
|
333
|
-
headers: { "Content-Type": "text/html" },
|
|
334
|
-
status: 500
|
|
335
|
-
});
|
|
336
|
-
}, renderSvelteError = async (conventionPath, errorProps) => {
|
|
337
|
-
const { render } = await import("svelte/server");
|
|
338
|
-
const mod = await import(conventionPath);
|
|
339
|
-
const ErrorComponent = mod.default;
|
|
340
|
-
const { head, body } = render(ErrorComponent, {
|
|
341
|
-
props: errorProps
|
|
342
|
-
});
|
|
343
|
-
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
344
|
-
return new Response(html, {
|
|
345
|
-
headers: { "Content-Type": "text/html" },
|
|
346
|
-
status: 500
|
|
347
|
-
});
|
|
348
|
-
}, unescapeVueStyles = (ssrBody) => {
|
|
349
|
-
let styles = "";
|
|
350
|
-
const body = ssrBody.replace(/<style>([\s\S]*?)<\/style>/g, (_, css) => {
|
|
351
|
-
styles += `<style>${css.replace(/"/g, '"').replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</style>`;
|
|
352
|
-
return "";
|
|
353
|
-
});
|
|
354
|
-
return { body, styles };
|
|
355
|
-
}, renderVueError = async (conventionPath, errorProps) => {
|
|
356
|
-
const { createSSRApp, h } = await import("vue");
|
|
357
|
-
const { renderToString } = await import("vue/server-renderer");
|
|
358
|
-
const mod = await import(conventionPath);
|
|
359
|
-
const ErrorComponent = mod.default;
|
|
360
|
-
const app = createSSRApp({
|
|
361
|
-
render: () => h(ErrorComponent, errorProps)
|
|
362
|
-
});
|
|
363
|
-
const rawBody = await renderToString(app);
|
|
364
|
-
const { styles, body } = unescapeVueStyles(rawBody);
|
|
365
|
-
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
366
|
-
return new Response(html, {
|
|
367
|
-
headers: { "Content-Type": "text/html" },
|
|
368
|
-
status: 500
|
|
369
|
-
});
|
|
370
|
-
}, renderAngularError = async (conventionPath, errorProps) => {
|
|
371
|
-
const mod = await import(conventionPath);
|
|
372
|
-
const renderError = mod.default ?? mod.renderError;
|
|
373
|
-
if (typeof renderError !== "function")
|
|
374
|
-
return null;
|
|
375
|
-
const html = renderError(errorProps);
|
|
376
|
-
return new Response(html, {
|
|
377
|
-
headers: { "Content-Type": "text/html" },
|
|
378
|
-
status: 500
|
|
379
|
-
});
|
|
380
|
-
}, logConventionRenderError = (framework, label, renderError) => {
|
|
381
|
-
const message = renderError instanceof Error ? renderError.message : "";
|
|
382
|
-
if (message.includes("Cannot find module") || message.includes("Cannot find package") || message.includes("not found in module")) {
|
|
383
|
-
console.error(`[SSR] Convention ${label} page for ${framework} failed: missing framework package. Ensure the ${framework} runtime is installed (e.g. bun add ${framework === "react" ? "react react-dom" : framework}).`);
|
|
308
|
+
return (error, slot) => {
|
|
309
|
+
policyOnError?.(error, slot);
|
|
310
|
+
enhancerOnError?.(error, slot);
|
|
311
|
+
};
|
|
312
|
+
}, createCombinedSlotMetricHandler = (policyOnSlotMetric, callOnSlotMetric) => {
|
|
313
|
+
if (!policyOnSlotMetric && !callOnSlotMetric)
|
|
384
314
|
return;
|
|
315
|
+
return (metric) => {
|
|
316
|
+
policyOnSlotMetric?.(metric);
|
|
317
|
+
callOnSlotMetric?.(metric);
|
|
318
|
+
};
|
|
319
|
+
}, resolveStreamingSlotPolicy = (overridePolicy = {}) => {
|
|
320
|
+
const base = getStreamingSlotPolicy();
|
|
321
|
+
return applyStreamingSlotPolicyOverrides(base, overridePolicy);
|
|
322
|
+
}, getStreamingSlotPolicy = () => clonePolicy(currentStreamingSlotPolicy), setStreamingSlotPolicy = (policy = {}) => {
|
|
323
|
+
const base = getStreamingSlotPolicy();
|
|
324
|
+
currentStreamingSlotPolicy = applyStreamingSlotPolicyOverrides(base, policy);
|
|
325
|
+
}, withStreamingSlotPolicy = async (policy, callback) => {
|
|
326
|
+
const previous = getStreamingSlotPolicy();
|
|
327
|
+
setStreamingSlotPolicy(policy);
|
|
328
|
+
try {
|
|
329
|
+
return await callback();
|
|
330
|
+
} finally {
|
|
331
|
+
currentStreamingSlotPolicy = previous;
|
|
385
332
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
const
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const { head, body } = render(NotFoundComponent);
|
|
418
|
-
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
419
|
-
return new Response(html, {
|
|
420
|
-
headers: { "Content-Type": "text/html" },
|
|
421
|
-
status: 404
|
|
422
|
-
});
|
|
423
|
-
}, renderVueNotFound = async (conventionPath) => {
|
|
424
|
-
const { createSSRApp, h } = await import("vue");
|
|
425
|
-
const { renderToString } = await import("vue/server-renderer");
|
|
426
|
-
const mod = await import(conventionPath);
|
|
427
|
-
const NotFoundComponent = mod.default;
|
|
428
|
-
const app = createSSRApp({
|
|
429
|
-
render: () => h(NotFoundComponent)
|
|
430
|
-
});
|
|
431
|
-
const rawBody = await renderToString(app);
|
|
432
|
-
const { styles, body } = unescapeVueStyles(rawBody);
|
|
433
|
-
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
434
|
-
return new Response(html, {
|
|
435
|
-
headers: { "Content-Type": "text/html" },
|
|
436
|
-
status: 404
|
|
437
|
-
});
|
|
438
|
-
}, renderAngularNotFound = async (conventionPath) => {
|
|
439
|
-
const mod = await import(conventionPath);
|
|
440
|
-
const renderNotFound = mod.default ?? mod.renderNotFound;
|
|
441
|
-
if (typeof renderNotFound !== "function")
|
|
442
|
-
return null;
|
|
443
|
-
const html = renderNotFound();
|
|
444
|
-
return new Response(html, {
|
|
445
|
-
headers: { "Content-Type": "text/html" },
|
|
446
|
-
status: 404
|
|
447
|
-
});
|
|
448
|
-
}, NOT_FOUND_RENDERERS, renderConventionNotFound = async (framework) => {
|
|
449
|
-
const conventionPath = resolveNotFoundConventionPath(framework);
|
|
450
|
-
if (!conventionPath)
|
|
451
|
-
return null;
|
|
452
|
-
const renderer = NOT_FOUND_RENDERERS[framework];
|
|
453
|
-
if (!renderer)
|
|
454
|
-
return null;
|
|
455
|
-
try {
|
|
456
|
-
return await renderer(conventionPath);
|
|
457
|
-
} catch (renderError) {
|
|
458
|
-
logConventionRenderError(framework, "not-found", renderError);
|
|
333
|
+
}, emitSlotMetric = (metric, onSlotMetric) => {
|
|
334
|
+
onSlotMetric?.(metric);
|
|
335
|
+
}, createTimeoutError = (slot, timeoutMs) => {
|
|
336
|
+
const error = new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`);
|
|
337
|
+
error.__absTimeout = true;
|
|
338
|
+
return error;
|
|
339
|
+
}, toStreamingSlot = (slot, policy) => ({
|
|
340
|
+
errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
|
|
341
|
+
fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
|
|
342
|
+
id: slot.id ?? createStreamingSlotId(),
|
|
343
|
+
timeoutMs: normalizeSlotBytes(slot.timeoutMs, policy.timeoutMs),
|
|
344
|
+
resolve: slot.resolve
|
|
345
|
+
}), prepareSlots = ({
|
|
346
|
+
policy,
|
|
347
|
+
slots,
|
|
348
|
+
onError,
|
|
349
|
+
onSlotMetric
|
|
350
|
+
}) => {
|
|
351
|
+
const preparedSlots = slots.map((slot) => toStreamingSlot(slot, policy));
|
|
352
|
+
const maxSlotsPerResponse = policy.maxSlotsPerResponse;
|
|
353
|
+
if (maxSlotsPerResponse === 0) {
|
|
354
|
+
const error = new Error("Streaming slot limit is set to 0");
|
|
355
|
+
for (const slot of preparedSlots) {
|
|
356
|
+
onError?.(error, slot);
|
|
357
|
+
emitSlotMetric({
|
|
358
|
+
type: "dropped",
|
|
359
|
+
slotId: slot.id,
|
|
360
|
+
reason: "maxSlotsPerResponse is 0"
|
|
361
|
+
}, onSlotMetric);
|
|
362
|
+
}
|
|
363
|
+
return [];
|
|
459
364
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (response)
|
|
467
|
-
return response;
|
|
365
|
+
if (preparedSlots.length <= maxSlotsPerResponse) {
|
|
366
|
+
preparedSlots.forEach((slot) => emitSlotMetric({
|
|
367
|
+
type: "prepared",
|
|
368
|
+
slotId: slot.id
|
|
369
|
+
}, onSlotMetric));
|
|
370
|
+
return preparedSlots;
|
|
468
371
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
NOT_FOUND_RENDERERS = {
|
|
479
|
-
angular: renderAngularNotFound,
|
|
480
|
-
react: renderReactNotFound,
|
|
481
|
-
svelte: renderSvelteNotFound,
|
|
482
|
-
vue: renderVueNotFound
|
|
483
|
-
};
|
|
484
|
-
NOT_FOUND_PRIORITY = [
|
|
485
|
-
"react",
|
|
486
|
-
"svelte",
|
|
487
|
-
"vue",
|
|
488
|
-
"angular"
|
|
489
|
-
];
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
// src/react/pageHandler.ts
|
|
493
|
-
var ssrDirty = false, buildDirtyResponse = (index, maybeProps) => {
|
|
494
|
-
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
495
|
-
const dirtyFlag = "window.__SSR_DIRTY__=true;";
|
|
496
|
-
const refreshSetup = "window.__REFRESH_BUFFER__=[];" + "window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};" + "window.$RefreshSig$=function(){return function(t){return t}};";
|
|
497
|
-
const inlineScript = `${propsScript}${dirtyFlag}${refreshSetup}`;
|
|
498
|
-
const html = `<!DOCTYPE html><html><head></head><body>` + `<script>${inlineScript}</script>` + `<script type="module" src="${index}"></script>` + `</body></html>`;
|
|
499
|
-
return new Response(html, {
|
|
500
|
-
headers: { "Content-Type": "text/html" }
|
|
372
|
+
const keptSlots = preparedSlots.slice(0, maxSlotsPerResponse);
|
|
373
|
+
const droppedSlots = preparedSlots.slice(maxSlotsPerResponse);
|
|
374
|
+
droppedSlots.forEach((slot) => {
|
|
375
|
+
onError?.(new Error(`Streaming slot "${slot.id}" dropped because ${maxSlotsPerResponse} slots is the configured maximum`), slot);
|
|
376
|
+
emitSlotMetric({
|
|
377
|
+
type: "dropped",
|
|
378
|
+
slotId: slot.id,
|
|
379
|
+
reason: `maxSlotsPerResponse is ${maxSlotsPerResponse}`
|
|
380
|
+
}, onSlotMetric);
|
|
501
381
|
});
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
382
|
+
keptSlots.forEach((slot) => emitSlotMetric({
|
|
383
|
+
type: "prepared",
|
|
384
|
+
slotId: slot.id
|
|
385
|
+
}, onSlotMetric));
|
|
386
|
+
return keptSlots;
|
|
387
|
+
}, htmlByteLength = (value, encoder) => encoder.encode(value).length, resolveSlot = async (slot, onError, policy, onSlotMetric) => {
|
|
388
|
+
const safePolicy = policy ?? getStreamingSlotPolicy();
|
|
389
|
+
const encoder = new TextEncoder;
|
|
390
|
+
const start = Date.now();
|
|
507
391
|
try {
|
|
508
|
-
const
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
392
|
+
const maybeAsyncValue = Promise.resolve(slot.resolve());
|
|
393
|
+
const resolved = typeof slot.timeoutMs === "number" && slot.timeoutMs > 0 ? await Promise.race([
|
|
394
|
+
maybeAsyncValue,
|
|
395
|
+
new Promise((_, reject) => setTimeout(() => {
|
|
396
|
+
reject(createTimeoutError(slot, slot.timeoutMs ?? 0));
|
|
397
|
+
}, slot.timeoutMs))
|
|
398
|
+
]) : await maybeAsyncValue;
|
|
399
|
+
const html = typeof resolved === "string" ? resolved : `${resolved}`;
|
|
400
|
+
if (safePolicy.maxSlotHtmlSizeBytes > 0 && htmlByteLength(html, encoder) > safePolicy.maxSlotHtmlSizeBytes) {
|
|
401
|
+
const bytes2 = htmlByteLength(html, encoder);
|
|
402
|
+
const error = new Error(`Streaming slot "${slot.id}" exceeded max payload size of ${safePolicy.maxSlotHtmlSizeBytes} bytes`);
|
|
403
|
+
const durationMs2 = Date.now() - start;
|
|
404
|
+
onError?.(error, slot);
|
|
405
|
+
emitSlotMetric({
|
|
406
|
+
type: "size_exceeded",
|
|
407
|
+
slotId: slot.id,
|
|
408
|
+
durationMs: durationMs2,
|
|
409
|
+
bytes: bytes2,
|
|
410
|
+
error
|
|
411
|
+
}, onSlotMetric);
|
|
412
|
+
const fallbackHtml = typeof slot.errorHtml === "string" ? slot.errorHtml : null;
|
|
413
|
+
return {
|
|
414
|
+
html: fallbackHtml,
|
|
415
|
+
id: slot.id,
|
|
416
|
+
durationMs: durationMs2,
|
|
417
|
+
bytes: fallbackHtml === null ? 0 : htmlByteLength(fallbackHtml, encoder)
|
|
418
|
+
};
|
|
522
419
|
}
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
420
|
+
const durationMs = Date.now() - start;
|
|
421
|
+
const bytes = htmlByteLength(html, encoder);
|
|
422
|
+
emitSlotMetric({
|
|
423
|
+
type: "resolved",
|
|
424
|
+
slotId: slot.id,
|
|
425
|
+
durationMs,
|
|
426
|
+
bytes
|
|
427
|
+
}, onSlotMetric);
|
|
428
|
+
return {
|
|
429
|
+
html,
|
|
430
|
+
id: slot.id,
|
|
431
|
+
durationMs,
|
|
432
|
+
bytes
|
|
433
|
+
};
|
|
527
434
|
} catch (error) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
435
|
+
const durationMs = Date.now() - start;
|
|
436
|
+
onError?.(error, slot);
|
|
437
|
+
emitSlotMetric({
|
|
438
|
+
type: error?.__absTimeout === true ? "timeout" : "error",
|
|
439
|
+
slotId: slot.id,
|
|
440
|
+
durationMs,
|
|
441
|
+
error
|
|
442
|
+
}, onSlotMetric);
|
|
443
|
+
if (typeof slot.errorHtml === "string") {
|
|
444
|
+
const html = slot.errorHtml;
|
|
445
|
+
return {
|
|
446
|
+
html,
|
|
447
|
+
id: slot.id,
|
|
448
|
+
durationMs,
|
|
449
|
+
bytes: htmlByteLength(html, encoder)
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
html: null,
|
|
454
|
+
id: slot.id,
|
|
455
|
+
durationMs,
|
|
456
|
+
bytes: 0
|
|
457
|
+
};
|
|
537
458
|
}
|
|
538
|
-
},
|
|
539
|
-
|
|
459
|
+
}, nextResolvedSlot = async (pending) => {
|
|
460
|
+
const wrapped = pending.map((promise) => promise.then((result) => ({
|
|
461
|
+
original: promise,
|
|
462
|
+
result
|
|
463
|
+
})));
|
|
464
|
+
return Promise.race(wrapped);
|
|
465
|
+
}, streamChunkToString2 = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true }), streamOutOfOrderSlots = ({
|
|
466
|
+
footerHtml = "",
|
|
467
|
+
headerHtml = "",
|
|
468
|
+
nonce,
|
|
469
|
+
policy,
|
|
470
|
+
onSlotMetric,
|
|
471
|
+
onError,
|
|
472
|
+
slots
|
|
473
|
+
}) => {
|
|
474
|
+
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
475
|
+
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
476
|
+
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
477
|
+
const effectivePolicy = {
|
|
478
|
+
...resolvedPolicy,
|
|
479
|
+
onSlotMetric: combinedOnSlotMetric
|
|
480
|
+
};
|
|
481
|
+
const preparedSlots = prepareSlots({
|
|
482
|
+
policy: effectivePolicy,
|
|
483
|
+
slots,
|
|
484
|
+
onError: combinedOnError,
|
|
485
|
+
onSlotMetric: combinedOnSlotMetric
|
|
486
|
+
});
|
|
487
|
+
const encoder = new TextEncoder;
|
|
488
|
+
return new ReadableStream({
|
|
489
|
+
async start(controller) {
|
|
490
|
+
try {
|
|
491
|
+
let header = headerHtml;
|
|
492
|
+
if (preparedSlots.length > 0 && !header.includes(STREAMING_RUNTIME_GLOBAL)) {
|
|
493
|
+
header = injectHtmlIntoHead(header, renderStreamingSlotsRuntimeTag(nonce));
|
|
494
|
+
}
|
|
495
|
+
controller.enqueue(toUint8(header, encoder));
|
|
496
|
+
const pending = preparedSlots.map((slot) => {
|
|
497
|
+
const fallback = renderStreamingSlotPlaceholder(slot.id, slot.fallbackHtml ?? "");
|
|
498
|
+
controller.enqueue(toUint8(fallback, encoder));
|
|
499
|
+
return resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric);
|
|
500
|
+
});
|
|
501
|
+
while (pending.length > 0) {
|
|
502
|
+
const { original, result } = await nextResolvedSlot(pending);
|
|
503
|
+
const index = pending.indexOf(original);
|
|
504
|
+
if (index >= 0)
|
|
505
|
+
pending.splice(index, 1);
|
|
506
|
+
if (result.html === null)
|
|
507
|
+
continue;
|
|
508
|
+
emitSlotMetric({
|
|
509
|
+
type: "patched",
|
|
510
|
+
slotId: result.id,
|
|
511
|
+
durationMs: result.durationMs,
|
|
512
|
+
bytes: result.bytes
|
|
513
|
+
}, combinedOnSlotMetric);
|
|
514
|
+
controller.enqueue(toUint8(renderStreamingSlotPatchTag(result.id, result.html, nonce), encoder));
|
|
515
|
+
}
|
|
516
|
+
if (footerHtml.length > 0) {
|
|
517
|
+
controller.enqueue(toUint8(footerHtml, encoder));
|
|
518
|
+
}
|
|
519
|
+
controller.close();
|
|
520
|
+
} catch (error) {
|
|
521
|
+
controller.error(error);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
}, injectStreamingRuntimeIntoStream = (stream, nonce) => {
|
|
526
|
+
const runtimeTag = renderStreamingSlotsRuntimeTag(nonce);
|
|
527
|
+
const encoder = new TextEncoder;
|
|
528
|
+
const decoder = new TextDecoder;
|
|
529
|
+
const lookbehind = CLOSING_HEAD_TAG_LENGTH - 1;
|
|
530
|
+
return new ReadableStream({
|
|
531
|
+
async start(controller) {
|
|
532
|
+
const reader = stream.getReader();
|
|
533
|
+
let injected = false;
|
|
534
|
+
let pending = "";
|
|
535
|
+
try {
|
|
536
|
+
for (;; ) {
|
|
537
|
+
const { done, value } = await reader.read();
|
|
538
|
+
if (done)
|
|
539
|
+
break;
|
|
540
|
+
if (!value)
|
|
541
|
+
continue;
|
|
542
|
+
pending += streamChunkToString2(value, decoder);
|
|
543
|
+
if (injected) {
|
|
544
|
+
controller.enqueue(encoder.encode(pending));
|
|
545
|
+
pending = "";
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
const headIndex = pending.indexOf(CLOSING_HEAD_TAG2);
|
|
549
|
+
if (headIndex >= 0) {
|
|
550
|
+
const withRuntime = `${pending.slice(0, headIndex)}${runtimeTag}${pending.slice(headIndex)}`;
|
|
551
|
+
controller.enqueue(encoder.encode(withRuntime));
|
|
552
|
+
pending = "";
|
|
553
|
+
injected = true;
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
if (pending.length > lookbehind) {
|
|
557
|
+
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
558
|
+
controller.enqueue(encoder.encode(safeText));
|
|
559
|
+
pending = pending.slice(-lookbehind);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
pending += decoder.decode();
|
|
563
|
+
if (!injected) {
|
|
564
|
+
pending = injectHtmlIntoHead(pending, runtimeTag);
|
|
565
|
+
}
|
|
566
|
+
if (pending.length > 0) {
|
|
567
|
+
controller.enqueue(encoder.encode(pending));
|
|
568
|
+
}
|
|
569
|
+
controller.close();
|
|
570
|
+
} catch (error) {
|
|
571
|
+
controller.error(error);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}, appendStreamingSlotPatchesToStream = (stream, slots = [], {
|
|
576
|
+
injectRuntime = true,
|
|
577
|
+
nonce,
|
|
578
|
+
onError,
|
|
579
|
+
onSlotMetric,
|
|
580
|
+
policy
|
|
581
|
+
} = {}) => {
|
|
582
|
+
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
583
|
+
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
584
|
+
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
585
|
+
const effectivePolicy = {
|
|
586
|
+
...resolvedPolicy,
|
|
587
|
+
onSlotMetric: combinedOnSlotMetric
|
|
588
|
+
};
|
|
589
|
+
const preparedSlots = prepareSlots({
|
|
590
|
+
policy: effectivePolicy,
|
|
591
|
+
slots,
|
|
592
|
+
onError: combinedOnError,
|
|
593
|
+
onSlotMetric: combinedOnSlotMetric
|
|
594
|
+
});
|
|
595
|
+
if (preparedSlots.length === 0)
|
|
596
|
+
return stream;
|
|
597
|
+
const source = injectRuntime ? injectStreamingRuntimeIntoStream(stream, nonce) : stream;
|
|
598
|
+
const encoder = new TextEncoder;
|
|
599
|
+
const decoder = new TextDecoder;
|
|
600
|
+
const reader = source.getReader();
|
|
601
|
+
const pending = preparedSlots.map((slot) => resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric));
|
|
602
|
+
return new ReadableStream({
|
|
603
|
+
async start(controller) {
|
|
604
|
+
let baseDone = false;
|
|
605
|
+
let baseRead = reader.read();
|
|
606
|
+
let tail = "";
|
|
607
|
+
let footer = "";
|
|
608
|
+
try {
|
|
609
|
+
while (!baseDone || pending.length > 0) {
|
|
610
|
+
const racers = [];
|
|
611
|
+
if (!baseDone) {
|
|
612
|
+
racers.push(baseRead.then(({ done, value }) => ({
|
|
613
|
+
done,
|
|
614
|
+
kind: "base",
|
|
615
|
+
value
|
|
616
|
+
})));
|
|
617
|
+
}
|
|
618
|
+
if (pending.length > 0) {
|
|
619
|
+
racers.push(nextResolvedSlot(pending).then((resolved) => ({
|
|
620
|
+
kind: "slot",
|
|
621
|
+
...resolved
|
|
622
|
+
})));
|
|
623
|
+
}
|
|
624
|
+
if (racers.length === 0)
|
|
625
|
+
break;
|
|
626
|
+
const winner = await Promise.race(racers);
|
|
627
|
+
if (winner.kind === "base") {
|
|
628
|
+
if (winner.done) {
|
|
629
|
+
baseDone = true;
|
|
630
|
+
tail += decoder.decode();
|
|
631
|
+
const footerStart = tail.search(CLOSING_PAGE_TAG_REGEX);
|
|
632
|
+
if (footerStart >= 0) {
|
|
633
|
+
const content = tail.slice(0, footerStart);
|
|
634
|
+
footer = tail.slice(footerStart);
|
|
635
|
+
if (content.length > 0) {
|
|
636
|
+
controller.enqueue(encoder.encode(content));
|
|
637
|
+
}
|
|
638
|
+
} else if (tail.length > 0) {
|
|
639
|
+
controller.enqueue(encoder.encode(tail));
|
|
640
|
+
}
|
|
641
|
+
tail = "";
|
|
642
|
+
} else if (winner.value) {
|
|
643
|
+
tail += streamChunkToString2(winner.value, decoder);
|
|
644
|
+
if (tail.length > STREAM_TAIL_LOOKBEHIND) {
|
|
645
|
+
const content = tail.slice(0, tail.length - STREAM_TAIL_LOOKBEHIND);
|
|
646
|
+
controller.enqueue(encoder.encode(content));
|
|
647
|
+
tail = tail.slice(-STREAM_TAIL_LOOKBEHIND);
|
|
648
|
+
}
|
|
649
|
+
baseRead = reader.read();
|
|
650
|
+
}
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
const index = pending.indexOf(winner.original);
|
|
654
|
+
if (index >= 0)
|
|
655
|
+
pending.splice(index, 1);
|
|
656
|
+
if (winner.result.html === null)
|
|
657
|
+
continue;
|
|
658
|
+
emitSlotMetric({
|
|
659
|
+
type: "patched",
|
|
660
|
+
slotId: winner.result.id,
|
|
661
|
+
durationMs: winner.result.durationMs,
|
|
662
|
+
bytes: winner.result.bytes
|
|
663
|
+
}, combinedOnSlotMetric);
|
|
664
|
+
controller.enqueue(encoder.encode(renderStreamingSlotPatchTag(winner.result.id, winner.result.html, nonce)));
|
|
665
|
+
}
|
|
666
|
+
if (footer.length > 0)
|
|
667
|
+
controller.enqueue(encoder.encode(footer));
|
|
668
|
+
controller.close();
|
|
669
|
+
} catch (error) {
|
|
670
|
+
controller.error(error);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
});
|
|
540
674
|
};
|
|
541
|
-
var
|
|
542
|
-
|
|
675
|
+
var init_streamingSlots = __esm(() => {
|
|
676
|
+
init_escapeScriptContent();
|
|
677
|
+
CLOSING_HEAD_TAG_LENGTH = CLOSING_HEAD_TAG2.length;
|
|
678
|
+
CLOSING_PAGE_TAG_REGEX = /<\/body>\s*<\/html>\s*$/i;
|
|
679
|
+
currentStreamingSlotPolicy = {
|
|
680
|
+
timeoutMs: STREAMING_SLOT_TIMEOUT_MS,
|
|
681
|
+
fallbackHtml: "",
|
|
682
|
+
errorHtml: undefined,
|
|
683
|
+
maxSlotsPerResponse: STREAMING_SLOT_MAX_PER_RESPONSE,
|
|
684
|
+
maxSlotHtmlSizeBytes: STREAMING_SLOT_MAX_HTML_BYTES
|
|
685
|
+
};
|
|
543
686
|
});
|
|
544
687
|
|
|
545
|
-
// src/core/
|
|
546
|
-
var
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
continue;
|
|
552
|
-
const component = key.slice(prefix.length);
|
|
553
|
-
if (!component)
|
|
554
|
-
continue;
|
|
555
|
-
entries[component] = value;
|
|
556
|
-
found = true;
|
|
557
|
-
}
|
|
558
|
-
return found ? entries : undefined;
|
|
559
|
-
}, getIslandManifestEntries = (manifest) => {
|
|
560
|
-
const islands = {};
|
|
561
|
-
const frameworks = ["react", "svelte", "vue", "angular"];
|
|
562
|
-
for (const framework of frameworks) {
|
|
563
|
-
const prefix = `Island${toIslandFrameworkSegment(framework)}`;
|
|
564
|
-
const entries = collectFrameworkIslands(manifest, prefix);
|
|
565
|
-
if (entries)
|
|
566
|
-
islands[framework] = entries;
|
|
567
|
-
}
|
|
568
|
-
return islands;
|
|
569
|
-
}, getIslandManifestKey = (framework, component) => `Island${toIslandFrameworkSegment(framework)}${component}`;
|
|
688
|
+
// src/core/streamingSlotRegistrar.ts
|
|
689
|
+
var registrar = null, setStreamingSlotRegistrar = (nextRegistrar) => {
|
|
690
|
+
registrar = nextRegistrar;
|
|
691
|
+
}, registerStreamingSlot = (slot) => {
|
|
692
|
+
registrar?.(slot);
|
|
693
|
+
};
|
|
570
694
|
|
|
571
|
-
// src/core/
|
|
572
|
-
|
|
573
|
-
if (
|
|
574
|
-
return
|
|
695
|
+
// src/core/streamingSlotRegistry.ts
|
|
696
|
+
var asyncLocalStorage, isServerRuntime = () => typeof process !== "undefined" && typeof process.versions?.node === "string", ensureAsyncLocalStorage = async () => {
|
|
697
|
+
if (typeof asyncLocalStorage !== "undefined")
|
|
698
|
+
return asyncLocalStorage;
|
|
699
|
+
if (!isServerRuntime()) {
|
|
700
|
+
asyncLocalStorage = null;
|
|
701
|
+
return asyncLocalStorage;
|
|
575
702
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
source: options.source
|
|
582
|
-
}), defineIslandRegistry = (registry) => registry, isRecord = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (component) => {
|
|
583
|
-
if (!isIslandComponentDefinition(component))
|
|
584
|
-
return null;
|
|
585
|
-
return {
|
|
586
|
-
export: component.export,
|
|
587
|
-
source: component.source
|
|
588
|
-
};
|
|
589
|
-
}, isIslandComponentDefinition = (value) => isRecord(value) && ("component" in value) && ("source" in value) && typeof value.source === "string", parseIslandProps = (rawProps) => {
|
|
590
|
-
if (!rawProps)
|
|
591
|
-
return {};
|
|
592
|
-
return JSON.parse(rawProps);
|
|
593
|
-
}, serializeIslandProps = (props) => JSON.stringify(props ?? {});
|
|
594
|
-
var init_islands = () => {};
|
|
595
|
-
|
|
596
|
-
// src/core/islandMarkupAttributes.ts
|
|
597
|
-
var getIslandMarkerAttributes = (props, islandId) => ({
|
|
598
|
-
"data-component": props.component,
|
|
599
|
-
"data-framework": props.framework,
|
|
600
|
-
"data-hydrate": props.hydrate ?? "load",
|
|
601
|
-
"data-island": "true",
|
|
602
|
-
...islandId ? { "data-island-id": islandId } : {},
|
|
603
|
-
"data-props": serializeIslandProps(props.props)
|
|
604
|
-
}), escapeHtmlAttribute = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">"), serializeIslandAttributes = (attributes) => Object.entries(attributes).map(([key, value]) => `${key}="${escapeHtmlAttribute(value)}"`).join(" ");
|
|
605
|
-
var init_islandMarkupAttributes = __esm(() => {
|
|
606
|
-
init_islands();
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
// src/core/currentIslandRegistry.ts
|
|
610
|
-
var requireCurrentIslandRegistry = () => {
|
|
611
|
-
const registry = globalThis.__absoluteIslandRegistry;
|
|
612
|
-
if (!registry) {
|
|
613
|
-
throw new Error("No island registry is active. Configure `islands.registry` in absolute.config.ts before rendering <Island />.");
|
|
614
|
-
}
|
|
615
|
-
return registry;
|
|
616
|
-
}, setCurrentIslandRegistry = (registry) => {
|
|
617
|
-
globalThis.__absoluteIslandRegistry = registry;
|
|
618
|
-
};
|
|
619
|
-
|
|
620
|
-
// src/angular/injectorPatch.ts
|
|
621
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
622
|
-
import { dirname, join, resolve } from "path";
|
|
623
|
-
var applyInjectorPatch = (chunkPath, content) => {
|
|
624
|
-
if (content.includes('Symbol.for("angular.currentInjector")')) {
|
|
703
|
+
const mod = await import("async_hooks");
|
|
704
|
+
asyncLocalStorage = new mod.AsyncLocalStorage;
|
|
705
|
+
return asyncLocalStorage;
|
|
706
|
+
}, registerStreamingSlot2 = (slot) => {
|
|
707
|
+
if (!asyncLocalStorage)
|
|
625
708
|
return;
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
"let _currentInjector = undefined;",
|
|
629
|
-
"function getCurrentInjector() {",
|
|
630
|
-
" return _currentInjector;",
|
|
631
|
-
"}",
|
|
632
|
-
"function setCurrentInjector(injector) {",
|
|
633
|
-
" const former = _currentInjector;",
|
|
634
|
-
" _currentInjector = injector;",
|
|
635
|
-
" return former;",
|
|
636
|
-
"}"
|
|
637
|
-
].join(`
|
|
638
|
-
`);
|
|
639
|
-
const replacement = [
|
|
640
|
-
'const _injSym = Symbol.for("angular.currentInjector");',
|
|
641
|
-
"if (!globalThis[_injSym]) globalThis[_injSym] = { v: undefined };",
|
|
642
|
-
"function getCurrentInjector() {",
|
|
643
|
-
" return globalThis[_injSym].v;",
|
|
644
|
-
"}",
|
|
645
|
-
"function setCurrentInjector(injector) {",
|
|
646
|
-
" const former = globalThis[_injSym].v;",
|
|
647
|
-
" globalThis[_injSym].v = injector;",
|
|
648
|
-
" return former;",
|
|
649
|
-
"}"
|
|
650
|
-
].join(`
|
|
651
|
-
`);
|
|
652
|
-
const patched = content.replace(original, replacement);
|
|
653
|
-
if (patched === content) {
|
|
709
|
+
const store = asyncLocalStorage.getStore();
|
|
710
|
+
if (!store)
|
|
654
711
|
return;
|
|
712
|
+
store.set(slot.id, slot);
|
|
713
|
+
}, runWithStreamingSlotRegistry = async (task) => {
|
|
714
|
+
const storage = await ensureAsyncLocalStorage();
|
|
715
|
+
if (!storage) {
|
|
716
|
+
return {
|
|
717
|
+
result: await task(),
|
|
718
|
+
slots: []
|
|
719
|
+
};
|
|
655
720
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
664
|
-
try {
|
|
665
|
-
const coreDir = resolveAngularCoreDir();
|
|
666
|
-
const chunkPath = join(coreDir, "fesm2022", "_not_found-chunk.mjs");
|
|
667
|
-
const content = readFileSync(chunkPath, "utf-8");
|
|
668
|
-
applyInjectorPatch(chunkPath, content);
|
|
669
|
-
} catch {}
|
|
721
|
+
return storage.run(new Map, async () => {
|
|
722
|
+
const result = await task();
|
|
723
|
+
const store = storage.getStore();
|
|
724
|
+
return {
|
|
725
|
+
result,
|
|
726
|
+
slots: store ? [...store.values()] : []
|
|
727
|
+
};
|
|
728
|
+
});
|
|
670
729
|
};
|
|
671
|
-
var
|
|
672
|
-
|
|
730
|
+
var init_streamingSlotRegistry = __esm(() => {
|
|
731
|
+
setStreamingSlotRegistrar(registerStreamingSlot2);
|
|
673
732
|
});
|
|
674
733
|
|
|
675
|
-
// src/
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
if (
|
|
681
|
-
return
|
|
734
|
+
// src/core/responseEnhancers.ts
|
|
735
|
+
var toResponse = async (responseLike) => await responseLike, cloneHeaders = (response) => {
|
|
736
|
+
const headers = new Headers(response.headers);
|
|
737
|
+
return headers;
|
|
738
|
+
}, enhanceHtmlResponseWithStreamingSlots = (response, { nonce, onError, streamingSlots = [], policy } = {}) => {
|
|
739
|
+
if (!response.body || streamingSlots.length === 0) {
|
|
740
|
+
return response;
|
|
682
741
|
}
|
|
683
|
-
|
|
742
|
+
const body = appendStreamingSlotPatchesToStream(response.body, streamingSlots, {
|
|
743
|
+
nonce,
|
|
744
|
+
onError,
|
|
745
|
+
policy
|
|
746
|
+
});
|
|
747
|
+
return new Response(body, {
|
|
748
|
+
headers: cloneHeaders(response),
|
|
749
|
+
status: response.status,
|
|
750
|
+
statusText: response.statusText
|
|
751
|
+
});
|
|
752
|
+
}, withStreamingSlots = async (responseLike, options = {}) => enhanceHtmlResponseWithStreamingSlots(await toResponse(responseLike), options), mergeStreamingSlots = (registered, explicit) => {
|
|
753
|
+
const merged = new Map;
|
|
754
|
+
for (const slot of registered)
|
|
755
|
+
merged.set(slot.id, slot);
|
|
756
|
+
for (const slot of explicit)
|
|
757
|
+
merged.set(slot.id, slot);
|
|
758
|
+
return [...merged.values()];
|
|
759
|
+
}, withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
|
|
760
|
+
const { result, slots } = await runWithStreamingSlotRegistry(renderResponse);
|
|
761
|
+
const explicit = options.streamingSlots ?? [];
|
|
762
|
+
return withStreamingSlots(result, {
|
|
763
|
+
...options,
|
|
764
|
+
streamingSlots: mergeStreamingSlots(slots, explicit)
|
|
765
|
+
});
|
|
684
766
|
};
|
|
685
|
-
var
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
var exports_angularPatch = {};
|
|
689
|
-
__export(exports_angularPatch, {
|
|
690
|
-
applyPatches: () => applyPatches
|
|
767
|
+
var init_responseEnhancers = __esm(() => {
|
|
768
|
+
init_streamingSlots();
|
|
769
|
+
init_streamingSlotRegistry();
|
|
691
770
|
});
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
return false;
|
|
703
|
-
}
|
|
704
|
-
const proto = \u{275}DominoAdapter.prototype;
|
|
705
|
-
const origGetBaseHref = proto.getBaseHref;
|
|
706
|
-
proto.getBaseHref = function(doc) {
|
|
707
|
-
if (!doc || !doc.head || typeof doc.head.children === "undefined") {
|
|
708
|
-
return "";
|
|
709
|
-
}
|
|
710
|
-
return origGetBaseHref.call(this, doc);
|
|
711
|
-
};
|
|
712
|
-
const origCreateHtmlDocument = proto.createHtmlDocument;
|
|
713
|
-
proto.createHtmlDocument = function() {
|
|
714
|
-
const doc = origCreateHtmlDocument.call(this);
|
|
715
|
-
ensureHead(doc);
|
|
716
|
-
return doc;
|
|
717
|
-
};
|
|
718
|
-
const origGetDefaultDocument = proto.getDefaultDocument;
|
|
719
|
-
proto.getDefaultDocument = function() {
|
|
720
|
-
const doc = origGetDefaultDocument.call(this);
|
|
721
|
-
ensureHead(doc);
|
|
722
|
-
return doc;
|
|
771
|
+
|
|
772
|
+
// src/utils/ssrErrorPage.ts
|
|
773
|
+
var ssrErrorPage = (framework, error) => {
|
|
774
|
+
const frameworkColors = {
|
|
775
|
+
angular: "#dd0031",
|
|
776
|
+
html: "#e34c26",
|
|
777
|
+
htmx: "#1a365d",
|
|
778
|
+
react: "#61dafb",
|
|
779
|
+
svelte: "#ff3e00",
|
|
780
|
+
vue: "#42b883"
|
|
723
781
|
};
|
|
724
|
-
|
|
782
|
+
const accent = frameworkColors[framework] ?? "#94a3b8";
|
|
783
|
+
const label = framework.charAt(0).toUpperCase() + framework.slice(1);
|
|
784
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
785
|
+
return `<!DOCTYPE html>
|
|
786
|
+
<html>
|
|
787
|
+
<head>
|
|
788
|
+
<meta charset="utf-8">
|
|
789
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
790
|
+
<title>SSR Error - AbsoluteJS</title>
|
|
791
|
+
<style>
|
|
792
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
793
|
+
body{min-height:100vh;background:linear-gradient(135deg,rgba(15,23,42,0.98) 0%,rgba(30,41,59,0.98) 100%);color:#e2e8f0;font-family:"JetBrains Mono","Fira Code",ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:14px;line-height:1.6;display:flex;align-items:flex-start;justify-content:center;padding:32px}
|
|
794
|
+
.card{max-width:720px;width:100%;background:rgba(30,41,59,0.6);border:1px solid rgba(71,85,105,0.5);border-radius:16px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5),0 0 0 1px rgba(255,255,255,0.05);overflow:hidden}
|
|
795
|
+
.header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 24px;background:rgba(15,23,42,0.5);border-bottom:1px solid rgba(71,85,105,0.4)}
|
|
796
|
+
.brand{font-weight:700;font-size:20px;color:#fff;letter-spacing:-0.02em}
|
|
797
|
+
.badge{padding:5px 10px;border-radius:8px;font-size:12px;font-weight:600;background:${accent};color:#fff;opacity:0.95;box-shadow:0 2px 4px rgba(0,0,0,0.2)}
|
|
798
|
+
.kind{color:#94a3b8;font-size:13px;font-weight:500}
|
|
799
|
+
.content{padding:24px}
|
|
800
|
+
.label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin-bottom:8px}
|
|
801
|
+
.message{margin:0;padding:16px 20px;background:rgba(239,68,68,0.12);border:1px solid rgba(239,68,68,0.25);border-radius:10px;overflow-x:auto;white-space:pre-wrap;word-break:break-word;color:#fca5a5;font-size:13px;line-height:1.5}
|
|
802
|
+
.hint{margin-top:20px;padding:12px 20px;background:rgba(71,85,105,0.3);border-radius:10px;border:1px solid rgba(71,85,105,0.4);color:#cbd5e1;font-size:13px}
|
|
803
|
+
</style>
|
|
804
|
+
</head>
|
|
805
|
+
<body>
|
|
806
|
+
<div class="card">
|
|
807
|
+
<div class="header">
|
|
808
|
+
<div style="display:flex;align-items:center;gap:12px">
|
|
809
|
+
<span class="brand">AbsoluteJS</span>
|
|
810
|
+
<span class="badge">${label}</span>
|
|
811
|
+
</div>
|
|
812
|
+
<span class="kind">Server Render Error</span>
|
|
813
|
+
</div>
|
|
814
|
+
<div class="content">
|
|
815
|
+
<div class="label">What went wrong</div>
|
|
816
|
+
<pre class="message">${message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</pre>
|
|
817
|
+
<div class="hint">A component threw during server-side rendering. Check the terminal for the full stack trace.</div>
|
|
818
|
+
</div>
|
|
819
|
+
</div>
|
|
820
|
+
</body>
|
|
821
|
+
</html>`;
|
|
725
822
|
};
|
|
726
|
-
var init_angularPatch = __esm(() => {
|
|
727
|
-
init_resolveAngularPackage();
|
|
728
|
-
});
|
|
729
823
|
|
|
730
|
-
// src/
|
|
731
|
-
var
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
DominoAdapter?.makeCurrent?.();
|
|
735
|
-
} catch (err) {
|
|
736
|
-
console.error("Failed to initialize DominoAdapter:", err);
|
|
824
|
+
// src/utils/stringModifiers.ts
|
|
825
|
+
var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9\-_]+/g, "").replace(/[-_]{2,}/g, "-"), toKebab = (str) => normalizeSlug(str).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), toPascal = (str) => {
|
|
826
|
+
if (!str.includes("-") && !str.includes("_")) {
|
|
827
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
737
828
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
await import(resolveAngularPackage("@angular/compiler"));
|
|
741
|
-
const { applyPatches: applyPatches2 } = await Promise.resolve().then(() => (init_angularPatch(), exports_angularPatch));
|
|
742
|
-
await applyPatches2();
|
|
743
|
-
const [platformBrowser, platformServer, common, core] = await Promise.all([
|
|
744
|
-
import(resolveAngularPackage("@angular/platform-browser")),
|
|
745
|
-
import(resolveAngularPackage("@angular/platform-server")),
|
|
746
|
-
import(resolveAngularPackage("@angular/common")),
|
|
747
|
-
import(resolveAngularPackage("@angular/core"))
|
|
748
|
-
]);
|
|
749
|
-
if (false) {}
|
|
750
|
-
initDominoAdapter(platformServer);
|
|
751
|
-
return {
|
|
752
|
-
APP_BASE_HREF: common.APP_BASE_HREF,
|
|
753
|
-
bootstrapApplication: platformBrowser.bootstrapApplication,
|
|
754
|
-
DomSanitizer: platformBrowser.DomSanitizer,
|
|
755
|
-
provideClientHydration: platformBrowser.provideClientHydration,
|
|
756
|
-
provideServerRendering: platformServer.provideServerRendering,
|
|
757
|
-
provideZonelessChangeDetection: core.provideZonelessChangeDetection,
|
|
758
|
-
reflectComponentType: core.reflectComponentType,
|
|
759
|
-
renderApplication: platformServer.renderApplication,
|
|
760
|
-
Sanitizer: core.Sanitizer,
|
|
761
|
-
SecurityContext: core.SecurityContext
|
|
762
|
-
};
|
|
763
|
-
}, angularDeps = null, getAngularDeps = () => {
|
|
764
|
-
if (!angularDeps) {
|
|
765
|
-
angularDeps = loadAngularDeps();
|
|
766
|
-
}
|
|
767
|
-
return angularDeps;
|
|
768
|
-
};
|
|
769
|
-
var init_angularDeps = __esm(() => {
|
|
770
|
-
init_injectorPatch();
|
|
771
|
-
init_resolveAngularPackage();
|
|
772
|
-
});
|
|
829
|
+
return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
|
|
830
|
+
}, toScreamingSnake = (str) => str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase();
|
|
773
831
|
|
|
774
|
-
// src/utils/
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
return
|
|
782
|
-
},
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
832
|
+
// src/utils/resolveConvention.ts
|
|
833
|
+
import { basename } from "path";
|
|
834
|
+
var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boolean(value) && typeof value === "object", getMap = () => {
|
|
835
|
+
const value = Reflect.get(globalThis, CONVENTIONS_KEY);
|
|
836
|
+
if (isConventionsMap(value))
|
|
837
|
+
return value;
|
|
838
|
+
const empty = {};
|
|
839
|
+
return empty;
|
|
840
|
+
}, derivePageName = (pagePath) => {
|
|
841
|
+
const base = basename(pagePath);
|
|
842
|
+
const dotIndex = base.indexOf(".");
|
|
843
|
+
const name = dotIndex > 0 ? base.slice(0, dotIndex) : base;
|
|
844
|
+
return toPascal(name);
|
|
845
|
+
}, resolveErrorConventionPath = (framework, pageName) => {
|
|
846
|
+
const conventions = getMap()[framework];
|
|
847
|
+
if (!conventions)
|
|
848
|
+
return;
|
|
849
|
+
return conventions.pages?.[pageName]?.error ?? conventions.defaults?.error;
|
|
850
|
+
}, resolveNotFoundConventionPath = (framework) => getMap()[framework]?.defaults?.notFound, setConventions = (map) => {
|
|
851
|
+
Reflect.set(globalThis, CONVENTIONS_KEY, map);
|
|
852
|
+
}, isDev = () => true, buildErrorProps = (error) => {
|
|
853
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
854
|
+
const stack = isDev() && error instanceof Error ? error.stack : undefined;
|
|
855
|
+
return { error: { message, stack } };
|
|
856
|
+
}, renderReactError = async (conventionPath, errorProps) => {
|
|
857
|
+
const { createElement } = await import("react");
|
|
858
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
859
|
+
const mod = await import(conventionPath);
|
|
860
|
+
const [firstKey] = Object.keys(mod);
|
|
861
|
+
const ErrorComponent = mod.default ?? (firstKey ? mod[firstKey] : undefined);
|
|
862
|
+
const element = createElement(ErrorComponent, errorProps);
|
|
863
|
+
const stream = await renderToReadableStream(element);
|
|
864
|
+
return new Response(stream, {
|
|
865
|
+
headers: { "Content-Type": "text/html" },
|
|
866
|
+
status: 500
|
|
867
|
+
});
|
|
868
|
+
}, renderSvelteError = async (conventionPath, errorProps) => {
|
|
869
|
+
const { render } = await import("svelte/server");
|
|
870
|
+
const mod = await import(conventionPath);
|
|
871
|
+
const ErrorComponent = mod.default;
|
|
872
|
+
const { head, body } = render(ErrorComponent, {
|
|
873
|
+
props: errorProps
|
|
874
|
+
});
|
|
875
|
+
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
876
|
+
return new Response(html, {
|
|
877
|
+
headers: { "Content-Type": "text/html" },
|
|
878
|
+
status: 500
|
|
879
|
+
});
|
|
880
|
+
}, unescapeVueStyles = (ssrBody) => {
|
|
881
|
+
let styles = "";
|
|
882
|
+
const body = ssrBody.replace(/<style>([\s\S]*?)<\/style>/g, (_, css) => {
|
|
883
|
+
styles += `<style>${css.replace(/"/g, '"').replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</style>`;
|
|
788
884
|
return "";
|
|
885
|
+
});
|
|
886
|
+
return { body, styles };
|
|
887
|
+
}, renderVueError = async (conventionPath, errorProps) => {
|
|
888
|
+
const { createSSRApp, h } = await import("vue");
|
|
889
|
+
const { renderToString } = await import("vue/server-renderer");
|
|
890
|
+
const mod = await import(conventionPath);
|
|
891
|
+
const ErrorComponent = mod.default;
|
|
892
|
+
const app = createSSRApp({
|
|
893
|
+
render: () => h(ErrorComponent, errorProps)
|
|
894
|
+
});
|
|
895
|
+
const rawBody = await renderToString(app);
|
|
896
|
+
const { styles, body } = unescapeVueStyles(rawBody);
|
|
897
|
+
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
898
|
+
return new Response(html, {
|
|
899
|
+
headers: { "Content-Type": "text/html" },
|
|
900
|
+
status: 500
|
|
901
|
+
});
|
|
902
|
+
}, renderAngularError = async (conventionPath, errorProps) => {
|
|
903
|
+
const mod = await import(conventionPath);
|
|
904
|
+
const renderError = mod.default ?? mod.renderError;
|
|
905
|
+
if (typeof renderError !== "function")
|
|
906
|
+
return null;
|
|
907
|
+
const html = renderError(errorProps);
|
|
908
|
+
return new Response(html, {
|
|
909
|
+
headers: { "Content-Type": "text/html" },
|
|
910
|
+
status: 500
|
|
911
|
+
});
|
|
912
|
+
}, logConventionRenderError = (framework, label, renderError) => {
|
|
913
|
+
const message = renderError instanceof Error ? renderError.message : "";
|
|
914
|
+
if (message.includes("Cannot find module") || message.includes("Cannot find package") || message.includes("not found in module")) {
|
|
915
|
+
console.error(`[SSR] Convention ${label} page for ${framework} failed: missing framework package. Ensure the ${framework} runtime is installed (e.g. bun add ${framework === "react" ? "react react-dom" : framework}).`);
|
|
916
|
+
return;
|
|
789
917
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
918
|
+
console.error(`[SSR] Failed to render ${framework} convention ${label} page:`, renderError);
|
|
919
|
+
}, ERROR_RENDERERS, renderConventionError = async (framework, pageName, error) => {
|
|
920
|
+
const conventionPath = resolveErrorConventionPath(framework, pageName);
|
|
921
|
+
if (!conventionPath)
|
|
922
|
+
return null;
|
|
923
|
+
const errorProps = buildErrorProps(error);
|
|
924
|
+
const renderer = ERROR_RENDERERS[framework];
|
|
925
|
+
if (!renderer)
|
|
926
|
+
return null;
|
|
927
|
+
try {
|
|
928
|
+
return await renderer(conventionPath, errorProps);
|
|
929
|
+
} catch (renderError) {
|
|
930
|
+
logConventionRenderError(framework, "error", renderError);
|
|
931
|
+
}
|
|
932
|
+
return null;
|
|
933
|
+
}, renderReactNotFound = async (conventionPath) => {
|
|
934
|
+
const { createElement } = await import("react");
|
|
935
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
936
|
+
const mod = await import(conventionPath);
|
|
937
|
+
const [nfKey] = Object.keys(mod);
|
|
938
|
+
const NotFoundComponent = mod.default ?? (nfKey ? mod[nfKey] : undefined);
|
|
939
|
+
const element = createElement(NotFoundComponent);
|
|
940
|
+
const stream = await renderToReadableStream(element);
|
|
941
|
+
return new Response(stream, {
|
|
942
|
+
headers: { "Content-Type": "text/html" },
|
|
943
|
+
status: 404
|
|
944
|
+
});
|
|
945
|
+
}, renderSvelteNotFound = async (conventionPath) => {
|
|
946
|
+
const { render } = await import("svelte/server");
|
|
947
|
+
const mod = await import(conventionPath);
|
|
948
|
+
const NotFoundComponent = mod.default;
|
|
949
|
+
const { head, body } = render(NotFoundComponent);
|
|
950
|
+
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
951
|
+
return new Response(html, {
|
|
952
|
+
headers: { "Content-Type": "text/html" },
|
|
953
|
+
status: 404
|
|
954
|
+
});
|
|
955
|
+
}, renderVueNotFound = async (conventionPath) => {
|
|
956
|
+
const { createSSRApp, h } = await import("vue");
|
|
957
|
+
const { renderToString } = await import("vue/server-renderer");
|
|
958
|
+
const mod = await import(conventionPath);
|
|
959
|
+
const NotFoundComponent = mod.default;
|
|
960
|
+
const app = createSSRApp({
|
|
961
|
+
render: () => h(NotFoundComponent)
|
|
962
|
+
});
|
|
963
|
+
const rawBody = await renderToString(app);
|
|
964
|
+
const { styles, body } = unescapeVueStyles(rawBody);
|
|
965
|
+
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
966
|
+
return new Response(html, {
|
|
967
|
+
headers: { "Content-Type": "text/html" },
|
|
968
|
+
status: 404
|
|
969
|
+
});
|
|
970
|
+
}, renderAngularNotFound = async (conventionPath) => {
|
|
971
|
+
const mod = await import(conventionPath);
|
|
972
|
+
const renderNotFound = mod.default ?? mod.renderNotFound;
|
|
973
|
+
if (typeof renderNotFound !== "function")
|
|
974
|
+
return null;
|
|
975
|
+
const html = renderNotFound();
|
|
976
|
+
return new Response(html, {
|
|
977
|
+
headers: { "Content-Type": "text/html" },
|
|
978
|
+
status: 404
|
|
979
|
+
});
|
|
980
|
+
}, NOT_FOUND_RENDERERS, renderConventionNotFound = async (framework) => {
|
|
981
|
+
const conventionPath = resolveNotFoundConventionPath(framework);
|
|
982
|
+
if (!conventionPath)
|
|
983
|
+
return null;
|
|
984
|
+
const renderer = NOT_FOUND_RENDERERS[framework];
|
|
985
|
+
if (!renderer)
|
|
986
|
+
return null;
|
|
987
|
+
try {
|
|
988
|
+
return await renderer(conventionPath);
|
|
989
|
+
} catch (renderError) {
|
|
990
|
+
logConventionRenderError(framework, "not-found", renderError);
|
|
991
|
+
}
|
|
992
|
+
return null;
|
|
993
|
+
}, NOT_FOUND_PRIORITY, renderFirstNotFound = async () => {
|
|
994
|
+
for (const framework of NOT_FOUND_PRIORITY) {
|
|
995
|
+
if (!getMap()[framework]?.defaults?.notFound)
|
|
996
|
+
continue;
|
|
997
|
+
const response = await renderConventionNotFound(framework);
|
|
998
|
+
if (response)
|
|
999
|
+
return response;
|
|
1000
|
+
}
|
|
1001
|
+
return null;
|
|
1002
|
+
};
|
|
1003
|
+
var init_resolveConvention = __esm(() => {
|
|
1004
|
+
ERROR_RENDERERS = {
|
|
1005
|
+
angular: renderAngularError,
|
|
1006
|
+
react: renderReactError,
|
|
1007
|
+
svelte: renderSvelteError,
|
|
1008
|
+
vue: renderVueError
|
|
1009
|
+
};
|
|
1010
|
+
NOT_FOUND_RENDERERS = {
|
|
1011
|
+
angular: renderAngularNotFound,
|
|
1012
|
+
react: renderReactNotFound,
|
|
1013
|
+
svelte: renderSvelteNotFound,
|
|
1014
|
+
vue: renderVueNotFound
|
|
1015
|
+
};
|
|
1016
|
+
NOT_FOUND_PRIORITY = [
|
|
1017
|
+
"react",
|
|
1018
|
+
"svelte",
|
|
1019
|
+
"vue",
|
|
1020
|
+
"angular"
|
|
1021
|
+
];
|
|
1022
|
+
});
|
|
805
1023
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
1024
|
+
// src/react/streamingSlotCollection.tsx
|
|
1025
|
+
import { createContext, useContext } from "react";
|
|
1026
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
1027
|
+
var StreamingSlotCollectorContext, StreamingSlotCollectorProvider = ({
|
|
1028
|
+
children,
|
|
1029
|
+
collector
|
|
1030
|
+
}) => /* @__PURE__ */ jsxDEV(StreamingSlotCollectorContext.Provider, {
|
|
1031
|
+
value: collector,
|
|
1032
|
+
children
|
|
1033
|
+
}, undefined, false, undefined, this), useStreamingSlotCollector = () => useContext(StreamingSlotCollectorContext);
|
|
1034
|
+
var init_streamingSlotCollection = __esm(() => {
|
|
1035
|
+
StreamingSlotCollectorContext = createContext(null);
|
|
1036
|
+
});
|
|
811
1037
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
})();`;
|
|
827
|
-
}).join(`
|
|
828
|
-
`);
|
|
829
|
-
return `<script>
|
|
830
|
-
(function() {
|
|
831
|
-
${scriptCode}
|
|
832
|
-
})();
|
|
833
|
-
</script>`;
|
|
834
|
-
}, getAndClearClientScripts = (requestId) => {
|
|
835
|
-
const id = requestId || ssrContextGetter?.();
|
|
836
|
-
if (!id)
|
|
837
|
-
return [];
|
|
838
|
-
const scripts = scriptRegistry.get(id);
|
|
839
|
-
if (!scripts) {
|
|
840
|
-
return [];
|
|
1038
|
+
// src/react/pageHandler.ts
|
|
1039
|
+
var ssrDirty = false, buildDirtyResponse = (index, maybeProps) => {
|
|
1040
|
+
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
1041
|
+
const dirtyFlag = "window.__SSR_DIRTY__=true;";
|
|
1042
|
+
const refreshSetup = "window.__REFRESH_BUFFER__=[];" + "window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};" + "window.$RefreshSig$=function(){return function(t){return t}};";
|
|
1043
|
+
const inlineScript = `${propsScript}${dirtyFlag}${refreshSetup}`;
|
|
1044
|
+
const html = `<!DOCTYPE html><html><head></head><body>` + `<script>${inlineScript}</script>` + `<script type="module" src="${index}"></script>` + `</body></html>`;
|
|
1045
|
+
return new Response(html, {
|
|
1046
|
+
headers: { "Content-Type": "text/html" }
|
|
1047
|
+
});
|
|
1048
|
+
}, handleReactPageRequest = async (PageComponent, index, ...props) => {
|
|
1049
|
+
const [maybeProps] = props;
|
|
1050
|
+
if (ssrDirty) {
|
|
1051
|
+
return buildDirtyResponse(index, maybeProps);
|
|
841
1052
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1053
|
+
try {
|
|
1054
|
+
const { createElement } = await import("react");
|
|
1055
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
1056
|
+
const slotCollector = new Map;
|
|
1057
|
+
const pageElement = maybeProps !== undefined ? createElement(PageComponent, maybeProps) : createElement(PageComponent);
|
|
1058
|
+
const element = createElement(StreamingSlotCollectorProvider, { collector: slotCollector }, pageElement);
|
|
1059
|
+
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
1060
|
+
const refreshSetup = "window.__REFRESH_BUFFER__=[];window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};window.$RefreshSig$=function(){return function(t){return t}};";
|
|
1061
|
+
const stream = await renderToReadableStream(element, {
|
|
1062
|
+
bootstrapModules: [index],
|
|
1063
|
+
bootstrapScriptContent: propsScript + refreshSetup || undefined,
|
|
1064
|
+
onError(error) {
|
|
1065
|
+
console.error("[SSR] React streaming error:", error);
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
if ("allReady" in stream && stream.allReady instanceof Promise) {
|
|
1069
|
+
await stream.allReady;
|
|
1070
|
+
}
|
|
1071
|
+
const htmlStream = injectIslandPageContextStream(stream);
|
|
1072
|
+
return withStreamingSlots(new Response(htmlStream, {
|
|
1073
|
+
headers: { "Content-Type": "text/html" }
|
|
1074
|
+
}), {
|
|
1075
|
+
streamingSlots: [...slotCollector.values()]
|
|
1076
|
+
});
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
console.error("[SSR] React render error:", error);
|
|
1079
|
+
const pageName = PageComponent.name || PageComponent.displayName || "";
|
|
1080
|
+
const conventionResponse = await renderConventionError("react", pageName, error);
|
|
1081
|
+
if (conventionResponse)
|
|
1082
|
+
return conventionResponse;
|
|
1083
|
+
return new Response(ssrErrorPage("react", error), {
|
|
1084
|
+
headers: { "Content-Type": "text/html" },
|
|
1085
|
+
status: 500
|
|
1086
|
+
});
|
|
850
1087
|
}
|
|
1088
|
+
}, invalidateReactSsrCache = () => {
|
|
1089
|
+
ssrDirty = true;
|
|
1090
|
+
};
|
|
1091
|
+
var init_pageHandler = __esm(() => {
|
|
1092
|
+
init_responseEnhancers();
|
|
1093
|
+
init_resolveConvention();
|
|
1094
|
+
init_streamingSlotCollection();
|
|
851
1095
|
});
|
|
852
1096
|
|
|
853
|
-
// src/
|
|
854
|
-
var
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1097
|
+
// src/core/islandManifest.ts
|
|
1098
|
+
var toIslandFrameworkSegment = (framework) => framework[0]?.toUpperCase() + framework.slice(1), collectFrameworkIslands = (manifest, prefix) => {
|
|
1099
|
+
const entries = {};
|
|
1100
|
+
let found = false;
|
|
1101
|
+
for (const [key, value] of Object.entries(manifest)) {
|
|
1102
|
+
if (!key.startsWith(prefix))
|
|
1103
|
+
continue;
|
|
1104
|
+
const component = key.slice(prefix.length);
|
|
1105
|
+
if (!component)
|
|
1106
|
+
continue;
|
|
1107
|
+
entries[component] = value;
|
|
1108
|
+
found = true;
|
|
860
1109
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
renderApplication: platformServer?.renderApplication ?? baseDeps.renderApplication,
|
|
871
|
-
Sanitizer: core.Sanitizer,
|
|
872
|
-
SecurityContext: core.SecurityContext
|
|
873
|
-
};
|
|
874
|
-
}, buildProviders = (deps, sanitizer, maybeProps, tokenMap) => {
|
|
875
|
-
const providers = [
|
|
876
|
-
deps.provideServerRendering(),
|
|
877
|
-
deps.provideClientHydration(),
|
|
878
|
-
deps.provideZonelessChangeDetection(),
|
|
879
|
-
{ provide: deps.APP_BASE_HREF, useValue: "/" },
|
|
880
|
-
{
|
|
881
|
-
provide: deps.DomSanitizer,
|
|
882
|
-
useValue: sanitizer
|
|
883
|
-
},
|
|
884
|
-
{ provide: deps.Sanitizer, useValue: sanitizer }
|
|
885
|
-
];
|
|
886
|
-
if (!maybeProps) {
|
|
887
|
-
return providers;
|
|
1110
|
+
return found ? entries : undefined;
|
|
1111
|
+
}, getIslandManifestEntries = (manifest) => {
|
|
1112
|
+
const islands = {};
|
|
1113
|
+
const frameworks = ["react", "svelte", "vue", "angular"];
|
|
1114
|
+
for (const framework of frameworks) {
|
|
1115
|
+
const prefix = `Island${toIslandFrameworkSegment(framework)}`;
|
|
1116
|
+
const entries = collectFrameworkIslands(manifest, prefix);
|
|
1117
|
+
if (entries)
|
|
1118
|
+
islands[framework] = entries;
|
|
888
1119
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
return false;
|
|
1120
|
+
return islands;
|
|
1121
|
+
}, getIslandManifestKey = (framework, component) => `Island${toIslandFrameworkSegment(framework)}${component}`;
|
|
1122
|
+
|
|
1123
|
+
// src/core/islands.ts
|
|
1124
|
+
function getIslandComponent(component) {
|
|
1125
|
+
if (isIslandComponentDefinition(component)) {
|
|
1126
|
+
return component.component;
|
|
897
1127
|
}
|
|
898
|
-
return
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
platformBrowser: ssrDeps.__angularPlatformBrowser,
|
|
907
|
-
platformServer: ssrDeps.__angularPlatformServer
|
|
908
|
-
};
|
|
909
|
-
return result;
|
|
910
|
-
} catch {
|
|
1128
|
+
return component;
|
|
1129
|
+
}
|
|
1130
|
+
var defineIslandComponent = (component, options) => ({
|
|
1131
|
+
component,
|
|
1132
|
+
export: options.export,
|
|
1133
|
+
source: options.source
|
|
1134
|
+
}), defineIslandRegistry = (registry) => registry, isRecord = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (component) => {
|
|
1135
|
+
if (!isIslandComponentDefinition(component))
|
|
911
1136
|
return null;
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
if (cached) {
|
|
916
|
-
return cached;
|
|
917
|
-
}
|
|
918
|
-
const selector = deps.reflectComponentType(PageComponent)?.selector ?? "ng-app";
|
|
919
|
-
selectorCache.set(pagePath, selector);
|
|
920
|
-
return selector;
|
|
921
|
-
}, injectBeforeClose = (html, snippet) => {
|
|
922
|
-
if (html.includes("</body>")) {
|
|
923
|
-
return html.replace("</body>", `${snippet}</body>`);
|
|
924
|
-
}
|
|
925
|
-
if (html.includes("</html>")) {
|
|
926
|
-
return html.replace("</html>", `${snippet}</html>`);
|
|
927
|
-
}
|
|
928
|
-
return html + snippet;
|
|
929
|
-
}, injectSsrScripts = (html, requestId, indexPath, props) => {
|
|
930
|
-
let result = html;
|
|
931
|
-
const registeredScripts = getAndClearClientScripts(requestId);
|
|
932
|
-
if (registeredScripts.length > 0) {
|
|
933
|
-
result = injectBeforeClose(result, generateClientScriptCode(registeredScripts));
|
|
934
|
-
}
|
|
935
|
-
if (props) {
|
|
936
|
-
result = injectBeforeClose(result, `<script>window.__ABS_ANGULAR_PAGE_PROPS__ = ${JSON.stringify(props)};</script>`);
|
|
937
|
-
}
|
|
938
|
-
if (indexPath) {
|
|
939
|
-
result = injectBeforeClose(result, `<script type="module" src="${indexPath}"></script>`);
|
|
940
|
-
}
|
|
941
|
-
return result;
|
|
942
|
-
}, renderAngularApp = async (deps, PageComponent, providers, document2) => {
|
|
943
|
-
const bootstrap = (context) => deps.bootstrapApplication(PageComponent, { providers }, context);
|
|
944
|
-
return withSuppressedAngularDevLogs(() => deps.renderApplication(bootstrap, {
|
|
945
|
-
document: document2,
|
|
946
|
-
platformProviders: [],
|
|
947
|
-
url: "/"
|
|
948
|
-
}));
|
|
949
|
-
}, withSuppressedAngularDevLogs = async (render) => {
|
|
950
|
-
const origLog = console.log;
|
|
951
|
-
console.log = (...args) => {
|
|
952
|
-
if (typeof args[0] === "string" && args[0].includes("development mode")) {
|
|
953
|
-
return;
|
|
954
|
-
}
|
|
955
|
-
origLog.apply(console, args);
|
|
1137
|
+
return {
|
|
1138
|
+
export: component.export,
|
|
1139
|
+
source: component.source
|
|
956
1140
|
};
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1141
|
+
}, isIslandComponentDefinition = (value) => isRecord(value) && ("component" in value) && ("source" in value) && typeof value.source === "string", parseIslandProps = (rawProps) => {
|
|
1142
|
+
if (!rawProps)
|
|
1143
|
+
return {};
|
|
1144
|
+
return JSON.parse(rawProps);
|
|
1145
|
+
}, serializeIslandProps = (props) => JSON.stringify(props ?? {});
|
|
1146
|
+
var init_islands = () => {};
|
|
1147
|
+
|
|
1148
|
+
// src/core/islandMarkupAttributes.ts
|
|
1149
|
+
var getIslandMarkerAttributes = (props, islandId) => ({
|
|
1150
|
+
"data-component": props.component,
|
|
1151
|
+
"data-framework": props.framework,
|
|
1152
|
+
"data-hydrate": props.hydrate ?? "load",
|
|
1153
|
+
"data-island": "true",
|
|
1154
|
+
...islandId ? { "data-island-id": islandId } : {},
|
|
1155
|
+
"data-props": serializeIslandProps(props.props)
|
|
1156
|
+
}), escapeHtmlAttribute = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">"), serializeIslandAttributes = (attributes) => Object.entries(attributes).map(([key, value]) => `${key}="${escapeHtmlAttribute(value)}"`).join(" ");
|
|
1157
|
+
var init_islandMarkupAttributes = __esm(() => {
|
|
1158
|
+
init_islands();
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
// src/core/currentIslandRegistry.ts
|
|
1162
|
+
var requireCurrentIslandRegistry = () => {
|
|
1163
|
+
const registry = globalThis.__absoluteIslandRegistry;
|
|
1164
|
+
if (!registry) {
|
|
1165
|
+
throw new Error("No island registry is active. Configure `islands.registry` in absolute.config.ts before rendering <Island />.");
|
|
961
1166
|
}
|
|
1167
|
+
return registry;
|
|
1168
|
+
}, setCurrentIslandRegistry = (registry) => {
|
|
1169
|
+
globalThis.__absoluteIslandRegistry = registry;
|
|
962
1170
|
};
|
|
963
|
-
var init_ssrRender = __esm(() => {
|
|
964
|
-
init_registerClientScript();
|
|
965
|
-
routePropsCache = new Map;
|
|
966
|
-
selectorCache = new Map;
|
|
967
|
-
});
|
|
968
1171
|
|
|
969
|
-
// src/angular/
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
const selector = firstChild.tagName.toLowerCase();
|
|
976
|
-
return selector.length > 0 ? selector : null;
|
|
977
|
-
}, getClientAngularComponentSelector = (component) => {
|
|
978
|
-
const maybeDef = Reflect.get(component, "\u0275cmp");
|
|
979
|
-
if (typeof maybeDef !== "object" || maybeDef === null) {
|
|
980
|
-
return null;
|
|
1172
|
+
// src/angular/injectorPatch.ts
|
|
1173
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
1174
|
+
import { dirname, join, resolve } from "path";
|
|
1175
|
+
var applyInjectorPatch = (chunkPath, content) => {
|
|
1176
|
+
if (content.includes('Symbol.for("angular.currentInjector")')) {
|
|
1177
|
+
return;
|
|
981
1178
|
}
|
|
982
|
-
const
|
|
983
|
-
|
|
984
|
-
|
|
1179
|
+
const original = [
|
|
1180
|
+
"let _currentInjector = undefined;",
|
|
1181
|
+
"function getCurrentInjector() {",
|
|
1182
|
+
" return _currentInjector;",
|
|
1183
|
+
"}",
|
|
1184
|
+
"function setCurrentInjector(injector) {",
|
|
1185
|
+
" const former = _currentInjector;",
|
|
1186
|
+
" _currentInjector = injector;",
|
|
1187
|
+
" return former;",
|
|
1188
|
+
"}"
|
|
1189
|
+
].join(`
|
|
1190
|
+
`);
|
|
1191
|
+
const replacement = [
|
|
1192
|
+
'const _injSym = Symbol.for("angular.currentInjector");',
|
|
1193
|
+
"if (!globalThis[_injSym]) globalThis[_injSym] = { v: undefined };",
|
|
1194
|
+
"function getCurrentInjector() {",
|
|
1195
|
+
" return globalThis[_injSym].v;",
|
|
1196
|
+
"}",
|
|
1197
|
+
"function setCurrentInjector(injector) {",
|
|
1198
|
+
" const former = globalThis[_injSym].v;",
|
|
1199
|
+
" globalThis[_injSym].v = injector;",
|
|
1200
|
+
" return former;",
|
|
1201
|
+
"}"
|
|
1202
|
+
].join(`
|
|
1203
|
+
`);
|
|
1204
|
+
const patched = content.replace(original, replacement);
|
|
1205
|
+
if (patched === content) {
|
|
1206
|
+
return;
|
|
985
1207
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1208
|
+
writeFileSync(chunkPath, patched, "utf-8");
|
|
1209
|
+
}, resolveAngularCoreDir = () => {
|
|
1210
|
+
const fromProject = resolve(process.cwd(), "node_modules/@angular/core");
|
|
1211
|
+
if (existsSync(join(fromProject, "package.json"))) {
|
|
1212
|
+
return fromProject;
|
|
989
1213
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1214
|
+
return dirname(__require.resolve("@angular/core/package.json"));
|
|
1215
|
+
}, patchAngularInjectorSingleton = () => {
|
|
1216
|
+
try {
|
|
1217
|
+
const coreDir = resolveAngularCoreDir();
|
|
1218
|
+
const chunkPath = join(coreDir, "fesm2022", "_not_found-chunk.mjs");
|
|
1219
|
+
const content = readFileSync(chunkPath, "utf-8");
|
|
1220
|
+
applyInjectorPatch(chunkPath, content);
|
|
1221
|
+
} catch {}
|
|
1222
|
+
};
|
|
1223
|
+
var init_injectorPatch = __esm(() => {
|
|
1224
|
+
patchAngularInjectorSingleton();
|
|
1225
|
+
});
|
|
1226
|
+
|
|
1227
|
+
// src/angular/resolveAngularPackage.ts
|
|
1228
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1229
|
+
import { resolve as resolve2 } from "path";
|
|
1230
|
+
var resolveAngularPackage = (specifier) => {
|
|
1231
|
+
const fromProject = resolve2(process.cwd(), "node_modules", specifier);
|
|
1232
|
+
if (existsSync2(fromProject)) {
|
|
1233
|
+
return fromProject;
|
|
1003
1234
|
}
|
|
1004
|
-
return
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1235
|
+
return specifier;
|
|
1236
|
+
};
|
|
1237
|
+
var init_resolveAngularPackage = () => {};
|
|
1238
|
+
|
|
1239
|
+
// src/angular/angularPatch.ts
|
|
1240
|
+
var exports_angularPatch = {};
|
|
1241
|
+
__export(exports_angularPatch, {
|
|
1242
|
+
applyPatches: () => applyPatches
|
|
1243
|
+
});
|
|
1244
|
+
var ensureHead = (doc) => {
|
|
1245
|
+
if (!doc || doc.head || !doc.documentElement) {
|
|
1246
|
+
return;
|
|
1009
1247
|
}
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1248
|
+
const head = doc.createElement("head");
|
|
1249
|
+
doc.documentElement.insertBefore(head, doc.documentElement.firstChild);
|
|
1250
|
+
}, applyPatches = async () => {
|
|
1251
|
+
const { \u{275}DominoAdapter } = await import(resolveAngularPackage("@angular/platform-server"));
|
|
1252
|
+
if (!\u{275}DominoAdapter?.prototype) {
|
|
1253
|
+
console.warn("[Angular Patch] \u0275DominoAdapter not found, skipping patches");
|
|
1254
|
+
return false;
|
|
1013
1255
|
}
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
const
|
|
1256
|
+
const proto = \u{275}DominoAdapter.prototype;
|
|
1257
|
+
const origGetBaseHref = proto.getBaseHref;
|
|
1258
|
+
proto.getBaseHref = function(doc) {
|
|
1259
|
+
if (!doc || !doc.head || typeof doc.head.children === "undefined") {
|
|
1260
|
+
return "";
|
|
1261
|
+
}
|
|
1262
|
+
return origGetBaseHref.call(this, doc);
|
|
1263
|
+
};
|
|
1264
|
+
const origCreateHtmlDocument = proto.createHtmlDocument;
|
|
1265
|
+
proto.createHtmlDocument = function() {
|
|
1266
|
+
const doc = origCreateHtmlDocument.call(this);
|
|
1267
|
+
ensureHead(doc);
|
|
1268
|
+
return doc;
|
|
1269
|
+
};
|
|
1270
|
+
const origGetDefaultDocument = proto.getDefaultDocument;
|
|
1271
|
+
proto.getDefaultDocument = function() {
|
|
1272
|
+
const doc = origGetDefaultDocument.call(this);
|
|
1273
|
+
ensureHead(doc);
|
|
1274
|
+
return doc;
|
|
1275
|
+
};
|
|
1276
|
+
return true;
|
|
1277
|
+
};
|
|
1278
|
+
var init_angularPatch = __esm(() => {
|
|
1279
|
+
init_resolveAngularPackage();
|
|
1280
|
+
});
|
|
1029
1281
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1282
|
+
// src/angular/angularDeps.ts
|
|
1283
|
+
var initDominoAdapter = (platformServer) => {
|
|
1284
|
+
try {
|
|
1285
|
+
const DominoAdapter = platformServer.\u{275}DominoAdapter;
|
|
1286
|
+
DominoAdapter?.makeCurrent?.();
|
|
1287
|
+
} catch (err) {
|
|
1288
|
+
console.error("Failed to initialize DominoAdapter:", err);
|
|
1033
1289
|
}
|
|
1290
|
+
}, loadAngularDeps = async () => {
|
|
1291
|
+
patchAngularInjectorSingleton();
|
|
1292
|
+
await import(resolveAngularPackage("@angular/compiler"));
|
|
1293
|
+
const { applyPatches: applyPatches2 } = await Promise.resolve().then(() => (init_angularPatch(), exports_angularPatch));
|
|
1294
|
+
await applyPatches2();
|
|
1295
|
+
const [platformBrowser, platformServer, common, core] = await Promise.all([
|
|
1296
|
+
import(resolveAngularPackage("@angular/platform-browser")),
|
|
1297
|
+
import(resolveAngularPackage("@angular/platform-server")),
|
|
1298
|
+
import(resolveAngularPackage("@angular/common")),
|
|
1299
|
+
import(resolveAngularPackage("@angular/core"))
|
|
1300
|
+
]);
|
|
1301
|
+
if (false) {}
|
|
1302
|
+
initDominoAdapter(platformServer);
|
|
1034
1303
|
return {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1304
|
+
APP_BASE_HREF: common.APP_BASE_HREF,
|
|
1305
|
+
bootstrapApplication: platformBrowser.bootstrapApplication,
|
|
1306
|
+
DomSanitizer: platformBrowser.DomSanitizer,
|
|
1307
|
+
provideClientHydration: platformBrowser.provideClientHydration,
|
|
1308
|
+
provideServerRendering: platformServer.provideServerRendering,
|
|
1309
|
+
provideZonelessChangeDetection: core.provideZonelessChangeDetection,
|
|
1310
|
+
reflectComponentType: core.reflectComponentType,
|
|
1311
|
+
renderApplication: platformServer.renderApplication,
|
|
1312
|
+
Sanitizer: core.Sanitizer,
|
|
1313
|
+
SecurityContext: core.SecurityContext
|
|
1044
1314
|
};
|
|
1045
|
-
},
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
if (cached) {
|
|
1049
|
-
return cached;
|
|
1050
|
-
}
|
|
1051
|
-
const metadataPromise = buildAngularIslandWrapperMetadata(component, islandId, wrapperKey);
|
|
1052
|
-
wrapperMetadataCache.set(wrapperKey, metadataPromise);
|
|
1053
|
-
return metadataPromise;
|
|
1054
|
-
}, extractAngularIslandRoot = (html, selector) => {
|
|
1055
|
-
const openTag = `<${selector}`;
|
|
1056
|
-
const start = html.indexOf(openTag);
|
|
1057
|
-
if (start < 0) {
|
|
1058
|
-
throw new Error(`Could not find Angular island root "${selector}".`);
|
|
1315
|
+
}, angularDeps = null, getAngularDeps = () => {
|
|
1316
|
+
if (!angularDeps) {
|
|
1317
|
+
angularDeps = loadAngularDeps();
|
|
1059
1318
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1319
|
+
return angularDeps;
|
|
1320
|
+
};
|
|
1321
|
+
var init_angularDeps = __esm(() => {
|
|
1322
|
+
init_injectorPatch();
|
|
1323
|
+
init_resolveAngularPackage();
|
|
1324
|
+
});
|
|
1325
|
+
|
|
1326
|
+
// src/utils/registerClientScript.ts
|
|
1327
|
+
var scriptRegistry, requestCounter = 0, getRequestId = () => `req_${Date.now()}_${++requestCounter}`, ssrContextGetter = null, getSsrContextId = () => ssrContextGetter?.() || Object.getOwnPropertyDescriptor(globalThis, "__absolutejs_requestId")?.value, registerClientScript = (script, requestId) => {
|
|
1328
|
+
const id = requestId || getSsrContextId() || getRequestId();
|
|
1329
|
+
if (!scriptRegistry.has(id)) {
|
|
1330
|
+
scriptRegistry.set(id, new Set);
|
|
1064
1331
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
if (
|
|
1073
|
-
|
|
1074
|
-
rootElement = element.querySelector(selector);
|
|
1332
|
+
scriptRegistry.get(id)?.add(script);
|
|
1333
|
+
return id;
|
|
1334
|
+
}, setSsrContextGetter = (getter) => {
|
|
1335
|
+
ssrContextGetter = getter;
|
|
1336
|
+
}, clearAllClientScripts = () => {
|
|
1337
|
+
scriptRegistry.clear();
|
|
1338
|
+
}, generateClientScriptCode = (scripts) => {
|
|
1339
|
+
if (scripts.length === 0) {
|
|
1340
|
+
return "";
|
|
1075
1341
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1342
|
+
const scriptCode = scripts.map((script, index) => {
|
|
1343
|
+
const funcString = script.toString();
|
|
1344
|
+
const bodyMatch = funcString.match(/\{([\s\S]*)\}/);
|
|
1345
|
+
if (!bodyMatch || !bodyMatch[1]) {
|
|
1346
|
+
return "";
|
|
1347
|
+
}
|
|
1348
|
+
const body = bodyMatch[1].trim();
|
|
1349
|
+
return `
|
|
1350
|
+
(function() {
|
|
1351
|
+
var executed = false;
|
|
1352
|
+
function executeScript_${index}() {
|
|
1353
|
+
if (executed) return;
|
|
1354
|
+
executed = true;
|
|
1355
|
+
${body}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
1359
|
+
executeScript_${index}();
|
|
1360
|
+
} else {
|
|
1361
|
+
document.addEventListener('DOMContentLoaded', executeScript_${index});
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// Watch for hydration-added elements
|
|
1365
|
+
var observer = new MutationObserver(function() {
|
|
1366
|
+
executeScript_${index}();
|
|
1367
|
+
if (executed) observer.disconnect();
|
|
1368
|
+
});
|
|
1369
|
+
if (!executed) {
|
|
1370
|
+
observer.observe(document.body || document.documentElement, { childList: true, subtree: true });
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// Single fallback timeout
|
|
1374
|
+
setTimeout(function() {
|
|
1375
|
+
executeScript_${index}();
|
|
1376
|
+
observer.disconnect();
|
|
1377
|
+
}, 1000);
|
|
1378
|
+
})();`;
|
|
1379
|
+
}).join(`
|
|
1380
|
+
`);
|
|
1381
|
+
return `<script>
|
|
1382
|
+
(function() {
|
|
1383
|
+
${scriptCode}
|
|
1384
|
+
})();
|
|
1385
|
+
</script>`;
|
|
1386
|
+
}, getAndClearClientScripts = (requestId) => {
|
|
1387
|
+
const id = requestId || ssrContextGetter?.();
|
|
1388
|
+
if (!id)
|
|
1389
|
+
return [];
|
|
1390
|
+
const scripts = scriptRegistry.get(id);
|
|
1391
|
+
if (!scripts) {
|
|
1392
|
+
return [];
|
|
1102
1393
|
}
|
|
1103
|
-
const
|
|
1394
|
+
const scriptArray = Array.from(scripts);
|
|
1395
|
+
scriptRegistry.delete(id);
|
|
1396
|
+
return scriptArray;
|
|
1397
|
+
};
|
|
1398
|
+
var init_registerClientScript = __esm(() => {
|
|
1399
|
+
scriptRegistry = new Map;
|
|
1400
|
+
if (typeof globalThis !== "undefined") {
|
|
1401
|
+
Object.assign(globalThis, { registerClientScript });
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
|
|
1405
|
+
// src/angular/ssrRender.ts
|
|
1406
|
+
var routePropsCache, cacheRouteData = (pagePath, data) => {
|
|
1407
|
+
const cacheKey = pagePath.split("?")[0] ?? pagePath;
|
|
1408
|
+
routePropsCache.set(cacheKey, data);
|
|
1409
|
+
}, getCachedRouteData = (pagePath) => routePropsCache.get(pagePath), selectorCache, buildDeps = (ssrResult, baseDeps) => {
|
|
1410
|
+
if (!ssrResult?.core) {
|
|
1411
|
+
return baseDeps;
|
|
1412
|
+
}
|
|
1413
|
+
const { common, core, platformBrowser, platformServer } = ssrResult;
|
|
1414
|
+
return {
|
|
1415
|
+
APP_BASE_HREF: common?.APP_BASE_HREF ?? baseDeps.APP_BASE_HREF,
|
|
1416
|
+
bootstrapApplication: platformBrowser?.bootstrapApplication ?? baseDeps.bootstrapApplication,
|
|
1417
|
+
DomSanitizer: platformBrowser?.DomSanitizer ?? baseDeps.DomSanitizer,
|
|
1418
|
+
provideClientHydration: platformBrowser?.provideClientHydration ?? baseDeps.provideClientHydration,
|
|
1419
|
+
provideServerRendering: platformServer?.provideServerRendering ?? baseDeps.provideServerRendering,
|
|
1420
|
+
provideZonelessChangeDetection: core.provideZonelessChangeDetection,
|
|
1421
|
+
reflectComponentType: core.reflectComponentType,
|
|
1422
|
+
renderApplication: platformServer?.renderApplication ?? baseDeps.renderApplication,
|
|
1423
|
+
Sanitizer: core.Sanitizer,
|
|
1424
|
+
SecurityContext: core.SecurityContext
|
|
1425
|
+
};
|
|
1426
|
+
}, buildProviders = (deps, sanitizer, maybeProps, tokenMap) => {
|
|
1104
1427
|
const providers = [
|
|
1105
1428
|
deps.provideServerRendering(),
|
|
1429
|
+
deps.provideClientHydration(),
|
|
1106
1430
|
deps.provideZonelessChangeDetection(),
|
|
1107
1431
|
{ provide: deps.APP_BASE_HREF, useValue: "/" },
|
|
1108
|
-
{
|
|
1432
|
+
{
|
|
1433
|
+
provide: deps.DomSanitizer,
|
|
1434
|
+
useValue: sanitizer
|
|
1435
|
+
},
|
|
1436
|
+
{ provide: deps.Sanitizer, useValue: sanitizer }
|
|
1109
1437
|
];
|
|
1110
|
-
|
|
1111
|
-
|
|
1438
|
+
if (!maybeProps) {
|
|
1439
|
+
return providers;
|
|
1440
|
+
}
|
|
1441
|
+
const propProviders = Object.entries(maybeProps).map(([propName, propValue]) => ({
|
|
1442
|
+
token: tokenMap.get(toScreamingSnake(propName)),
|
|
1443
|
+
value: propValue
|
|
1444
|
+
})).filter((entry) => entry.token).map((entry) => ({ provide: entry.token, useValue: entry.value }));
|
|
1445
|
+
return [...providers, ...propProviders];
|
|
1446
|
+
}, clearSelectorCache = () => selectorCache.clear(), isInjectionToken = (value) => {
|
|
1447
|
+
if (!value || typeof value !== "object") {
|
|
1448
|
+
return false;
|
|
1449
|
+
}
|
|
1450
|
+
return "ngMetadataName" in value && value.ngMetadataName === "InjectionToken";
|
|
1451
|
+
}, discoverTokens = (pageModule) => new Map(Object.entries(pageModule).filter(([, value]) => isInjectionToken(value))), loadSsrDeps = async (pagePath) => {
|
|
1452
|
+
const ssrDepsPath = (pagePath.split("?")[0] ?? pagePath).replace(/\.js$/, ".ssr-deps.js");
|
|
1453
|
+
try {
|
|
1454
|
+
const ssrDeps = await import(ssrDepsPath);
|
|
1455
|
+
const result = {
|
|
1456
|
+
common: ssrDeps.__angularCommon,
|
|
1457
|
+
core: ssrDeps.__angularCore,
|
|
1458
|
+
platformBrowser: ssrDeps.__angularPlatformBrowser,
|
|
1459
|
+
platformServer: ssrDeps.__angularPlatformServer
|
|
1460
|
+
};
|
|
1461
|
+
return result;
|
|
1462
|
+
} catch {
|
|
1463
|
+
return null;
|
|
1464
|
+
}
|
|
1465
|
+
}, resolveSelector = (deps, pagePath, PageComponent) => {
|
|
1466
|
+
const cached = selectorCache.get(pagePath);
|
|
1467
|
+
if (cached) {
|
|
1468
|
+
return cached;
|
|
1469
|
+
}
|
|
1470
|
+
const selector = deps.reflectComponentType(PageComponent)?.selector ?? "ng-app";
|
|
1471
|
+
selectorCache.set(pagePath, selector);
|
|
1472
|
+
return selector;
|
|
1473
|
+
}, injectBeforeClose = (html, snippet) => {
|
|
1474
|
+
if (html.includes("</body>")) {
|
|
1475
|
+
return html.replace("</body>", `${snippet}</body>`);
|
|
1476
|
+
}
|
|
1477
|
+
if (html.includes("</html>")) {
|
|
1478
|
+
return html.replace("</html>", `${snippet}</html>`);
|
|
1479
|
+
}
|
|
1480
|
+
return html + snippet;
|
|
1481
|
+
}, injectSsrScripts = (html, requestId, indexPath, props) => {
|
|
1482
|
+
let result = html;
|
|
1483
|
+
const registeredScripts = getAndClearClientScripts(requestId);
|
|
1484
|
+
if (registeredScripts.length > 0) {
|
|
1485
|
+
result = injectBeforeClose(result, generateClientScriptCode(registeredScripts));
|
|
1486
|
+
}
|
|
1487
|
+
if (props) {
|
|
1488
|
+
result = injectBeforeClose(result, `<script>window.__ABS_ANGULAR_PAGE_PROPS__ = ${JSON.stringify(props)};</script>`);
|
|
1489
|
+
}
|
|
1490
|
+
if (indexPath) {
|
|
1491
|
+
result = injectBeforeClose(result, `<script type="module" src="${indexPath}"></script>`);
|
|
1492
|
+
}
|
|
1493
|
+
return result;
|
|
1494
|
+
}, renderAngularApp = async (deps, PageComponent, providers, document2) => {
|
|
1495
|
+
const bootstrap = (context) => deps.bootstrapApplication(PageComponent, { providers }, context);
|
|
1496
|
+
return withSuppressedAngularDevLogs(() => deps.renderApplication(bootstrap, {
|
|
1112
1497
|
document: document2,
|
|
1113
1498
|
platformProviders: [],
|
|
1114
1499
|
url: "/"
|
|
1115
1500
|
}));
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1501
|
+
}, withSuppressedAngularDevLogs = async (render) => {
|
|
1502
|
+
const origLog = console.log;
|
|
1503
|
+
console.log = (...args) => {
|
|
1504
|
+
if (typeof args[0] === "string" && args[0].includes("development mode")) {
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
origLog.apply(console, args);
|
|
1508
|
+
};
|
|
1509
|
+
try {
|
|
1510
|
+
return await render();
|
|
1511
|
+
} finally {
|
|
1512
|
+
console.log = origLog;
|
|
1513
|
+
}
|
|
1119
1514
|
};
|
|
1120
|
-
var
|
|
1121
|
-
init_angularDeps();
|
|
1122
|
-
init_ssrRender();
|
|
1515
|
+
var init_ssrRender = __esm(() => {
|
|
1123
1516
|
init_registerClientScript();
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
});
|
|
1127
|
-
|
|
1128
|
-
// src/core/islandSsr.ts
|
|
1129
|
-
import { createElement } from "react";
|
|
1130
|
-
import { renderToStaticMarkup } from "react-dom/server";
|
|
1131
|
-
import { render as renderSvelte } from "svelte/server";
|
|
1132
|
-
import { createSSRApp, h } from "vue";
|
|
1133
|
-
import { renderToString as renderVueToString } from "vue/server-renderer";
|
|
1134
|
-
var renderReactIslandToHtml = (component, props) => renderToStaticMarkup(createElement(component, props)), renderSvelteIslandToHtml = (component, props) => {
|
|
1135
|
-
const { body } = renderSvelte(component, { props });
|
|
1136
|
-
return body;
|
|
1137
|
-
}, renderVueIslandToHtml = (component, props) => {
|
|
1138
|
-
const app = createSSRApp({
|
|
1139
|
-
render: () => h(component, props)
|
|
1140
|
-
});
|
|
1141
|
-
return renderVueToString(app);
|
|
1142
|
-
};
|
|
1143
|
-
var init_islandSsr = __esm(() => {
|
|
1144
|
-
init_islands2();
|
|
1145
|
-
});
|
|
1146
|
-
|
|
1147
|
-
// src/constants.ts
|
|
1148
|
-
var ANGULAR_INIT_TIMEOUT_MS = 500, ANSI_ESCAPE_LENGTH = 3, ASCII_SPACE = 32, BASE_36_RADIX = 36, BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet", BODY_SLICE_LENGTH = 2000, BYTES_PER_KILOBYTE = 1024, CLI_ARGS_OFFSET = 3, CSS_ERROR_RESOLVE_DELAY_MS = 50, CSS_MAX_CHECK_ATTEMPTS = 10, CSS_MAX_PARSE_TIMEOUT_MS = 500, CSS_SHEET_READY_TIMEOUT_MS = 100, DEFAULT_CHUNK_SIZE = 16384, DEFAULT_DEBOUNCE_MS = 15, DEFAULT_PORT = 3000, DEV_SERVER_RESTART_DEBOUNCE_MS = 100, DOM_UPDATE_DELAY_MS = 50, FILE_PROTOCOL_PREFIX_LENGTH = 7, FOCUS_ID_PREFIX_LENGTH = 3, FOCUS_IDX_PREFIX_LENGTH = 4, FOCUS_NAME_PREFIX_LENGTH = 5, HMR_UPDATE_TIMEOUT_MS = 2000, HOOK_SIGNATURE_LENGTH = 12, EXCLUDE_LAST_OFFSET = -1, HOURS_IN_DAY = 24, HOURS_IN_HALF_DAY = 12, MAX_ERROR_LENGTH = 200, MAX_RECONNECT_ATTEMPTS = 60, MILLISECONDS_IN_A_SECOND = 1000, MINUTES_IN_AN_HOUR = 60, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_MINUTE, MILLISECONDS_IN_A_DAY, OVERLAY_FADE_DURATION_MS = 150, PING_INTERVAL_MS = 30000, RAF_BATCH_COUNT = 3, RANDOM_ID_END_INDEX = 11, REBUILD_BATCH_DELAY_MS = 10, REBUILD_RELOAD_DELAY_MS = 200, RECONNECT_INITIAL_DELAY_MS = 500, RECONNECT_POLL_INTERVAL_MS = 300, SIGINT_EXIT_CODE = 130, SIGTERM_EXIT_CODE = 143, SVELTE_CSS_LOAD_TIMEOUT_MS = 500, TIME_PRECISION = 2, TWO_THIRDS, UNFOUND_INDEX = -1, WEBSOCKET_NORMAL_CLOSURE = 1000;
|
|
1149
|
-
var init_constants = __esm(() => {
|
|
1150
|
-
MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
|
|
1151
|
-
MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
|
|
1152
|
-
TWO_THIRDS = 2 / 3;
|
|
1517
|
+
routePropsCache = new Map;
|
|
1518
|
+
selectorCache = new Map;
|
|
1153
1519
|
});
|
|
1154
1520
|
|
|
1155
|
-
// src/
|
|
1156
|
-
var
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
if (char === "{")
|
|
1161
|
-
depth += 1;
|
|
1162
|
-
if (char === "}")
|
|
1163
|
-
depth -= 1;
|
|
1164
|
-
if (depth === 0) {
|
|
1165
|
-
return text.slice(braceStart + 1, index).trim();
|
|
1166
|
-
}
|
|
1521
|
+
// src/angular/islands.ts
|
|
1522
|
+
var angularIslandSelector = "abs-angular-island", getAngularIslandSelector = (_islandId) => angularIslandSelector, getSelectorFromRenderedIsland = (rootElement) => {
|
|
1523
|
+
const firstChild = rootElement.firstElementChild;
|
|
1524
|
+
if (!(firstChild instanceof HTMLElement)) {
|
|
1525
|
+
return null;
|
|
1167
1526
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1527
|
+
const selector = firstChild.tagName.toLowerCase();
|
|
1528
|
+
return selector.length > 0 ? selector : null;
|
|
1529
|
+
}, getClientAngularComponentSelector = (component) => {
|
|
1530
|
+
const maybeDef = Reflect.get(component, "\u0275cmp");
|
|
1531
|
+
if (typeof maybeDef !== "object" || maybeDef === null) {
|
|
1532
|
+
return null;
|
|
1173
1533
|
}
|
|
1174
|
-
const
|
|
1175
|
-
if (
|
|
1176
|
-
return { expression: "", found: false };
|
|
1177
|
-
}
|
|
1178
|
-
const braceStart = attributeString.indexOf("{", attributeIndex);
|
|
1179
|
-
if (braceStart < 0) {
|
|
1180
|
-
return { expression: "", found: false };
|
|
1181
|
-
}
|
|
1182
|
-
const expression = extractBracedExpression(attributeString, braceStart);
|
|
1183
|
-
if (expression === null) {
|
|
1184
|
-
return { expression: "", found: false };
|
|
1185
|
-
}
|
|
1186
|
-
return { expression, found: true };
|
|
1187
|
-
}, lowerSvelteIslandSyntax = (source, _mode = "server") => {
|
|
1188
|
-
if (!source.includes("<Island")) {
|
|
1189
|
-
return { code: source, transformed: false };
|
|
1190
|
-
}
|
|
1191
|
-
let islandIndex = 0;
|
|
1192
|
-
const transformedMarkup = source.replace(ISLAND_TAG_RE, (fullMatch, attributeString) => {
|
|
1193
|
-
const framework = extractIslandAttribute(attributeString, "framework");
|
|
1194
|
-
const component = extractIslandAttribute(attributeString, "component");
|
|
1195
|
-
if (!framework.found || !component.found) {
|
|
1196
|
-
return fullMatch;
|
|
1197
|
-
}
|
|
1198
|
-
const hydrate = extractIslandAttribute(attributeString, "hydrate");
|
|
1199
|
-
const props = extractIslandAttribute(attributeString, "props");
|
|
1200
|
-
const slotId = `absolute-svelte-island-${islandIndex.toString(BASE_36_RADIX)}`;
|
|
1201
|
-
islandIndex += 1;
|
|
1202
|
-
const resolveExpression = `await __absoluteResolveIslandHtml(${JSON.stringify(slotId)}, { component: ${component.expression}, framework: ${framework.expression}, hydrate: ${hydrate.found ? hydrate.expression : JSON.stringify("load")}, props: ${props.found ? props.expression : "{}"} })`;
|
|
1203
|
-
return `<div data-absolute-island-slot="${slotId}" style="display: contents">{@html ${resolveExpression}}</div>`;
|
|
1204
|
-
});
|
|
1205
|
-
const importLine = 'import { resolveIslandHtml as __absoluteResolveIslandHtml } from "@absolutejs/absolute/svelte";';
|
|
1206
|
-
if (transformedMarkup.includes("<script")) {
|
|
1207
|
-
return {
|
|
1208
|
-
code: transformedMarkup.replace(/<script(\s[^>]*)?>/, (match) => `${match}
|
|
1209
|
-
${importLine}
|
|
1210
|
-
`),
|
|
1211
|
-
transformed: true
|
|
1212
|
-
};
|
|
1213
|
-
}
|
|
1214
|
-
return {
|
|
1215
|
-
code: `<script lang="ts">
|
|
1216
|
-
${importLine}
|
|
1217
|
-
</script>
|
|
1218
|
-
${transformedMarkup}`,
|
|
1219
|
-
transformed: true
|
|
1220
|
-
};
|
|
1221
|
-
};
|
|
1222
|
-
var init_lowerIslandSyntax = __esm(() => {
|
|
1223
|
-
init_constants();
|
|
1224
|
-
ISLAND_TAG_RE = /<Island\b([\s\S]*?)\/>/g;
|
|
1225
|
-
});
|
|
1226
|
-
|
|
1227
|
-
// src/core/svelteServerModule.ts
|
|
1228
|
-
import { mkdir, readdir } from "fs/promises";
|
|
1229
|
-
import { basename as basename2, dirname as dirname2, extname, join as join2, relative, resolve as resolve3 } from "path";
|
|
1230
|
-
var serverCacheRoot, compiledModuleCache, originalSourcePathCache, transpiler, ensureRelativeImportPath = (from, target) => {
|
|
1231
|
-
const importPath = relative(dirname2(from), target).replace(/\\/g, "/");
|
|
1232
|
-
return importPath.startsWith(".") ? importPath : `./${importPath}`;
|
|
1233
|
-
}, processDirectoryEntries = (entries, dir, targetFileName, stack) => {
|
|
1234
|
-
for (const entry of entries) {
|
|
1235
|
-
const entryPath = join2(dir, entry.name);
|
|
1236
|
-
if (entry.isDirectory())
|
|
1237
|
-
stack.push(entryPath);
|
|
1238
|
-
if (entry.isFile() && entry.name === targetFileName) {
|
|
1239
|
-
return entryPath;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
return null;
|
|
1243
|
-
}, searchDirectoryLevel = async (dirs, targetFileName) => {
|
|
1244
|
-
if (dirs.length === 0)
|
|
1534
|
+
const maybeSelectors = Reflect.get(maybeDef, "selectors");
|
|
1535
|
+
if (!Array.isArray(maybeSelectors)) {
|
|
1245
1536
|
return null;
|
|
1246
|
-
const nextStack = [];
|
|
1247
|
-
const dirEntries = await Promise.all(dirs.map(async (dir) => ({
|
|
1248
|
-
dir,
|
|
1249
|
-
entries: await readdir(dir, {
|
|
1250
|
-
encoding: "utf-8",
|
|
1251
|
-
withFileTypes: true
|
|
1252
|
-
})
|
|
1253
|
-
})));
|
|
1254
|
-
for (const { dir, entries } of dirEntries) {
|
|
1255
|
-
const found = processDirectoryEntries(entries, dir, targetFileName, nextStack);
|
|
1256
|
-
if (found)
|
|
1257
|
-
return found;
|
|
1258
|
-
}
|
|
1259
|
-
return searchDirectoryLevel(nextStack, targetFileName);
|
|
1260
|
-
}, findSourceFileByBasename = async (searchRoot, targetFileName) => searchDirectoryLevel([searchRoot], targetFileName), normalizeBuiltSvelteFileName = (sourcePath) => basename2(sourcePath).replace(/-[a-z0-9]{6,}(?=\.svelte$)/i, ""), resolveOriginalSourcePath = async (sourcePath) => {
|
|
1261
|
-
const cachedPath = originalSourcePathCache.get(sourcePath);
|
|
1262
|
-
if (cachedPath !== undefined) {
|
|
1263
|
-
return cachedPath;
|
|
1264
1537
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
return sourcePath;
|
|
1268
|
-
}
|
|
1269
|
-
const resolvedSourcePath = await findSourceFileByBasename(join2(process.cwd(), "src"), normalizeBuiltSvelteFileName(sourcePath));
|
|
1270
|
-
const nextPath = resolvedSourcePath ?? sourcePath;
|
|
1271
|
-
originalSourcePathCache.set(sourcePath, nextPath);
|
|
1272
|
-
return nextPath;
|
|
1273
|
-
}, resolveRelativeModule = async (spec, from) => {
|
|
1274
|
-
if (!spec.startsWith(".")) {
|
|
1538
|
+
const [firstSelectorGroup] = maybeSelectors;
|
|
1539
|
+
if (!Array.isArray(firstSelectorGroup)) {
|
|
1275
1540
|
return null;
|
|
1276
1541
|
}
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
];
|
|
1291
|
-
const existResults = await Promise.all(candidates.map((candidate) => Bun.file(candidate).exists()));
|
|
1292
|
-
const foundIndex = existResults.indexOf(true);
|
|
1293
|
-
return foundIndex >= 0 ? candidates[foundIndex] ?? null : null;
|
|
1294
|
-
}, getCachedModulePath = (sourcePath) => {
|
|
1295
|
-
const relativeSourcePath = relative(process.cwd(), sourcePath).replace(/\\/g, "/");
|
|
1296
|
-
const normalizedSourcePath = relativeSourcePath.startsWith("..") ? sourcePath.replace(/[:\\/]/g, "_") : relativeSourcePath;
|
|
1297
|
-
return join2(serverCacheRoot, `${normalizedSourcePath}.server.js`);
|
|
1298
|
-
}, resolveSvelteImport = async (spec, from) => {
|
|
1299
|
-
if (spec.startsWith("/")) {
|
|
1300
|
-
return spec;
|
|
1542
|
+
const [selector] = firstSelectorGroup;
|
|
1543
|
+
return typeof selector === "string" && selector.length > 0 ? selector : null;
|
|
1544
|
+
}, createAngularIslandApp = async () => {
|
|
1545
|
+
const { EnvironmentInjector, provideZonelessChangeDetection } = await import("@angular/core");
|
|
1546
|
+
const { createApplication } = await import("@angular/platform-browser");
|
|
1547
|
+
const app = await createApplication({
|
|
1548
|
+
providers: [provideZonelessChangeDetection()]
|
|
1549
|
+
});
|
|
1550
|
+
const environmentInjector = app.injector.get(EnvironmentInjector);
|
|
1551
|
+
return { app, environmentInjector };
|
|
1552
|
+
}, angularIslandAppPromise = null, getAngularIslandApp = async () => {
|
|
1553
|
+
if (!angularIslandAppPromise) {
|
|
1554
|
+
angularIslandAppPromise = createAngularIslandApp();
|
|
1301
1555
|
}
|
|
1302
|
-
|
|
1556
|
+
return angularIslandAppPromise;
|
|
1557
|
+
}, wrapperMetadataCache, requestRenderCache, getRequestRenderCache = () => {
|
|
1558
|
+
const requestId = getSsrContextId();
|
|
1559
|
+
if (!requestId) {
|
|
1303
1560
|
return null;
|
|
1304
1561
|
}
|
|
1305
|
-
const
|
|
1306
|
-
if (
|
|
1307
|
-
return
|
|
1308
|
-
}
|
|
1309
|
-
const candidate = `${explicitPath}.svelte`;
|
|
1310
|
-
if (await Bun.file(candidate).exists() === true) {
|
|
1311
|
-
return candidate;
|
|
1312
|
-
}
|
|
1313
|
-
return null;
|
|
1314
|
-
}, writeIfChanged = async (path, content) => {
|
|
1315
|
-
const targetFile = Bun.file(path);
|
|
1316
|
-
const exists = await targetFile.exists();
|
|
1317
|
-
if (exists) {
|
|
1318
|
-
const currentContent = await targetFile.text();
|
|
1319
|
-
if (currentContent === content) {
|
|
1320
|
-
return;
|
|
1321
|
-
}
|
|
1562
|
+
const cached = requestRenderCache.get(requestId);
|
|
1563
|
+
if (cached) {
|
|
1564
|
+
return cached;
|
|
1322
1565
|
}
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1566
|
+
const renderCache = new Map;
|
|
1567
|
+
requestRenderCache.set(requestId, renderCache);
|
|
1568
|
+
return renderCache;
|
|
1569
|
+
}, getAngularIslandWrapperKey = (component, _islandId) => {
|
|
1570
|
+
const componentName = typeof component.name === "string" && component.name.length > 0 ? component.name : "AngularIsland";
|
|
1571
|
+
return `${componentName}:${angularIslandSelector}`;
|
|
1572
|
+
}, getIslandRenderCacheKey = (component, props) => {
|
|
1573
|
+
const componentName = typeof component.name === "string" && component.name.length > 0 ? component.name : "AngularIsland";
|
|
1574
|
+
return `${componentName}:${JSON.stringify(props)}`;
|
|
1575
|
+
}, buildAngularIslandWrapperMetadata = async (component, islandId, wrapperKey) => {
|
|
1576
|
+
const { Component, InjectionToken, inject } = await import("@angular/core");
|
|
1577
|
+
const { NgComponentOutlet } = await import("@angular/common");
|
|
1578
|
+
const deps = await getAngularDeps();
|
|
1579
|
+
const selector = getAngularIslandSelector(islandId);
|
|
1580
|
+
const propsToken = new InjectionToken(`${wrapperKey}:props`);
|
|
1581
|
+
|
|
1582
|
+
class AngularIslandWrapperComponent {
|
|
1583
|
+
component = component;
|
|
1584
|
+
props = inject(propsToken);
|
|
1328
1585
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
return
|
|
1345
|
-
compiledPath: await compileSvelteServerModule(resolvedChild),
|
|
1346
|
-
spec
|
|
1347
|
-
};
|
|
1348
|
-
}));
|
|
1349
|
-
for (const result of compiledChildren) {
|
|
1350
|
-
if (result)
|
|
1351
|
-
childModulePaths.set(result.spec, result.compiledPath);
|
|
1586
|
+
return {
|
|
1587
|
+
deps,
|
|
1588
|
+
propsToken,
|
|
1589
|
+
selector,
|
|
1590
|
+
WrapperComponent: Component({
|
|
1591
|
+
imports: [NgComponentOutlet, component],
|
|
1592
|
+
selector,
|
|
1593
|
+
standalone: true,
|
|
1594
|
+
template: '<ng-container *ngComponentOutlet="component; inputs: props"></ng-container>'
|
|
1595
|
+
})(AngularIslandWrapperComponent)
|
|
1596
|
+
};
|
|
1597
|
+
}, createAngularIslandWrapper = async (component, islandId) => {
|
|
1598
|
+
const wrapperKey = getAngularIslandWrapperKey(component, islandId);
|
|
1599
|
+
const cached = wrapperMetadataCache.get(wrapperKey);
|
|
1600
|
+
if (cached) {
|
|
1601
|
+
return cached;
|
|
1352
1602
|
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1603
|
+
const metadataPromise = buildAngularIslandWrapperMetadata(component, islandId, wrapperKey);
|
|
1604
|
+
wrapperMetadataCache.set(wrapperKey, metadataPromise);
|
|
1605
|
+
return metadataPromise;
|
|
1606
|
+
}, extractAngularIslandRoot = (html, selector) => {
|
|
1607
|
+
const openTag = `<${selector}`;
|
|
1608
|
+
const start = html.indexOf(openTag);
|
|
1609
|
+
if (start < 0) {
|
|
1610
|
+
throw new Error(`Could not find Angular island root "${selector}".`);
|
|
1361
1611
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1612
|
+
const endTag = `</${selector}>`;
|
|
1613
|
+
const end = html.indexOf(endTag, start);
|
|
1614
|
+
if (end < 0) {
|
|
1615
|
+
throw new Error(`Could not close Angular island root "${selector}".`);
|
|
1364
1616
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
transpiler = new Bun.Transpiler({
|
|
1391
|
-
loader: "ts",
|
|
1392
|
-
target: "browser"
|
|
1393
|
-
});
|
|
1394
|
-
});
|
|
1395
|
-
|
|
1396
|
-
// src/core/renderIslandMarkup.ts
|
|
1397
|
-
var islandSequence = 0, resolvedServerComponentCache, resolvedServerBuildComponentCache, nextIslandId = () => {
|
|
1398
|
-
islandSequence += 1;
|
|
1399
|
-
return `island-${islandSequence}`;
|
|
1400
|
-
}, isRecord2 = (value) => typeof value === "object" && value !== null, isReactServerIslandComponent = (value) => typeof value === "function", isSvelteServerIslandComponent = (value) => typeof value === "function", isVueServerIslandComponent = (value) => typeof value === "function" || isRecord2(value), isAngularServerIslandComponent = (value) => typeof value === "function", resolveBuildReferencePath = (source, registryPath) => {
|
|
1401
|
-
if (source.startsWith("file://"))
|
|
1402
|
-
return new URL(source).pathname;
|
|
1403
|
-
if (source.startsWith("."))
|
|
1404
|
-
return new URL(source, registryPath).pathname;
|
|
1405
|
-
return source;
|
|
1406
|
-
}, loadAndCompileServerBuildComponent = async (buildReferencePath) => {
|
|
1407
|
-
const compiledModulePath = await compileSvelteServerModule(buildReferencePath);
|
|
1408
|
-
const loadedModule = await import(compiledModulePath);
|
|
1409
|
-
return "default" in loadedModule ? loadedModule.default : loadedModule;
|
|
1410
|
-
}, loadServerBuildComponent = async (buildReferencePath) => {
|
|
1411
|
-
const cachedBuildComponent = resolvedServerBuildComponentCache.get(buildReferencePath);
|
|
1412
|
-
if (cachedBuildComponent) {
|
|
1413
|
-
return cachedBuildComponent;
|
|
1414
|
-
}
|
|
1415
|
-
const loadPromise = loadAndCompileServerBuildComponent(buildReferencePath);
|
|
1416
|
-
resolvedServerBuildComponentCache.set(buildReferencePath, loadPromise);
|
|
1417
|
-
return loadPromise;
|
|
1418
|
-
}, loadServerImportComponent = async (resolvedComponent) => {
|
|
1419
|
-
const resolvedModulePath = resolvedComponent.startsWith(".") ? new URL(resolvedComponent, import.meta.url).pathname : resolvedComponent;
|
|
1420
|
-
const importTarget = resolvedModulePath.endsWith(".svelte") ? await compileSvelteServerModule(resolvedModulePath) : resolvedModulePath;
|
|
1421
|
-
const loadedModule = await import(importTarget);
|
|
1422
|
-
return "default" in loadedModule ? loadedModule.default : loadedModule;
|
|
1423
|
-
}, resolveIslandComponent = async (component) => {
|
|
1424
|
-
const buildReference = getIslandBuildReference(component);
|
|
1425
|
-
const buildReferencePath = buildReference?.source ? resolveBuildReferencePath(buildReference.source, import.meta.url) : null;
|
|
1426
|
-
if (buildReferencePath?.endsWith(".svelte")) {
|
|
1427
|
-
return loadServerBuildComponent(buildReferencePath);
|
|
1428
|
-
}
|
|
1429
|
-
const resolvedComponent = getIslandComponent(component);
|
|
1430
|
-
if (typeof resolvedComponent !== "string") {
|
|
1431
|
-
return resolvedComponent;
|
|
1432
|
-
}
|
|
1433
|
-
return loadServerImportComponent(resolvedComponent);
|
|
1434
|
-
}, resolveServerIslandComponent = async (component) => {
|
|
1435
|
-
const cachedResolvedComponent = resolvedServerComponentCache.get(component);
|
|
1436
|
-
if (cachedResolvedComponent) {
|
|
1437
|
-
return cachedResolvedComponent;
|
|
1438
|
-
}
|
|
1439
|
-
const resolutionPromise = resolveIslandComponent(component);
|
|
1440
|
-
resolvedServerComponentCache.set(component, resolutionPromise);
|
|
1441
|
-
return resolutionPromise;
|
|
1442
|
-
}, resolveReactServerIslandComponent = async (component) => {
|
|
1443
|
-
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
1444
|
-
if (!isReactServerIslandComponent(resolvedComponent)) {
|
|
1445
|
-
throw new Error("Resolved React island is not a valid React component.");
|
|
1446
|
-
}
|
|
1447
|
-
return resolvedComponent;
|
|
1448
|
-
}, resolveSvelteServerIslandComponent = async (component) => {
|
|
1449
|
-
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
1450
|
-
if (!isSvelteServerIslandComponent(resolvedComponent)) {
|
|
1451
|
-
throw new Error("Resolved Svelte island is not a valid Svelte component.");
|
|
1452
|
-
}
|
|
1453
|
-
return resolvedComponent;
|
|
1454
|
-
}, resolveVueServerIslandComponent = async (component) => {
|
|
1455
|
-
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
1456
|
-
if (!isVueServerIslandComponent(resolvedComponent)) {
|
|
1457
|
-
throw new Error("Resolved Vue island is not a valid Vue component.");
|
|
1458
|
-
}
|
|
1459
|
-
return resolvedComponent;
|
|
1460
|
-
}, resolveAngularServerIslandComponent = async (component) => {
|
|
1461
|
-
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
1462
|
-
if (!isAngularServerIslandComponent(resolvedComponent)) {
|
|
1463
|
-
throw new Error("Resolved Angular island is not a valid Angular component.");
|
|
1464
|
-
}
|
|
1465
|
-
return resolvedComponent;
|
|
1466
|
-
}, renderIslandMarkup = async (registry, props) => {
|
|
1467
|
-
const result = await renderIslandResult(registry, props);
|
|
1468
|
-
return `<div ${serializeIslandAttributes(result.attributes)}>${result.html}</div>`;
|
|
1469
|
-
}, renderIslandResult = async (registry, props) => {
|
|
1470
|
-
const islandId = nextIslandId();
|
|
1471
|
-
const attributes = getIslandMarkerAttributes(props);
|
|
1472
|
-
if (props.framework === "react") {
|
|
1473
|
-
const entry = registry.react?.[props.component];
|
|
1474
|
-
if (!entry) {
|
|
1475
|
-
throw new Error(`Island component "${props.component}" is not registered for framework "react".`);
|
|
1476
|
-
}
|
|
1477
|
-
const component = await resolveReactServerIslandComponent(entry);
|
|
1478
|
-
const html = renderReactIslandToHtml(component, props.props);
|
|
1479
|
-
return { attributes, html };
|
|
1480
|
-
}
|
|
1481
|
-
if (props.framework === "svelte") {
|
|
1482
|
-
const entry = registry.svelte?.[props.component];
|
|
1483
|
-
if (!entry) {
|
|
1484
|
-
throw new Error(`Island component "${props.component}" is not registered for framework "svelte".`);
|
|
1485
|
-
}
|
|
1486
|
-
const component = await resolveSvelteServerIslandComponent(entry);
|
|
1487
|
-
const html = renderSvelteIslandToHtml(component, props.props);
|
|
1488
|
-
return { attributes, html };
|
|
1489
|
-
}
|
|
1490
|
-
if (props.framework === "vue") {
|
|
1491
|
-
const entry = registry.vue?.[props.component];
|
|
1492
|
-
if (!entry) {
|
|
1493
|
-
throw new Error(`Island component "${props.component}" is not registered for framework "vue".`);
|
|
1494
|
-
}
|
|
1495
|
-
const component = await resolveVueServerIslandComponent(entry);
|
|
1496
|
-
const html = await renderVueIslandToHtml(component, props.props);
|
|
1497
|
-
return { attributes, html };
|
|
1498
|
-
}
|
|
1499
|
-
if (props.framework === "angular") {
|
|
1500
|
-
const entry = registry.angular?.[props.component];
|
|
1501
|
-
if (!entry) {
|
|
1502
|
-
throw new Error(`Island component "${props.component}" is not registered for framework "angular".`);
|
|
1503
|
-
}
|
|
1504
|
-
const component = await resolveAngularServerIslandComponent(entry);
|
|
1505
|
-
const html = await renderAngularIslandToHtml(component, props.props, islandId);
|
|
1506
|
-
return {
|
|
1507
|
-
attributes: {
|
|
1508
|
-
...getIslandMarkerAttributes(props, islandId)
|
|
1509
|
-
},
|
|
1510
|
-
html
|
|
1511
|
-
};
|
|
1512
|
-
}
|
|
1513
|
-
throw new Error(`Framework "${props.framework}" is not implemented in this prototype.`);
|
|
1514
|
-
};
|
|
1515
|
-
var init_renderIslandMarkup = __esm(() => {
|
|
1516
|
-
init_islandSsr();
|
|
1517
|
-
init_svelteServerModule();
|
|
1518
|
-
init_islandMarkupAttributes();
|
|
1519
|
-
init_islands();
|
|
1520
|
-
resolvedServerComponentCache = new Map;
|
|
1521
|
-
resolvedServerBuildComponentCache = new Map;
|
|
1522
|
-
});
|
|
1523
|
-
|
|
1524
|
-
// src/client/streamSwap.ts
|
|
1525
|
-
var streamSwapRuntime = () => {
|
|
1526
|
-
if (window.__ABS_SLOT_RUNTIME__ === true)
|
|
1527
|
-
return;
|
|
1528
|
-
window.__ABS_SLOT_RUNTIME__ = true;
|
|
1529
|
-
window.__ABS_SLOT_PENDING__ = window.__ABS_SLOT_PENDING__ ?? {};
|
|
1530
|
-
const pending = window.__ABS_SLOT_PENDING__;
|
|
1531
|
-
const apply = (id, html) => {
|
|
1532
|
-
const node = document.getElementById(`slot-${id}`);
|
|
1533
|
-
if (!node) {
|
|
1534
|
-
pending[id] = html;
|
|
1535
|
-
return;
|
|
1536
|
-
}
|
|
1537
|
-
node.innerHTML = html;
|
|
1538
|
-
delete pending[id];
|
|
1539
|
-
};
|
|
1540
|
-
const flush = () => {
|
|
1541
|
-
for (const id in pending) {
|
|
1542
|
-
if (!Object.prototype.hasOwnProperty.call(pending, id))
|
|
1543
|
-
continue;
|
|
1544
|
-
apply(id, pending[id] ?? "");
|
|
1545
|
-
}
|
|
1546
|
-
};
|
|
1547
|
-
window.__ABS_SLOT_ENQUEUE__ = (id, html) => {
|
|
1548
|
-
apply(id, html);
|
|
1549
|
-
};
|
|
1550
|
-
if (typeof MutationObserver === "function") {
|
|
1551
|
-
const observer = new MutationObserver(flush);
|
|
1552
|
-
const root = document.documentElement ?? document.body ?? document;
|
|
1553
|
-
observer.observe(root, { childList: true, subtree: true });
|
|
1554
|
-
}
|
|
1555
|
-
if (document.readyState === "loading") {
|
|
1556
|
-
document.addEventListener("DOMContentLoaded", flush, { once: true });
|
|
1557
|
-
}
|
|
1558
|
-
flush();
|
|
1559
|
-
};
|
|
1560
|
-
var stripFunctionWrapper = (value) => {
|
|
1561
|
-
const start = value.indexOf("{");
|
|
1562
|
-
const end = value.lastIndexOf("}");
|
|
1563
|
-
if (start < 0 || end <= start)
|
|
1564
|
-
return "";
|
|
1565
|
-
return value.slice(start + 1, end);
|
|
1566
|
-
};
|
|
1567
|
-
var getStreamSwapRuntimeScript = () => `(function(){${stripFunctionWrapper(streamSwapRuntime.toString())}})();`;
|
|
1568
|
-
|
|
1569
|
-
// src/utils/streamingSlots.ts
|
|
1570
|
-
init_escapeScriptContent();
|
|
1571
|
-
var SLOT_ID_PREFIX = "abs-slot-";
|
|
1572
|
-
var SLOT_PLACEHOLDER_PREFIX = "slot-";
|
|
1573
|
-
var CLOSING_HEAD_TAG = "</head>";
|
|
1574
|
-
var CLOSING_HEAD_TAG_LENGTH = CLOSING_HEAD_TAG.length;
|
|
1575
|
-
var CLOSING_PAGE_TAG_REGEX = /<\/body>\s*<\/html>\s*$/i;
|
|
1576
|
-
var STREAMING_RUNTIME_GLOBAL = "__ABS_SLOT_ENQUEUE__";
|
|
1577
|
-
var STREAMING_PENDING_GLOBAL = "__ABS_SLOT_PENDING__";
|
|
1578
|
-
var STREAM_TAIL_LOOKBEHIND = 128;
|
|
1579
|
-
var STREAMING_SLOT_TIMEOUT_MS = 5000;
|
|
1580
|
-
var STREAMING_SLOT_MAX_PER_RESPONSE = 128;
|
|
1581
|
-
var STREAMING_SLOT_MAX_HTML_BYTES = 64000;
|
|
1582
|
-
var createSlotPlaceholderId = (id) => `${SLOT_PLACEHOLDER_PREFIX}${id}`;
|
|
1583
|
-
var createSlotPatchStatement = (id, html) => `(window.${STREAMING_RUNTIME_GLOBAL}||function(i,h){window.${STREAMING_PENDING_GLOBAL}=window.${STREAMING_PENDING_GLOBAL}||{};window.${STREAMING_PENDING_GLOBAL}[i]=h;})(${JSON.stringify(id)},${JSON.stringify(html)});`;
|
|
1584
|
-
var createNonceAttr = (nonce) => nonce ? ` nonce="${nonce}"` : "";
|
|
1585
|
-
var createStreamingSlotId = () => `${SLOT_ID_PREFIX}${Math.random().toString(36).slice(2, 10)}`;
|
|
1586
|
-
var getStreamingSlotsRuntimeScript = () => getStreamSwapRuntimeScript();
|
|
1587
|
-
var renderStreamingSlotsRuntimeTag = (nonce) => `<script${createNonceAttr(nonce)}>${escapeScriptContent(getStreamingSlotsRuntimeScript())}</script>`;
|
|
1588
|
-
var renderStreamingSlotPlaceholder = (id, fallbackHtml = "") => `<div id="${createSlotPlaceholderId(id)}" data-absolute-slot="true">${fallbackHtml}</div>`;
|
|
1589
|
-
var renderStreamingSlotPatchTag = (id, html, nonce) => `<script${createNonceAttr(nonce)}>${escapeScriptContent(createSlotPatchStatement(id, html))}</script>`;
|
|
1590
|
-
var injectHtmlIntoHead = (html, injection) => {
|
|
1591
|
-
const closingHeadIndex = html.indexOf(CLOSING_HEAD_TAG);
|
|
1592
|
-
if (closingHeadIndex >= 0) {
|
|
1593
|
-
return `${html.slice(0, closingHeadIndex)}${injection}${html.slice(closingHeadIndex)}`;
|
|
1594
|
-
}
|
|
1595
|
-
return `${html}${injection}`;
|
|
1596
|
-
};
|
|
1597
|
-
var toUint8 = (value, encoder) => encoder.encode(value);
|
|
1598
|
-
var currentStreamingSlotPolicy = {
|
|
1599
|
-
timeoutMs: STREAMING_SLOT_TIMEOUT_MS,
|
|
1600
|
-
fallbackHtml: "",
|
|
1601
|
-
errorHtml: undefined,
|
|
1602
|
-
maxSlotsPerResponse: STREAMING_SLOT_MAX_PER_RESPONSE,
|
|
1603
|
-
maxSlotHtmlSizeBytes: STREAMING_SLOT_MAX_HTML_BYTES
|
|
1604
|
-
};
|
|
1605
|
-
var clonePolicy = (policy) => ({
|
|
1606
|
-
...policy
|
|
1607
|
-
});
|
|
1608
|
-
var normalizeSlotBytes = (value, fallback) => {
|
|
1609
|
-
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
1610
|
-
return Math.floor(value);
|
|
1611
|
-
}
|
|
1612
|
-
return fallback;
|
|
1613
|
-
};
|
|
1614
|
-
var normalizeSlotText = (value, fallback) => typeof value === "string" ? value : fallback;
|
|
1615
|
-
var normalizeSlotError = (value, fallback) => typeof value === "string" ? value : fallback;
|
|
1616
|
-
var hasPolicyValue = (policy, key) => Object.prototype.hasOwnProperty.call(policy, key);
|
|
1617
|
-
var applyStreamingSlotPolicyOverrides = (base, overridePolicy = {}) => ({
|
|
1618
|
-
timeoutMs: hasPolicyValue(overridePolicy, "timeoutMs") ? normalizeSlotBytes(overridePolicy.timeoutMs, base.timeoutMs) : base.timeoutMs,
|
|
1619
|
-
fallbackHtml: hasPolicyValue(overridePolicy, "fallbackHtml") ? normalizeSlotText(overridePolicy.fallbackHtml, "") : base.fallbackHtml,
|
|
1620
|
-
errorHtml: hasPolicyValue(overridePolicy, "errorHtml") ? normalizeSlotError(overridePolicy.errorHtml) : base.errorHtml,
|
|
1621
|
-
maxSlotsPerResponse: hasPolicyValue(overridePolicy, "maxSlotsPerResponse") ? normalizeSlotBytes(overridePolicy.maxSlotsPerResponse, base.maxSlotsPerResponse) : base.maxSlotsPerResponse,
|
|
1622
|
-
maxSlotHtmlSizeBytes: hasPolicyValue(overridePolicy, "maxSlotHtmlSizeBytes") ? normalizeSlotBytes(overridePolicy.maxSlotHtmlSizeBytes, base.maxSlotHtmlSizeBytes) : base.maxSlotHtmlSizeBytes,
|
|
1623
|
-
onError: hasPolicyValue(overridePolicy, "onError") ? overridePolicy.onError : base.onError,
|
|
1624
|
-
onSlotMetric: hasPolicyValue(overridePolicy, "onSlotMetric") ? overridePolicy.onSlotMetric : base.onSlotMetric
|
|
1625
|
-
});
|
|
1626
|
-
var createCombinedSlotErrorHandler = (policyOnError, enhancerOnError) => {
|
|
1627
|
-
if (!policyOnError && !enhancerOnError)
|
|
1628
|
-
return;
|
|
1629
|
-
return (error, slot) => {
|
|
1630
|
-
policyOnError?.(error, slot);
|
|
1631
|
-
enhancerOnError?.(error, slot);
|
|
1632
|
-
};
|
|
1633
|
-
};
|
|
1634
|
-
var createCombinedSlotMetricHandler = (policyOnSlotMetric, callOnSlotMetric) => {
|
|
1635
|
-
if (!policyOnSlotMetric && !callOnSlotMetric)
|
|
1636
|
-
return;
|
|
1637
|
-
return (metric) => {
|
|
1638
|
-
policyOnSlotMetric?.(metric);
|
|
1639
|
-
callOnSlotMetric?.(metric);
|
|
1640
|
-
};
|
|
1641
|
-
};
|
|
1642
|
-
var resolveStreamingSlotPolicy = (overridePolicy = {}) => {
|
|
1643
|
-
const base = getStreamingSlotPolicy();
|
|
1644
|
-
return applyStreamingSlotPolicyOverrides(base, overridePolicy);
|
|
1645
|
-
};
|
|
1646
|
-
var getStreamingSlotPolicy = () => clonePolicy(currentStreamingSlotPolicy);
|
|
1647
|
-
var setStreamingSlotPolicy = (policy = {}) => {
|
|
1648
|
-
const base = getStreamingSlotPolicy();
|
|
1649
|
-
currentStreamingSlotPolicy = applyStreamingSlotPolicyOverrides(base, policy);
|
|
1650
|
-
};
|
|
1651
|
-
var withStreamingSlotPolicy = async (policy, callback) => {
|
|
1652
|
-
const previous = getStreamingSlotPolicy();
|
|
1653
|
-
setStreamingSlotPolicy(policy);
|
|
1654
|
-
try {
|
|
1655
|
-
return await callback();
|
|
1656
|
-
} finally {
|
|
1657
|
-
currentStreamingSlotPolicy = previous;
|
|
1658
|
-
}
|
|
1659
|
-
};
|
|
1660
|
-
var emitSlotMetric = (metric, onSlotMetric) => {
|
|
1661
|
-
onSlotMetric?.(metric);
|
|
1662
|
-
};
|
|
1663
|
-
var createTimeoutError = (slot, timeoutMs) => {
|
|
1664
|
-
const error = new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`);
|
|
1665
|
-
error.__absTimeout = true;
|
|
1666
|
-
return error;
|
|
1667
|
-
};
|
|
1668
|
-
var toStreamingSlot = (slot, policy) => ({
|
|
1669
|
-
errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
|
|
1670
|
-
fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
|
|
1671
|
-
id: slot.id ?? createStreamingSlotId(),
|
|
1672
|
-
timeoutMs: normalizeSlotBytes(slot.timeoutMs, policy.timeoutMs),
|
|
1673
|
-
resolve: slot.resolve
|
|
1674
|
-
});
|
|
1675
|
-
var prepareSlots = ({
|
|
1676
|
-
policy,
|
|
1677
|
-
slots,
|
|
1678
|
-
onError,
|
|
1679
|
-
onSlotMetric
|
|
1680
|
-
}) => {
|
|
1681
|
-
const preparedSlots = slots.map((slot) => toStreamingSlot(slot, policy));
|
|
1682
|
-
const maxSlotsPerResponse = policy.maxSlotsPerResponse;
|
|
1683
|
-
if (maxSlotsPerResponse === 0) {
|
|
1684
|
-
const error = new Error("Streaming slot limit is set to 0");
|
|
1685
|
-
for (const slot of preparedSlots) {
|
|
1686
|
-
onError?.(error, slot);
|
|
1687
|
-
emitSlotMetric({
|
|
1688
|
-
type: "dropped",
|
|
1689
|
-
slotId: slot.id,
|
|
1690
|
-
reason: "maxSlotsPerResponse is 0"
|
|
1691
|
-
}, onSlotMetric);
|
|
1692
|
-
}
|
|
1693
|
-
return [];
|
|
1694
|
-
}
|
|
1695
|
-
if (preparedSlots.length <= maxSlotsPerResponse) {
|
|
1696
|
-
preparedSlots.forEach((slot) => emitSlotMetric({
|
|
1697
|
-
type: "prepared",
|
|
1698
|
-
slotId: slot.id
|
|
1699
|
-
}, onSlotMetric));
|
|
1700
|
-
return preparedSlots;
|
|
1701
|
-
}
|
|
1702
|
-
const keptSlots = preparedSlots.slice(0, maxSlotsPerResponse);
|
|
1703
|
-
const droppedSlots = preparedSlots.slice(maxSlotsPerResponse);
|
|
1704
|
-
droppedSlots.forEach((slot) => {
|
|
1705
|
-
onError?.(new Error(`Streaming slot "${slot.id}" dropped because ${maxSlotsPerResponse} slots is the configured maximum`), slot);
|
|
1706
|
-
emitSlotMetric({
|
|
1707
|
-
type: "dropped",
|
|
1708
|
-
slotId: slot.id,
|
|
1709
|
-
reason: `maxSlotsPerResponse is ${maxSlotsPerResponse}`
|
|
1710
|
-
}, onSlotMetric);
|
|
1711
|
-
});
|
|
1712
|
-
keptSlots.forEach((slot) => emitSlotMetric({
|
|
1713
|
-
type: "prepared",
|
|
1714
|
-
slotId: slot.id
|
|
1715
|
-
}, onSlotMetric));
|
|
1716
|
-
return keptSlots;
|
|
1717
|
-
};
|
|
1718
|
-
var htmlByteLength = (value, encoder) => encoder.encode(value).length;
|
|
1719
|
-
var resolveSlot = async (slot, onError, policy, onSlotMetric) => {
|
|
1720
|
-
const safePolicy = policy ?? getStreamingSlotPolicy();
|
|
1721
|
-
const encoder = new TextEncoder;
|
|
1722
|
-
const start = Date.now();
|
|
1723
|
-
try {
|
|
1724
|
-
const maybeAsyncValue = Promise.resolve(slot.resolve());
|
|
1725
|
-
const resolved = typeof slot.timeoutMs === "number" && slot.timeoutMs > 0 ? await Promise.race([
|
|
1726
|
-
maybeAsyncValue,
|
|
1727
|
-
new Promise((_, reject) => setTimeout(() => {
|
|
1728
|
-
reject(createTimeoutError(slot, slot.timeoutMs ?? 0));
|
|
1729
|
-
}, slot.timeoutMs))
|
|
1730
|
-
]) : await maybeAsyncValue;
|
|
1731
|
-
const html = typeof resolved === "string" ? resolved : `${resolved}`;
|
|
1732
|
-
if (safePolicy.maxSlotHtmlSizeBytes > 0 && htmlByteLength(html, encoder) > safePolicy.maxSlotHtmlSizeBytes) {
|
|
1733
|
-
const bytes2 = htmlByteLength(html, encoder);
|
|
1734
|
-
const error = new Error(`Streaming slot "${slot.id}" exceeded max payload size of ${safePolicy.maxSlotHtmlSizeBytes} bytes`);
|
|
1735
|
-
const durationMs2 = Date.now() - start;
|
|
1736
|
-
onError?.(error, slot);
|
|
1737
|
-
emitSlotMetric({
|
|
1738
|
-
type: "size_exceeded",
|
|
1739
|
-
slotId: slot.id,
|
|
1740
|
-
durationMs: durationMs2,
|
|
1741
|
-
bytes: bytes2,
|
|
1742
|
-
error
|
|
1743
|
-
}, onSlotMetric);
|
|
1744
|
-
const fallbackHtml = typeof slot.errorHtml === "string" ? slot.errorHtml : null;
|
|
1745
|
-
return {
|
|
1746
|
-
html: fallbackHtml,
|
|
1747
|
-
id: slot.id,
|
|
1748
|
-
durationMs: durationMs2,
|
|
1749
|
-
bytes: fallbackHtml === null ? 0 : htmlByteLength(fallbackHtml, encoder)
|
|
1750
|
-
};
|
|
1751
|
-
}
|
|
1752
|
-
const durationMs = Date.now() - start;
|
|
1753
|
-
const bytes = htmlByteLength(html, encoder);
|
|
1754
|
-
emitSlotMetric({
|
|
1755
|
-
type: "resolved",
|
|
1756
|
-
slotId: slot.id,
|
|
1757
|
-
durationMs,
|
|
1758
|
-
bytes
|
|
1759
|
-
}, onSlotMetric);
|
|
1760
|
-
return {
|
|
1761
|
-
html,
|
|
1762
|
-
id: slot.id,
|
|
1763
|
-
durationMs,
|
|
1764
|
-
bytes
|
|
1765
|
-
};
|
|
1766
|
-
} catch (error) {
|
|
1767
|
-
const durationMs = Date.now() - start;
|
|
1768
|
-
onError?.(error, slot);
|
|
1769
|
-
emitSlotMetric({
|
|
1770
|
-
type: error?.__absTimeout === true ? "timeout" : "error",
|
|
1771
|
-
slotId: slot.id,
|
|
1772
|
-
durationMs,
|
|
1773
|
-
error
|
|
1774
|
-
}, onSlotMetric);
|
|
1775
|
-
if (typeof slot.errorHtml === "string") {
|
|
1776
|
-
const html = slot.errorHtml;
|
|
1777
|
-
return {
|
|
1778
|
-
html,
|
|
1779
|
-
id: slot.id,
|
|
1780
|
-
durationMs,
|
|
1781
|
-
bytes: htmlByteLength(html, encoder)
|
|
1782
|
-
};
|
|
1783
|
-
}
|
|
1784
|
-
return {
|
|
1785
|
-
html: null,
|
|
1786
|
-
id: slot.id,
|
|
1787
|
-
durationMs,
|
|
1788
|
-
bytes: 0
|
|
1789
|
-
};
|
|
1790
|
-
}
|
|
1791
|
-
};
|
|
1792
|
-
var nextResolvedSlot = async (pending) => {
|
|
1793
|
-
const wrapped = pending.map((promise) => promise.then((result) => ({
|
|
1794
|
-
original: promise,
|
|
1795
|
-
result
|
|
1796
|
-
})));
|
|
1797
|
-
return Promise.race(wrapped);
|
|
1798
|
-
};
|
|
1799
|
-
var streamChunkToString = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true });
|
|
1800
|
-
var streamOutOfOrderSlots = ({
|
|
1801
|
-
footerHtml = "",
|
|
1802
|
-
headerHtml = "",
|
|
1803
|
-
nonce,
|
|
1804
|
-
policy,
|
|
1805
|
-
onSlotMetric,
|
|
1806
|
-
onError,
|
|
1807
|
-
slots
|
|
1808
|
-
}) => {
|
|
1809
|
-
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
1810
|
-
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
1811
|
-
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
1812
|
-
const effectivePolicy = {
|
|
1813
|
-
...resolvedPolicy,
|
|
1814
|
-
onSlotMetric: combinedOnSlotMetric
|
|
1815
|
-
};
|
|
1816
|
-
const preparedSlots = prepareSlots({
|
|
1817
|
-
policy: effectivePolicy,
|
|
1818
|
-
slots,
|
|
1819
|
-
onError: combinedOnError,
|
|
1820
|
-
onSlotMetric: combinedOnSlotMetric
|
|
1821
|
-
});
|
|
1822
|
-
const encoder = new TextEncoder;
|
|
1823
|
-
return new ReadableStream({
|
|
1824
|
-
async start(controller) {
|
|
1825
|
-
try {
|
|
1826
|
-
let header = headerHtml;
|
|
1827
|
-
if (preparedSlots.length > 0 && !header.includes(STREAMING_RUNTIME_GLOBAL)) {
|
|
1828
|
-
header = injectHtmlIntoHead(header, renderStreamingSlotsRuntimeTag(nonce));
|
|
1829
|
-
}
|
|
1830
|
-
controller.enqueue(toUint8(header, encoder));
|
|
1831
|
-
const pending = preparedSlots.map((slot) => {
|
|
1832
|
-
const fallback = renderStreamingSlotPlaceholder(slot.id, slot.fallbackHtml ?? "");
|
|
1833
|
-
controller.enqueue(toUint8(fallback, encoder));
|
|
1834
|
-
return resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric);
|
|
1835
|
-
});
|
|
1836
|
-
while (pending.length > 0) {
|
|
1837
|
-
const { original, result } = await nextResolvedSlot(pending);
|
|
1838
|
-
const index = pending.indexOf(original);
|
|
1839
|
-
if (index >= 0)
|
|
1840
|
-
pending.splice(index, 1);
|
|
1841
|
-
if (result.html === null)
|
|
1842
|
-
continue;
|
|
1843
|
-
emitSlotMetric({
|
|
1844
|
-
type: "patched",
|
|
1845
|
-
slotId: result.id,
|
|
1846
|
-
durationMs: result.durationMs,
|
|
1847
|
-
bytes: result.bytes
|
|
1848
|
-
}, combinedOnSlotMetric);
|
|
1849
|
-
controller.enqueue(toUint8(renderStreamingSlotPatchTag(result.id, result.html, nonce), encoder));
|
|
1850
|
-
}
|
|
1851
|
-
if (footerHtml.length > 0) {
|
|
1852
|
-
controller.enqueue(toUint8(footerHtml, encoder));
|
|
1853
|
-
}
|
|
1854
|
-
controller.close();
|
|
1855
|
-
} catch (error) {
|
|
1856
|
-
controller.error(error);
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
});
|
|
1860
|
-
};
|
|
1861
|
-
var injectStreamingRuntimeIntoStream = (stream, nonce) => {
|
|
1862
|
-
const runtimeTag = renderStreamingSlotsRuntimeTag(nonce);
|
|
1863
|
-
const encoder = new TextEncoder;
|
|
1864
|
-
const decoder = new TextDecoder;
|
|
1865
|
-
const lookbehind = CLOSING_HEAD_TAG_LENGTH - 1;
|
|
1866
|
-
return new ReadableStream({
|
|
1867
|
-
async start(controller) {
|
|
1868
|
-
const reader = stream.getReader();
|
|
1869
|
-
let injected = false;
|
|
1870
|
-
let pending = "";
|
|
1871
|
-
try {
|
|
1872
|
-
for (;; ) {
|
|
1873
|
-
const { done, value } = await reader.read();
|
|
1874
|
-
if (done)
|
|
1875
|
-
break;
|
|
1876
|
-
if (!value)
|
|
1877
|
-
continue;
|
|
1878
|
-
pending += streamChunkToString(value, decoder);
|
|
1879
|
-
if (injected) {
|
|
1880
|
-
controller.enqueue(encoder.encode(pending));
|
|
1881
|
-
pending = "";
|
|
1882
|
-
continue;
|
|
1883
|
-
}
|
|
1884
|
-
const headIndex = pending.indexOf(CLOSING_HEAD_TAG);
|
|
1885
|
-
if (headIndex >= 0) {
|
|
1886
|
-
const withRuntime = `${pending.slice(0, headIndex)}${runtimeTag}${pending.slice(headIndex)}`;
|
|
1887
|
-
controller.enqueue(encoder.encode(withRuntime));
|
|
1888
|
-
pending = "";
|
|
1889
|
-
injected = true;
|
|
1890
|
-
continue;
|
|
1891
|
-
}
|
|
1892
|
-
if (pending.length > lookbehind) {
|
|
1893
|
-
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
1894
|
-
controller.enqueue(encoder.encode(safeText));
|
|
1895
|
-
pending = pending.slice(-lookbehind);
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
pending += decoder.decode();
|
|
1899
|
-
if (!injected) {
|
|
1900
|
-
pending = injectHtmlIntoHead(pending, runtimeTag);
|
|
1901
|
-
}
|
|
1902
|
-
if (pending.length > 0) {
|
|
1903
|
-
controller.enqueue(encoder.encode(pending));
|
|
1904
|
-
}
|
|
1905
|
-
controller.close();
|
|
1906
|
-
} catch (error) {
|
|
1907
|
-
controller.error(error);
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
});
|
|
1911
|
-
};
|
|
1912
|
-
var appendStreamingSlotPatchesToStream = (stream, slots = [], {
|
|
1913
|
-
injectRuntime = true,
|
|
1914
|
-
nonce,
|
|
1915
|
-
onError,
|
|
1916
|
-
onSlotMetric,
|
|
1917
|
-
policy
|
|
1918
|
-
} = {}) => {
|
|
1919
|
-
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
1920
|
-
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
1921
|
-
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
1922
|
-
const effectivePolicy = {
|
|
1923
|
-
...resolvedPolicy,
|
|
1924
|
-
onSlotMetric: combinedOnSlotMetric
|
|
1925
|
-
};
|
|
1926
|
-
const preparedSlots = prepareSlots({
|
|
1927
|
-
policy: effectivePolicy,
|
|
1928
|
-
slots,
|
|
1929
|
-
onError: combinedOnError,
|
|
1930
|
-
onSlotMetric: combinedOnSlotMetric
|
|
1931
|
-
});
|
|
1932
|
-
if (preparedSlots.length === 0)
|
|
1933
|
-
return stream;
|
|
1934
|
-
const source = injectRuntime ? injectStreamingRuntimeIntoStream(stream, nonce) : stream;
|
|
1935
|
-
const encoder = new TextEncoder;
|
|
1936
|
-
const decoder = new TextDecoder;
|
|
1937
|
-
const reader = source.getReader();
|
|
1938
|
-
const pending = preparedSlots.map((slot) => resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric));
|
|
1939
|
-
return new ReadableStream({
|
|
1940
|
-
async start(controller) {
|
|
1941
|
-
let baseDone = false;
|
|
1942
|
-
let baseRead = reader.read();
|
|
1943
|
-
let tail = "";
|
|
1944
|
-
let footer = "";
|
|
1945
|
-
try {
|
|
1946
|
-
while (!baseDone || pending.length > 0) {
|
|
1947
|
-
const racers = [];
|
|
1948
|
-
if (!baseDone) {
|
|
1949
|
-
racers.push(baseRead.then(({ done, value }) => ({
|
|
1950
|
-
done,
|
|
1951
|
-
kind: "base",
|
|
1952
|
-
value
|
|
1953
|
-
})));
|
|
1954
|
-
}
|
|
1955
|
-
if (pending.length > 0) {
|
|
1956
|
-
racers.push(nextResolvedSlot(pending).then((resolved) => ({
|
|
1957
|
-
kind: "slot",
|
|
1958
|
-
...resolved
|
|
1959
|
-
})));
|
|
1960
|
-
}
|
|
1961
|
-
if (racers.length === 0)
|
|
1962
|
-
break;
|
|
1963
|
-
const winner = await Promise.race(racers);
|
|
1964
|
-
if (winner.kind === "base") {
|
|
1965
|
-
if (winner.done) {
|
|
1966
|
-
baseDone = true;
|
|
1967
|
-
tail += decoder.decode();
|
|
1968
|
-
const footerStart = tail.search(CLOSING_PAGE_TAG_REGEX);
|
|
1969
|
-
if (footerStart >= 0) {
|
|
1970
|
-
const content = tail.slice(0, footerStart);
|
|
1971
|
-
footer = tail.slice(footerStart);
|
|
1972
|
-
if (content.length > 0) {
|
|
1973
|
-
controller.enqueue(encoder.encode(content));
|
|
1974
|
-
}
|
|
1975
|
-
} else if (tail.length > 0) {
|
|
1976
|
-
controller.enqueue(encoder.encode(tail));
|
|
1977
|
-
}
|
|
1978
|
-
tail = "";
|
|
1979
|
-
} else if (winner.value) {
|
|
1980
|
-
tail += streamChunkToString(winner.value, decoder);
|
|
1981
|
-
if (tail.length > STREAM_TAIL_LOOKBEHIND) {
|
|
1982
|
-
const content = tail.slice(0, tail.length - STREAM_TAIL_LOOKBEHIND);
|
|
1983
|
-
controller.enqueue(encoder.encode(content));
|
|
1984
|
-
tail = tail.slice(-STREAM_TAIL_LOOKBEHIND);
|
|
1985
|
-
}
|
|
1986
|
-
baseRead = reader.read();
|
|
1987
|
-
}
|
|
1988
|
-
continue;
|
|
1989
|
-
}
|
|
1990
|
-
const index = pending.indexOf(winner.original);
|
|
1991
|
-
if (index >= 0)
|
|
1992
|
-
pending.splice(index, 1);
|
|
1993
|
-
if (winner.result.html === null)
|
|
1994
|
-
continue;
|
|
1995
|
-
emitSlotMetric({
|
|
1996
|
-
type: "patched",
|
|
1997
|
-
slotId: winner.result.id,
|
|
1998
|
-
durationMs: winner.result.durationMs,
|
|
1999
|
-
bytes: winner.result.bytes
|
|
2000
|
-
}, combinedOnSlotMetric);
|
|
2001
|
-
controller.enqueue(encoder.encode(renderStreamingSlotPatchTag(winner.result.id, winner.result.html, nonce)));
|
|
2002
|
-
}
|
|
2003
|
-
if (footer.length > 0)
|
|
2004
|
-
controller.enqueue(encoder.encode(footer));
|
|
2005
|
-
controller.close();
|
|
2006
|
-
} catch (error) {
|
|
2007
|
-
controller.error(error);
|
|
2008
|
-
}
|
|
2009
|
-
}
|
|
1617
|
+
return html.slice(start, end + endTag.length);
|
|
1618
|
+
}, mountAngularIsland = async (component, element, props, islandId) => {
|
|
1619
|
+
await import("@angular/compiler");
|
|
1620
|
+
const { createComponent, inputBinding } = await import("@angular/core");
|
|
1621
|
+
const selector = getAngularIslandSelector(islandId);
|
|
1622
|
+
const { app, environmentInjector } = await getAngularIslandApp();
|
|
1623
|
+
let rootElement = element.querySelector(selector);
|
|
1624
|
+
if (!(rootElement instanceof HTMLElement)) {
|
|
1625
|
+
element.innerHTML = `<${selector}></${selector}>`;
|
|
1626
|
+
rootElement = element.querySelector(selector);
|
|
1627
|
+
}
|
|
1628
|
+
if (!(rootElement instanceof HTMLElement))
|
|
1629
|
+
return app;
|
|
1630
|
+
const componentSelector = getClientAngularComponentSelector(component) ?? getSelectorFromRenderedIsland(rootElement);
|
|
1631
|
+
if (!componentSelector)
|
|
1632
|
+
return app;
|
|
1633
|
+
rootElement.innerHTML = `<${componentSelector}></${componentSelector}>`;
|
|
1634
|
+
const hostElement = rootElement.querySelector(componentSelector);
|
|
1635
|
+
if (!(hostElement instanceof HTMLElement))
|
|
1636
|
+
return app;
|
|
1637
|
+
const bindings = Object.entries(props).map(([key, value]) => inputBinding(key, () => value));
|
|
1638
|
+
const componentRef = createComponent(component, {
|
|
1639
|
+
bindings,
|
|
1640
|
+
environmentInjector,
|
|
1641
|
+
hostElement
|
|
2010
1642
|
});
|
|
1643
|
+
app.attachView(componentRef.hostView);
|
|
1644
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
1645
|
+
window.__ABS_ANGULAR_ISLAND_APPS__ ??= [];
|
|
1646
|
+
window.__ABS_ANGULAR_ISLAND_APPS__.push(app);
|
|
1647
|
+
return app;
|
|
1648
|
+
}, renderAngularIslandToHtml = async (component, props, islandId) => {
|
|
1649
|
+
const requestCache = getRequestRenderCache();
|
|
1650
|
+
const renderCacheKey = getIslandRenderCacheKey(component, props);
|
|
1651
|
+
const cachedHtml = requestCache?.get(renderCacheKey);
|
|
1652
|
+
if (cachedHtml) {
|
|
1653
|
+
return cachedHtml;
|
|
1654
|
+
}
|
|
1655
|
+
const { deps, propsToken, selector, WrapperComponent } = await createAngularIslandWrapper(component, islandId);
|
|
1656
|
+
const providers = [
|
|
1657
|
+
deps.provideServerRendering(),
|
|
1658
|
+
deps.provideZonelessChangeDetection(),
|
|
1659
|
+
{ provide: deps.APP_BASE_HREF, useValue: "/" },
|
|
1660
|
+
{ provide: propsToken, useValue: props }
|
|
1661
|
+
];
|
|
1662
|
+
const document2 = `<!DOCTYPE html><html><body><${selector}></${selector}></body></html>`;
|
|
1663
|
+
const html = await withSuppressedAngularDevLogs(() => deps.renderApplication((context) => deps.bootstrapApplication(WrapperComponent, { providers }, context), {
|
|
1664
|
+
document: document2,
|
|
1665
|
+
platformProviders: [],
|
|
1666
|
+
url: "/"
|
|
1667
|
+
}));
|
|
1668
|
+
const islandHtml = extractAngularIslandRoot(html, selector);
|
|
1669
|
+
requestCache?.set(renderCacheKey, islandHtml);
|
|
1670
|
+
return islandHtml;
|
|
2011
1671
|
};
|
|
1672
|
+
var init_islands2 = __esm(() => {
|
|
1673
|
+
init_angularDeps();
|
|
1674
|
+
init_ssrRender();
|
|
1675
|
+
init_registerClientScript();
|
|
1676
|
+
wrapperMetadataCache = new Map;
|
|
1677
|
+
requestRenderCache = new Map;
|
|
1678
|
+
});
|
|
2012
1679
|
|
|
2013
|
-
// src/core/
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
1680
|
+
// src/core/islandSsr.ts
|
|
1681
|
+
import { createElement } from "react";
|
|
1682
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
1683
|
+
import { render as renderSvelte } from "svelte/server";
|
|
1684
|
+
import { createSSRApp, h } from "vue";
|
|
1685
|
+
import { renderToString as renderVueToString } from "vue/server-renderer";
|
|
1686
|
+
var renderReactIslandToHtml = (component, props) => renderToStaticMarkup(createElement(component, props)), renderSvelteIslandToHtml = (component, props) => {
|
|
1687
|
+
const { body } = renderSvelte(component, { props });
|
|
1688
|
+
return body;
|
|
1689
|
+
}, renderVueIslandToHtml = (component, props) => {
|
|
1690
|
+
const app = createSSRApp({
|
|
1691
|
+
render: () => h(component, props)
|
|
1692
|
+
});
|
|
1693
|
+
return renderVueToString(app);
|
|
2017
1694
|
};
|
|
2018
|
-
var
|
|
2019
|
-
|
|
1695
|
+
var init_islandSsr = __esm(() => {
|
|
1696
|
+
init_islands2();
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
// src/constants.ts
|
|
1700
|
+
var ANGULAR_INIT_TIMEOUT_MS = 500, ANSI_ESCAPE_LENGTH = 3, ASCII_SPACE = 32, BASE_36_RADIX = 36, BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet", BODY_SLICE_LENGTH = 2000, BYTES_PER_KILOBYTE = 1024, CLI_ARGS_OFFSET = 3, CSS_ERROR_RESOLVE_DELAY_MS = 50, CSS_MAX_CHECK_ATTEMPTS = 10, CSS_MAX_PARSE_TIMEOUT_MS = 500, CSS_SHEET_READY_TIMEOUT_MS = 100, DEFAULT_CHUNK_SIZE = 16384, DEFAULT_DEBOUNCE_MS = 15, DEFAULT_PORT = 3000, DEV_SERVER_RESTART_DEBOUNCE_MS = 100, DOM_UPDATE_DELAY_MS = 50, FILE_PROTOCOL_PREFIX_LENGTH = 7, FOCUS_ID_PREFIX_LENGTH = 3, FOCUS_IDX_PREFIX_LENGTH = 4, FOCUS_NAME_PREFIX_LENGTH = 5, HMR_UPDATE_TIMEOUT_MS = 2000, HOOK_SIGNATURE_LENGTH = 12, EXCLUDE_LAST_OFFSET = -1, HOURS_IN_DAY = 24, HOURS_IN_HALF_DAY = 12, MAX_ERROR_LENGTH = 200, MAX_RECONNECT_ATTEMPTS = 60, MILLISECONDS_IN_A_SECOND = 1000, MINUTES_IN_AN_HOUR = 60, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_MINUTE, MILLISECONDS_IN_A_DAY, OVERLAY_FADE_DURATION_MS = 150, PING_INTERVAL_MS = 30000, RAF_BATCH_COUNT = 3, RANDOM_ID_END_INDEX = 11, REBUILD_BATCH_DELAY_MS = 10, REBUILD_RELOAD_DELAY_MS = 200, RECONNECT_INITIAL_DELAY_MS = 500, RECONNECT_POLL_INTERVAL_MS = 300, SIGINT_EXIT_CODE = 130, SIGTERM_EXIT_CODE = 143, SVELTE_CSS_LOAD_TIMEOUT_MS = 500, TIME_PRECISION = 2, TWO_THIRDS, UNFOUND_INDEX = -1, WEBSOCKET_NORMAL_CLOSURE = 1000;
|
|
1701
|
+
var init_constants = __esm(() => {
|
|
1702
|
+
MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
|
|
1703
|
+
MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
|
|
1704
|
+
TWO_THIRDS = 2 / 3;
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1707
|
+
// src/svelte/lowerIslandSyntax.ts
|
|
1708
|
+
var ISLAND_TAG_RE, extractBracedExpression = (text, braceStart) => {
|
|
1709
|
+
let depth = 0;
|
|
1710
|
+
for (let index = braceStart;index < text.length; index += 1) {
|
|
1711
|
+
const char = text[index];
|
|
1712
|
+
if (char === "{")
|
|
1713
|
+
depth += 1;
|
|
1714
|
+
if (char === "}")
|
|
1715
|
+
depth -= 1;
|
|
1716
|
+
if (depth === 0) {
|
|
1717
|
+
return text.slice(braceStart + 1, index).trim();
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
return null;
|
|
1721
|
+
}, extractIslandAttribute = (attributeString, name) => {
|
|
1722
|
+
const quotedMatch = attributeString.match(new RegExp(`\\b${name}\\s*=\\s*["']([^"']+)["']`));
|
|
1723
|
+
if (quotedMatch?.[1]) {
|
|
1724
|
+
return { expression: JSON.stringify(quotedMatch[1]), found: true };
|
|
1725
|
+
}
|
|
1726
|
+
const attributeIndex = attributeString.search(new RegExp(`\\b${name}\\s*=\\s*\\{`));
|
|
1727
|
+
if (attributeIndex < 0) {
|
|
1728
|
+
return { expression: "", found: false };
|
|
1729
|
+
}
|
|
1730
|
+
const braceStart = attributeString.indexOf("{", attributeIndex);
|
|
1731
|
+
if (braceStart < 0) {
|
|
1732
|
+
return { expression: "", found: false };
|
|
1733
|
+
}
|
|
1734
|
+
const expression = extractBracedExpression(attributeString, braceStart);
|
|
1735
|
+
if (expression === null) {
|
|
1736
|
+
return { expression: "", found: false };
|
|
1737
|
+
}
|
|
1738
|
+
return { expression, found: true };
|
|
1739
|
+
}, lowerSvelteIslandSyntax = (source, _mode = "server") => {
|
|
1740
|
+
if (!source.includes("<Island")) {
|
|
1741
|
+
return { code: source, transformed: false };
|
|
1742
|
+
}
|
|
1743
|
+
let islandIndex = 0;
|
|
1744
|
+
const transformedMarkup = source.replace(ISLAND_TAG_RE, (fullMatch, attributeString) => {
|
|
1745
|
+
const framework = extractIslandAttribute(attributeString, "framework");
|
|
1746
|
+
const component = extractIslandAttribute(attributeString, "component");
|
|
1747
|
+
if (!framework.found || !component.found) {
|
|
1748
|
+
return fullMatch;
|
|
1749
|
+
}
|
|
1750
|
+
const hydrate = extractIslandAttribute(attributeString, "hydrate");
|
|
1751
|
+
const props = extractIslandAttribute(attributeString, "props");
|
|
1752
|
+
const slotId = `absolute-svelte-island-${islandIndex.toString(BASE_36_RADIX)}`;
|
|
1753
|
+
islandIndex += 1;
|
|
1754
|
+
const resolveExpression = `await __absoluteResolveIslandHtml(${JSON.stringify(slotId)}, { component: ${component.expression}, framework: ${framework.expression}, hydrate: ${hydrate.found ? hydrate.expression : JSON.stringify("load")}, props: ${props.found ? props.expression : "{}"} })`;
|
|
1755
|
+
return `<div data-absolute-island-slot="${slotId}" style="display: contents">{@html ${resolveExpression}}</div>`;
|
|
1756
|
+
});
|
|
1757
|
+
const importLine = 'import { resolveIslandHtml as __absoluteResolveIslandHtml } from "@absolutejs/absolute/svelte";';
|
|
1758
|
+
if (transformedMarkup.includes("<script")) {
|
|
1759
|
+
return {
|
|
1760
|
+
code: transformedMarkup.replace(/<script(\s[^>]*)?>/, (match) => `${match}
|
|
1761
|
+
${importLine}
|
|
1762
|
+
`),
|
|
1763
|
+
transformed: true
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
return {
|
|
1767
|
+
code: `<script lang="ts">
|
|
1768
|
+
${importLine}
|
|
1769
|
+
</script>
|
|
1770
|
+
${transformedMarkup}`,
|
|
1771
|
+
transformed: true
|
|
1772
|
+
};
|
|
2020
1773
|
};
|
|
1774
|
+
var init_lowerIslandSyntax = __esm(() => {
|
|
1775
|
+
init_constants();
|
|
1776
|
+
ISLAND_TAG_RE = /<Island\b([\s\S]*?)\/>/g;
|
|
1777
|
+
});
|
|
2021
1778
|
|
|
2022
|
-
// src/core/
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
var
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
1779
|
+
// src/core/svelteServerModule.ts
|
|
1780
|
+
import { mkdir, readdir } from "fs/promises";
|
|
1781
|
+
import { basename as basename2, dirname as dirname2, extname, join as join2, relative, resolve as resolve3 } from "path";
|
|
1782
|
+
var serverCacheRoot, compiledModuleCache, originalSourcePathCache, transpiler, ensureRelativeImportPath = (from, target) => {
|
|
1783
|
+
const importPath = relative(dirname2(from), target).replace(/\\/g, "/");
|
|
1784
|
+
return importPath.startsWith(".") ? importPath : `./${importPath}`;
|
|
1785
|
+
}, processDirectoryEntries = (entries, dir, targetFileName, stack) => {
|
|
1786
|
+
for (const entry of entries) {
|
|
1787
|
+
const entryPath = join2(dir, entry.name);
|
|
1788
|
+
if (entry.isDirectory())
|
|
1789
|
+
stack.push(entryPath);
|
|
1790
|
+
if (entry.isFile() && entry.name === targetFileName) {
|
|
1791
|
+
return entryPath;
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
return null;
|
|
1795
|
+
}, searchDirectoryLevel = async (dirs, targetFileName) => {
|
|
1796
|
+
if (dirs.length === 0)
|
|
1797
|
+
return null;
|
|
1798
|
+
const nextStack = [];
|
|
1799
|
+
const dirEntries = await Promise.all(dirs.map(async (dir) => ({
|
|
1800
|
+
dir,
|
|
1801
|
+
entries: await readdir(dir, {
|
|
1802
|
+
encoding: "utf-8",
|
|
1803
|
+
withFileTypes: true
|
|
1804
|
+
})
|
|
1805
|
+
})));
|
|
1806
|
+
for (const { dir, entries } of dirEntries) {
|
|
1807
|
+
const found = processDirectoryEntries(entries, dir, targetFileName, nextStack);
|
|
1808
|
+
if (found)
|
|
1809
|
+
return found;
|
|
1810
|
+
}
|
|
1811
|
+
return searchDirectoryLevel(nextStack, targetFileName);
|
|
1812
|
+
}, findSourceFileByBasename = async (searchRoot, targetFileName) => searchDirectoryLevel([searchRoot], targetFileName), normalizeBuiltSvelteFileName = (sourcePath) => basename2(sourcePath).replace(/-[a-z0-9]{6,}(?=\.svelte$)/i, ""), resolveOriginalSourcePath = async (sourcePath) => {
|
|
1813
|
+
const cachedPath = originalSourcePathCache.get(sourcePath);
|
|
1814
|
+
if (cachedPath !== undefined) {
|
|
1815
|
+
return cachedPath;
|
|
1816
|
+
}
|
|
1817
|
+
if (!sourcePath.includes(`${join2(process.cwd(), "build")}${process.platform === "win32" ? "" : "/"}`) && !sourcePath.includes("/build/")) {
|
|
1818
|
+
originalSourcePathCache.set(sourcePath, sourcePath);
|
|
1819
|
+
return sourcePath;
|
|
1820
|
+
}
|
|
1821
|
+
const resolvedSourcePath = await findSourceFileByBasename(join2(process.cwd(), "src"), normalizeBuiltSvelteFileName(sourcePath));
|
|
1822
|
+
const nextPath = resolvedSourcePath ?? sourcePath;
|
|
1823
|
+
originalSourcePathCache.set(sourcePath, nextPath);
|
|
1824
|
+
return nextPath;
|
|
1825
|
+
}, resolveRelativeModule = async (spec, from) => {
|
|
1826
|
+
if (!spec.startsWith(".")) {
|
|
1827
|
+
return null;
|
|
1828
|
+
}
|
|
1829
|
+
const basePath = resolve3(dirname2(from), spec);
|
|
1830
|
+
const candidates = [
|
|
1831
|
+
basePath,
|
|
1832
|
+
`${basePath}.ts`,
|
|
1833
|
+
`${basePath}.js`,
|
|
1834
|
+
`${basePath}.mjs`,
|
|
1835
|
+
`${basePath}.cjs`,
|
|
1836
|
+
`${basePath}.json`,
|
|
1837
|
+
join2(basePath, "index.ts"),
|
|
1838
|
+
join2(basePath, "index.js"),
|
|
1839
|
+
join2(basePath, "index.mjs"),
|
|
1840
|
+
join2(basePath, "index.cjs"),
|
|
1841
|
+
join2(basePath, "index.json")
|
|
1842
|
+
];
|
|
1843
|
+
const existResults = await Promise.all(candidates.map((candidate) => Bun.file(candidate).exists()));
|
|
1844
|
+
const foundIndex = existResults.indexOf(true);
|
|
1845
|
+
return foundIndex >= 0 ? candidates[foundIndex] ?? null : null;
|
|
1846
|
+
}, getCachedModulePath = (sourcePath) => {
|
|
1847
|
+
const relativeSourcePath = relative(process.cwd(), sourcePath).replace(/\\/g, "/");
|
|
1848
|
+
const normalizedSourcePath = relativeSourcePath.startsWith("..") ? sourcePath.replace(/[:\\/]/g, "_") : relativeSourcePath;
|
|
1849
|
+
return join2(serverCacheRoot, `${normalizedSourcePath}.server.js`);
|
|
1850
|
+
}, resolveSvelteImport = async (spec, from) => {
|
|
1851
|
+
if (spec.startsWith("/")) {
|
|
1852
|
+
return spec;
|
|
1853
|
+
}
|
|
1854
|
+
if (!spec.startsWith(".")) {
|
|
1855
|
+
return null;
|
|
1856
|
+
}
|
|
1857
|
+
const explicitPath = resolve3(dirname2(from), spec);
|
|
1858
|
+
if (extname(explicitPath) === ".svelte") {
|
|
1859
|
+
return explicitPath;
|
|
1860
|
+
}
|
|
1861
|
+
const candidate = `${explicitPath}.svelte`;
|
|
1862
|
+
if (await Bun.file(candidate).exists() === true) {
|
|
1863
|
+
return candidate;
|
|
1864
|
+
}
|
|
1865
|
+
return null;
|
|
1866
|
+
}, writeIfChanged = async (path, content) => {
|
|
1867
|
+
const targetFile = Bun.file(path);
|
|
1868
|
+
const exists = await targetFile.exists();
|
|
1869
|
+
if (exists) {
|
|
1870
|
+
const currentContent = await targetFile.text();
|
|
1871
|
+
if (currentContent === content) {
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
2031
1874
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
if (!asyncLocalStorage)
|
|
2038
|
-
return;
|
|
2039
|
-
const store = asyncLocalStorage.getStore();
|
|
2040
|
-
if (!store)
|
|
2041
|
-
return;
|
|
2042
|
-
store.set(slot.id, slot);
|
|
2043
|
-
};
|
|
2044
|
-
setStreamingSlotRegistrar(registerStreamingSlot2);
|
|
2045
|
-
var runWithStreamingSlotRegistry = async (task) => {
|
|
2046
|
-
const storage = await ensureAsyncLocalStorage();
|
|
2047
|
-
if (!storage) {
|
|
2048
|
-
return {
|
|
2049
|
-
result: await task(),
|
|
2050
|
-
slots: []
|
|
2051
|
-
};
|
|
1875
|
+
await Bun.write(path, content);
|
|
1876
|
+
}, compileSvelteServerModule = async (sourcePath) => {
|
|
1877
|
+
const cachedModulePath = compiledModuleCache.get(sourcePath);
|
|
1878
|
+
if (cachedModulePath) {
|
|
1879
|
+
return cachedModulePath;
|
|
2052
1880
|
}
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
1881
|
+
const resolutionSourcePath = await resolveOriginalSourcePath(sourcePath);
|
|
1882
|
+
const source = await Bun.file(sourcePath).text();
|
|
1883
|
+
const { compile, preprocess } = await import("svelte/compiler");
|
|
1884
|
+
const loweredSource = lowerSvelteIslandSyntax(source, "server");
|
|
1885
|
+
const preprocessed = await preprocess(loweredSource.code, {});
|
|
1886
|
+
let transpiled = sourcePath.endsWith(".ts") || sourcePath.endsWith(".svelte.ts") ? transpiler.transformSync(preprocessed.code) : preprocessed.code;
|
|
1887
|
+
const childImportSpecs = Array.from(transpiled.matchAll(/from\s+['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((value) => value !== undefined);
|
|
1888
|
+
const resolvedChildModules = await Promise.all(childImportSpecs.map((spec) => resolveSvelteImport(spec, resolutionSourcePath)));
|
|
1889
|
+
const resolvedModuleImports = await Promise.all(childImportSpecs.map((spec) => resolveRelativeModule(spec, resolutionSourcePath)));
|
|
1890
|
+
const childModulePaths = new Map;
|
|
1891
|
+
const rewrittenModulePaths = new Map;
|
|
1892
|
+
const compiledChildren = await Promise.all(childImportSpecs.map(async (spec, index) => {
|
|
1893
|
+
const resolvedChild = resolvedChildModules[index];
|
|
1894
|
+
if (!spec || !resolvedChild)
|
|
1895
|
+
return null;
|
|
2056
1896
|
return {
|
|
2057
|
-
|
|
2058
|
-
|
|
1897
|
+
compiledPath: await compileSvelteServerModule(resolvedChild),
|
|
1898
|
+
spec
|
|
2059
1899
|
};
|
|
2060
|
-
});
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
var toResponse = async (responseLike) => await responseLike;
|
|
2065
|
-
var cloneHeaders = (response) => {
|
|
2066
|
-
const headers = new Headers(response.headers);
|
|
2067
|
-
return headers;
|
|
2068
|
-
};
|
|
2069
|
-
var enhanceHtmlResponseWithStreamingSlots = (response, { nonce, onError, streamingSlots = [], policy } = {}) => {
|
|
2070
|
-
if (!response.body || streamingSlots.length === 0) {
|
|
2071
|
-
return response;
|
|
1900
|
+
}));
|
|
1901
|
+
for (const result of compiledChildren) {
|
|
1902
|
+
if (result)
|
|
1903
|
+
childModulePaths.set(result.spec, result.compiledPath);
|
|
2072
1904
|
}
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
1905
|
+
for (let index = 0;index < childImportSpecs.length; index += 1) {
|
|
1906
|
+
const spec = childImportSpecs[index];
|
|
1907
|
+
const resolvedModuleImport = resolvedModuleImports[index];
|
|
1908
|
+
if (!spec || !resolvedModuleImport)
|
|
1909
|
+
continue;
|
|
1910
|
+
if (resolvedChildModules[index])
|
|
1911
|
+
continue;
|
|
1912
|
+
rewrittenModulePaths.set(spec, ensureRelativeImportPath(getCachedModulePath(sourcePath), resolvedModuleImport));
|
|
1913
|
+
}
|
|
1914
|
+
for (const [spec, resolvedModuleImport] of rewrittenModulePaths) {
|
|
1915
|
+
transpiled = transpiled.replaceAll(spec, resolvedModuleImport);
|
|
1916
|
+
}
|
|
1917
|
+
let compiledCode = compile(transpiled, {
|
|
1918
|
+
css: "injected",
|
|
1919
|
+
experimental: {
|
|
1920
|
+
async: loweredSource.transformed
|
|
1921
|
+
},
|
|
1922
|
+
filename: resolutionSourcePath,
|
|
1923
|
+
generate: "server"
|
|
1924
|
+
}).js.code;
|
|
1925
|
+
for (const [spec, compiledChildPath] of childModulePaths) {
|
|
1926
|
+
compiledCode = compiledCode.replaceAll(spec, ensureRelativeImportPath(getCachedModulePath(sourcePath), compiledChildPath));
|
|
1927
|
+
}
|
|
1928
|
+
for (const [spec, resolvedModuleImport] of rewrittenModulePaths) {
|
|
1929
|
+
compiledCode = compiledCode.replaceAll(spec, resolvedModuleImport);
|
|
1930
|
+
}
|
|
1931
|
+
const compiledModulePath = getCachedModulePath(sourcePath);
|
|
1932
|
+
await mkdir(dirname2(compiledModulePath), { recursive: true });
|
|
1933
|
+
await writeIfChanged(compiledModulePath, compiledCode);
|
|
1934
|
+
compiledModuleCache.set(sourcePath, compiledModulePath);
|
|
1935
|
+
return compiledModulePath;
|
|
2092
1936
|
};
|
|
2093
|
-
var
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
1937
|
+
var init_svelteServerModule = __esm(() => {
|
|
1938
|
+
init_lowerIslandSyntax();
|
|
1939
|
+
serverCacheRoot = join2(process.cwd(), ".absolutejs", "islands", "svelte");
|
|
1940
|
+
compiledModuleCache = new Map;
|
|
1941
|
+
originalSourcePathCache = new Map;
|
|
1942
|
+
transpiler = new Bun.Transpiler({
|
|
1943
|
+
loader: "ts",
|
|
1944
|
+
target: "browser"
|
|
2099
1945
|
});
|
|
2100
|
-
};
|
|
1946
|
+
});
|
|
2101
1947
|
|
|
2102
|
-
// src/core/
|
|
2103
|
-
var
|
|
1948
|
+
// src/core/renderIslandMarkup.ts
|
|
1949
|
+
var islandSequence = 0, resolvedServerComponentCache, resolvedServerBuildComponentCache, nextIslandId = () => {
|
|
1950
|
+
islandSequence += 1;
|
|
1951
|
+
return `island-${islandSequence}`;
|
|
1952
|
+
}, isRecord2 = (value) => typeof value === "object" && value !== null, isReactServerIslandComponent = (value) => typeof value === "function", isSvelteServerIslandComponent = (value) => typeof value === "function", isVueServerIslandComponent = (value) => typeof value === "function" || isRecord2(value), isAngularServerIslandComponent = (value) => typeof value === "function", resolveBuildReferencePath = (source, registryPath) => {
|
|
1953
|
+
if (source.startsWith("file://"))
|
|
1954
|
+
return new URL(source).pathname;
|
|
1955
|
+
if (source.startsWith("."))
|
|
1956
|
+
return new URL(source, registryPath).pathname;
|
|
1957
|
+
return source;
|
|
1958
|
+
}, loadAndCompileServerBuildComponent = async (buildReferencePath) => {
|
|
1959
|
+
const compiledModulePath = await compileSvelteServerModule(buildReferencePath);
|
|
1960
|
+
const loadedModule = await import(compiledModulePath);
|
|
1961
|
+
return "default" in loadedModule ? loadedModule.default : loadedModule;
|
|
1962
|
+
}, loadServerBuildComponent = async (buildReferencePath) => {
|
|
1963
|
+
const cachedBuildComponent = resolvedServerBuildComponentCache.get(buildReferencePath);
|
|
1964
|
+
if (cachedBuildComponent) {
|
|
1965
|
+
return cachedBuildComponent;
|
|
1966
|
+
}
|
|
1967
|
+
const loadPromise = loadAndCompileServerBuildComponent(buildReferencePath);
|
|
1968
|
+
resolvedServerBuildComponentCache.set(buildReferencePath, loadPromise);
|
|
1969
|
+
return loadPromise;
|
|
1970
|
+
}, loadServerImportComponent = async (resolvedComponent) => {
|
|
1971
|
+
const resolvedModulePath = resolvedComponent.startsWith(".") ? new URL(resolvedComponent, import.meta.url).pathname : resolvedComponent;
|
|
1972
|
+
const importTarget = resolvedModulePath.endsWith(".svelte") ? await compileSvelteServerModule(resolvedModulePath) : resolvedModulePath;
|
|
1973
|
+
const loadedModule = await import(importTarget);
|
|
1974
|
+
return "default" in loadedModule ? loadedModule.default : loadedModule;
|
|
1975
|
+
}, resolveIslandComponent = async (component) => {
|
|
1976
|
+
const buildReference = getIslandBuildReference(component);
|
|
1977
|
+
const buildReferencePath = buildReference?.source ? resolveBuildReferencePath(buildReference.source, import.meta.url) : null;
|
|
1978
|
+
if (buildReferencePath?.endsWith(".svelte")) {
|
|
1979
|
+
return loadServerBuildComponent(buildReferencePath);
|
|
1980
|
+
}
|
|
1981
|
+
const resolvedComponent = getIslandComponent(component);
|
|
1982
|
+
if (typeof resolvedComponent !== "string") {
|
|
1983
|
+
return resolvedComponent;
|
|
1984
|
+
}
|
|
1985
|
+
return loadServerImportComponent(resolvedComponent);
|
|
1986
|
+
}, resolveServerIslandComponent = async (component) => {
|
|
1987
|
+
const cachedResolvedComponent = resolvedServerComponentCache.get(component);
|
|
1988
|
+
if (cachedResolvedComponent) {
|
|
1989
|
+
return cachedResolvedComponent;
|
|
1990
|
+
}
|
|
1991
|
+
const resolutionPromise = resolveIslandComponent(component);
|
|
1992
|
+
resolvedServerComponentCache.set(component, resolutionPromise);
|
|
1993
|
+
return resolutionPromise;
|
|
1994
|
+
}, resolveReactServerIslandComponent = async (component) => {
|
|
1995
|
+
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
1996
|
+
if (!isReactServerIslandComponent(resolvedComponent)) {
|
|
1997
|
+
throw new Error("Resolved React island is not a valid React component.");
|
|
1998
|
+
}
|
|
1999
|
+
return resolvedComponent;
|
|
2000
|
+
}, resolveSvelteServerIslandComponent = async (component) => {
|
|
2001
|
+
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
2002
|
+
if (!isSvelteServerIslandComponent(resolvedComponent)) {
|
|
2003
|
+
throw new Error("Resolved Svelte island is not a valid Svelte component.");
|
|
2004
|
+
}
|
|
2005
|
+
return resolvedComponent;
|
|
2006
|
+
}, resolveVueServerIslandComponent = async (component) => {
|
|
2007
|
+
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
2008
|
+
if (!isVueServerIslandComponent(resolvedComponent)) {
|
|
2009
|
+
throw new Error("Resolved Vue island is not a valid Vue component.");
|
|
2010
|
+
}
|
|
2011
|
+
return resolvedComponent;
|
|
2012
|
+
}, resolveAngularServerIslandComponent = async (component) => {
|
|
2013
|
+
const resolvedComponent = await resolveServerIslandComponent(component);
|
|
2014
|
+
if (!isAngularServerIslandComponent(resolvedComponent)) {
|
|
2015
|
+
throw new Error("Resolved Angular island is not a valid Angular component.");
|
|
2016
|
+
}
|
|
2017
|
+
return resolvedComponent;
|
|
2018
|
+
}, renderIslandMarkup = async (registry, props) => {
|
|
2019
|
+
const result = await renderIslandResult(registry, props);
|
|
2020
|
+
return `<div ${serializeIslandAttributes(result.attributes)}>${result.html}</div>`;
|
|
2021
|
+
}, renderIslandResult = async (registry, props) => {
|
|
2022
|
+
const islandId = nextIslandId();
|
|
2023
|
+
const attributes = getIslandMarkerAttributes(props);
|
|
2024
|
+
if (props.framework === "react") {
|
|
2025
|
+
const entry = registry.react?.[props.component];
|
|
2026
|
+
if (!entry) {
|
|
2027
|
+
throw new Error(`Island component "${props.component}" is not registered for framework "react".`);
|
|
2028
|
+
}
|
|
2029
|
+
const component = await resolveReactServerIslandComponent(entry);
|
|
2030
|
+
const html = renderReactIslandToHtml(component, props.props);
|
|
2031
|
+
return { attributes, html };
|
|
2032
|
+
}
|
|
2033
|
+
if (props.framework === "svelte") {
|
|
2034
|
+
const entry = registry.svelte?.[props.component];
|
|
2035
|
+
if (!entry) {
|
|
2036
|
+
throw new Error(`Island component "${props.component}" is not registered for framework "svelte".`);
|
|
2037
|
+
}
|
|
2038
|
+
const component = await resolveSvelteServerIslandComponent(entry);
|
|
2039
|
+
const html = renderSvelteIslandToHtml(component, props.props);
|
|
2040
|
+
return { attributes, html };
|
|
2041
|
+
}
|
|
2042
|
+
if (props.framework === "vue") {
|
|
2043
|
+
const entry = registry.vue?.[props.component];
|
|
2044
|
+
if (!entry) {
|
|
2045
|
+
throw new Error(`Island component "${props.component}" is not registered for framework "vue".`);
|
|
2046
|
+
}
|
|
2047
|
+
const component = await resolveVueServerIslandComponent(entry);
|
|
2048
|
+
const html = await renderVueIslandToHtml(component, props.props);
|
|
2049
|
+
return { attributes, html };
|
|
2050
|
+
}
|
|
2051
|
+
if (props.framework === "angular") {
|
|
2052
|
+
const entry = registry.angular?.[props.component];
|
|
2053
|
+
if (!entry) {
|
|
2054
|
+
throw new Error(`Island component "${props.component}" is not registered for framework "angular".`);
|
|
2055
|
+
}
|
|
2056
|
+
const component = await resolveAngularServerIslandComponent(entry);
|
|
2057
|
+
const html = await renderAngularIslandToHtml(component, props.props, islandId);
|
|
2058
|
+
return {
|
|
2059
|
+
attributes: {
|
|
2060
|
+
...getIslandMarkerAttributes(props, islandId)
|
|
2061
|
+
},
|
|
2062
|
+
html
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
2065
|
+
throw new Error(`Framework "${props.framework}" is not implemented in this prototype.`);
|
|
2066
|
+
};
|
|
2067
|
+
var init_renderIslandMarkup = __esm(() => {
|
|
2068
|
+
init_islandSsr();
|
|
2069
|
+
init_svelteServerModule();
|
|
2070
|
+
init_islandMarkupAttributes();
|
|
2071
|
+
init_islands();
|
|
2072
|
+
resolvedServerComponentCache = new Map;
|
|
2073
|
+
resolvedServerBuildComponentCache = new Map;
|
|
2074
|
+
});
|
|
2104
2075
|
|
|
2105
2076
|
// src/react/index.ts
|
|
2106
2077
|
init_pageHandler();
|
|
@@ -2108,16 +2079,16 @@ init_pageHandler();
|
|
|
2108
2079
|
// src/react/Island.tsx
|
|
2109
2080
|
init_islandMarkupAttributes();
|
|
2110
2081
|
init_renderIslandMarkup();
|
|
2111
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
2082
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
2112
2083
|
var Island = async (props) => {
|
|
2113
2084
|
if (typeof window !== "undefined") {
|
|
2114
|
-
return /* @__PURE__ */
|
|
2085
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
2115
2086
|
...getIslandMarkerAttributes(props),
|
|
2116
2087
|
suppressHydrationWarning: true
|
|
2117
2088
|
}, undefined, false, undefined, this);
|
|
2118
2089
|
}
|
|
2119
2090
|
const result = await renderIslandResult(requireCurrentIslandRegistry(), props);
|
|
2120
|
-
return /* @__PURE__ */
|
|
2091
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
2121
2092
|
...result.attributes,
|
|
2122
2093
|
dangerouslySetInnerHTML: { __html: result.html }
|
|
2123
2094
|
}, undefined, false, undefined, this);
|
|
@@ -2125,17 +2096,17 @@ var Island = async (props) => {
|
|
|
2125
2096
|
// src/react/createIsland.tsx
|
|
2126
2097
|
init_islandMarkupAttributes();
|
|
2127
2098
|
init_renderIslandMarkup();
|
|
2128
|
-
import { jsxDEV as
|
|
2099
|
+
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
2129
2100
|
var createTypedIsland = (registry) => {
|
|
2130
2101
|
const Island2 = async (props) => {
|
|
2131
2102
|
if (typeof window !== "undefined") {
|
|
2132
|
-
return /* @__PURE__ */
|
|
2103
|
+
return /* @__PURE__ */ jsxDEV3("div", {
|
|
2133
2104
|
...getIslandMarkerAttributes(props),
|
|
2134
2105
|
suppressHydrationWarning: true
|
|
2135
2106
|
}, undefined, false, undefined, this);
|
|
2136
2107
|
}
|
|
2137
2108
|
const result = await renderIslandResult(registry, props);
|
|
2138
|
-
return /* @__PURE__ */
|
|
2109
|
+
return /* @__PURE__ */ jsxDEV3("div", {
|
|
2139
2110
|
...result.attributes,
|
|
2140
2111
|
dangerouslySetInnerHTML: { __html: result.html }
|
|
2141
2112
|
}, undefined, false, undefined, this);
|
|
@@ -2262,15 +2233,12 @@ var subscribeIslandStore = (store, selector, listener) => {
|
|
|
2262
2233
|
var useIslandStore = (store, selector) => useSyncExternalStore((listener) => subscribeIslandStore(store, selector, () => {
|
|
2263
2234
|
listener();
|
|
2264
2235
|
}), () => readIslandStore(store, selector), () => getIslandStoreServerSnapshot(store, selector));
|
|
2265
|
-
|
|
2266
|
-
// src/react/index.ts
|
|
2267
|
-
var handleReactPageRequest2 = wrapPageHandlerWithStreamingSlots(handleReactPageRequest);
|
|
2268
2236
|
export {
|
|
2269
2237
|
useIslandStore,
|
|
2270
|
-
|
|
2238
|
+
handleReactPageRequest,
|
|
2271
2239
|
createTypedIsland,
|
|
2272
2240
|
Island
|
|
2273
2241
|
};
|
|
2274
2242
|
|
|
2275
|
-
//# debugId=
|
|
2243
|
+
//# debugId=15AFCB77217FB62264756E2164756E21
|
|
2276
2244
|
//# sourceMappingURL=index.js.map
|