@absolutejs/absolute 0.19.0-beta.367 → 0.19.0-beta.369
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 +13 -8
- package/dist/angular/browser.js.map +4 -4
- package/dist/angular/components/core/streamingSlotRegistrar.js +4 -3
- package/dist/angular/components/core/streamingSlotRegistry.js +4 -3
- package/dist/angular/index.js +668 -622
- package/dist/angular/index.js.map +8 -8
- package/dist/build.js +24 -576
- package/dist/build.js.map +4 -10
- package/dist/client/index.js +45 -44
- package/dist/client/index.js.map +4 -4
- package/dist/index.js +1320 -1135
- package/dist/index.js.map +28 -22
- package/dist/react/components/browser/index.js +9 -20
- package/dist/react/components/index.js +17 -35
- package/dist/react/components/index.js.map +5 -6
- package/dist/react/index.js +1268 -1235
- package/dist/react/index.js.map +12 -12
- package/dist/react/server.js +3 -571
- package/dist/react/server.js.map +4 -11
- package/dist/src/core/pageHandlers.d.ts +1 -1
- package/dist/src/react/index.d.ts +1 -1
- package/dist/svelte/index.js +1506 -1460
- package/dist/svelte/index.js.map +8 -8
- package/dist/vue/components/index.js +13 -8
- package/dist/vue/components/index.js.map +5 -5
- package/dist/vue/index.js +667 -619
- package/dist/vue/index.js.map +8 -8
- package/package.json +1 -1
- package/dist/src/react/streamingSlotCollection.d.ts +0 -9
package/dist/index.js
CHANGED
|
@@ -78,81 +78,468 @@ 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
|
-
//
|
|
82
|
-
var
|
|
83
|
-
|
|
84
|
-
|
|
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
|
+
// 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__", CLOSING_HEAD_TAG2 = "</head>", buildIslandsHeadMarkup = (manifest) => {
|
|
99
|
+
const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
|
|
100
|
+
const islandStateScript = `<script>window.__ABS_ISLAND_STATE__ = ${JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {})}</script>`;
|
|
101
|
+
const bootstrapPath = manifest[BOOTSTRAP_MANIFEST_KEY];
|
|
102
|
+
const bootstrapScript = bootstrapPath ? `<script type="module" src="${bootstrapPath}"></script>` : "";
|
|
103
|
+
return `${manifestScript}${islandStateScript}${bootstrapScript}`;
|
|
104
|
+
}, injectHeadMarkup = (html, markup) => {
|
|
105
|
+
const closingHeadIndex = html.indexOf("</head>");
|
|
106
|
+
if (closingHeadIndex >= 0) {
|
|
107
|
+
return `${html.slice(0, closingHeadIndex)}${markup}${html.slice(closingHeadIndex)}`;
|
|
85
108
|
}
|
|
86
|
-
|
|
87
|
-
|
|
109
|
+
const openingBodyIndex = html.indexOf("<body");
|
|
110
|
+
if (openingBodyIndex >= 0) {
|
|
111
|
+
const bodyStart = html.indexOf(">", openingBodyIndex);
|
|
112
|
+
if (bodyStart >= 0) {
|
|
113
|
+
return `${html.slice(0, openingBodyIndex)}<head>${markup}</head>${html.slice(openingBodyIndex)}`;
|
|
114
|
+
}
|
|
88
115
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
return `<!DOCTYPE html><html><head>${markup}</head><body>${html}</body></html>`;
|
|
117
|
+
}, streamChunkToString2 = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true }), pipeStreamWithHeadInjection = (stream, markup) => {
|
|
118
|
+
const encoder = new TextEncoder;
|
|
119
|
+
const decoder = new TextDecoder;
|
|
120
|
+
const lookbehind = CLOSING_HEAD_TAG2.length - 1;
|
|
121
|
+
return new ReadableStream({
|
|
122
|
+
async start(controller) {
|
|
123
|
+
const reader = stream.getReader();
|
|
124
|
+
let injected = false;
|
|
125
|
+
let pending = "";
|
|
126
|
+
try {
|
|
127
|
+
for (;; ) {
|
|
128
|
+
const { done, value } = await reader.read();
|
|
129
|
+
if (done)
|
|
130
|
+
break;
|
|
131
|
+
if (!value)
|
|
132
|
+
continue;
|
|
133
|
+
pending += streamChunkToString2(value, decoder);
|
|
134
|
+
if (injected) {
|
|
135
|
+
controller.enqueue(encoder.encode(pending));
|
|
136
|
+
pending = "";
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const headIndex = pending.indexOf(CLOSING_HEAD_TAG2);
|
|
140
|
+
if (headIndex >= 0) {
|
|
141
|
+
const next = `${pending.slice(0, headIndex)}${markup}${pending.slice(headIndex)}`;
|
|
142
|
+
controller.enqueue(encoder.encode(next));
|
|
143
|
+
pending = "";
|
|
144
|
+
injected = true;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (pending.length > lookbehind) {
|
|
148
|
+
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
149
|
+
controller.enqueue(encoder.encode(safeText));
|
|
150
|
+
pending = pending.slice(-lookbehind);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
pending += decoder.decode();
|
|
154
|
+
if (!injected) {
|
|
155
|
+
pending = injectHeadMarkup(pending, markup);
|
|
156
|
+
}
|
|
157
|
+
if (pending.length > 0) {
|
|
158
|
+
controller.enqueue(encoder.encode(pending));
|
|
159
|
+
}
|
|
160
|
+
controller.close();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
controller.error(error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}, pipeStreamWithIslandMarkerDetection = (stream, markup) => {
|
|
167
|
+
const encoder = new TextEncoder;
|
|
168
|
+
const decoder = new TextDecoder;
|
|
169
|
+
const lookbehind = Math.max(ISLAND_MARKER.length, 1024);
|
|
170
|
+
return new ReadableStream({
|
|
171
|
+
async start(controller) {
|
|
172
|
+
const reader = stream.getReader();
|
|
173
|
+
let injected = false;
|
|
174
|
+
let pending = "";
|
|
175
|
+
try {
|
|
176
|
+
for (;; ) {
|
|
177
|
+
const { done, value } = await reader.read();
|
|
178
|
+
if (done)
|
|
179
|
+
break;
|
|
180
|
+
if (!value)
|
|
181
|
+
continue;
|
|
182
|
+
pending += streamChunkToString2(value, decoder);
|
|
183
|
+
if (injected) {
|
|
184
|
+
controller.enqueue(encoder.encode(pending));
|
|
185
|
+
pending = "";
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const markerIndex = pending.indexOf(ISLAND_MARKER);
|
|
189
|
+
if (markerIndex >= 0) {
|
|
190
|
+
const tagStart = pending.lastIndexOf("<", markerIndex);
|
|
191
|
+
const injectAt = tagStart >= 0 ? tagStart : markerIndex;
|
|
192
|
+
const next = `${pending.slice(0, injectAt)}${markup}${pending.slice(injectAt)}`;
|
|
193
|
+
controller.enqueue(encoder.encode(next));
|
|
194
|
+
pending = "";
|
|
195
|
+
injected = true;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (pending.length > lookbehind) {
|
|
199
|
+
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
200
|
+
controller.enqueue(encoder.encode(safeText));
|
|
201
|
+
pending = pending.slice(-lookbehind);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
pending += decoder.decode();
|
|
205
|
+
if (pending.length > 0) {
|
|
206
|
+
controller.enqueue(encoder.encode(pending));
|
|
207
|
+
}
|
|
208
|
+
controller.close();
|
|
209
|
+
} catch (error) {
|
|
210
|
+
controller.error(error);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}, htmlContainsIslands = (html) => html.includes(ISLAND_MARKER), injectIslandPageContext = (html, options) => {
|
|
215
|
+
const manifest = globalThis.__absoluteManifest;
|
|
216
|
+
const hasIslands = options?.hasIslands ?? htmlContainsIslands(html);
|
|
217
|
+
if (!manifest || !hasIslands) {
|
|
218
|
+
return html;
|
|
98
219
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return false;
|
|
220
|
+
if (html.includes(MANIFEST_MARKER) || html.includes(ISLAND_STATE_MARKER)) {
|
|
221
|
+
return html;
|
|
102
222
|
}
|
|
103
|
-
|
|
104
|
-
|
|
223
|
+
return injectHeadMarkup(html, buildIslandsHeadMarkup(manifest));
|
|
224
|
+
}, injectIslandPageContextStream = (stream, options) => {
|
|
225
|
+
const manifest = globalThis.__absoluteManifest;
|
|
226
|
+
if (!manifest)
|
|
227
|
+
return stream;
|
|
228
|
+
const markup = buildIslandsHeadMarkup(manifest);
|
|
229
|
+
if (options?.hasIslands === true) {
|
|
230
|
+
return pipeStreamWithHeadInjection(stream, markup);
|
|
105
231
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return "content" in data && typeof data.content === "string" && "messageId" in data && "conversationId" in data;
|
|
109
|
-
case "thinking":
|
|
110
|
-
return "content" in data && typeof data.content === "string" && "messageId" in data && "conversationId" in data;
|
|
111
|
-
case "tool_status":
|
|
112
|
-
return "name" in data && "status" in data && "messageId" in data && "conversationId" in data;
|
|
113
|
-
case "image":
|
|
114
|
-
return "data" in data && typeof data.data === "string" && "format" in data && typeof data.format === "string" && "isPartial" in data && typeof data.isPartial === "boolean" && "messageId" in data && "conversationId" in data;
|
|
115
|
-
case "complete":
|
|
116
|
-
return "messageId" in data && "conversationId" in data;
|
|
117
|
-
case "rag_retrieved":
|
|
118
|
-
return "conversationId" in data && "messageId" in data && "sources" in data && Array.isArray(data.sources);
|
|
119
|
-
case "error":
|
|
120
|
-
return "message" in data && typeof data.message === "string";
|
|
121
|
-
default:
|
|
122
|
-
return false;
|
|
232
|
+
if (options?.hasIslands === false) {
|
|
233
|
+
return stream;
|
|
123
234
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
235
|
+
return pipeStreamWithIslandMarkerDetection(stream, markup);
|
|
236
|
+
}, setCurrentIslandManifest = (manifest) => {
|
|
237
|
+
globalThis.__absoluteManifest = manifest;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/utils/ssrErrorPage.ts
|
|
241
|
+
var ssrErrorPage = (framework, error) => {
|
|
242
|
+
const frameworkColors = {
|
|
243
|
+
angular: "#dd0031",
|
|
244
|
+
html: "#e34c26",
|
|
245
|
+
htmx: "#1a365d",
|
|
246
|
+
react: "#61dafb",
|
|
247
|
+
svelte: "#ff3e00",
|
|
248
|
+
vue: "#42b883"
|
|
249
|
+
};
|
|
250
|
+
const accent = frameworkColors[framework] ?? "#94a3b8";
|
|
251
|
+
const label = framework.charAt(0).toUpperCase() + framework.slice(1);
|
|
252
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
253
|
+
return `<!DOCTYPE html>
|
|
254
|
+
<html>
|
|
255
|
+
<head>
|
|
256
|
+
<meta charset="utf-8">
|
|
257
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
258
|
+
<title>SSR Error - AbsoluteJS</title>
|
|
259
|
+
<style>
|
|
260
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
261
|
+
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}
|
|
262
|
+
.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}
|
|
263
|
+
.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)}
|
|
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);
|
|
127
296
|
}
|
|
128
|
-
|
|
129
|
-
|
|
297
|
+
return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
|
|
298
|
+
}, toScreamingSnake = (str) => str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase();
|
|
299
|
+
|
|
300
|
+
// src/utils/resolveConvention.ts
|
|
301
|
+
import { basename } from "path";
|
|
302
|
+
var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boolean(value) && typeof value === "object", getMap = () => {
|
|
303
|
+
const value = Reflect.get(globalThis, CONVENTIONS_KEY);
|
|
304
|
+
if (isConventionsMap(value))
|
|
305
|
+
return value;
|
|
306
|
+
const empty = {};
|
|
307
|
+
return empty;
|
|
308
|
+
}, derivePageName = (pagePath) => {
|
|
309
|
+
const base = basename(pagePath);
|
|
310
|
+
const dotIndex = base.indexOf(".");
|
|
311
|
+
const name = dotIndex > 0 ? base.slice(0, dotIndex) : base;
|
|
312
|
+
return toPascal(name);
|
|
313
|
+
}, resolveErrorConventionPath = (framework, pageName) => {
|
|
314
|
+
const conventions = getMap()[framework];
|
|
315
|
+
if (!conventions)
|
|
316
|
+
return;
|
|
317
|
+
return conventions.pages?.[pageName]?.error ?? conventions.defaults?.error;
|
|
318
|
+
}, resolveNotFoundConventionPath = (framework) => getMap()[framework]?.defaults?.notFound, setConventions = (map) => {
|
|
319
|
+
Reflect.set(globalThis, CONVENTIONS_KEY, map);
|
|
320
|
+
}, isDev = () => true, buildErrorProps = (error) => {
|
|
321
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
322
|
+
const stack = isDev() && error instanceof Error ? error.stack : undefined;
|
|
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}).`);
|
|
384
|
+
return;
|
|
130
385
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
386
|
+
console.error(`[SSR] Failed to render ${framework} convention ${label} page:`, renderError);
|
|
387
|
+
}, ERROR_RENDERERS, renderConventionError = async (framework, pageName, error) => {
|
|
388
|
+
const conventionPath = resolveErrorConventionPath(framework, pageName);
|
|
389
|
+
if (!conventionPath)
|
|
390
|
+
return null;
|
|
391
|
+
const errorProps = buildErrorProps(error);
|
|
392
|
+
const renderer = ERROR_RENDERERS[framework];
|
|
393
|
+
if (!renderer)
|
|
394
|
+
return null;
|
|
395
|
+
try {
|
|
396
|
+
return await renderer(conventionPath, errorProps);
|
|
397
|
+
} catch (renderError) {
|
|
398
|
+
logConventionRenderError(framework, "error", renderError);
|
|
144
399
|
}
|
|
400
|
+
return null;
|
|
401
|
+
}, renderReactNotFound = async (conventionPath) => {
|
|
402
|
+
const { createElement } = await import("react");
|
|
403
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
404
|
+
const mod = await import(conventionPath);
|
|
405
|
+
const [nfKey] = Object.keys(mod);
|
|
406
|
+
const NotFoundComponent = mod.default ?? (nfKey ? mod[nfKey] : undefined);
|
|
407
|
+
const element = createElement(NotFoundComponent);
|
|
408
|
+
const stream = await renderToReadableStream(element);
|
|
409
|
+
return new Response(stream, {
|
|
410
|
+
headers: { "Content-Type": "text/html" },
|
|
411
|
+
status: 404
|
|
412
|
+
});
|
|
413
|
+
}, renderSvelteNotFound = async (conventionPath) => {
|
|
414
|
+
const { render } = await import("svelte/server");
|
|
415
|
+
const mod = await import(conventionPath);
|
|
416
|
+
const NotFoundComponent = mod.default;
|
|
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);
|
|
459
|
+
}
|
|
460
|
+
return null;
|
|
461
|
+
}, NOT_FOUND_PRIORITY, renderFirstNotFound = async () => {
|
|
462
|
+
for (const framework of NOT_FOUND_PRIORITY) {
|
|
463
|
+
if (!getMap()[framework]?.defaults?.notFound)
|
|
464
|
+
continue;
|
|
465
|
+
const response = await renderConventionNotFound(framework);
|
|
466
|
+
if (response)
|
|
467
|
+
return response;
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
145
470
|
};
|
|
471
|
+
var init_resolveConvention = __esm(() => {
|
|
472
|
+
ERROR_RENDERERS = {
|
|
473
|
+
angular: renderAngularError,
|
|
474
|
+
react: renderReactError,
|
|
475
|
+
svelte: renderSvelteError,
|
|
476
|
+
vue: renderVueError
|
|
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
|
+
});
|
|
146
491
|
|
|
147
|
-
//
|
|
148
|
-
var
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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" }
|
|
501
|
+
});
|
|
502
|
+
}, handleReactPageRequest = async (PageComponent, index, ...props) => {
|
|
503
|
+
const [maybeProps] = props;
|
|
504
|
+
if (ssrDirty) {
|
|
505
|
+
return buildDirtyResponse(index, maybeProps);
|
|
506
|
+
}
|
|
507
|
+
try {
|
|
508
|
+
const { createElement } = await import("react");
|
|
509
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
510
|
+
const element = maybeProps !== undefined ? createElement(PageComponent, maybeProps) : createElement(PageComponent);
|
|
511
|
+
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
512
|
+
const refreshSetup = "window.__REFRESH_BUFFER__=[];window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};window.$RefreshSig$=function(){return function(t){return t}};";
|
|
513
|
+
const stream = await renderToReadableStream(element, {
|
|
514
|
+
bootstrapModules: [index],
|
|
515
|
+
bootstrapScriptContent: propsScript + refreshSetup || undefined,
|
|
516
|
+
onError(error) {
|
|
517
|
+
console.error("[SSR] React streaming error:", error);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
if ("allReady" in stream && stream.allReady instanceof Promise) {
|
|
521
|
+
await stream.allReady;
|
|
522
|
+
}
|
|
523
|
+
const htmlStream = injectIslandPageContextStream(stream);
|
|
524
|
+
return new Response(htmlStream, {
|
|
525
|
+
headers: { "Content-Type": "text/html" }
|
|
526
|
+
});
|
|
527
|
+
} catch (error) {
|
|
528
|
+
console.error("[SSR] React render error:", error);
|
|
529
|
+
const pageName = PageComponent.name || PageComponent.displayName || "";
|
|
530
|
+
const conventionResponse = await renderConventionError("react", pageName, error);
|
|
531
|
+
if (conventionResponse)
|
|
532
|
+
return conventionResponse;
|
|
533
|
+
return new Response(ssrErrorPage("react", error), {
|
|
534
|
+
headers: { "Content-Type": "text/html" },
|
|
535
|
+
status: 500
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}, invalidateReactSsrCache = () => {
|
|
539
|
+
ssrDirty = true;
|
|
540
|
+
};
|
|
541
|
+
var init_pageHandler = __esm(() => {
|
|
542
|
+
init_resolveConvention();
|
|
156
543
|
});
|
|
157
544
|
|
|
158
545
|
// src/core/islandManifest.ts
|
|
@@ -206,6 +593,30 @@ var defineIslandComponent = (component, options) => ({
|
|
|
206
593
|
}, serializeIslandProps = (props) => JSON.stringify(props ?? {});
|
|
207
594
|
var init_islands = () => {};
|
|
208
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
|
+
|
|
209
620
|
// src/angular/injectorPatch.ts
|
|
210
621
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
211
622
|
import { dirname, join, resolve } from "path";
|
|
@@ -360,14 +771,6 @@ var init_angularDeps = __esm(() => {
|
|
|
360
771
|
init_resolveAngularPackage();
|
|
361
772
|
});
|
|
362
773
|
|
|
363
|
-
// src/utils/stringModifiers.ts
|
|
364
|
-
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) => {
|
|
365
|
-
if (!str.includes("-") && !str.includes("_")) {
|
|
366
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
367
|
-
}
|
|
368
|
-
return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
|
|
369
|
-
}, toScreamingSnake = (str) => str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase();
|
|
370
|
-
|
|
371
774
|
// src/utils/registerClientScript.ts
|
|
372
775
|
var scriptRegistry, requestCounter = 0, getRequestId = () => `req_${Date.now()}_${++requestCounter}`, ssrContextGetter = null, getSsrContextId = () => ssrContextGetter?.() || Object.getOwnPropertyDescriptor(globalThis, "__absolutejs_requestId")?.value, registerClientScript = (script, requestId) => {
|
|
373
776
|
const id = requestId || getSsrContextId() || getRequestId();
|
|
@@ -741,6 +1144,14 @@ var init_islandSsr = __esm(() => {
|
|
|
741
1144
|
init_islands2();
|
|
742
1145
|
});
|
|
743
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;
|
|
1153
|
+
});
|
|
1154
|
+
|
|
744
1155
|
// src/svelte/lowerIslandSyntax.ts
|
|
745
1156
|
var ISLAND_TAG_RE, extractBracedExpression = (text, braceStart) => {
|
|
746
1157
|
let depth = 0;
|
|
@@ -815,7 +1226,7 @@ var init_lowerIslandSyntax = __esm(() => {
|
|
|
815
1226
|
|
|
816
1227
|
// src/core/svelteServerModule.ts
|
|
817
1228
|
import { mkdir, readdir } from "fs/promises";
|
|
818
|
-
import { basename, dirname as dirname2, extname, join as join2, relative, resolve as resolve3 } from "path";
|
|
1229
|
+
import { basename as basename2, dirname as dirname2, extname, join as join2, relative, resolve as resolve3 } from "path";
|
|
819
1230
|
var serverCacheRoot, compiledModuleCache, originalSourcePathCache, transpiler, ensureRelativeImportPath = (from, target) => {
|
|
820
1231
|
const importPath = relative(dirname2(from), target).replace(/\\/g, "/");
|
|
821
1232
|
return importPath.startsWith(".") ? importPath : `./${importPath}`;
|
|
@@ -846,7 +1257,7 @@ var serverCacheRoot, compiledModuleCache, originalSourcePathCache, transpiler, e
|
|
|
846
1257
|
return found;
|
|
847
1258
|
}
|
|
848
1259
|
return searchDirectoryLevel(nextStack, targetFileName);
|
|
849
|
-
}, findSourceFileByBasename = async (searchRoot, targetFileName) => searchDirectoryLevel([searchRoot], targetFileName), normalizeBuiltSvelteFileName = (sourcePath) =>
|
|
1260
|
+
}, findSourceFileByBasename = async (searchRoot, targetFileName) => searchDirectoryLevel([searchRoot], targetFileName), normalizeBuiltSvelteFileName = (sourcePath) => basename2(sourcePath).replace(/-[a-z0-9]{6,}(?=\.svelte$)/i, ""), resolveOriginalSourcePath = async (sourcePath) => {
|
|
850
1261
|
const cachedPath = originalSourcePathCache.get(sourcePath);
|
|
851
1262
|
if (cachedPath !== undefined) {
|
|
852
1263
|
return cachedPath;
|
|
@@ -982,19 +1393,6 @@ var init_svelteServerModule = __esm(() => {
|
|
|
982
1393
|
});
|
|
983
1394
|
});
|
|
984
1395
|
|
|
985
|
-
// src/core/islandMarkupAttributes.ts
|
|
986
|
-
var getIslandMarkerAttributes = (props, islandId) => ({
|
|
987
|
-
"data-component": props.component,
|
|
988
|
-
"data-framework": props.framework,
|
|
989
|
-
"data-hydrate": props.hydrate ?? "load",
|
|
990
|
-
"data-island": "true",
|
|
991
|
-
...islandId ? { "data-island-id": islandId } : {},
|
|
992
|
-
"data-props": serializeIslandProps(props.props)
|
|
993
|
-
}), escapeHtmlAttribute = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">"), serializeIslandAttributes = (attributes) => Object.entries(attributes).map(([key, value]) => `${key}="${escapeHtmlAttribute(value)}"`).join(" ");
|
|
994
|
-
var init_islandMarkupAttributes = __esm(() => {
|
|
995
|
-
init_islands();
|
|
996
|
-
});
|
|
997
|
-
|
|
998
1396
|
// src/core/renderIslandMarkup.ts
|
|
999
1397
|
var islandSequence = 0, resolvedServerComponentCache, resolvedServerBuildComponentCache, nextIslandId = () => {
|
|
1000
1398
|
islandSequence += 1;
|
|
@@ -1123,6 +1521,75 @@ var init_renderIslandMarkup = __esm(() => {
|
|
|
1123
1521
|
resolvedServerBuildComponentCache = new Map;
|
|
1124
1522
|
});
|
|
1125
1523
|
|
|
1524
|
+
// types/typeGuards.ts
|
|
1525
|
+
var isValidAIClientMessage = (data) => {
|
|
1526
|
+
if (!data || typeof data !== "object") {
|
|
1527
|
+
return false;
|
|
1528
|
+
}
|
|
1529
|
+
if (!("type" in data) || typeof data.type !== "string") {
|
|
1530
|
+
return false;
|
|
1531
|
+
}
|
|
1532
|
+
switch (data.type) {
|
|
1533
|
+
case "message":
|
|
1534
|
+
return "content" in data && typeof data.content === "string";
|
|
1535
|
+
case "cancel":
|
|
1536
|
+
return "conversationId" in data && typeof data.conversationId === "string";
|
|
1537
|
+
case "branch":
|
|
1538
|
+
return "messageId" in data && typeof data.messageId === "string" && "content" in data && typeof data.content === "string" && "conversationId" in data && typeof data.conversationId === "string";
|
|
1539
|
+
default:
|
|
1540
|
+
return false;
|
|
1541
|
+
}
|
|
1542
|
+
}, isValidAIServerMessage = (data) => {
|
|
1543
|
+
if (!data || typeof data !== "object") {
|
|
1544
|
+
return false;
|
|
1545
|
+
}
|
|
1546
|
+
if (!("type" in data) || typeof data.type !== "string") {
|
|
1547
|
+
return false;
|
|
1548
|
+
}
|
|
1549
|
+
switch (data.type) {
|
|
1550
|
+
case "chunk":
|
|
1551
|
+
return "content" in data && typeof data.content === "string" && "messageId" in data && "conversationId" in data;
|
|
1552
|
+
case "thinking":
|
|
1553
|
+
return "content" in data && typeof data.content === "string" && "messageId" in data && "conversationId" in data;
|
|
1554
|
+
case "tool_status":
|
|
1555
|
+
return "name" in data && "status" in data && "messageId" in data && "conversationId" in data;
|
|
1556
|
+
case "image":
|
|
1557
|
+
return "data" in data && typeof data.data === "string" && "format" in data && typeof data.format === "string" && "isPartial" in data && typeof data.isPartial === "boolean" && "messageId" in data && "conversationId" in data;
|
|
1558
|
+
case "complete":
|
|
1559
|
+
return "messageId" in data && "conversationId" in data;
|
|
1560
|
+
case "rag_retrieved":
|
|
1561
|
+
return "conversationId" in data && "messageId" in data && "sources" in data && Array.isArray(data.sources);
|
|
1562
|
+
case "error":
|
|
1563
|
+
return "message" in data && typeof data.message === "string";
|
|
1564
|
+
default:
|
|
1565
|
+
return false;
|
|
1566
|
+
}
|
|
1567
|
+
}, isValidHMRClientMessage = (data) => {
|
|
1568
|
+
if (!data || typeof data !== "object") {
|
|
1569
|
+
return false;
|
|
1570
|
+
}
|
|
1571
|
+
if (!("type" in data) || typeof data.type !== "string") {
|
|
1572
|
+
return false;
|
|
1573
|
+
}
|
|
1574
|
+
switch (data.type) {
|
|
1575
|
+
case "ping":
|
|
1576
|
+
return true;
|
|
1577
|
+
case "ready":
|
|
1578
|
+
return true;
|
|
1579
|
+
case "request-rebuild":
|
|
1580
|
+
return true;
|
|
1581
|
+
case "hydration-error":
|
|
1582
|
+
return true;
|
|
1583
|
+
case "hmr-timing":
|
|
1584
|
+
return true;
|
|
1585
|
+
default:
|
|
1586
|
+
return false;
|
|
1587
|
+
}
|
|
1588
|
+
};
|
|
1589
|
+
|
|
1590
|
+
// types/websocket.ts
|
|
1591
|
+
var WS_READY_STATE_OPEN = 1;
|
|
1592
|
+
|
|
1126
1593
|
// node_modules/typescript/lib/typescript.js
|
|
1127
1594
|
var require_typescript = __commonJS((exports, module) => {
|
|
1128
1595
|
var __dirname = "/home/alexkahn/abs/absolutejs/node_modules/typescript/lib", __filename = "/home/alexkahn/abs/absolutejs/node_modules/typescript/lib/typescript.js";
|
|
@@ -1416,7 +1883,7 @@ var require_typescript = __commonJS((exports, module) => {
|
|
|
1416
1883
|
codefix: () => ts_codefix_exports,
|
|
1417
1884
|
collapseTextChangeRangesAcrossMultipleVersions: () => collapseTextChangeRangesAcrossMultipleVersions,
|
|
1418
1885
|
collectExternalModuleInfo: () => collectExternalModuleInfo,
|
|
1419
|
-
combine: () =>
|
|
1886
|
+
combine: () => combine2,
|
|
1420
1887
|
combinePaths: () => combinePaths,
|
|
1421
1888
|
commandLineOptionOfCustomType: () => commandLineOptionOfCustomType,
|
|
1422
1889
|
commentPragmas: () => commentPragmas,
|
|
@@ -3991,7 +4458,7 @@ var require_typescript = __commonJS((exports, module) => {
|
|
|
3991
4458
|
to.push(value);
|
|
3992
4459
|
return to;
|
|
3993
4460
|
}
|
|
3994
|
-
function
|
|
4461
|
+
function combine2(xs, ys) {
|
|
3995
4462
|
if (xs === undefined)
|
|
3996
4463
|
return ys;
|
|
3997
4464
|
if (ys === undefined)
|
|
@@ -109092,10 +109559,10 @@ ${lanes.join(`
|
|
|
109092
109559
|
}
|
|
109093
109560
|
function getDefaultLibFilePriority(a) {
|
|
109094
109561
|
if (containsPath(defaultLibraryPath, a.fileName, false)) {
|
|
109095
|
-
const
|
|
109096
|
-
if (
|
|
109562
|
+
const basename3 = getBaseFileName(a.fileName);
|
|
109563
|
+
if (basename3 === "lib.d.ts" || basename3 === "lib.es6.d.ts")
|
|
109097
109564
|
return 0;
|
|
109098
|
-
const name = removeSuffix(removePrefix(
|
|
109565
|
+
const name = removeSuffix(removePrefix(basename3, "lib."), ".d.ts");
|
|
109099
109566
|
const index = libs.indexOf(name);
|
|
109100
109567
|
if (index !== -1)
|
|
109101
109568
|
return index + 1;
|
|
@@ -136199,9 +136666,9 @@ ${newComment.split(`
|
|
|
136199
136666
|
const moduleSpecifier = key.slice(2);
|
|
136200
136667
|
const getDeclarations = useRequire ? getNewRequires : getNewImports;
|
|
136201
136668
|
const declarations = getDeclarations(moduleSpecifier, quotePreference, defaultImport, namedImports && arrayFrom(namedImports.entries(), ([name, [addAsTypeOnly, propertyName]]) => ({ addAsTypeOnly, propertyName, name })), namespaceLikeImport, compilerOptions, preferences);
|
|
136202
|
-
newDeclarations =
|
|
136669
|
+
newDeclarations = combine2(newDeclarations, declarations);
|
|
136203
136670
|
});
|
|
136204
|
-
newDeclarations =
|
|
136671
|
+
newDeclarations = combine2(newDeclarations, getCombinedVerbatimImports());
|
|
136205
136672
|
if (newDeclarations) {
|
|
136206
136673
|
insertImports(changeTracker, sourceFile, newDeclarations, true, preferences);
|
|
136207
136674
|
}
|
|
@@ -136951,11 +137418,11 @@ ${newComment.split(`
|
|
|
136951
137418
|
let statements;
|
|
136952
137419
|
if (defaultImport !== undefined || (namedImports == null ? undefined : namedImports.length)) {
|
|
136953
137420
|
const topLevelTypeOnly = (!defaultImport || needsTypeOnly(defaultImport)) && every(namedImports, needsTypeOnly) || (compilerOptions.verbatimModuleSyntax || preferences.preferTypeOnlyAutoImports) && (defaultImport == null ? undefined : defaultImport.addAsTypeOnly) !== 4 && !some(namedImports, (i) => i.addAsTypeOnly === 4);
|
|
136954
|
-
statements =
|
|
137421
|
+
statements = combine2(statements, makeImport(defaultImport && factory.createIdentifier(defaultImport.name), namedImports == null ? undefined : namedImports.map((namedImport) => factory.createImportSpecifier(!topLevelTypeOnly && shouldUseTypeOnly(namedImport, preferences), namedImport.propertyName === undefined ? undefined : factory.createIdentifier(namedImport.propertyName), factory.createIdentifier(namedImport.name))), moduleSpecifier, quotePreference, topLevelTypeOnly));
|
|
136955
137422
|
}
|
|
136956
137423
|
if (namespaceLikeImport) {
|
|
136957
137424
|
const declaration = namespaceLikeImport.importKind === 3 ? factory.createImportEqualsDeclaration(undefined, shouldUseTypeOnly(namespaceLikeImport, preferences), factory.createIdentifier(namespaceLikeImport.name), factory.createExternalModuleReference(quotedModuleSpecifier)) : factory.createImportDeclaration(undefined, factory.createImportClause(shouldUseTypeOnly(namespaceLikeImport, preferences) ? 156 : undefined, undefined, factory.createNamespaceImport(factory.createIdentifier(namespaceLikeImport.name))), quotedModuleSpecifier, undefined);
|
|
136958
|
-
statements =
|
|
137425
|
+
statements = combine2(statements, declaration);
|
|
136959
137426
|
}
|
|
136960
137427
|
return Debug.checkDefined(statements);
|
|
136961
137428
|
}
|
|
@@ -136968,11 +137435,11 @@ ${newComment.split(`
|
|
|
136968
137435
|
bindingElements.unshift(factory.createBindingElement(undefined, "default", defaultImport.name));
|
|
136969
137436
|
}
|
|
136970
137437
|
const declaration = createConstEqualsRequireDeclaration(factory.createObjectBindingPattern(bindingElements), quotedModuleSpecifier);
|
|
136971
|
-
statements =
|
|
137438
|
+
statements = combine2(statements, declaration);
|
|
136972
137439
|
}
|
|
136973
137440
|
if (namespaceLikeImport) {
|
|
136974
137441
|
const declaration = createConstEqualsRequireDeclaration(namespaceLikeImport.name, quotedModuleSpecifier);
|
|
136975
|
-
statements =
|
|
137442
|
+
statements = combine2(statements, declaration);
|
|
136976
137443
|
}
|
|
136977
137444
|
return Debug.checkDefined(statements);
|
|
136978
137445
|
}
|
|
@@ -141424,7 +141891,7 @@ ${newComment.split(`
|
|
|
141424
141891
|
function createModifiers() {
|
|
141425
141892
|
let modifiers2;
|
|
141426
141893
|
if (modifierFlags) {
|
|
141427
|
-
modifiers2 =
|
|
141894
|
+
modifiers2 = combine2(modifiers2, factory.createModifiersFromModifierFlags(modifierFlags));
|
|
141428
141895
|
}
|
|
141429
141896
|
if (shouldAddOverrideKeyword()) {
|
|
141430
141897
|
modifiers2 = append(modifiers2, factory.createToken(164));
|
|
@@ -157416,7 +157883,7 @@ ${options.prefix}` : `
|
|
|
157416
157883
|
codefix: () => ts_codefix_exports,
|
|
157417
157884
|
collapseTextChangeRangesAcrossMultipleVersions: () => collapseTextChangeRangesAcrossMultipleVersions,
|
|
157418
157885
|
collectExternalModuleInfo: () => collectExternalModuleInfo,
|
|
157419
|
-
combine: () =>
|
|
157886
|
+
combine: () => combine2,
|
|
157420
157887
|
combinePaths: () => combinePaths,
|
|
157421
157888
|
commandLineOptionOfCustomType: () => commandLineOptionOfCustomType,
|
|
157422
157889
|
commentPragmas: () => commentPragmas,
|
|
@@ -161658,8 +162125,8 @@ ${options.prefix}` : `
|
|
|
161658
162125
|
}
|
|
161659
162126
|
};
|
|
161660
162127
|
for (const file of files) {
|
|
161661
|
-
const
|
|
161662
|
-
if (
|
|
162128
|
+
const basename3 = getBaseFileName(file);
|
|
162129
|
+
if (basename3 === "package.json" || basename3 === "bower.json") {
|
|
161663
162130
|
createProjectWatcher(file, "FileWatcher");
|
|
161664
162131
|
continue;
|
|
161665
162132
|
}
|
|
@@ -164536,8 +165003,8 @@ All files are: ${JSON.stringify(names)}`, "Err");
|
|
|
164536
165003
|
const fileOrDirectoryPath = removeIgnoredPath(this.toPath(fileOrDirectory));
|
|
164537
165004
|
if (!fileOrDirectoryPath)
|
|
164538
165005
|
return;
|
|
164539
|
-
const
|
|
164540
|
-
if (((_a = result.affectedModuleSpecifierCacheProjects) == null ? undefined : _a.size) && (
|
|
165006
|
+
const basename3 = getBaseFileName(fileOrDirectoryPath);
|
|
165007
|
+
if (((_a = result.affectedModuleSpecifierCacheProjects) == null ? undefined : _a.size) && (basename3 === "package.json" || basename3 === "node_modules")) {
|
|
164541
165008
|
result.affectedModuleSpecifierCacheProjects.forEach((project) => {
|
|
164542
165009
|
var _a2;
|
|
164543
165010
|
(_a2 = project.getModuleSpecifierCache()) == null || _a2.clear();
|
|
@@ -170061,17 +170528,6 @@ var init_islandEntries = __esm(() => {
|
|
|
170061
170528
|
];
|
|
170062
170529
|
});
|
|
170063
170530
|
|
|
170064
|
-
// src/core/currentIslandRegistry.ts
|
|
170065
|
-
var requireCurrentIslandRegistry = () => {
|
|
170066
|
-
const registry = globalThis.__absoluteIslandRegistry;
|
|
170067
|
-
if (!registry) {
|
|
170068
|
-
throw new Error("No island registry is active. Configure `islands.registry` in absolute.config.ts before rendering <Island />.");
|
|
170069
|
-
}
|
|
170070
|
-
return registry;
|
|
170071
|
-
}, setCurrentIslandRegistry = (registry) => {
|
|
170072
|
-
globalThis.__absoluteIslandRegistry = registry;
|
|
170073
|
-
};
|
|
170074
|
-
|
|
170075
170531
|
// src/build/staticIslandPages.ts
|
|
170076
170532
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
170077
170533
|
var ISLAND_TAG_RE_SOURCE = "<(?:absolute-island|island)\\b([^>]*?)(?:\\/\\>|>(?:[\\s\\S]*?)<\\/(?:absolute-island|island)>)", ATTRIBUTE_RE_SOURCE = `([A-Za-z_:][-A-Za-z0-9_:.]*)\\s*=\\s*(?:"([^"]*)"|'([^']*)')`, islandFrameworks, islandHydrationModes, isRecord4 = (value) => typeof value === "object" && value !== null, isIslandFramework = (value) => islandFrameworks.some((framework) => framework === value), isIslandHydrationMode = (value) => islandHydrationModes.some((mode) => mode === value), parseIslandAttributes = (attributeString) => {
|
|
@@ -170162,1014 +170618,6 @@ var init_staticIslandPages = __esm(() => {
|
|
|
170162
170618
|
islandHydrationModes = ["load", "idle", "visible", "none"];
|
|
170163
170619
|
});
|
|
170164
170620
|
|
|
170165
|
-
// src/core/islandPageContext.ts
|
|
170166
|
-
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) => {
|
|
170167
|
-
const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
|
|
170168
|
-
const islandStateScript = `<script>window.__ABS_ISLAND_STATE__ = ${JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {})}</script>`;
|
|
170169
|
-
const bootstrapPath = manifest[BOOTSTRAP_MANIFEST_KEY];
|
|
170170
|
-
const bootstrapScript = bootstrapPath ? `<script type="module" src="${bootstrapPath}"></script>` : "";
|
|
170171
|
-
return `${manifestScript}${islandStateScript}${bootstrapScript}`;
|
|
170172
|
-
}, injectHeadMarkup = (html, markup) => {
|
|
170173
|
-
const closingHeadIndex = html.indexOf("</head>");
|
|
170174
|
-
if (closingHeadIndex >= 0) {
|
|
170175
|
-
return `${html.slice(0, closingHeadIndex)}${markup}${html.slice(closingHeadIndex)}`;
|
|
170176
|
-
}
|
|
170177
|
-
const openingBodyIndex = html.indexOf("<body");
|
|
170178
|
-
if (openingBodyIndex >= 0) {
|
|
170179
|
-
const bodyStart = html.indexOf(">", openingBodyIndex);
|
|
170180
|
-
if (bodyStart >= 0) {
|
|
170181
|
-
return `${html.slice(0, openingBodyIndex)}<head>${markup}</head>${html.slice(openingBodyIndex)}`;
|
|
170182
|
-
}
|
|
170183
|
-
}
|
|
170184
|
-
return `<!DOCTYPE html><html><head>${markup}</head><body>${html}</body></html>`;
|
|
170185
|
-
}, streamChunkToString = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true }), pipeStreamWithHeadInjection = (stream, markup) => {
|
|
170186
|
-
const encoder = new TextEncoder;
|
|
170187
|
-
const decoder = new TextDecoder;
|
|
170188
|
-
const lookbehind = CLOSING_HEAD_TAG.length - 1;
|
|
170189
|
-
return new ReadableStream({
|
|
170190
|
-
async start(controller) {
|
|
170191
|
-
const reader = stream.getReader();
|
|
170192
|
-
let injected = false;
|
|
170193
|
-
let pending = "";
|
|
170194
|
-
try {
|
|
170195
|
-
for (;; ) {
|
|
170196
|
-
const { done, value } = await reader.read();
|
|
170197
|
-
if (done)
|
|
170198
|
-
break;
|
|
170199
|
-
if (!value)
|
|
170200
|
-
continue;
|
|
170201
|
-
pending += streamChunkToString(value, decoder);
|
|
170202
|
-
if (injected) {
|
|
170203
|
-
controller.enqueue(encoder.encode(pending));
|
|
170204
|
-
pending = "";
|
|
170205
|
-
continue;
|
|
170206
|
-
}
|
|
170207
|
-
const headIndex = pending.indexOf(CLOSING_HEAD_TAG);
|
|
170208
|
-
if (headIndex >= 0) {
|
|
170209
|
-
const next = `${pending.slice(0, headIndex)}${markup}${pending.slice(headIndex)}`;
|
|
170210
|
-
controller.enqueue(encoder.encode(next));
|
|
170211
|
-
pending = "";
|
|
170212
|
-
injected = true;
|
|
170213
|
-
continue;
|
|
170214
|
-
}
|
|
170215
|
-
if (pending.length > lookbehind) {
|
|
170216
|
-
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
170217
|
-
controller.enqueue(encoder.encode(safeText));
|
|
170218
|
-
pending = pending.slice(-lookbehind);
|
|
170219
|
-
}
|
|
170220
|
-
}
|
|
170221
|
-
pending += decoder.decode();
|
|
170222
|
-
if (!injected) {
|
|
170223
|
-
pending = injectHeadMarkup(pending, markup);
|
|
170224
|
-
}
|
|
170225
|
-
if (pending.length > 0) {
|
|
170226
|
-
controller.enqueue(encoder.encode(pending));
|
|
170227
|
-
}
|
|
170228
|
-
controller.close();
|
|
170229
|
-
} catch (error) {
|
|
170230
|
-
controller.error(error);
|
|
170231
|
-
}
|
|
170232
|
-
}
|
|
170233
|
-
});
|
|
170234
|
-
}, pipeStreamWithIslandMarkerDetection = (stream, markup) => {
|
|
170235
|
-
const encoder = new TextEncoder;
|
|
170236
|
-
const decoder = new TextDecoder;
|
|
170237
|
-
const lookbehind = Math.max(ISLAND_MARKER.length, 1024);
|
|
170238
|
-
return new ReadableStream({
|
|
170239
|
-
async start(controller) {
|
|
170240
|
-
const reader = stream.getReader();
|
|
170241
|
-
let injected = false;
|
|
170242
|
-
let pending = "";
|
|
170243
|
-
try {
|
|
170244
|
-
for (;; ) {
|
|
170245
|
-
const { done, value } = await reader.read();
|
|
170246
|
-
if (done)
|
|
170247
|
-
break;
|
|
170248
|
-
if (!value)
|
|
170249
|
-
continue;
|
|
170250
|
-
pending += streamChunkToString(value, decoder);
|
|
170251
|
-
if (injected) {
|
|
170252
|
-
controller.enqueue(encoder.encode(pending));
|
|
170253
|
-
pending = "";
|
|
170254
|
-
continue;
|
|
170255
|
-
}
|
|
170256
|
-
const markerIndex = pending.indexOf(ISLAND_MARKER);
|
|
170257
|
-
if (markerIndex >= 0) {
|
|
170258
|
-
const tagStart = pending.lastIndexOf("<", markerIndex);
|
|
170259
|
-
const injectAt = tagStart >= 0 ? tagStart : markerIndex;
|
|
170260
|
-
const next = `${pending.slice(0, injectAt)}${markup}${pending.slice(injectAt)}`;
|
|
170261
|
-
controller.enqueue(encoder.encode(next));
|
|
170262
|
-
pending = "";
|
|
170263
|
-
injected = true;
|
|
170264
|
-
continue;
|
|
170265
|
-
}
|
|
170266
|
-
if (pending.length > lookbehind) {
|
|
170267
|
-
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
170268
|
-
controller.enqueue(encoder.encode(safeText));
|
|
170269
|
-
pending = pending.slice(-lookbehind);
|
|
170270
|
-
}
|
|
170271
|
-
}
|
|
170272
|
-
pending += decoder.decode();
|
|
170273
|
-
if (pending.length > 0) {
|
|
170274
|
-
controller.enqueue(encoder.encode(pending));
|
|
170275
|
-
}
|
|
170276
|
-
controller.close();
|
|
170277
|
-
} catch (error) {
|
|
170278
|
-
controller.error(error);
|
|
170279
|
-
}
|
|
170280
|
-
}
|
|
170281
|
-
});
|
|
170282
|
-
}, htmlContainsIslands = (html) => html.includes(ISLAND_MARKER), injectIslandPageContext = (html, options) => {
|
|
170283
|
-
const manifest = globalThis.__absoluteManifest;
|
|
170284
|
-
const hasIslands = options?.hasIslands ?? htmlContainsIslands(html);
|
|
170285
|
-
if (!manifest || !hasIslands) {
|
|
170286
|
-
return html;
|
|
170287
|
-
}
|
|
170288
|
-
if (html.includes(MANIFEST_MARKER) || html.includes(ISLAND_STATE_MARKER)) {
|
|
170289
|
-
return html;
|
|
170290
|
-
}
|
|
170291
|
-
return injectHeadMarkup(html, buildIslandsHeadMarkup(manifest));
|
|
170292
|
-
}, injectIslandPageContextStream = (stream, options) => {
|
|
170293
|
-
const manifest = globalThis.__absoluteManifest;
|
|
170294
|
-
if (!manifest)
|
|
170295
|
-
return stream;
|
|
170296
|
-
const markup = buildIslandsHeadMarkup(manifest);
|
|
170297
|
-
if (options?.hasIslands === true) {
|
|
170298
|
-
return pipeStreamWithHeadInjection(stream, markup);
|
|
170299
|
-
}
|
|
170300
|
-
if (options?.hasIslands === false) {
|
|
170301
|
-
return stream;
|
|
170302
|
-
}
|
|
170303
|
-
return pipeStreamWithIslandMarkerDetection(stream, markup);
|
|
170304
|
-
}, setCurrentIslandManifest = (manifest) => {
|
|
170305
|
-
globalThis.__absoluteManifest = manifest;
|
|
170306
|
-
};
|
|
170307
|
-
|
|
170308
|
-
// src/client/streamSwap.ts
|
|
170309
|
-
var streamSwapRuntime = () => {
|
|
170310
|
-
if (window.__ABS_SLOT_RUNTIME__ === true)
|
|
170311
|
-
return;
|
|
170312
|
-
window.__ABS_SLOT_RUNTIME__ = true;
|
|
170313
|
-
window.__ABS_SLOT_PENDING__ = window.__ABS_SLOT_PENDING__ ?? {};
|
|
170314
|
-
const pending = window.__ABS_SLOT_PENDING__;
|
|
170315
|
-
const apply = (id, html) => {
|
|
170316
|
-
const node = document.getElementById(`slot-${id}`);
|
|
170317
|
-
if (!node) {
|
|
170318
|
-
pending[id] = html;
|
|
170319
|
-
return;
|
|
170320
|
-
}
|
|
170321
|
-
node.innerHTML = html;
|
|
170322
|
-
delete pending[id];
|
|
170323
|
-
};
|
|
170324
|
-
const flush = () => {
|
|
170325
|
-
for (const id in pending) {
|
|
170326
|
-
if (!Object.prototype.hasOwnProperty.call(pending, id))
|
|
170327
|
-
continue;
|
|
170328
|
-
apply(id, pending[id] ?? "");
|
|
170329
|
-
}
|
|
170330
|
-
};
|
|
170331
|
-
window.__ABS_SLOT_ENQUEUE__ = (id, html) => {
|
|
170332
|
-
apply(id, html);
|
|
170333
|
-
};
|
|
170334
|
-
if (typeof MutationObserver === "function") {
|
|
170335
|
-
const observer = new MutationObserver(flush);
|
|
170336
|
-
const root = document.documentElement ?? document.body ?? document;
|
|
170337
|
-
observer.observe(root, { childList: true, subtree: true });
|
|
170338
|
-
}
|
|
170339
|
-
if (document.readyState === "loading") {
|
|
170340
|
-
document.addEventListener("DOMContentLoaded", flush, { once: true });
|
|
170341
|
-
}
|
|
170342
|
-
flush();
|
|
170343
|
-
}, stripFunctionWrapper = (value) => {
|
|
170344
|
-
const start = value.indexOf("{");
|
|
170345
|
-
const end = value.lastIndexOf("}");
|
|
170346
|
-
if (start < 0 || end <= start)
|
|
170347
|
-
return "";
|
|
170348
|
-
return value.slice(start + 1, end);
|
|
170349
|
-
}, getStreamSwapRuntimeScript = () => `(function(){${stripFunctionWrapper(streamSwapRuntime.toString())}})();`;
|
|
170350
|
-
|
|
170351
|
-
// src/utils/escapeScriptContent.ts
|
|
170352
|
-
var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
|
|
170353
|
-
const escaped = ESCAPE_LOOKUP[char];
|
|
170354
|
-
return escaped !== undefined ? escaped : char;
|
|
170355
|
-
});
|
|
170356
|
-
var init_escapeScriptContent = __esm(() => {
|
|
170357
|
-
ESCAPE_LOOKUP = {
|
|
170358
|
-
"\u2028": "\\u2028",
|
|
170359
|
-
"\u2029": "\\u2029",
|
|
170360
|
-
"&": "\\u0026",
|
|
170361
|
-
"<": "\\u003C",
|
|
170362
|
-
">": "\\u003E"
|
|
170363
|
-
};
|
|
170364
|
-
ESCAPE_REGEX = /[&><\u2028\u2029]/g;
|
|
170365
|
-
});
|
|
170366
|
-
|
|
170367
|
-
// src/utils/streamingSlots.ts
|
|
170368
|
-
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) => {
|
|
170369
|
-
const closingHeadIndex = html.indexOf(CLOSING_HEAD_TAG2);
|
|
170370
|
-
if (closingHeadIndex >= 0) {
|
|
170371
|
-
return `${html.slice(0, closingHeadIndex)}${injection}${html.slice(closingHeadIndex)}`;
|
|
170372
|
-
}
|
|
170373
|
-
return `${html}${injection}`;
|
|
170374
|
-
}, toUint8 = (value, encoder) => encoder.encode(value), currentStreamingSlotPolicy, clonePolicy = (policy) => ({
|
|
170375
|
-
...policy
|
|
170376
|
-
}), normalizeSlotBytes = (value, fallback) => {
|
|
170377
|
-
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
170378
|
-
return Math.floor(value);
|
|
170379
|
-
}
|
|
170380
|
-
return fallback;
|
|
170381
|
-
}, 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 = {}) => ({
|
|
170382
|
-
timeoutMs: hasPolicyValue(overridePolicy, "timeoutMs") ? normalizeSlotBytes(overridePolicy.timeoutMs, base.timeoutMs) : base.timeoutMs,
|
|
170383
|
-
fallbackHtml: hasPolicyValue(overridePolicy, "fallbackHtml") ? normalizeSlotText(overridePolicy.fallbackHtml, "") : base.fallbackHtml,
|
|
170384
|
-
errorHtml: hasPolicyValue(overridePolicy, "errorHtml") ? normalizeSlotError(overridePolicy.errorHtml) : base.errorHtml,
|
|
170385
|
-
maxSlotsPerResponse: hasPolicyValue(overridePolicy, "maxSlotsPerResponse") ? normalizeSlotBytes(overridePolicy.maxSlotsPerResponse, base.maxSlotsPerResponse) : base.maxSlotsPerResponse,
|
|
170386
|
-
maxSlotHtmlSizeBytes: hasPolicyValue(overridePolicy, "maxSlotHtmlSizeBytes") ? normalizeSlotBytes(overridePolicy.maxSlotHtmlSizeBytes, base.maxSlotHtmlSizeBytes) : base.maxSlotHtmlSizeBytes,
|
|
170387
|
-
onError: hasPolicyValue(overridePolicy, "onError") ? overridePolicy.onError : base.onError,
|
|
170388
|
-
onSlotMetric: hasPolicyValue(overridePolicy, "onSlotMetric") ? overridePolicy.onSlotMetric : base.onSlotMetric
|
|
170389
|
-
}), createCombinedSlotErrorHandler = (policyOnError, enhancerOnError) => {
|
|
170390
|
-
if (!policyOnError && !enhancerOnError)
|
|
170391
|
-
return;
|
|
170392
|
-
return (error, slot) => {
|
|
170393
|
-
policyOnError?.(error, slot);
|
|
170394
|
-
enhancerOnError?.(error, slot);
|
|
170395
|
-
};
|
|
170396
|
-
}, createCombinedSlotMetricHandler = (policyOnSlotMetric, callOnSlotMetric) => {
|
|
170397
|
-
if (!policyOnSlotMetric && !callOnSlotMetric)
|
|
170398
|
-
return;
|
|
170399
|
-
return (metric) => {
|
|
170400
|
-
policyOnSlotMetric?.(metric);
|
|
170401
|
-
callOnSlotMetric?.(metric);
|
|
170402
|
-
};
|
|
170403
|
-
}, resolveStreamingSlotPolicy = (overridePolicy = {}) => {
|
|
170404
|
-
const base = getStreamingSlotPolicy();
|
|
170405
|
-
return applyStreamingSlotPolicyOverrides(base, overridePolicy);
|
|
170406
|
-
}, getStreamingSlotPolicy = () => clonePolicy(currentStreamingSlotPolicy), setStreamingSlotPolicy = (policy = {}) => {
|
|
170407
|
-
const base = getStreamingSlotPolicy();
|
|
170408
|
-
currentStreamingSlotPolicy = applyStreamingSlotPolicyOverrides(base, policy);
|
|
170409
|
-
}, withStreamingSlotPolicy = async (policy, callback) => {
|
|
170410
|
-
const previous = getStreamingSlotPolicy();
|
|
170411
|
-
setStreamingSlotPolicy(policy);
|
|
170412
|
-
try {
|
|
170413
|
-
return await callback();
|
|
170414
|
-
} finally {
|
|
170415
|
-
currentStreamingSlotPolicy = previous;
|
|
170416
|
-
}
|
|
170417
|
-
}, emitSlotMetric = (metric, onSlotMetric) => {
|
|
170418
|
-
onSlotMetric?.(metric);
|
|
170419
|
-
}, createTimeoutError = (slot, timeoutMs) => {
|
|
170420
|
-
const error = new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`);
|
|
170421
|
-
error.__absTimeout = true;
|
|
170422
|
-
return error;
|
|
170423
|
-
}, toStreamingSlot = (slot, policy) => ({
|
|
170424
|
-
errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
|
|
170425
|
-
fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
|
|
170426
|
-
id: slot.id ?? createStreamingSlotId(),
|
|
170427
|
-
timeoutMs: normalizeSlotBytes(slot.timeoutMs, policy.timeoutMs),
|
|
170428
|
-
resolve: slot.resolve
|
|
170429
|
-
}), prepareSlots = ({
|
|
170430
|
-
policy,
|
|
170431
|
-
slots,
|
|
170432
|
-
onError,
|
|
170433
|
-
onSlotMetric
|
|
170434
|
-
}) => {
|
|
170435
|
-
const preparedSlots = slots.map((slot) => toStreamingSlot(slot, policy));
|
|
170436
|
-
const maxSlotsPerResponse = policy.maxSlotsPerResponse;
|
|
170437
|
-
if (maxSlotsPerResponse === 0) {
|
|
170438
|
-
const error = new Error("Streaming slot limit is set to 0");
|
|
170439
|
-
for (const slot of preparedSlots) {
|
|
170440
|
-
onError?.(error, slot);
|
|
170441
|
-
emitSlotMetric({
|
|
170442
|
-
type: "dropped",
|
|
170443
|
-
slotId: slot.id,
|
|
170444
|
-
reason: "maxSlotsPerResponse is 0"
|
|
170445
|
-
}, onSlotMetric);
|
|
170446
|
-
}
|
|
170447
|
-
return [];
|
|
170448
|
-
}
|
|
170449
|
-
if (preparedSlots.length <= maxSlotsPerResponse) {
|
|
170450
|
-
preparedSlots.forEach((slot) => emitSlotMetric({
|
|
170451
|
-
type: "prepared",
|
|
170452
|
-
slotId: slot.id
|
|
170453
|
-
}, onSlotMetric));
|
|
170454
|
-
return preparedSlots;
|
|
170455
|
-
}
|
|
170456
|
-
const keptSlots = preparedSlots.slice(0, maxSlotsPerResponse);
|
|
170457
|
-
const droppedSlots = preparedSlots.slice(maxSlotsPerResponse);
|
|
170458
|
-
droppedSlots.forEach((slot) => {
|
|
170459
|
-
onError?.(new Error(`Streaming slot "${slot.id}" dropped because ${maxSlotsPerResponse} slots is the configured maximum`), slot);
|
|
170460
|
-
emitSlotMetric({
|
|
170461
|
-
type: "dropped",
|
|
170462
|
-
slotId: slot.id,
|
|
170463
|
-
reason: `maxSlotsPerResponse is ${maxSlotsPerResponse}`
|
|
170464
|
-
}, onSlotMetric);
|
|
170465
|
-
});
|
|
170466
|
-
keptSlots.forEach((slot) => emitSlotMetric({
|
|
170467
|
-
type: "prepared",
|
|
170468
|
-
slotId: slot.id
|
|
170469
|
-
}, onSlotMetric));
|
|
170470
|
-
return keptSlots;
|
|
170471
|
-
}, htmlByteLength = (value, encoder) => encoder.encode(value).length, resolveSlot = async (slot, onError, policy, onSlotMetric) => {
|
|
170472
|
-
const safePolicy = policy ?? getStreamingSlotPolicy();
|
|
170473
|
-
const encoder = new TextEncoder;
|
|
170474
|
-
const start = Date.now();
|
|
170475
|
-
try {
|
|
170476
|
-
const maybeAsyncValue = Promise.resolve(slot.resolve());
|
|
170477
|
-
const resolved = typeof slot.timeoutMs === "number" && slot.timeoutMs > 0 ? await Promise.race([
|
|
170478
|
-
maybeAsyncValue,
|
|
170479
|
-
new Promise((_, reject) => setTimeout(() => {
|
|
170480
|
-
reject(createTimeoutError(slot, slot.timeoutMs ?? 0));
|
|
170481
|
-
}, slot.timeoutMs))
|
|
170482
|
-
]) : await maybeAsyncValue;
|
|
170483
|
-
const html = typeof resolved === "string" ? resolved : `${resolved}`;
|
|
170484
|
-
if (safePolicy.maxSlotHtmlSizeBytes > 0 && htmlByteLength(html, encoder) > safePolicy.maxSlotHtmlSizeBytes) {
|
|
170485
|
-
const bytes2 = htmlByteLength(html, encoder);
|
|
170486
|
-
const error = new Error(`Streaming slot "${slot.id}" exceeded max payload size of ${safePolicy.maxSlotHtmlSizeBytes} bytes`);
|
|
170487
|
-
const durationMs2 = Date.now() - start;
|
|
170488
|
-
onError?.(error, slot);
|
|
170489
|
-
emitSlotMetric({
|
|
170490
|
-
type: "size_exceeded",
|
|
170491
|
-
slotId: slot.id,
|
|
170492
|
-
durationMs: durationMs2,
|
|
170493
|
-
bytes: bytes2,
|
|
170494
|
-
error
|
|
170495
|
-
}, onSlotMetric);
|
|
170496
|
-
const fallbackHtml = typeof slot.errorHtml === "string" ? slot.errorHtml : null;
|
|
170497
|
-
return {
|
|
170498
|
-
html: fallbackHtml,
|
|
170499
|
-
id: slot.id,
|
|
170500
|
-
durationMs: durationMs2,
|
|
170501
|
-
bytes: fallbackHtml === null ? 0 : htmlByteLength(fallbackHtml, encoder)
|
|
170502
|
-
};
|
|
170503
|
-
}
|
|
170504
|
-
const durationMs = Date.now() - start;
|
|
170505
|
-
const bytes = htmlByteLength(html, encoder);
|
|
170506
|
-
emitSlotMetric({
|
|
170507
|
-
type: "resolved",
|
|
170508
|
-
slotId: slot.id,
|
|
170509
|
-
durationMs,
|
|
170510
|
-
bytes
|
|
170511
|
-
}, onSlotMetric);
|
|
170512
|
-
return {
|
|
170513
|
-
html,
|
|
170514
|
-
id: slot.id,
|
|
170515
|
-
durationMs,
|
|
170516
|
-
bytes
|
|
170517
|
-
};
|
|
170518
|
-
} catch (error) {
|
|
170519
|
-
const durationMs = Date.now() - start;
|
|
170520
|
-
onError?.(error, slot);
|
|
170521
|
-
emitSlotMetric({
|
|
170522
|
-
type: error?.__absTimeout === true ? "timeout" : "error",
|
|
170523
|
-
slotId: slot.id,
|
|
170524
|
-
durationMs,
|
|
170525
|
-
error
|
|
170526
|
-
}, onSlotMetric);
|
|
170527
|
-
if (typeof slot.errorHtml === "string") {
|
|
170528
|
-
const html = slot.errorHtml;
|
|
170529
|
-
return {
|
|
170530
|
-
html,
|
|
170531
|
-
id: slot.id,
|
|
170532
|
-
durationMs,
|
|
170533
|
-
bytes: htmlByteLength(html, encoder)
|
|
170534
|
-
};
|
|
170535
|
-
}
|
|
170536
|
-
return {
|
|
170537
|
-
html: null,
|
|
170538
|
-
id: slot.id,
|
|
170539
|
-
durationMs,
|
|
170540
|
-
bytes: 0
|
|
170541
|
-
};
|
|
170542
|
-
}
|
|
170543
|
-
}, nextResolvedSlot = async (pending) => {
|
|
170544
|
-
const wrapped = pending.map((promise) => promise.then((result) => ({
|
|
170545
|
-
original: promise,
|
|
170546
|
-
result
|
|
170547
|
-
})));
|
|
170548
|
-
return Promise.race(wrapped);
|
|
170549
|
-
}, streamChunkToString2 = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true }), streamOutOfOrderSlots = ({
|
|
170550
|
-
footerHtml = "",
|
|
170551
|
-
headerHtml = "",
|
|
170552
|
-
nonce,
|
|
170553
|
-
policy,
|
|
170554
|
-
onSlotMetric,
|
|
170555
|
-
onError,
|
|
170556
|
-
slots
|
|
170557
|
-
}) => {
|
|
170558
|
-
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
170559
|
-
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
170560
|
-
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
170561
|
-
const effectivePolicy = {
|
|
170562
|
-
...resolvedPolicy,
|
|
170563
|
-
onSlotMetric: combinedOnSlotMetric
|
|
170564
|
-
};
|
|
170565
|
-
const preparedSlots = prepareSlots({
|
|
170566
|
-
policy: effectivePolicy,
|
|
170567
|
-
slots,
|
|
170568
|
-
onError: combinedOnError,
|
|
170569
|
-
onSlotMetric: combinedOnSlotMetric
|
|
170570
|
-
});
|
|
170571
|
-
const encoder = new TextEncoder;
|
|
170572
|
-
return new ReadableStream({
|
|
170573
|
-
async start(controller) {
|
|
170574
|
-
try {
|
|
170575
|
-
let header = headerHtml;
|
|
170576
|
-
if (preparedSlots.length > 0 && !header.includes(STREAMING_RUNTIME_GLOBAL)) {
|
|
170577
|
-
header = injectHtmlIntoHead(header, renderStreamingSlotsRuntimeTag(nonce));
|
|
170578
|
-
}
|
|
170579
|
-
controller.enqueue(toUint8(header, encoder));
|
|
170580
|
-
const pending = preparedSlots.map((slot) => {
|
|
170581
|
-
const fallback = renderStreamingSlotPlaceholder(slot.id, slot.fallbackHtml ?? "");
|
|
170582
|
-
controller.enqueue(toUint8(fallback, encoder));
|
|
170583
|
-
return resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric);
|
|
170584
|
-
});
|
|
170585
|
-
while (pending.length > 0) {
|
|
170586
|
-
const { original, result } = await nextResolvedSlot(pending);
|
|
170587
|
-
const index = pending.indexOf(original);
|
|
170588
|
-
if (index >= 0)
|
|
170589
|
-
pending.splice(index, 1);
|
|
170590
|
-
if (result.html === null)
|
|
170591
|
-
continue;
|
|
170592
|
-
emitSlotMetric({
|
|
170593
|
-
type: "patched",
|
|
170594
|
-
slotId: result.id,
|
|
170595
|
-
durationMs: result.durationMs,
|
|
170596
|
-
bytes: result.bytes
|
|
170597
|
-
}, combinedOnSlotMetric);
|
|
170598
|
-
controller.enqueue(toUint8(renderStreamingSlotPatchTag(result.id, result.html, nonce), encoder));
|
|
170599
|
-
}
|
|
170600
|
-
if (footerHtml.length > 0) {
|
|
170601
|
-
controller.enqueue(toUint8(footerHtml, encoder));
|
|
170602
|
-
}
|
|
170603
|
-
controller.close();
|
|
170604
|
-
} catch (error) {
|
|
170605
|
-
controller.error(error);
|
|
170606
|
-
}
|
|
170607
|
-
}
|
|
170608
|
-
});
|
|
170609
|
-
}, injectStreamingRuntimeIntoStream = (stream, nonce) => {
|
|
170610
|
-
const runtimeTag = renderStreamingSlotsRuntimeTag(nonce);
|
|
170611
|
-
const encoder = new TextEncoder;
|
|
170612
|
-
const decoder = new TextDecoder;
|
|
170613
|
-
const lookbehind = CLOSING_HEAD_TAG_LENGTH - 1;
|
|
170614
|
-
return new ReadableStream({
|
|
170615
|
-
async start(controller) {
|
|
170616
|
-
const reader = stream.getReader();
|
|
170617
|
-
let injected = false;
|
|
170618
|
-
let pending = "";
|
|
170619
|
-
try {
|
|
170620
|
-
for (;; ) {
|
|
170621
|
-
const { done, value } = await reader.read();
|
|
170622
|
-
if (done)
|
|
170623
|
-
break;
|
|
170624
|
-
if (!value)
|
|
170625
|
-
continue;
|
|
170626
|
-
pending += streamChunkToString2(value, decoder);
|
|
170627
|
-
if (injected) {
|
|
170628
|
-
controller.enqueue(encoder.encode(pending));
|
|
170629
|
-
pending = "";
|
|
170630
|
-
continue;
|
|
170631
|
-
}
|
|
170632
|
-
const headIndex = pending.indexOf(CLOSING_HEAD_TAG2);
|
|
170633
|
-
if (headIndex >= 0) {
|
|
170634
|
-
const withRuntime = `${pending.slice(0, headIndex)}${runtimeTag}${pending.slice(headIndex)}`;
|
|
170635
|
-
controller.enqueue(encoder.encode(withRuntime));
|
|
170636
|
-
pending = "";
|
|
170637
|
-
injected = true;
|
|
170638
|
-
continue;
|
|
170639
|
-
}
|
|
170640
|
-
if (pending.length > lookbehind) {
|
|
170641
|
-
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
170642
|
-
controller.enqueue(encoder.encode(safeText));
|
|
170643
|
-
pending = pending.slice(-lookbehind);
|
|
170644
|
-
}
|
|
170645
|
-
}
|
|
170646
|
-
pending += decoder.decode();
|
|
170647
|
-
if (!injected) {
|
|
170648
|
-
pending = injectHtmlIntoHead(pending, runtimeTag);
|
|
170649
|
-
}
|
|
170650
|
-
if (pending.length > 0) {
|
|
170651
|
-
controller.enqueue(encoder.encode(pending));
|
|
170652
|
-
}
|
|
170653
|
-
controller.close();
|
|
170654
|
-
} catch (error) {
|
|
170655
|
-
controller.error(error);
|
|
170656
|
-
}
|
|
170657
|
-
}
|
|
170658
|
-
});
|
|
170659
|
-
}, appendStreamingSlotPatchesToStream = (stream, slots = [], {
|
|
170660
|
-
injectRuntime = true,
|
|
170661
|
-
nonce,
|
|
170662
|
-
onError,
|
|
170663
|
-
onSlotMetric,
|
|
170664
|
-
policy
|
|
170665
|
-
} = {}) => {
|
|
170666
|
-
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
170667
|
-
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
170668
|
-
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
170669
|
-
const effectivePolicy = {
|
|
170670
|
-
...resolvedPolicy,
|
|
170671
|
-
onSlotMetric: combinedOnSlotMetric
|
|
170672
|
-
};
|
|
170673
|
-
const preparedSlots = prepareSlots({
|
|
170674
|
-
policy: effectivePolicy,
|
|
170675
|
-
slots,
|
|
170676
|
-
onError: combinedOnError,
|
|
170677
|
-
onSlotMetric: combinedOnSlotMetric
|
|
170678
|
-
});
|
|
170679
|
-
if (preparedSlots.length === 0)
|
|
170680
|
-
return stream;
|
|
170681
|
-
const source = injectRuntime ? injectStreamingRuntimeIntoStream(stream, nonce) : stream;
|
|
170682
|
-
const encoder = new TextEncoder;
|
|
170683
|
-
const decoder = new TextDecoder;
|
|
170684
|
-
const reader = source.getReader();
|
|
170685
|
-
const pending = preparedSlots.map((slot) => resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric));
|
|
170686
|
-
return new ReadableStream({
|
|
170687
|
-
async start(controller) {
|
|
170688
|
-
let baseDone = false;
|
|
170689
|
-
let baseRead = reader.read();
|
|
170690
|
-
let tail = "";
|
|
170691
|
-
let footer = "";
|
|
170692
|
-
try {
|
|
170693
|
-
while (!baseDone || pending.length > 0) {
|
|
170694
|
-
const racers = [];
|
|
170695
|
-
if (!baseDone) {
|
|
170696
|
-
racers.push(baseRead.then(({ done, value }) => ({
|
|
170697
|
-
done,
|
|
170698
|
-
kind: "base",
|
|
170699
|
-
value
|
|
170700
|
-
})));
|
|
170701
|
-
}
|
|
170702
|
-
if (pending.length > 0) {
|
|
170703
|
-
racers.push(nextResolvedSlot(pending).then((resolved) => ({
|
|
170704
|
-
kind: "slot",
|
|
170705
|
-
...resolved
|
|
170706
|
-
})));
|
|
170707
|
-
}
|
|
170708
|
-
if (racers.length === 0)
|
|
170709
|
-
break;
|
|
170710
|
-
const winner = await Promise.race(racers);
|
|
170711
|
-
if (winner.kind === "base") {
|
|
170712
|
-
if (winner.done) {
|
|
170713
|
-
baseDone = true;
|
|
170714
|
-
tail += decoder.decode();
|
|
170715
|
-
const footerStart = tail.search(CLOSING_PAGE_TAG_REGEX);
|
|
170716
|
-
if (footerStart >= 0) {
|
|
170717
|
-
const content = tail.slice(0, footerStart);
|
|
170718
|
-
footer = tail.slice(footerStart);
|
|
170719
|
-
if (content.length > 0) {
|
|
170720
|
-
controller.enqueue(encoder.encode(content));
|
|
170721
|
-
}
|
|
170722
|
-
} else if (tail.length > 0) {
|
|
170723
|
-
controller.enqueue(encoder.encode(tail));
|
|
170724
|
-
}
|
|
170725
|
-
tail = "";
|
|
170726
|
-
} else if (winner.value) {
|
|
170727
|
-
tail += streamChunkToString2(winner.value, decoder);
|
|
170728
|
-
if (tail.length > STREAM_TAIL_LOOKBEHIND) {
|
|
170729
|
-
const content = tail.slice(0, tail.length - STREAM_TAIL_LOOKBEHIND);
|
|
170730
|
-
controller.enqueue(encoder.encode(content));
|
|
170731
|
-
tail = tail.slice(-STREAM_TAIL_LOOKBEHIND);
|
|
170732
|
-
}
|
|
170733
|
-
baseRead = reader.read();
|
|
170734
|
-
}
|
|
170735
|
-
continue;
|
|
170736
|
-
}
|
|
170737
|
-
const index = pending.indexOf(winner.original);
|
|
170738
|
-
if (index >= 0)
|
|
170739
|
-
pending.splice(index, 1);
|
|
170740
|
-
if (winner.result.html === null)
|
|
170741
|
-
continue;
|
|
170742
|
-
emitSlotMetric({
|
|
170743
|
-
type: "patched",
|
|
170744
|
-
slotId: winner.result.id,
|
|
170745
|
-
durationMs: winner.result.durationMs,
|
|
170746
|
-
bytes: winner.result.bytes
|
|
170747
|
-
}, combinedOnSlotMetric);
|
|
170748
|
-
controller.enqueue(encoder.encode(renderStreamingSlotPatchTag(winner.result.id, winner.result.html, nonce)));
|
|
170749
|
-
}
|
|
170750
|
-
if (footer.length > 0)
|
|
170751
|
-
controller.enqueue(encoder.encode(footer));
|
|
170752
|
-
controller.close();
|
|
170753
|
-
} catch (error) {
|
|
170754
|
-
controller.error(error);
|
|
170755
|
-
}
|
|
170756
|
-
}
|
|
170757
|
-
});
|
|
170758
|
-
};
|
|
170759
|
-
var init_streamingSlots = __esm(() => {
|
|
170760
|
-
init_escapeScriptContent();
|
|
170761
|
-
CLOSING_HEAD_TAG_LENGTH = CLOSING_HEAD_TAG2.length;
|
|
170762
|
-
CLOSING_PAGE_TAG_REGEX = /<\/body>\s*<\/html>\s*$/i;
|
|
170763
|
-
currentStreamingSlotPolicy = {
|
|
170764
|
-
timeoutMs: STREAMING_SLOT_TIMEOUT_MS,
|
|
170765
|
-
fallbackHtml: "",
|
|
170766
|
-
errorHtml: undefined,
|
|
170767
|
-
maxSlotsPerResponse: STREAMING_SLOT_MAX_PER_RESPONSE,
|
|
170768
|
-
maxSlotHtmlSizeBytes: STREAMING_SLOT_MAX_HTML_BYTES
|
|
170769
|
-
};
|
|
170770
|
-
});
|
|
170771
|
-
|
|
170772
|
-
// src/core/streamingSlotRegistrar.ts
|
|
170773
|
-
var registrar = null, setStreamingSlotRegistrar = (nextRegistrar) => {
|
|
170774
|
-
registrar = nextRegistrar;
|
|
170775
|
-
}, registerStreamingSlot = (slot) => {
|
|
170776
|
-
registrar?.(slot);
|
|
170777
|
-
};
|
|
170778
|
-
|
|
170779
|
-
// src/core/streamingSlotRegistry.ts
|
|
170780
|
-
var asyncLocalStorage, isServerRuntime = () => typeof process !== "undefined" && typeof process.versions?.node === "string", ensureAsyncLocalStorage = async () => {
|
|
170781
|
-
if (typeof asyncLocalStorage !== "undefined")
|
|
170782
|
-
return asyncLocalStorage;
|
|
170783
|
-
if (!isServerRuntime()) {
|
|
170784
|
-
asyncLocalStorage = null;
|
|
170785
|
-
return asyncLocalStorage;
|
|
170786
|
-
}
|
|
170787
|
-
const mod = await import("async_hooks");
|
|
170788
|
-
asyncLocalStorage = new mod.AsyncLocalStorage;
|
|
170789
|
-
return asyncLocalStorage;
|
|
170790
|
-
}, registerStreamingSlot2 = (slot) => {
|
|
170791
|
-
if (!asyncLocalStorage)
|
|
170792
|
-
return;
|
|
170793
|
-
const store = asyncLocalStorage.getStore();
|
|
170794
|
-
if (!store)
|
|
170795
|
-
return;
|
|
170796
|
-
store.set(slot.id, slot);
|
|
170797
|
-
}, runWithStreamingSlotRegistry = async (task) => {
|
|
170798
|
-
const storage = await ensureAsyncLocalStorage();
|
|
170799
|
-
if (!storage) {
|
|
170800
|
-
return {
|
|
170801
|
-
result: await task(),
|
|
170802
|
-
slots: []
|
|
170803
|
-
};
|
|
170804
|
-
}
|
|
170805
|
-
return storage.run(new Map, async () => {
|
|
170806
|
-
const result = await task();
|
|
170807
|
-
const store = storage.getStore();
|
|
170808
|
-
return {
|
|
170809
|
-
result,
|
|
170810
|
-
slots: store ? [...store.values()] : []
|
|
170811
|
-
};
|
|
170812
|
-
});
|
|
170813
|
-
};
|
|
170814
|
-
var init_streamingSlotRegistry = __esm(() => {
|
|
170815
|
-
setStreamingSlotRegistrar(registerStreamingSlot2);
|
|
170816
|
-
});
|
|
170817
|
-
|
|
170818
|
-
// src/core/responseEnhancers.ts
|
|
170819
|
-
var toResponse = async (responseLike) => await responseLike, cloneHeaders = (response) => {
|
|
170820
|
-
const headers = new Headers(response.headers);
|
|
170821
|
-
return headers;
|
|
170822
|
-
}, enhanceHtmlResponseWithStreamingSlots = (response, { nonce, onError, streamingSlots = [], policy } = {}) => {
|
|
170823
|
-
if (!response.body || streamingSlots.length === 0) {
|
|
170824
|
-
return response;
|
|
170825
|
-
}
|
|
170826
|
-
const body = appendStreamingSlotPatchesToStream(response.body, streamingSlots, {
|
|
170827
|
-
nonce,
|
|
170828
|
-
onError,
|
|
170829
|
-
policy
|
|
170830
|
-
});
|
|
170831
|
-
return new Response(body, {
|
|
170832
|
-
headers: cloneHeaders(response),
|
|
170833
|
-
status: response.status,
|
|
170834
|
-
statusText: response.statusText
|
|
170835
|
-
});
|
|
170836
|
-
}, withStreamingSlots = async (responseLike, options = {}) => enhanceHtmlResponseWithStreamingSlots(await toResponse(responseLike), options), mergeStreamingSlots = (registered, explicit) => {
|
|
170837
|
-
const merged = new Map;
|
|
170838
|
-
for (const slot of registered)
|
|
170839
|
-
merged.set(slot.id, slot);
|
|
170840
|
-
for (const slot of explicit)
|
|
170841
|
-
merged.set(slot.id, slot);
|
|
170842
|
-
return [...merged.values()];
|
|
170843
|
-
}, withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
|
|
170844
|
-
const { result, slots } = await runWithStreamingSlotRegistry(renderResponse);
|
|
170845
|
-
const explicit = options.streamingSlots ?? [];
|
|
170846
|
-
return withStreamingSlots(result, {
|
|
170847
|
-
...options,
|
|
170848
|
-
streamingSlots: mergeStreamingSlots(slots, explicit)
|
|
170849
|
-
});
|
|
170850
|
-
};
|
|
170851
|
-
var init_responseEnhancers = __esm(() => {
|
|
170852
|
-
init_streamingSlots();
|
|
170853
|
-
init_streamingSlotRegistry();
|
|
170854
|
-
});
|
|
170855
|
-
|
|
170856
|
-
// src/utils/ssrErrorPage.ts
|
|
170857
|
-
var ssrErrorPage = (framework, error) => {
|
|
170858
|
-
const frameworkColors = {
|
|
170859
|
-
angular: "#dd0031",
|
|
170860
|
-
html: "#e34c26",
|
|
170861
|
-
htmx: "#1a365d",
|
|
170862
|
-
react: "#61dafb",
|
|
170863
|
-
svelte: "#ff3e00",
|
|
170864
|
-
vue: "#42b883"
|
|
170865
|
-
};
|
|
170866
|
-
const accent = frameworkColors[framework] ?? "#94a3b8";
|
|
170867
|
-
const label = framework.charAt(0).toUpperCase() + framework.slice(1);
|
|
170868
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
170869
|
-
return `<!DOCTYPE html>
|
|
170870
|
-
<html>
|
|
170871
|
-
<head>
|
|
170872
|
-
<meta charset="utf-8">
|
|
170873
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
170874
|
-
<title>SSR Error - AbsoluteJS</title>
|
|
170875
|
-
<style>
|
|
170876
|
-
*{margin:0;padding:0;box-sizing:border-box}
|
|
170877
|
-
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}
|
|
170878
|
-
.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}
|
|
170879
|
-
.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)}
|
|
170880
|
-
.brand{font-weight:700;font-size:20px;color:#fff;letter-spacing:-0.02em}
|
|
170881
|
-
.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)}
|
|
170882
|
-
.kind{color:#94a3b8;font-size:13px;font-weight:500}
|
|
170883
|
-
.content{padding:24px}
|
|
170884
|
-
.label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.08em;color:#94a3b8;margin-bottom:8px}
|
|
170885
|
-
.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}
|
|
170886
|
-
.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}
|
|
170887
|
-
</style>
|
|
170888
|
-
</head>
|
|
170889
|
-
<body>
|
|
170890
|
-
<div class="card">
|
|
170891
|
-
<div class="header">
|
|
170892
|
-
<div style="display:flex;align-items:center;gap:12px">
|
|
170893
|
-
<span class="brand">AbsoluteJS</span>
|
|
170894
|
-
<span class="badge">${label}</span>
|
|
170895
|
-
</div>
|
|
170896
|
-
<span class="kind">Server Render Error</span>
|
|
170897
|
-
</div>
|
|
170898
|
-
<div class="content">
|
|
170899
|
-
<div class="label">What went wrong</div>
|
|
170900
|
-
<pre class="message">${message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</pre>
|
|
170901
|
-
<div class="hint">A component threw during server-side rendering. Check the terminal for the full stack trace.</div>
|
|
170902
|
-
</div>
|
|
170903
|
-
</div>
|
|
170904
|
-
</body>
|
|
170905
|
-
</html>`;
|
|
170906
|
-
};
|
|
170907
|
-
|
|
170908
|
-
// src/utils/resolveConvention.ts
|
|
170909
|
-
import { basename as basename2 } from "path";
|
|
170910
|
-
var CONVENTIONS_KEY = "__absoluteConventions", isConventionsMap = (value) => Boolean(value) && typeof value === "object", getMap = () => {
|
|
170911
|
-
const value = Reflect.get(globalThis, CONVENTIONS_KEY);
|
|
170912
|
-
if (isConventionsMap(value))
|
|
170913
|
-
return value;
|
|
170914
|
-
const empty = {};
|
|
170915
|
-
return empty;
|
|
170916
|
-
}, derivePageName = (pagePath) => {
|
|
170917
|
-
const base = basename2(pagePath);
|
|
170918
|
-
const dotIndex = base.indexOf(".");
|
|
170919
|
-
const name = dotIndex > 0 ? base.slice(0, dotIndex) : base;
|
|
170920
|
-
return toPascal(name);
|
|
170921
|
-
}, resolveErrorConventionPath = (framework, pageName) => {
|
|
170922
|
-
const conventions2 = getMap()[framework];
|
|
170923
|
-
if (!conventions2)
|
|
170924
|
-
return;
|
|
170925
|
-
return conventions2.pages?.[pageName]?.error ?? conventions2.defaults?.error;
|
|
170926
|
-
}, resolveNotFoundConventionPath = (framework) => getMap()[framework]?.defaults?.notFound, setConventions = (map) => {
|
|
170927
|
-
Reflect.set(globalThis, CONVENTIONS_KEY, map);
|
|
170928
|
-
}, isDev = () => true, buildErrorProps = (error) => {
|
|
170929
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
170930
|
-
const stack = isDev() && error instanceof Error ? error.stack : undefined;
|
|
170931
|
-
return { error: { message, stack } };
|
|
170932
|
-
}, renderReactError = async (conventionPath, errorProps) => {
|
|
170933
|
-
const { createElement: createElement2 } = await import("react");
|
|
170934
|
-
const { renderToReadableStream } = await import("react-dom/server");
|
|
170935
|
-
const mod = await import(conventionPath);
|
|
170936
|
-
const [firstKey] = Object.keys(mod);
|
|
170937
|
-
const ErrorComponent = mod.default ?? (firstKey ? mod[firstKey] : undefined);
|
|
170938
|
-
const element = createElement2(ErrorComponent, errorProps);
|
|
170939
|
-
const stream = await renderToReadableStream(element);
|
|
170940
|
-
return new Response(stream, {
|
|
170941
|
-
headers: { "Content-Type": "text/html" },
|
|
170942
|
-
status: 500
|
|
170943
|
-
});
|
|
170944
|
-
}, renderSvelteError = async (conventionPath, errorProps) => {
|
|
170945
|
-
const { render } = await import("svelte/server");
|
|
170946
|
-
const mod = await import(conventionPath);
|
|
170947
|
-
const ErrorComponent = mod.default;
|
|
170948
|
-
const { head, body } = render(ErrorComponent, {
|
|
170949
|
-
props: errorProps
|
|
170950
|
-
});
|
|
170951
|
-
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
170952
|
-
return new Response(html, {
|
|
170953
|
-
headers: { "Content-Type": "text/html" },
|
|
170954
|
-
status: 500
|
|
170955
|
-
});
|
|
170956
|
-
}, unescapeVueStyles = (ssrBody) => {
|
|
170957
|
-
let styles = "";
|
|
170958
|
-
const body = ssrBody.replace(/<style>([\s\S]*?)<\/style>/g, (_, css) => {
|
|
170959
|
-
styles += `<style>${css.replace(/"/g, '"').replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</style>`;
|
|
170960
|
-
return "";
|
|
170961
|
-
});
|
|
170962
|
-
return { body, styles };
|
|
170963
|
-
}, renderVueError = async (conventionPath, errorProps) => {
|
|
170964
|
-
const { createSSRApp: createSSRApp2, h: h2 } = await import("vue");
|
|
170965
|
-
const { renderToString } = await import("vue/server-renderer");
|
|
170966
|
-
const mod = await import(conventionPath);
|
|
170967
|
-
const ErrorComponent = mod.default;
|
|
170968
|
-
const app = createSSRApp2({
|
|
170969
|
-
render: () => h2(ErrorComponent, errorProps)
|
|
170970
|
-
});
|
|
170971
|
-
const rawBody = await renderToString(app);
|
|
170972
|
-
const { styles, body } = unescapeVueStyles(rawBody);
|
|
170973
|
-
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
170974
|
-
return new Response(html, {
|
|
170975
|
-
headers: { "Content-Type": "text/html" },
|
|
170976
|
-
status: 500
|
|
170977
|
-
});
|
|
170978
|
-
}, renderAngularError = async (conventionPath, errorProps) => {
|
|
170979
|
-
const mod = await import(conventionPath);
|
|
170980
|
-
const renderError = mod.default ?? mod.renderError;
|
|
170981
|
-
if (typeof renderError !== "function")
|
|
170982
|
-
return null;
|
|
170983
|
-
const html = renderError(errorProps);
|
|
170984
|
-
return new Response(html, {
|
|
170985
|
-
headers: { "Content-Type": "text/html" },
|
|
170986
|
-
status: 500
|
|
170987
|
-
});
|
|
170988
|
-
}, logConventionRenderError = (framework, label, renderError) => {
|
|
170989
|
-
const message = renderError instanceof Error ? renderError.message : "";
|
|
170990
|
-
if (message.includes("Cannot find module") || message.includes("Cannot find package") || message.includes("not found in module")) {
|
|
170991
|
-
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}).`);
|
|
170992
|
-
return;
|
|
170993
|
-
}
|
|
170994
|
-
console.error(`[SSR] Failed to render ${framework} convention ${label} page:`, renderError);
|
|
170995
|
-
}, ERROR_RENDERERS, renderConventionError = async (framework, pageName, error) => {
|
|
170996
|
-
const conventionPath = resolveErrorConventionPath(framework, pageName);
|
|
170997
|
-
if (!conventionPath)
|
|
170998
|
-
return null;
|
|
170999
|
-
const errorProps = buildErrorProps(error);
|
|
171000
|
-
const renderer = ERROR_RENDERERS[framework];
|
|
171001
|
-
if (!renderer)
|
|
171002
|
-
return null;
|
|
171003
|
-
try {
|
|
171004
|
-
return await renderer(conventionPath, errorProps);
|
|
171005
|
-
} catch (renderError) {
|
|
171006
|
-
logConventionRenderError(framework, "error", renderError);
|
|
171007
|
-
}
|
|
171008
|
-
return null;
|
|
171009
|
-
}, renderReactNotFound = async (conventionPath) => {
|
|
171010
|
-
const { createElement: createElement2 } = await import("react");
|
|
171011
|
-
const { renderToReadableStream } = await import("react-dom/server");
|
|
171012
|
-
const mod = await import(conventionPath);
|
|
171013
|
-
const [nfKey] = Object.keys(mod);
|
|
171014
|
-
const NotFoundComponent = mod.default ?? (nfKey ? mod[nfKey] : undefined);
|
|
171015
|
-
const element = createElement2(NotFoundComponent);
|
|
171016
|
-
const stream = await renderToReadableStream(element);
|
|
171017
|
-
return new Response(stream, {
|
|
171018
|
-
headers: { "Content-Type": "text/html" },
|
|
171019
|
-
status: 404
|
|
171020
|
-
});
|
|
171021
|
-
}, renderSvelteNotFound = async (conventionPath) => {
|
|
171022
|
-
const { render } = await import("svelte/server");
|
|
171023
|
-
const mod = await import(conventionPath);
|
|
171024
|
-
const NotFoundComponent = mod.default;
|
|
171025
|
-
const { head, body } = render(NotFoundComponent);
|
|
171026
|
-
const html = `<!DOCTYPE html><html><head>${head}</head><body>${body}</body></html>`;
|
|
171027
|
-
return new Response(html, {
|
|
171028
|
-
headers: { "Content-Type": "text/html" },
|
|
171029
|
-
status: 404
|
|
171030
|
-
});
|
|
171031
|
-
}, renderVueNotFound = async (conventionPath) => {
|
|
171032
|
-
const { createSSRApp: createSSRApp2, h: h2 } = await import("vue");
|
|
171033
|
-
const { renderToString } = await import("vue/server-renderer");
|
|
171034
|
-
const mod = await import(conventionPath);
|
|
171035
|
-
const NotFoundComponent = mod.default;
|
|
171036
|
-
const app = createSSRApp2({
|
|
171037
|
-
render: () => h2(NotFoundComponent)
|
|
171038
|
-
});
|
|
171039
|
-
const rawBody = await renderToString(app);
|
|
171040
|
-
const { styles, body } = unescapeVueStyles(rawBody);
|
|
171041
|
-
const html = `<!DOCTYPE html><html><head>${styles}</head><body><div id="root">${body}</div></body></html>`;
|
|
171042
|
-
return new Response(html, {
|
|
171043
|
-
headers: { "Content-Type": "text/html" },
|
|
171044
|
-
status: 404
|
|
171045
|
-
});
|
|
171046
|
-
}, renderAngularNotFound = async (conventionPath) => {
|
|
171047
|
-
const mod = await import(conventionPath);
|
|
171048
|
-
const renderNotFound = mod.default ?? mod.renderNotFound;
|
|
171049
|
-
if (typeof renderNotFound !== "function")
|
|
171050
|
-
return null;
|
|
171051
|
-
const html = renderNotFound();
|
|
171052
|
-
return new Response(html, {
|
|
171053
|
-
headers: { "Content-Type": "text/html" },
|
|
171054
|
-
status: 404
|
|
171055
|
-
});
|
|
171056
|
-
}, NOT_FOUND_RENDERERS, renderConventionNotFound = async (framework) => {
|
|
171057
|
-
const conventionPath = resolveNotFoundConventionPath(framework);
|
|
171058
|
-
if (!conventionPath)
|
|
171059
|
-
return null;
|
|
171060
|
-
const renderer = NOT_FOUND_RENDERERS[framework];
|
|
171061
|
-
if (!renderer)
|
|
171062
|
-
return null;
|
|
171063
|
-
try {
|
|
171064
|
-
return await renderer(conventionPath);
|
|
171065
|
-
} catch (renderError) {
|
|
171066
|
-
logConventionRenderError(framework, "not-found", renderError);
|
|
171067
|
-
}
|
|
171068
|
-
return null;
|
|
171069
|
-
}, NOT_FOUND_PRIORITY, renderFirstNotFound = async () => {
|
|
171070
|
-
for (const framework of NOT_FOUND_PRIORITY) {
|
|
171071
|
-
if (!getMap()[framework]?.defaults?.notFound)
|
|
171072
|
-
continue;
|
|
171073
|
-
const response = await renderConventionNotFound(framework);
|
|
171074
|
-
if (response)
|
|
171075
|
-
return response;
|
|
171076
|
-
}
|
|
171077
|
-
return null;
|
|
171078
|
-
};
|
|
171079
|
-
var init_resolveConvention = __esm(() => {
|
|
171080
|
-
ERROR_RENDERERS = {
|
|
171081
|
-
angular: renderAngularError,
|
|
171082
|
-
react: renderReactError,
|
|
171083
|
-
svelte: renderSvelteError,
|
|
171084
|
-
vue: renderVueError
|
|
171085
|
-
};
|
|
171086
|
-
NOT_FOUND_RENDERERS = {
|
|
171087
|
-
angular: renderAngularNotFound,
|
|
171088
|
-
react: renderReactNotFound,
|
|
171089
|
-
svelte: renderSvelteNotFound,
|
|
171090
|
-
vue: renderVueNotFound
|
|
171091
|
-
};
|
|
171092
|
-
NOT_FOUND_PRIORITY = [
|
|
171093
|
-
"react",
|
|
171094
|
-
"svelte",
|
|
171095
|
-
"vue",
|
|
171096
|
-
"angular"
|
|
171097
|
-
];
|
|
171098
|
-
});
|
|
171099
|
-
|
|
171100
|
-
// src/react/streamingSlotCollection.tsx
|
|
171101
|
-
import { createContext, useContext } from "react";
|
|
171102
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
171103
|
-
var StreamingSlotCollectorContext, StreamingSlotCollectorProvider = ({
|
|
171104
|
-
children,
|
|
171105
|
-
collector
|
|
171106
|
-
}) => /* @__PURE__ */ jsxDEV(StreamingSlotCollectorContext.Provider, {
|
|
171107
|
-
value: collector,
|
|
171108
|
-
children
|
|
171109
|
-
}, undefined, false, undefined, this), useStreamingSlotCollector = () => useContext(StreamingSlotCollectorContext);
|
|
171110
|
-
var init_streamingSlotCollection = __esm(() => {
|
|
171111
|
-
StreamingSlotCollectorContext = createContext(null);
|
|
171112
|
-
});
|
|
171113
|
-
|
|
171114
|
-
// src/react/pageHandler.ts
|
|
171115
|
-
var ssrDirty = false, buildDirtyResponse = (index, maybeProps) => {
|
|
171116
|
-
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
171117
|
-
const dirtyFlag = "window.__SSR_DIRTY__=true;";
|
|
171118
|
-
const refreshSetup = "window.__REFRESH_BUFFER__=[];" + "window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};" + "window.$RefreshSig$=function(){return function(t){return t}};";
|
|
171119
|
-
const inlineScript = `${propsScript}${dirtyFlag}${refreshSetup}`;
|
|
171120
|
-
const html = `<!DOCTYPE html><html><head></head><body>` + `<script>${inlineScript}</script>` + `<script type="module" src="${index}"></script>` + `</body></html>`;
|
|
171121
|
-
return new Response(html, {
|
|
171122
|
-
headers: { "Content-Type": "text/html" }
|
|
171123
|
-
});
|
|
171124
|
-
}, handleReactPageRequest = async (PageComponent, index, ...props) => {
|
|
171125
|
-
const [maybeProps] = props;
|
|
171126
|
-
if (ssrDirty) {
|
|
171127
|
-
return buildDirtyResponse(index, maybeProps);
|
|
171128
|
-
}
|
|
171129
|
-
try {
|
|
171130
|
-
const { createElement: createElement2 } = await import("react");
|
|
171131
|
-
const { renderToReadableStream } = await import("react-dom/server");
|
|
171132
|
-
const slotCollector = new Map;
|
|
171133
|
-
const pageElement = maybeProps !== undefined ? createElement2(PageComponent, maybeProps) : createElement2(PageComponent);
|
|
171134
|
-
const element = createElement2(StreamingSlotCollectorProvider, { collector: slotCollector }, pageElement);
|
|
171135
|
-
const propsScript = maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)};` : "";
|
|
171136
|
-
const refreshSetup = "window.__REFRESH_BUFFER__=[];window.$RefreshReg$=function(t,i){window.__REFRESH_BUFFER__.push([t,i])};window.$RefreshSig$=function(){return function(t){return t}};";
|
|
171137
|
-
const stream = await renderToReadableStream(element, {
|
|
171138
|
-
bootstrapModules: [index],
|
|
171139
|
-
bootstrapScriptContent: propsScript + refreshSetup || undefined,
|
|
171140
|
-
onError(error) {
|
|
171141
|
-
console.error("[SSR] React streaming error:", error);
|
|
171142
|
-
}
|
|
171143
|
-
});
|
|
171144
|
-
if ("allReady" in stream && stream.allReady instanceof Promise) {
|
|
171145
|
-
await stream.allReady;
|
|
171146
|
-
}
|
|
171147
|
-
const htmlStream = injectIslandPageContextStream(stream);
|
|
171148
|
-
return withStreamingSlots(new Response(htmlStream, {
|
|
171149
|
-
headers: { "Content-Type": "text/html" }
|
|
171150
|
-
}), {
|
|
171151
|
-
streamingSlots: [...slotCollector.values()]
|
|
171152
|
-
});
|
|
171153
|
-
} catch (error) {
|
|
171154
|
-
console.error("[SSR] React render error:", error);
|
|
171155
|
-
const pageName = PageComponent.name || PageComponent.displayName || "";
|
|
171156
|
-
const conventionResponse = await renderConventionError("react", pageName, error);
|
|
171157
|
-
if (conventionResponse)
|
|
171158
|
-
return conventionResponse;
|
|
171159
|
-
return new Response(ssrErrorPage("react", error), {
|
|
171160
|
-
headers: { "Content-Type": "text/html" },
|
|
171161
|
-
status: 500
|
|
171162
|
-
});
|
|
171163
|
-
}
|
|
171164
|
-
}, invalidateReactSsrCache = () => {
|
|
171165
|
-
ssrDirty = true;
|
|
171166
|
-
};
|
|
171167
|
-
var init_pageHandler = __esm(() => {
|
|
171168
|
-
init_responseEnhancers();
|
|
171169
|
-
init_resolveConvention();
|
|
171170
|
-
init_streamingSlotCollection();
|
|
171171
|
-
});
|
|
171172
|
-
|
|
171173
170621
|
// src/build/scanEntryPoints.ts
|
|
171174
170622
|
import { existsSync as existsSync3 } from "fs";
|
|
171175
170623
|
var {Glob } = globalThis.Bun;
|
|
@@ -173705,7 +173153,7 @@ ${registrations}
|
|
|
173705
173153
|
({ tsLibDir } = cached);
|
|
173706
173154
|
cached.lastUsed = Date.now();
|
|
173707
173155
|
} else {
|
|
173708
|
-
const tsPath = __require.resolve("
|
|
173156
|
+
const tsPath = __require.resolve("typescript");
|
|
173709
173157
|
const tsRootDir = dirname9(tsPath);
|
|
173710
173158
|
tsLibDir = tsRootDir.endsWith("lib") ? tsRootDir : resolve18(tsRootDir, "lib");
|
|
173711
173159
|
const config = readConfiguration("./tsconfig.json");
|
|
@@ -180463,6 +179911,752 @@ var init_devCert = __esm(() => {
|
|
|
180463
179911
|
CERT_PATH = join23(CERT_DIR, "cert.pem");
|
|
180464
179912
|
KEY_PATH = join23(CERT_DIR, "key.pem");
|
|
180465
179913
|
});
|
|
179914
|
+
|
|
179915
|
+
// src/client/streamSwap.ts
|
|
179916
|
+
var streamSwapRuntime = () => {
|
|
179917
|
+
if (window.__ABS_SLOT_RUNTIME__ === true)
|
|
179918
|
+
return;
|
|
179919
|
+
window.__ABS_SLOT_RUNTIME__ = true;
|
|
179920
|
+
window.__ABS_SLOT_PENDING__ = window.__ABS_SLOT_PENDING__ ?? {};
|
|
179921
|
+
const pending = window.__ABS_SLOT_PENDING__;
|
|
179922
|
+
const apply = (id, html) => {
|
|
179923
|
+
const node = document.getElementById(`slot-${id}`);
|
|
179924
|
+
if (!node) {
|
|
179925
|
+
pending[id] = html;
|
|
179926
|
+
return;
|
|
179927
|
+
}
|
|
179928
|
+
node.innerHTML = html;
|
|
179929
|
+
delete pending[id];
|
|
179930
|
+
};
|
|
179931
|
+
const flush = () => {
|
|
179932
|
+
for (const id in pending) {
|
|
179933
|
+
if (!Object.prototype.hasOwnProperty.call(pending, id))
|
|
179934
|
+
continue;
|
|
179935
|
+
apply(id, pending[id] ?? "");
|
|
179936
|
+
}
|
|
179937
|
+
};
|
|
179938
|
+
window.__ABS_SLOT_ENQUEUE__ = (id, html) => {
|
|
179939
|
+
apply(id, html);
|
|
179940
|
+
};
|
|
179941
|
+
if (typeof MutationObserver === "function") {
|
|
179942
|
+
const observer = new MutationObserver(flush);
|
|
179943
|
+
const root = document.documentElement ?? document.body ?? document;
|
|
179944
|
+
observer.observe(root, { childList: true, subtree: true });
|
|
179945
|
+
}
|
|
179946
|
+
if (document.readyState === "loading") {
|
|
179947
|
+
document.addEventListener("DOMContentLoaded", flush, { once: true });
|
|
179948
|
+
}
|
|
179949
|
+
flush();
|
|
179950
|
+
};
|
|
179951
|
+
var stripFunctionWrapper = (value) => {
|
|
179952
|
+
const start = value.indexOf("{");
|
|
179953
|
+
const end = value.lastIndexOf("}");
|
|
179954
|
+
if (start < 0 || end <= start)
|
|
179955
|
+
return "";
|
|
179956
|
+
return value.slice(start + 1, end);
|
|
179957
|
+
};
|
|
179958
|
+
var getStreamSwapRuntimeScript = () => `(function(){${stripFunctionWrapper(streamSwapRuntime.toString())}})();`;
|
|
179959
|
+
|
|
179960
|
+
// src/utils/streamingSlots.ts
|
|
179961
|
+
init_escapeScriptContent();
|
|
179962
|
+
var SLOT_ID_PREFIX = "abs-slot-";
|
|
179963
|
+
var SLOT_PLACEHOLDER_PREFIX = "slot-";
|
|
179964
|
+
var CLOSING_HEAD_TAG = "</head>";
|
|
179965
|
+
var CLOSING_HEAD_TAG_LENGTH = CLOSING_HEAD_TAG.length;
|
|
179966
|
+
var CLOSING_PAGE_TAG_REGEX = /<\/body>\s*<\/html>\s*$/i;
|
|
179967
|
+
var STREAMING_RUNTIME_GLOBAL = "__ABS_SLOT_ENQUEUE__";
|
|
179968
|
+
var STREAMING_PENDING_GLOBAL = "__ABS_SLOT_PENDING__";
|
|
179969
|
+
var STREAM_TAIL_LOOKBEHIND = 128;
|
|
179970
|
+
var STREAMING_SLOT_TIMEOUT_MS = 5000;
|
|
179971
|
+
var STREAMING_SLOT_MAX_PER_RESPONSE = 128;
|
|
179972
|
+
var STREAMING_SLOT_MAX_HTML_BYTES = 64000;
|
|
179973
|
+
var createSlotPlaceholderId = (id) => `${SLOT_PLACEHOLDER_PREFIX}${id}`;
|
|
179974
|
+
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)});`;
|
|
179975
|
+
var createNonceAttr = (nonce) => nonce ? ` nonce="${nonce}"` : "";
|
|
179976
|
+
var createStreamingSlotId = () => `${SLOT_ID_PREFIX}${Math.random().toString(36).slice(2, 10)}`;
|
|
179977
|
+
var getStreamingSlotsRuntimeScript = () => getStreamSwapRuntimeScript();
|
|
179978
|
+
var renderStreamingSlotsRuntimeTag = (nonce) => `<script${createNonceAttr(nonce)}>${escapeScriptContent(getStreamingSlotsRuntimeScript())}</script>`;
|
|
179979
|
+
var renderStreamingSlotPlaceholder = (id, fallbackHtml = "") => `<div id="${createSlotPlaceholderId(id)}" data-absolute-slot="true">${fallbackHtml}</div>`;
|
|
179980
|
+
var renderStreamingSlotPatchTag = (id, html, nonce) => `<script${createNonceAttr(nonce)}>${escapeScriptContent(createSlotPatchStatement(id, html))}</script>`;
|
|
179981
|
+
var injectHtmlIntoHead = (html, injection) => {
|
|
179982
|
+
const closingHeadIndex = html.indexOf(CLOSING_HEAD_TAG);
|
|
179983
|
+
if (closingHeadIndex >= 0) {
|
|
179984
|
+
return `${html.slice(0, closingHeadIndex)}${injection}${html.slice(closingHeadIndex)}`;
|
|
179985
|
+
}
|
|
179986
|
+
return `${html}${injection}`;
|
|
179987
|
+
};
|
|
179988
|
+
var toUint8 = (value, encoder) => encoder.encode(value);
|
|
179989
|
+
var currentStreamingSlotPolicy = {
|
|
179990
|
+
timeoutMs: STREAMING_SLOT_TIMEOUT_MS,
|
|
179991
|
+
fallbackHtml: "",
|
|
179992
|
+
errorHtml: undefined,
|
|
179993
|
+
maxSlotsPerResponse: STREAMING_SLOT_MAX_PER_RESPONSE,
|
|
179994
|
+
maxSlotHtmlSizeBytes: STREAMING_SLOT_MAX_HTML_BYTES
|
|
179995
|
+
};
|
|
179996
|
+
var clonePolicy = (policy) => ({
|
|
179997
|
+
...policy
|
|
179998
|
+
});
|
|
179999
|
+
var normalizeSlotBytes = (value, fallback) => {
|
|
180000
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
180001
|
+
return Math.floor(value);
|
|
180002
|
+
}
|
|
180003
|
+
return fallback;
|
|
180004
|
+
};
|
|
180005
|
+
var normalizeSlotText = (value, fallback) => typeof value === "string" ? value : fallback;
|
|
180006
|
+
var normalizeSlotError = (value, fallback) => typeof value === "string" ? value : fallback;
|
|
180007
|
+
var hasPolicyValue = (policy, key) => Object.prototype.hasOwnProperty.call(policy, key);
|
|
180008
|
+
var applyStreamingSlotPolicyOverrides = (base, overridePolicy = {}) => ({
|
|
180009
|
+
timeoutMs: hasPolicyValue(overridePolicy, "timeoutMs") ? normalizeSlotBytes(overridePolicy.timeoutMs, base.timeoutMs) : base.timeoutMs,
|
|
180010
|
+
fallbackHtml: hasPolicyValue(overridePolicy, "fallbackHtml") ? normalizeSlotText(overridePolicy.fallbackHtml, "") : base.fallbackHtml,
|
|
180011
|
+
errorHtml: hasPolicyValue(overridePolicy, "errorHtml") ? normalizeSlotError(overridePolicy.errorHtml) : base.errorHtml,
|
|
180012
|
+
maxSlotsPerResponse: hasPolicyValue(overridePolicy, "maxSlotsPerResponse") ? normalizeSlotBytes(overridePolicy.maxSlotsPerResponse, base.maxSlotsPerResponse) : base.maxSlotsPerResponse,
|
|
180013
|
+
maxSlotHtmlSizeBytes: hasPolicyValue(overridePolicy, "maxSlotHtmlSizeBytes") ? normalizeSlotBytes(overridePolicy.maxSlotHtmlSizeBytes, base.maxSlotHtmlSizeBytes) : base.maxSlotHtmlSizeBytes,
|
|
180014
|
+
onError: hasPolicyValue(overridePolicy, "onError") ? overridePolicy.onError : base.onError,
|
|
180015
|
+
onSlotMetric: hasPolicyValue(overridePolicy, "onSlotMetric") ? overridePolicy.onSlotMetric : base.onSlotMetric
|
|
180016
|
+
});
|
|
180017
|
+
var createCombinedSlotErrorHandler = (policyOnError, enhancerOnError) => {
|
|
180018
|
+
if (!policyOnError && !enhancerOnError)
|
|
180019
|
+
return;
|
|
180020
|
+
return (error, slot) => {
|
|
180021
|
+
policyOnError?.(error, slot);
|
|
180022
|
+
enhancerOnError?.(error, slot);
|
|
180023
|
+
};
|
|
180024
|
+
};
|
|
180025
|
+
var createCombinedSlotMetricHandler = (policyOnSlotMetric, callOnSlotMetric) => {
|
|
180026
|
+
if (!policyOnSlotMetric && !callOnSlotMetric)
|
|
180027
|
+
return;
|
|
180028
|
+
return (metric) => {
|
|
180029
|
+
policyOnSlotMetric?.(metric);
|
|
180030
|
+
callOnSlotMetric?.(metric);
|
|
180031
|
+
};
|
|
180032
|
+
};
|
|
180033
|
+
var resolveStreamingSlotPolicy = (overridePolicy = {}) => {
|
|
180034
|
+
const base = getStreamingSlotPolicy();
|
|
180035
|
+
return applyStreamingSlotPolicyOverrides(base, overridePolicy);
|
|
180036
|
+
};
|
|
180037
|
+
var getStreamingSlotPolicy = () => clonePolicy(currentStreamingSlotPolicy);
|
|
180038
|
+
var setStreamingSlotPolicy = (policy = {}) => {
|
|
180039
|
+
const base = getStreamingSlotPolicy();
|
|
180040
|
+
currentStreamingSlotPolicy = applyStreamingSlotPolicyOverrides(base, policy);
|
|
180041
|
+
};
|
|
180042
|
+
var withStreamingSlotPolicy = async (policy, callback) => {
|
|
180043
|
+
const previous = getStreamingSlotPolicy();
|
|
180044
|
+
setStreamingSlotPolicy(policy);
|
|
180045
|
+
try {
|
|
180046
|
+
return await callback();
|
|
180047
|
+
} finally {
|
|
180048
|
+
currentStreamingSlotPolicy = previous;
|
|
180049
|
+
}
|
|
180050
|
+
};
|
|
180051
|
+
var emitSlotMetric = (metric, onSlotMetric) => {
|
|
180052
|
+
onSlotMetric?.(metric);
|
|
180053
|
+
};
|
|
180054
|
+
var createTimeoutError = (slot, timeoutMs) => {
|
|
180055
|
+
const error = new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`);
|
|
180056
|
+
error.__absTimeout = true;
|
|
180057
|
+
return error;
|
|
180058
|
+
};
|
|
180059
|
+
var toStreamingSlot = (slot, policy) => ({
|
|
180060
|
+
errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
|
|
180061
|
+
fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
|
|
180062
|
+
id: slot.id ?? createStreamingSlotId(),
|
|
180063
|
+
timeoutMs: normalizeSlotBytes(slot.timeoutMs, policy.timeoutMs),
|
|
180064
|
+
resolve: slot.resolve
|
|
180065
|
+
});
|
|
180066
|
+
var prepareSlots = ({
|
|
180067
|
+
policy,
|
|
180068
|
+
slots,
|
|
180069
|
+
onError,
|
|
180070
|
+
onSlotMetric
|
|
180071
|
+
}) => {
|
|
180072
|
+
const preparedSlots = slots.map((slot) => toStreamingSlot(slot, policy));
|
|
180073
|
+
const maxSlotsPerResponse = policy.maxSlotsPerResponse;
|
|
180074
|
+
if (maxSlotsPerResponse === 0) {
|
|
180075
|
+
const error = new Error("Streaming slot limit is set to 0");
|
|
180076
|
+
for (const slot of preparedSlots) {
|
|
180077
|
+
onError?.(error, slot);
|
|
180078
|
+
emitSlotMetric({
|
|
180079
|
+
type: "dropped",
|
|
180080
|
+
slotId: slot.id,
|
|
180081
|
+
reason: "maxSlotsPerResponse is 0"
|
|
180082
|
+
}, onSlotMetric);
|
|
180083
|
+
}
|
|
180084
|
+
return [];
|
|
180085
|
+
}
|
|
180086
|
+
if (preparedSlots.length <= maxSlotsPerResponse) {
|
|
180087
|
+
preparedSlots.forEach((slot) => emitSlotMetric({
|
|
180088
|
+
type: "prepared",
|
|
180089
|
+
slotId: slot.id
|
|
180090
|
+
}, onSlotMetric));
|
|
180091
|
+
return preparedSlots;
|
|
180092
|
+
}
|
|
180093
|
+
const keptSlots = preparedSlots.slice(0, maxSlotsPerResponse);
|
|
180094
|
+
const droppedSlots = preparedSlots.slice(maxSlotsPerResponse);
|
|
180095
|
+
droppedSlots.forEach((slot) => {
|
|
180096
|
+
onError?.(new Error(`Streaming slot "${slot.id}" dropped because ${maxSlotsPerResponse} slots is the configured maximum`), slot);
|
|
180097
|
+
emitSlotMetric({
|
|
180098
|
+
type: "dropped",
|
|
180099
|
+
slotId: slot.id,
|
|
180100
|
+
reason: `maxSlotsPerResponse is ${maxSlotsPerResponse}`
|
|
180101
|
+
}, onSlotMetric);
|
|
180102
|
+
});
|
|
180103
|
+
keptSlots.forEach((slot) => emitSlotMetric({
|
|
180104
|
+
type: "prepared",
|
|
180105
|
+
slotId: slot.id
|
|
180106
|
+
}, onSlotMetric));
|
|
180107
|
+
return keptSlots;
|
|
180108
|
+
};
|
|
180109
|
+
var htmlByteLength = (value, encoder) => encoder.encode(value).length;
|
|
180110
|
+
var resolveSlot = async (slot, onError, policy, onSlotMetric) => {
|
|
180111
|
+
const safePolicy = policy ?? getStreamingSlotPolicy();
|
|
180112
|
+
const encoder = new TextEncoder;
|
|
180113
|
+
const start = Date.now();
|
|
180114
|
+
try {
|
|
180115
|
+
const maybeAsyncValue = Promise.resolve(slot.resolve());
|
|
180116
|
+
const resolved = typeof slot.timeoutMs === "number" && slot.timeoutMs > 0 ? await Promise.race([
|
|
180117
|
+
maybeAsyncValue,
|
|
180118
|
+
new Promise((_, reject) => setTimeout(() => {
|
|
180119
|
+
reject(createTimeoutError(slot, slot.timeoutMs ?? 0));
|
|
180120
|
+
}, slot.timeoutMs))
|
|
180121
|
+
]) : await maybeAsyncValue;
|
|
180122
|
+
const html = typeof resolved === "string" ? resolved : `${resolved}`;
|
|
180123
|
+
if (safePolicy.maxSlotHtmlSizeBytes > 0 && htmlByteLength(html, encoder) > safePolicy.maxSlotHtmlSizeBytes) {
|
|
180124
|
+
const bytes2 = htmlByteLength(html, encoder);
|
|
180125
|
+
const error = new Error(`Streaming slot "${slot.id}" exceeded max payload size of ${safePolicy.maxSlotHtmlSizeBytes} bytes`);
|
|
180126
|
+
const durationMs2 = Date.now() - start;
|
|
180127
|
+
onError?.(error, slot);
|
|
180128
|
+
emitSlotMetric({
|
|
180129
|
+
type: "size_exceeded",
|
|
180130
|
+
slotId: slot.id,
|
|
180131
|
+
durationMs: durationMs2,
|
|
180132
|
+
bytes: bytes2,
|
|
180133
|
+
error
|
|
180134
|
+
}, onSlotMetric);
|
|
180135
|
+
const fallbackHtml = typeof slot.errorHtml === "string" ? slot.errorHtml : null;
|
|
180136
|
+
return {
|
|
180137
|
+
html: fallbackHtml,
|
|
180138
|
+
id: slot.id,
|
|
180139
|
+
durationMs: durationMs2,
|
|
180140
|
+
bytes: fallbackHtml === null ? 0 : htmlByteLength(fallbackHtml, encoder)
|
|
180141
|
+
};
|
|
180142
|
+
}
|
|
180143
|
+
const durationMs = Date.now() - start;
|
|
180144
|
+
const bytes = htmlByteLength(html, encoder);
|
|
180145
|
+
emitSlotMetric({
|
|
180146
|
+
type: "resolved",
|
|
180147
|
+
slotId: slot.id,
|
|
180148
|
+
durationMs,
|
|
180149
|
+
bytes
|
|
180150
|
+
}, onSlotMetric);
|
|
180151
|
+
return {
|
|
180152
|
+
html,
|
|
180153
|
+
id: slot.id,
|
|
180154
|
+
durationMs,
|
|
180155
|
+
bytes
|
|
180156
|
+
};
|
|
180157
|
+
} catch (error) {
|
|
180158
|
+
const durationMs = Date.now() - start;
|
|
180159
|
+
onError?.(error, slot);
|
|
180160
|
+
emitSlotMetric({
|
|
180161
|
+
type: error?.__absTimeout === true ? "timeout" : "error",
|
|
180162
|
+
slotId: slot.id,
|
|
180163
|
+
durationMs,
|
|
180164
|
+
error
|
|
180165
|
+
}, onSlotMetric);
|
|
180166
|
+
if (typeof slot.errorHtml === "string") {
|
|
180167
|
+
const html = slot.errorHtml;
|
|
180168
|
+
return {
|
|
180169
|
+
html,
|
|
180170
|
+
id: slot.id,
|
|
180171
|
+
durationMs,
|
|
180172
|
+
bytes: htmlByteLength(html, encoder)
|
|
180173
|
+
};
|
|
180174
|
+
}
|
|
180175
|
+
return {
|
|
180176
|
+
html: null,
|
|
180177
|
+
id: slot.id,
|
|
180178
|
+
durationMs,
|
|
180179
|
+
bytes: 0
|
|
180180
|
+
};
|
|
180181
|
+
}
|
|
180182
|
+
};
|
|
180183
|
+
var nextResolvedSlot = async (pending) => {
|
|
180184
|
+
const wrapped = pending.map((promise) => promise.then((result) => ({
|
|
180185
|
+
original: promise,
|
|
180186
|
+
result
|
|
180187
|
+
})));
|
|
180188
|
+
return Promise.race(wrapped);
|
|
180189
|
+
};
|
|
180190
|
+
var streamChunkToString = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true });
|
|
180191
|
+
var streamOutOfOrderSlots = ({
|
|
180192
|
+
footerHtml = "",
|
|
180193
|
+
headerHtml = "",
|
|
180194
|
+
nonce,
|
|
180195
|
+
policy,
|
|
180196
|
+
onSlotMetric,
|
|
180197
|
+
onError,
|
|
180198
|
+
slots
|
|
180199
|
+
}) => {
|
|
180200
|
+
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
180201
|
+
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
180202
|
+
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
180203
|
+
const effectivePolicy = {
|
|
180204
|
+
...resolvedPolicy,
|
|
180205
|
+
onSlotMetric: combinedOnSlotMetric
|
|
180206
|
+
};
|
|
180207
|
+
const preparedSlots = prepareSlots({
|
|
180208
|
+
policy: effectivePolicy,
|
|
180209
|
+
slots,
|
|
180210
|
+
onError: combinedOnError,
|
|
180211
|
+
onSlotMetric: combinedOnSlotMetric
|
|
180212
|
+
});
|
|
180213
|
+
const encoder = new TextEncoder;
|
|
180214
|
+
return new ReadableStream({
|
|
180215
|
+
async start(controller) {
|
|
180216
|
+
try {
|
|
180217
|
+
let header = headerHtml;
|
|
180218
|
+
if (preparedSlots.length > 0 && !header.includes(STREAMING_RUNTIME_GLOBAL)) {
|
|
180219
|
+
header = injectHtmlIntoHead(header, renderStreamingSlotsRuntimeTag(nonce));
|
|
180220
|
+
}
|
|
180221
|
+
controller.enqueue(toUint8(header, encoder));
|
|
180222
|
+
const pending = preparedSlots.map((slot) => {
|
|
180223
|
+
const fallback = renderStreamingSlotPlaceholder(slot.id, slot.fallbackHtml ?? "");
|
|
180224
|
+
controller.enqueue(toUint8(fallback, encoder));
|
|
180225
|
+
return resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric);
|
|
180226
|
+
});
|
|
180227
|
+
while (pending.length > 0) {
|
|
180228
|
+
const { original, result } = await nextResolvedSlot(pending);
|
|
180229
|
+
const index = pending.indexOf(original);
|
|
180230
|
+
if (index >= 0)
|
|
180231
|
+
pending.splice(index, 1);
|
|
180232
|
+
if (result.html === null)
|
|
180233
|
+
continue;
|
|
180234
|
+
emitSlotMetric({
|
|
180235
|
+
type: "patched",
|
|
180236
|
+
slotId: result.id,
|
|
180237
|
+
durationMs: result.durationMs,
|
|
180238
|
+
bytes: result.bytes
|
|
180239
|
+
}, combinedOnSlotMetric);
|
|
180240
|
+
controller.enqueue(toUint8(renderStreamingSlotPatchTag(result.id, result.html, nonce), encoder));
|
|
180241
|
+
}
|
|
180242
|
+
if (footerHtml.length > 0) {
|
|
180243
|
+
controller.enqueue(toUint8(footerHtml, encoder));
|
|
180244
|
+
}
|
|
180245
|
+
controller.close();
|
|
180246
|
+
} catch (error) {
|
|
180247
|
+
controller.error(error);
|
|
180248
|
+
}
|
|
180249
|
+
}
|
|
180250
|
+
});
|
|
180251
|
+
};
|
|
180252
|
+
var injectStreamingRuntimeIntoStream = (stream, nonce) => {
|
|
180253
|
+
const runtimeTag = renderStreamingSlotsRuntimeTag(nonce);
|
|
180254
|
+
const encoder = new TextEncoder;
|
|
180255
|
+
const decoder = new TextDecoder;
|
|
180256
|
+
const lookbehind = CLOSING_HEAD_TAG_LENGTH - 1;
|
|
180257
|
+
return new ReadableStream({
|
|
180258
|
+
async start(controller) {
|
|
180259
|
+
const reader = stream.getReader();
|
|
180260
|
+
let injected = false;
|
|
180261
|
+
let pending = "";
|
|
180262
|
+
try {
|
|
180263
|
+
for (;; ) {
|
|
180264
|
+
const { done, value } = await reader.read();
|
|
180265
|
+
if (done)
|
|
180266
|
+
break;
|
|
180267
|
+
if (!value)
|
|
180268
|
+
continue;
|
|
180269
|
+
pending += streamChunkToString(value, decoder);
|
|
180270
|
+
if (injected) {
|
|
180271
|
+
controller.enqueue(encoder.encode(pending));
|
|
180272
|
+
pending = "";
|
|
180273
|
+
continue;
|
|
180274
|
+
}
|
|
180275
|
+
const headIndex = pending.indexOf(CLOSING_HEAD_TAG);
|
|
180276
|
+
if (headIndex >= 0) {
|
|
180277
|
+
const withRuntime = `${pending.slice(0, headIndex)}${runtimeTag}${pending.slice(headIndex)}`;
|
|
180278
|
+
controller.enqueue(encoder.encode(withRuntime));
|
|
180279
|
+
pending = "";
|
|
180280
|
+
injected = true;
|
|
180281
|
+
continue;
|
|
180282
|
+
}
|
|
180283
|
+
if (pending.length > lookbehind) {
|
|
180284
|
+
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
180285
|
+
controller.enqueue(encoder.encode(safeText));
|
|
180286
|
+
pending = pending.slice(-lookbehind);
|
|
180287
|
+
}
|
|
180288
|
+
}
|
|
180289
|
+
pending += decoder.decode();
|
|
180290
|
+
if (!injected) {
|
|
180291
|
+
pending = injectHtmlIntoHead(pending, runtimeTag);
|
|
180292
|
+
}
|
|
180293
|
+
if (pending.length > 0) {
|
|
180294
|
+
controller.enqueue(encoder.encode(pending));
|
|
180295
|
+
}
|
|
180296
|
+
controller.close();
|
|
180297
|
+
} catch (error) {
|
|
180298
|
+
controller.error(error);
|
|
180299
|
+
}
|
|
180300
|
+
}
|
|
180301
|
+
});
|
|
180302
|
+
};
|
|
180303
|
+
var appendStreamingSlotPatchesToStream = (stream, slots = [], {
|
|
180304
|
+
injectRuntime = true,
|
|
180305
|
+
nonce,
|
|
180306
|
+
onError,
|
|
180307
|
+
onSlotMetric,
|
|
180308
|
+
policy
|
|
180309
|
+
} = {}) => {
|
|
180310
|
+
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
180311
|
+
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
180312
|
+
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
180313
|
+
const effectivePolicy = {
|
|
180314
|
+
...resolvedPolicy,
|
|
180315
|
+
onSlotMetric: combinedOnSlotMetric
|
|
180316
|
+
};
|
|
180317
|
+
const preparedSlots = prepareSlots({
|
|
180318
|
+
policy: effectivePolicy,
|
|
180319
|
+
slots,
|
|
180320
|
+
onError: combinedOnError,
|
|
180321
|
+
onSlotMetric: combinedOnSlotMetric
|
|
180322
|
+
});
|
|
180323
|
+
if (preparedSlots.length === 0)
|
|
180324
|
+
return stream;
|
|
180325
|
+
const source = injectRuntime ? injectStreamingRuntimeIntoStream(stream, nonce) : stream;
|
|
180326
|
+
const encoder = new TextEncoder;
|
|
180327
|
+
const decoder = new TextDecoder;
|
|
180328
|
+
const reader = source.getReader();
|
|
180329
|
+
const pending = preparedSlots.map((slot) => resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric));
|
|
180330
|
+
return new ReadableStream({
|
|
180331
|
+
async start(controller) {
|
|
180332
|
+
let baseDone = false;
|
|
180333
|
+
let baseRead = reader.read();
|
|
180334
|
+
let tail = "";
|
|
180335
|
+
let footer = "";
|
|
180336
|
+
try {
|
|
180337
|
+
while (!baseDone || pending.length > 0) {
|
|
180338
|
+
const racers = [];
|
|
180339
|
+
if (!baseDone) {
|
|
180340
|
+
racers.push(baseRead.then(({ done, value }) => ({
|
|
180341
|
+
done,
|
|
180342
|
+
kind: "base",
|
|
180343
|
+
value
|
|
180344
|
+
})));
|
|
180345
|
+
}
|
|
180346
|
+
if (pending.length > 0) {
|
|
180347
|
+
racers.push(nextResolvedSlot(pending).then((resolved) => ({
|
|
180348
|
+
kind: "slot",
|
|
180349
|
+
...resolved
|
|
180350
|
+
})));
|
|
180351
|
+
}
|
|
180352
|
+
if (racers.length === 0)
|
|
180353
|
+
break;
|
|
180354
|
+
const winner = await Promise.race(racers);
|
|
180355
|
+
if (winner.kind === "base") {
|
|
180356
|
+
if (winner.done) {
|
|
180357
|
+
baseDone = true;
|
|
180358
|
+
tail += decoder.decode();
|
|
180359
|
+
const footerStart = tail.search(CLOSING_PAGE_TAG_REGEX);
|
|
180360
|
+
if (footerStart >= 0) {
|
|
180361
|
+
const content = tail.slice(0, footerStart);
|
|
180362
|
+
footer = tail.slice(footerStart);
|
|
180363
|
+
if (content.length > 0) {
|
|
180364
|
+
controller.enqueue(encoder.encode(content));
|
|
180365
|
+
}
|
|
180366
|
+
} else if (tail.length > 0) {
|
|
180367
|
+
controller.enqueue(encoder.encode(tail));
|
|
180368
|
+
}
|
|
180369
|
+
tail = "";
|
|
180370
|
+
} else if (winner.value) {
|
|
180371
|
+
tail += streamChunkToString(winner.value, decoder);
|
|
180372
|
+
if (tail.length > STREAM_TAIL_LOOKBEHIND) {
|
|
180373
|
+
const content = tail.slice(0, tail.length - STREAM_TAIL_LOOKBEHIND);
|
|
180374
|
+
controller.enqueue(encoder.encode(content));
|
|
180375
|
+
tail = tail.slice(-STREAM_TAIL_LOOKBEHIND);
|
|
180376
|
+
}
|
|
180377
|
+
baseRead = reader.read();
|
|
180378
|
+
}
|
|
180379
|
+
continue;
|
|
180380
|
+
}
|
|
180381
|
+
const index = pending.indexOf(winner.original);
|
|
180382
|
+
if (index >= 0)
|
|
180383
|
+
pending.splice(index, 1);
|
|
180384
|
+
if (winner.result.html === null)
|
|
180385
|
+
continue;
|
|
180386
|
+
emitSlotMetric({
|
|
180387
|
+
type: "patched",
|
|
180388
|
+
slotId: winner.result.id,
|
|
180389
|
+
durationMs: winner.result.durationMs,
|
|
180390
|
+
bytes: winner.result.bytes
|
|
180391
|
+
}, combinedOnSlotMetric);
|
|
180392
|
+
controller.enqueue(encoder.encode(renderStreamingSlotPatchTag(winner.result.id, winner.result.html, nonce)));
|
|
180393
|
+
}
|
|
180394
|
+
if (footer.length > 0)
|
|
180395
|
+
controller.enqueue(encoder.encode(footer));
|
|
180396
|
+
controller.close();
|
|
180397
|
+
} catch (error) {
|
|
180398
|
+
controller.error(error);
|
|
180399
|
+
}
|
|
180400
|
+
}
|
|
180401
|
+
});
|
|
180402
|
+
};
|
|
180403
|
+
|
|
180404
|
+
// src/core/streamingSlotRegistrar.ts
|
|
180405
|
+
var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
|
|
180406
|
+
var getRegistrarGlobal = () => globalThis;
|
|
180407
|
+
var setStreamingSlotRegistrar = (nextRegistrar) => {
|
|
180408
|
+
getRegistrarGlobal()[STREAMING_SLOT_REGISTRAR_KEY] = nextRegistrar;
|
|
180409
|
+
};
|
|
180410
|
+
var registerStreamingSlot = (slot) => {
|
|
180411
|
+
getRegistrarGlobal()[STREAMING_SLOT_REGISTRAR_KEY]?.(slot);
|
|
180412
|
+
};
|
|
180413
|
+
|
|
180414
|
+
// src/core/streamingSlotRegistry.ts
|
|
180415
|
+
var asyncLocalStorage;
|
|
180416
|
+
var isServerRuntime = () => typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
180417
|
+
var ensureAsyncLocalStorage = async () => {
|
|
180418
|
+
if (typeof asyncLocalStorage !== "undefined")
|
|
180419
|
+
return asyncLocalStorage;
|
|
180420
|
+
if (!isServerRuntime()) {
|
|
180421
|
+
asyncLocalStorage = null;
|
|
180422
|
+
return asyncLocalStorage;
|
|
180423
|
+
}
|
|
180424
|
+
const mod = await import("async_hooks");
|
|
180425
|
+
asyncLocalStorage = new mod.AsyncLocalStorage;
|
|
180426
|
+
return asyncLocalStorage;
|
|
180427
|
+
};
|
|
180428
|
+
var registerStreamingSlot2 = (slot) => {
|
|
180429
|
+
if (!asyncLocalStorage)
|
|
180430
|
+
return;
|
|
180431
|
+
const store = asyncLocalStorage.getStore();
|
|
180432
|
+
if (!store)
|
|
180433
|
+
return;
|
|
180434
|
+
store.set(slot.id, slot);
|
|
180435
|
+
};
|
|
180436
|
+
setStreamingSlotRegistrar(registerStreamingSlot2);
|
|
180437
|
+
var runWithStreamingSlotRegistry = async (task) => {
|
|
180438
|
+
const storage = await ensureAsyncLocalStorage();
|
|
180439
|
+
if (!storage) {
|
|
180440
|
+
return {
|
|
180441
|
+
result: await task(),
|
|
180442
|
+
slots: []
|
|
180443
|
+
};
|
|
180444
|
+
}
|
|
180445
|
+
return storage.run(new Map, async () => {
|
|
180446
|
+
const result = await task();
|
|
180447
|
+
const store = storage.getStore();
|
|
180448
|
+
return {
|
|
180449
|
+
result,
|
|
180450
|
+
slots: store ? [...store.values()] : []
|
|
180451
|
+
};
|
|
180452
|
+
});
|
|
180453
|
+
};
|
|
180454
|
+
|
|
180455
|
+
// src/core/responseEnhancers.ts
|
|
180456
|
+
var toResponse = async (responseLike) => await responseLike;
|
|
180457
|
+
var cloneHeaders = (response) => {
|
|
180458
|
+
const headers = new Headers(response.headers);
|
|
180459
|
+
return headers;
|
|
180460
|
+
};
|
|
180461
|
+
var enhanceHtmlResponseWithStreamingSlots = (response, { nonce, onError, streamingSlots = [], policy } = {}) => {
|
|
180462
|
+
if (!response.body || streamingSlots.length === 0) {
|
|
180463
|
+
return response;
|
|
180464
|
+
}
|
|
180465
|
+
const body = appendStreamingSlotPatchesToStream(response.body, streamingSlots, {
|
|
180466
|
+
nonce,
|
|
180467
|
+
onError,
|
|
180468
|
+
policy
|
|
180469
|
+
});
|
|
180470
|
+
return new Response(body, {
|
|
180471
|
+
headers: cloneHeaders(response),
|
|
180472
|
+
status: response.status,
|
|
180473
|
+
statusText: response.statusText
|
|
180474
|
+
});
|
|
180475
|
+
};
|
|
180476
|
+
var withStreamingSlots = async (responseLike, options = {}) => enhanceHtmlResponseWithStreamingSlots(await toResponse(responseLike), options);
|
|
180477
|
+
var mergeStreamingSlots = (registered, explicit) => {
|
|
180478
|
+
const merged = new Map;
|
|
180479
|
+
for (const slot of registered)
|
|
180480
|
+
merged.set(slot.id, slot);
|
|
180481
|
+
for (const slot of explicit)
|
|
180482
|
+
merged.set(slot.id, slot);
|
|
180483
|
+
return [...merged.values()];
|
|
180484
|
+
};
|
|
180485
|
+
var withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
|
|
180486
|
+
const { result, slots } = await runWithStreamingSlotRegistry(renderResponse);
|
|
180487
|
+
const explicit = options.streamingSlots ?? [];
|
|
180488
|
+
return withStreamingSlots(result, {
|
|
180489
|
+
...options,
|
|
180490
|
+
streamingSlots: mergeStreamingSlots(slots, explicit)
|
|
180491
|
+
});
|
|
180492
|
+
};
|
|
180493
|
+
|
|
180494
|
+
// src/core/wrapPageHandlerWithStreamingSlots.ts
|
|
180495
|
+
var wrapPageHandlerWithStreamingSlots = (handler) => (...args) => withRegisteredStreamingSlots(() => handler(...args));
|
|
180496
|
+
|
|
180497
|
+
// src/react/index.ts
|
|
180498
|
+
init_pageHandler();
|
|
180499
|
+
|
|
180500
|
+
// src/react/Island.tsx
|
|
180501
|
+
init_islandMarkupAttributes();
|
|
180502
|
+
init_renderIslandMarkup();
|
|
180503
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
180504
|
+
var Island = async (props) => {
|
|
180505
|
+
if (typeof window !== "undefined") {
|
|
180506
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
180507
|
+
...getIslandMarkerAttributes(props),
|
|
180508
|
+
suppressHydrationWarning: true
|
|
180509
|
+
}, undefined, false, undefined, this);
|
|
180510
|
+
}
|
|
180511
|
+
const result = await renderIslandResult(requireCurrentIslandRegistry(), props);
|
|
180512
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
180513
|
+
...result.attributes,
|
|
180514
|
+
dangerouslySetInnerHTML: { __html: result.html }
|
|
180515
|
+
}, undefined, false, undefined, this);
|
|
180516
|
+
};
|
|
180517
|
+
// src/react/createIsland.tsx
|
|
180518
|
+
init_islandMarkupAttributes();
|
|
180519
|
+
init_renderIslandMarkup();
|
|
180520
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
180521
|
+
var createTypedIsland = (registry) => {
|
|
180522
|
+
const Island2 = async (props) => {
|
|
180523
|
+
if (typeof window !== "undefined") {
|
|
180524
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
180525
|
+
...getIslandMarkerAttributes(props),
|
|
180526
|
+
suppressHydrationWarning: true
|
|
180527
|
+
}, undefined, false, undefined, this);
|
|
180528
|
+
}
|
|
180529
|
+
const result = await renderIslandResult(registry, props);
|
|
180530
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
180531
|
+
...result.attributes,
|
|
180532
|
+
dangerouslySetInnerHTML: { __html: result.html }
|
|
180533
|
+
}, undefined, false, undefined, this);
|
|
180534
|
+
};
|
|
180535
|
+
return Island2;
|
|
180536
|
+
};
|
|
180537
|
+
// src/react/hooks/useIslandStore.ts
|
|
180538
|
+
import { useSyncExternalStore } from "react";
|
|
180539
|
+
|
|
180540
|
+
// node_modules/zustand/esm/vanilla.mjs
|
|
180541
|
+
var createStoreImpl = (createState) => {
|
|
180542
|
+
let state;
|
|
180543
|
+
const listeners = /* @__PURE__ */ new Set;
|
|
180544
|
+
const setState = (partial, replace) => {
|
|
180545
|
+
const nextState = typeof partial === "function" ? partial(state) : partial;
|
|
180546
|
+
if (!Object.is(nextState, state)) {
|
|
180547
|
+
const previousState = state;
|
|
180548
|
+
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
|
|
180549
|
+
listeners.forEach((listener) => listener(state, previousState));
|
|
180550
|
+
}
|
|
180551
|
+
};
|
|
180552
|
+
const getState = () => state;
|
|
180553
|
+
const getInitialState = () => initialState;
|
|
180554
|
+
const subscribe = (listener) => {
|
|
180555
|
+
listeners.add(listener);
|
|
180556
|
+
return () => listeners.delete(listener);
|
|
180557
|
+
};
|
|
180558
|
+
const api = { setState, getState, getInitialState, subscribe };
|
|
180559
|
+
const initialState = state = createState(setState, getState, api);
|
|
180560
|
+
return api;
|
|
180561
|
+
};
|
|
180562
|
+
var createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
|
|
180563
|
+
|
|
180564
|
+
// node_modules/zustand/esm/middleware.mjs
|
|
180565
|
+
function combine(initialState, create) {
|
|
180566
|
+
return (...args) => Object.assign({}, initialState, create(...args));
|
|
180567
|
+
}
|
|
180568
|
+
|
|
180569
|
+
// src/client/islandStore.ts
|
|
180570
|
+
var getIslandStoreSnapshot = () => {
|
|
180571
|
+
globalThis.__ABS_ISLAND_STATE__ ??= {};
|
|
180572
|
+
return globalThis.__ABS_ISLAND_STATE__;
|
|
180573
|
+
};
|
|
180574
|
+
var getIslandStores = () => {
|
|
180575
|
+
globalThis.__ABS_ISLAND_STORES__ ??= new Map;
|
|
180576
|
+
return globalThis.__ABS_ISLAND_STORES__;
|
|
180577
|
+
};
|
|
180578
|
+
var isSerializableValue = (value) => typeof value !== "function" && value !== undefined;
|
|
180579
|
+
var toSerializableState = (state) => Object.fromEntries(Object.entries(state).filter(([, value]) => isSerializableValue(value)));
|
|
180580
|
+
var applySnapshot = (store, snapshot) => {
|
|
180581
|
+
if (!snapshot) {
|
|
180582
|
+
return;
|
|
180583
|
+
}
|
|
180584
|
+
store.setState({
|
|
180585
|
+
...store.getState(),
|
|
180586
|
+
...snapshot
|
|
180587
|
+
});
|
|
180588
|
+
};
|
|
180589
|
+
var getPeerStores = (storeInstances, ownerStore) => [...storeInstances].filter((peer) => peer.store !== ownerStore);
|
|
180590
|
+
var syncIslandSnapshot = (storeId, state, storeInstances, ownerStore) => {
|
|
180591
|
+
const nextSnapshot = toSerializableState(state);
|
|
180592
|
+
getIslandStoreSnapshot()[storeId] = nextSnapshot;
|
|
180593
|
+
for (const peerStore of getPeerStores(storeInstances, ownerStore)) {
|
|
180594
|
+
peerStore.applyExternalSnapshot(nextSnapshot);
|
|
180595
|
+
}
|
|
180596
|
+
};
|
|
180597
|
+
var createIslandStore = (storeId, initialState, createState) => {
|
|
180598
|
+
const store = createStore(combine(initialState, createState));
|
|
180599
|
+
const stores = getIslandStores();
|
|
180600
|
+
const storeInstances = stores.get(storeId) ?? new Set;
|
|
180601
|
+
const initialSnapshot = getIslandStoreSnapshot()[storeId];
|
|
180602
|
+
applySnapshot(store, initialSnapshot);
|
|
180603
|
+
let isApplyingExternalSnapshot = false;
|
|
180604
|
+
const applyExternalSnapshot = (snapshot) => {
|
|
180605
|
+
isApplyingExternalSnapshot = true;
|
|
180606
|
+
applySnapshot(store, snapshot);
|
|
180607
|
+
};
|
|
180608
|
+
storeInstances.add({
|
|
180609
|
+
applyExternalSnapshot,
|
|
180610
|
+
store
|
|
180611
|
+
});
|
|
180612
|
+
stores.set(storeId, storeInstances);
|
|
180613
|
+
syncIslandSnapshot(storeId, store.getState(), storeInstances, store);
|
|
180614
|
+
store.subscribe((state) => {
|
|
180615
|
+
if (isApplyingExternalSnapshot) {
|
|
180616
|
+
isApplyingExternalSnapshot = false;
|
|
180617
|
+
return;
|
|
180618
|
+
}
|
|
180619
|
+
syncIslandSnapshot(storeId, state, storeInstances, store);
|
|
180620
|
+
});
|
|
180621
|
+
return store;
|
|
180622
|
+
};
|
|
180623
|
+
var getIslandStoreServerSnapshot = (store, selector) => selector(store.getInitialState());
|
|
180624
|
+
var applySnapshotToStoreInstances = (storeId, instances, snapshot) => {
|
|
180625
|
+
for (const instance of instances) {
|
|
180626
|
+
instance.applyExternalSnapshot(snapshot[storeId] ?? {});
|
|
180627
|
+
}
|
|
180628
|
+
};
|
|
180629
|
+
var initializeIslandStores = (state) => {
|
|
180630
|
+
const currentSnapshot = getIslandStoreSnapshot();
|
|
180631
|
+
const nextSnapshot = {
|
|
180632
|
+
...state,
|
|
180633
|
+
...currentSnapshot
|
|
180634
|
+
};
|
|
180635
|
+
globalThis.__ABS_ISLAND_STATE__ = nextSnapshot;
|
|
180636
|
+
for (const [storeId, store] of getIslandStores()) {
|
|
180637
|
+
applySnapshotToStoreInstances(storeId, store, nextSnapshot);
|
|
180638
|
+
}
|
|
180639
|
+
};
|
|
180640
|
+
var readIslandStore = (store, selector) => selector(store.getState());
|
|
180641
|
+
var subscribeIslandStore = (store, selector, listener) => {
|
|
180642
|
+
let currentSelection = selector(store.getState());
|
|
180643
|
+
return store.subscribe((state) => {
|
|
180644
|
+
const nextSelection = selector(state);
|
|
180645
|
+
if (Object.is(nextSelection, currentSelection)) {
|
|
180646
|
+
return;
|
|
180647
|
+
}
|
|
180648
|
+
currentSelection = nextSelection;
|
|
180649
|
+
listener(nextSelection);
|
|
180650
|
+
});
|
|
180651
|
+
};
|
|
180652
|
+
|
|
180653
|
+
// src/react/hooks/useIslandStore.ts
|
|
180654
|
+
var useIslandStore = (store, selector) => useSyncExternalStore((listener) => subscribeIslandStore(store, selector, () => {
|
|
180655
|
+
listener();
|
|
180656
|
+
}), () => readIslandStore(store, selector), () => getIslandStoreServerSnapshot(store, selector));
|
|
180657
|
+
|
|
180658
|
+
// src/react/index.ts
|
|
180659
|
+
var handleReactPageRequest2 = wrapPageHandlerWithStreamingSlots(handleReactPageRequest);
|
|
180466
180660
|
// types/client.ts
|
|
180467
180661
|
var hmrState = {
|
|
180468
180662
|
isConnected: false,
|
|
@@ -180488,7 +180682,6 @@ init_islands();
|
|
|
180488
180682
|
|
|
180489
180683
|
// src/core/pageHandlers.ts
|
|
180490
180684
|
init_staticIslandPages();
|
|
180491
|
-
init_pageHandler();
|
|
180492
180685
|
var {file } = globalThis.Bun;
|
|
180493
180686
|
var handleStaticPageRequest = async (pagePath) => {
|
|
180494
180687
|
const html = await file(pagePath).text();
|
|
@@ -180765,12 +180958,7 @@ var prepare = async (configOrPath) => {
|
|
|
180765
180958
|
};
|
|
180766
180959
|
|
|
180767
180960
|
// src/core/index.ts
|
|
180768
|
-
init_responseEnhancers();
|
|
180769
180961
|
init_renderIslandMarkup();
|
|
180770
|
-
|
|
180771
|
-
// src/core/wrapPageHandlerWithStreamingSlots.ts
|
|
180772
|
-
init_responseEnhancers();
|
|
180773
|
-
var wrapPageHandlerWithStreamingSlots = (handler) => (...args) => withRegisteredStreamingSlots(() => handler(...args));
|
|
180774
180962
|
// src/plugins/networking.ts
|
|
180775
180963
|
init_constants();
|
|
180776
180964
|
import { argv } from "process";
|
|
@@ -187127,9 +187315,6 @@ var createStreamingSlotMetricSink = ({
|
|
|
187127
187315
|
});
|
|
187128
187316
|
};
|
|
187129
187317
|
};
|
|
187130
|
-
|
|
187131
|
-
// src/utils/index.ts
|
|
187132
|
-
init_streamingSlots();
|
|
187133
187318
|
export {
|
|
187134
187319
|
wrapPageHandlerWithStreamingSlots,
|
|
187135
187320
|
withStreamingSlots,
|
|
@@ -187157,7 +187342,7 @@ export {
|
|
|
187157
187342
|
injectStreamingRuntimeIntoStream,
|
|
187158
187343
|
injectHtmlIntoHead,
|
|
187159
187344
|
hmrState,
|
|
187160
|
-
handleReactPageRequest,
|
|
187345
|
+
handleReactPageRequest2 as handleReactPageRequest,
|
|
187161
187346
|
handleHTMXPageRequest,
|
|
187162
187347
|
handleHTMLPageRequest,
|
|
187163
187348
|
getStreamingSlotsRuntimeScript,
|
|
@@ -187234,5 +187419,5 @@ export {
|
|
|
187234
187419
|
ANGULAR_INIT_TIMEOUT_MS
|
|
187235
187420
|
};
|
|
187236
187421
|
|
|
187237
|
-
//# debugId=
|
|
187422
|
+
//# debugId=C88BAB0C6BD3F8AB64756E2164756E21
|
|
187238
187423
|
//# sourceMappingURL=index.js.map
|