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