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