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