@absolutejs/absolute 0.19.0-beta.366 → 0.19.0-beta.368
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/browser.js +13 -8
- package/dist/angular/browser.js.map +4 -4
- package/dist/angular/components/core/streamingSlotRegistrar.js +4 -3
- package/dist/angular/components/core/streamingSlotRegistry.js +4 -3
- package/dist/angular/index.js +668 -622
- package/dist/angular/index.js.map +8 -8
- package/dist/build.js +24 -579
- package/dist/build.js.map +4 -10
- package/dist/client/index.js +45 -44
- package/dist/client/index.js.map +4 -4
- package/dist/index.js +1322 -1138
- package/dist/index.js.map +28 -22
- package/dist/react/components/browser/index.js +9 -20
- package/dist/react/components/index.js +17 -35
- package/dist/react/components/index.js.map +5 -6
- package/dist/react/index.js +1125 -1095
- package/dist/react/index.js.map +12 -12
- package/dist/react/server.js +3 -574
- package/dist/react/server.js.map +4 -11
- package/dist/src/core/pageHandlers.d.ts +1 -0
- package/dist/src/react/index.d.ts +1 -1
- package/dist/svelte/index.js +1506 -1460
- package/dist/svelte/index.js.map +8 -8
- package/dist/vue/components/index.js +13 -8
- package/dist/vue/components/index.js.map +5 -5
- package/dist/vue/index.js +667 -619
- package/dist/vue/index.js.map +8 -8
- package/package.json +1 -1
- package/dist/src/react/streamingSlotCollection.d.ts +0 -9
package/dist/angular/index.js
CHANGED
|
@@ -78,49 +78,6 @@ var __legacyMetadataTS = (k, v) => {
|
|
|
78
78
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
79
79
|
var __require = import.meta.require;
|
|
80
80
|
|
|
81
|
-
// src/client/streamSwap.ts
|
|
82
|
-
var streamSwapRuntime = () => {
|
|
83
|
-
if (window.__ABS_SLOT_RUNTIME__ === true)
|
|
84
|
-
return;
|
|
85
|
-
window.__ABS_SLOT_RUNTIME__ = true;
|
|
86
|
-
window.__ABS_SLOT_PENDING__ = window.__ABS_SLOT_PENDING__ ?? {};
|
|
87
|
-
const pending = window.__ABS_SLOT_PENDING__;
|
|
88
|
-
const apply = (id, html) => {
|
|
89
|
-
const node = document.getElementById(`slot-${id}`);
|
|
90
|
-
if (!node) {
|
|
91
|
-
pending[id] = html;
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
node.innerHTML = html;
|
|
95
|
-
delete pending[id];
|
|
96
|
-
};
|
|
97
|
-
const flush = () => {
|
|
98
|
-
for (const id in pending) {
|
|
99
|
-
if (!Object.prototype.hasOwnProperty.call(pending, id))
|
|
100
|
-
continue;
|
|
101
|
-
apply(id, pending[id] ?? "");
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
window.__ABS_SLOT_ENQUEUE__ = (id, html) => {
|
|
105
|
-
apply(id, html);
|
|
106
|
-
};
|
|
107
|
-
if (typeof MutationObserver === "function") {
|
|
108
|
-
const observer = new MutationObserver(flush);
|
|
109
|
-
const root = document.documentElement ?? document.body ?? document;
|
|
110
|
-
observer.observe(root, { childList: true, subtree: true });
|
|
111
|
-
}
|
|
112
|
-
if (document.readyState === "loading") {
|
|
113
|
-
document.addEventListener("DOMContentLoaded", flush, { once: true });
|
|
114
|
-
}
|
|
115
|
-
flush();
|
|
116
|
-
}, stripFunctionWrapper = (value) => {
|
|
117
|
-
const start = value.indexOf("{");
|
|
118
|
-
const end = value.lastIndexOf("}");
|
|
119
|
-
if (start < 0 || end <= start)
|
|
120
|
-
return "";
|
|
121
|
-
return value.slice(start + 1, end);
|
|
122
|
-
}, getStreamSwapRuntimeScript = () => `(function(){${stripFunctionWrapper(streamSwapRuntime.toString())}})();`;
|
|
123
|
-
|
|
124
81
|
// src/utils/escapeScriptContent.ts
|
|
125
82
|
var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
|
|
126
83
|
const escaped = ESCAPE_LOOKUP[char];
|
|
@@ -137,258 +94,43 @@ var init_escapeScriptContent = __esm(() => {
|
|
|
137
94
|
ESCAPE_REGEX = /[&><\u2028\u2029]/g;
|
|
138
95
|
});
|
|
139
96
|
|
|
140
|
-
// src/
|
|
141
|
-
var
|
|
142
|
-
|
|
97
|
+
// src/constants.ts
|
|
98
|
+
var ANGULAR_INIT_TIMEOUT_MS = 500, ANSI_ESCAPE_LENGTH = 3, ASCII_SPACE = 32, BASE_36_RADIX = 36, BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet", BODY_SLICE_LENGTH = 2000, BYTES_PER_KILOBYTE = 1024, CLI_ARGS_OFFSET = 3, CSS_ERROR_RESOLVE_DELAY_MS = 50, CSS_MAX_CHECK_ATTEMPTS = 10, CSS_MAX_PARSE_TIMEOUT_MS = 500, CSS_SHEET_READY_TIMEOUT_MS = 100, DEFAULT_CHUNK_SIZE = 16384, DEFAULT_DEBOUNCE_MS = 15, DEFAULT_PORT = 3000, DEV_SERVER_RESTART_DEBOUNCE_MS = 100, DOM_UPDATE_DELAY_MS = 50, FILE_PROTOCOL_PREFIX_LENGTH = 7, FOCUS_ID_PREFIX_LENGTH = 3, FOCUS_IDX_PREFIX_LENGTH = 4, FOCUS_NAME_PREFIX_LENGTH = 5, HMR_UPDATE_TIMEOUT_MS = 2000, HOOK_SIGNATURE_LENGTH = 12, EXCLUDE_LAST_OFFSET = -1, HOURS_IN_DAY = 24, HOURS_IN_HALF_DAY = 12, MAX_ERROR_LENGTH = 200, MAX_RECONNECT_ATTEMPTS = 60, MILLISECONDS_IN_A_SECOND = 1000, MINUTES_IN_AN_HOUR = 60, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_MINUTE, MILLISECONDS_IN_A_DAY, OVERLAY_FADE_DURATION_MS = 150, PING_INTERVAL_MS = 30000, RAF_BATCH_COUNT = 3, RANDOM_ID_END_INDEX = 11, REBUILD_BATCH_DELAY_MS = 10, REBUILD_RELOAD_DELAY_MS = 200, RECONNECT_INITIAL_DELAY_MS = 500, RECONNECT_POLL_INTERVAL_MS = 300, SIGINT_EXIT_CODE = 130, SIGTERM_EXIT_CODE = 143, SVELTE_CSS_LOAD_TIMEOUT_MS = 500, TIME_PRECISION = 2, TWO_THIRDS, UNFOUND_INDEX = -1, WEBSOCKET_NORMAL_CLOSURE = 1000;
|
|
99
|
+
var init_constants = __esm(() => {
|
|
100
|
+
MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
|
|
101
|
+
MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
|
|
102
|
+
TWO_THIRDS = 2 / 3;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// src/core/islandPageContext.ts
|
|
106
|
+
var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST__", ISLAND_STATE_MARKER = "__ABS_ISLAND_STATE__", CLOSING_HEAD_TAG2 = "</head>", buildIslandsHeadMarkup = (manifest) => {
|
|
107
|
+
const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
|
|
108
|
+
const islandStateScript = `<script>window.__ABS_ISLAND_STATE__ = ${JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {})}</script>`;
|
|
109
|
+
const bootstrapPath = manifest[BOOTSTRAP_MANIFEST_KEY];
|
|
110
|
+
const bootstrapScript = bootstrapPath ? `<script type="module" src="${bootstrapPath}"></script>` : "";
|
|
111
|
+
return `${manifestScript}${islandStateScript}${bootstrapScript}`;
|
|
112
|
+
}, injectHeadMarkup = (html, markup) => {
|
|
113
|
+
const closingHeadIndex = html.indexOf("</head>");
|
|
143
114
|
if (closingHeadIndex >= 0) {
|
|
144
|
-
return `${html.slice(0, closingHeadIndex)}${
|
|
145
|
-
}
|
|
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);
|
|
152
|
-
}
|
|
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;
|
|
189
|
-
}
|
|
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 [];
|
|
221
|
-
}
|
|
222
|
-
if (preparedSlots.length <= maxSlotsPerResponse) {
|
|
223
|
-
preparedSlots.forEach((slot) => emitSlotMetric({
|
|
224
|
-
type: "prepared",
|
|
225
|
-
slotId: slot.id
|
|
226
|
-
}, onSlotMetric));
|
|
227
|
-
return preparedSlots;
|
|
115
|
+
return `${html.slice(0, closingHeadIndex)}${markup}${html.slice(closingHeadIndex)}`;
|
|
228
116
|
}
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
type: "dropped",
|
|
235
|
-
slotId: slot.id,
|
|
236
|
-
reason: `maxSlotsPerResponse is ${maxSlotsPerResponse}`
|
|
237
|
-
}, onSlotMetric);
|
|
238
|
-
});
|
|
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);
|
|
285
|
-
return {
|
|
286
|
-
html,
|
|
287
|
-
id: slot.id,
|
|
288
|
-
durationMs,
|
|
289
|
-
bytes
|
|
290
|
-
};
|
|
291
|
-
} catch (error) {
|
|
292
|
-
const durationMs = Date.now() - start;
|
|
293
|
-
onError?.(error, slot);
|
|
294
|
-
emitSlotMetric({
|
|
295
|
-
type: error?.__absTimeout === true ? "timeout" : "error",
|
|
296
|
-
slotId: slot.id,
|
|
297
|
-
durationMs,
|
|
298
|
-
error
|
|
299
|
-
}, onSlotMetric);
|
|
300
|
-
if (typeof slot.errorHtml === "string") {
|
|
301
|
-
const html = slot.errorHtml;
|
|
302
|
-
return {
|
|
303
|
-
html,
|
|
304
|
-
id: slot.id,
|
|
305
|
-
durationMs,
|
|
306
|
-
bytes: htmlByteLength(html, encoder)
|
|
307
|
-
};
|
|
117
|
+
const openingBodyIndex = html.indexOf("<body");
|
|
118
|
+
if (openingBodyIndex >= 0) {
|
|
119
|
+
const bodyStart = html.indexOf(">", openingBodyIndex);
|
|
120
|
+
if (bodyStart >= 0) {
|
|
121
|
+
return `${html.slice(0, openingBodyIndex)}<head>${markup}</head>${html.slice(openingBodyIndex)}`;
|
|
308
122
|
}
|
|
309
|
-
return {
|
|
310
|
-
html: null,
|
|
311
|
-
id: slot.id,
|
|
312
|
-
durationMs,
|
|
313
|
-
bytes: 0
|
|
314
|
-
};
|
|
315
123
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
original: promise,
|
|
319
|
-
result
|
|
320
|
-
})));
|
|
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
|
-
});
|
|
124
|
+
return `<!DOCTYPE html><html><head>${markup}</head><body>${html}</body></html>`;
|
|
125
|
+
}, streamChunkToString2 = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true }), pipeStreamWithHeadInjection = (stream, markup) => {
|
|
344
126
|
const encoder = new TextEncoder;
|
|
127
|
+
const decoder = new TextDecoder;
|
|
128
|
+
const lookbehind = CLOSING_HEAD_TAG2.length - 1;
|
|
345
129
|
return new ReadableStream({
|
|
346
130
|
async start(controller) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
header = injectHtmlIntoHead(header, renderStreamingSlotsRuntimeTag(nonce));
|
|
351
|
-
}
|
|
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));
|
|
372
|
-
}
|
|
373
|
-
if (footerHtml.length > 0) {
|
|
374
|
-
controller.enqueue(toUint8(footerHtml, encoder));
|
|
375
|
-
}
|
|
376
|
-
controller.close();
|
|
377
|
-
} catch (error) {
|
|
378
|
-
controller.error(error);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
});
|
|
382
|
-
}, injectStreamingRuntimeIntoStream = (stream, nonce) => {
|
|
383
|
-
const runtimeTag = renderStreamingSlotsRuntimeTag(nonce);
|
|
384
|
-
const encoder = new TextEncoder;
|
|
385
|
-
const decoder = new TextDecoder;
|
|
386
|
-
const lookbehind = CLOSING_HEAD_TAG_LENGTH - 1;
|
|
387
|
-
return new ReadableStream({
|
|
388
|
-
async start(controller) {
|
|
389
|
-
const reader = stream.getReader();
|
|
390
|
-
let injected = false;
|
|
391
|
-
let pending = "";
|
|
131
|
+
const reader = stream.getReader();
|
|
132
|
+
let injected = false;
|
|
133
|
+
let pending = "";
|
|
392
134
|
try {
|
|
393
135
|
for (;; ) {
|
|
394
136
|
const { done, value } = await reader.read();
|
|
@@ -396,16 +138,16 @@ var SLOT_ID_PREFIX = "abs-slot-", SLOT_PLACEHOLDER_PREFIX = "slot-", CLOSING_HEA
|
|
|
396
138
|
break;
|
|
397
139
|
if (!value)
|
|
398
140
|
continue;
|
|
399
|
-
pending +=
|
|
141
|
+
pending += streamChunkToString2(value, decoder);
|
|
400
142
|
if (injected) {
|
|
401
143
|
controller.enqueue(encoder.encode(pending));
|
|
402
144
|
pending = "";
|
|
403
145
|
continue;
|
|
404
146
|
}
|
|
405
|
-
const headIndex = pending.indexOf(
|
|
147
|
+
const headIndex = pending.indexOf(CLOSING_HEAD_TAG2);
|
|
406
148
|
if (headIndex >= 0) {
|
|
407
|
-
const
|
|
408
|
-
controller.enqueue(encoder.encode(
|
|
149
|
+
const next = `${pending.slice(0, headIndex)}${markup}${pending.slice(headIndex)}`;
|
|
150
|
+
controller.enqueue(encoder.encode(next));
|
|
409
151
|
pending = "";
|
|
410
152
|
injected = true;
|
|
411
153
|
continue;
|
|
@@ -418,7 +160,7 @@ var SLOT_ID_PREFIX = "abs-slot-", SLOT_PLACEHOLDER_PREFIX = "slot-", CLOSING_HEA
|
|
|
418
160
|
}
|
|
419
161
|
pending += decoder.decode();
|
|
420
162
|
if (!injected) {
|
|
421
|
-
pending =
|
|
163
|
+
pending = injectHeadMarkup(pending, markup);
|
|
422
164
|
}
|
|
423
165
|
if (pending.length > 0) {
|
|
424
166
|
controller.enqueue(encoder.encode(pending));
|
|
@@ -429,352 +171,78 @@ var SLOT_ID_PREFIX = "abs-slot-", SLOT_PLACEHOLDER_PREFIX = "slot-", CLOSING_HEA
|
|
|
429
171
|
}
|
|
430
172
|
}
|
|
431
173
|
});
|
|
432
|
-
},
|
|
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)
|
|
453
|
-
return stream;
|
|
454
|
-
const source = injectRuntime ? injectStreamingRuntimeIntoStream(stream, nonce) : stream;
|
|
174
|
+
}, pipeStreamWithIslandMarkerDetection = (stream, markup) => {
|
|
455
175
|
const encoder = new TextEncoder;
|
|
456
176
|
const decoder = new TextDecoder;
|
|
457
|
-
const
|
|
458
|
-
const pending = preparedSlots.map((slot) => resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric));
|
|
177
|
+
const lookbehind = Math.max(ISLAND_MARKER.length, 1024);
|
|
459
178
|
return new ReadableStream({
|
|
460
179
|
async start(controller) {
|
|
461
|
-
|
|
462
|
-
let
|
|
463
|
-
let
|
|
464
|
-
let footer = "";
|
|
180
|
+
const reader = stream.getReader();
|
|
181
|
+
let injected = false;
|
|
182
|
+
let pending = "";
|
|
465
183
|
try {
|
|
466
|
-
|
|
467
|
-
const
|
|
468
|
-
if (
|
|
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)
|
|
184
|
+
for (;; ) {
|
|
185
|
+
const { done, value } = await reader.read();
|
|
186
|
+
if (done)
|
|
482
187
|
break;
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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
|
-
}
|
|
188
|
+
if (!value)
|
|
189
|
+
continue;
|
|
190
|
+
pending += streamChunkToString2(value, decoder);
|
|
191
|
+
if (injected) {
|
|
192
|
+
controller.enqueue(encoder.encode(pending));
|
|
193
|
+
pending = "";
|
|
508
194
|
continue;
|
|
509
195
|
}
|
|
510
|
-
const
|
|
511
|
-
if (
|
|
512
|
-
pending.
|
|
513
|
-
|
|
196
|
+
const markerIndex = pending.indexOf(ISLAND_MARKER);
|
|
197
|
+
if (markerIndex >= 0) {
|
|
198
|
+
const tagStart = pending.lastIndexOf("<", markerIndex);
|
|
199
|
+
const injectAt = tagStart >= 0 ? tagStart : markerIndex;
|
|
200
|
+
const next = `${pending.slice(0, injectAt)}${markup}${pending.slice(injectAt)}`;
|
|
201
|
+
controller.enqueue(encoder.encode(next));
|
|
202
|
+
pending = "";
|
|
203
|
+
injected = true;
|
|
514
204
|
continue;
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
|
|
205
|
+
}
|
|
206
|
+
if (pending.length > lookbehind) {
|
|
207
|
+
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
208
|
+
controller.enqueue(encoder.encode(safeText));
|
|
209
|
+
pending = pending.slice(-lookbehind);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
pending += decoder.decode();
|
|
213
|
+
if (pending.length > 0) {
|
|
214
|
+
controller.enqueue(encoder.encode(pending));
|
|
522
215
|
}
|
|
523
|
-
if (footer.length > 0)
|
|
524
|
-
controller.enqueue(encoder.encode(footer));
|
|
525
216
|
controller.close();
|
|
526
217
|
} catch (error) {
|
|
527
218
|
controller.error(error);
|
|
528
219
|
}
|
|
529
220
|
}
|
|
530
221
|
});
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
currentStreamingSlotPolicy = {
|
|
537
|
-
timeoutMs: STREAMING_SLOT_TIMEOUT_MS,
|
|
538
|
-
fallbackHtml: "",
|
|
539
|
-
errorHtml: undefined,
|
|
540
|
-
maxSlotsPerResponse: STREAMING_SLOT_MAX_PER_RESPONSE,
|
|
541
|
-
maxSlotHtmlSizeBytes: STREAMING_SLOT_MAX_HTML_BYTES
|
|
542
|
-
};
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
// src/core/streamingSlotRegistrar.ts
|
|
546
|
-
var registrar = null, setStreamingSlotRegistrar = (nextRegistrar) => {
|
|
547
|
-
registrar = nextRegistrar;
|
|
548
|
-
}, registerStreamingSlot = (slot) => {
|
|
549
|
-
registrar?.(slot);
|
|
550
|
-
};
|
|
551
|
-
|
|
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;
|
|
222
|
+
}, htmlContainsIslands = (html) => html.includes(ISLAND_MARKER), injectIslandPageContext = (html, options) => {
|
|
223
|
+
const manifest = globalThis.__absoluteManifest;
|
|
224
|
+
const hasIslands = options?.hasIslands ?? htmlContainsIslands(html);
|
|
225
|
+
if (!manifest || !hasIslands) {
|
|
226
|
+
return html;
|
|
559
227
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
return asyncLocalStorage;
|
|
563
|
-
}, registerStreamingSlot2 = (slot) => {
|
|
564
|
-
if (!asyncLocalStorage)
|
|
565
|
-
return;
|
|
566
|
-
const store = asyncLocalStorage.getStore();
|
|
567
|
-
if (!store)
|
|
568
|
-
return;
|
|
569
|
-
store.set(slot.id, slot);
|
|
570
|
-
}, runWithStreamingSlotRegistry = async (task) => {
|
|
571
|
-
const storage = await ensureAsyncLocalStorage();
|
|
572
|
-
if (!storage) {
|
|
573
|
-
return {
|
|
574
|
-
result: await task(),
|
|
575
|
-
slots: []
|
|
576
|
-
};
|
|
228
|
+
if (html.includes(MANIFEST_MARKER) || html.includes(ISLAND_STATE_MARKER)) {
|
|
229
|
+
return html;
|
|
577
230
|
}
|
|
578
|
-
return
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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;
|
|
231
|
+
return injectHeadMarkup(html, buildIslandsHeadMarkup(manifest));
|
|
232
|
+
}, injectIslandPageContextStream = (stream, options) => {
|
|
233
|
+
const manifest = globalThis.__absoluteManifest;
|
|
234
|
+
if (!manifest)
|
|
235
|
+
return stream;
|
|
236
|
+
const markup = buildIslandsHeadMarkup(manifest);
|
|
237
|
+
if (options?.hasIslands === true) {
|
|
238
|
+
return pipeStreamWithHeadInjection(stream, markup);
|
|
598
239
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
headers: cloneHeaders(response),
|
|
606
|
-
status: response.status,
|
|
607
|
-
statusText: response.statusText
|
|
608
|
-
});
|
|
609
|
-
}, withStreamingSlots = async (responseLike, options = {}) => enhanceHtmlResponseWithStreamingSlots(await toResponse(responseLike), options), mergeStreamingSlots = (registered, explicit) => {
|
|
610
|
-
const merged = new Map;
|
|
611
|
-
for (const slot of registered)
|
|
612
|
-
merged.set(slot.id, slot);
|
|
613
|
-
for (const slot of explicit)
|
|
614
|
-
merged.set(slot.id, slot);
|
|
615
|
-
return [...merged.values()];
|
|
616
|
-
}, withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
|
|
617
|
-
const { result, slots } = await runWithStreamingSlotRegistry(renderResponse);
|
|
618
|
-
const explicit = options.streamingSlots ?? [];
|
|
619
|
-
return withStreamingSlots(result, {
|
|
620
|
-
...options,
|
|
621
|
-
streamingSlots: mergeStreamingSlots(slots, explicit)
|
|
622
|
-
});
|
|
623
|
-
};
|
|
624
|
-
var init_responseEnhancers = __esm(() => {
|
|
625
|
-
init_streamingSlots();
|
|
626
|
-
init_streamingSlotRegistry();
|
|
627
|
-
});
|
|
628
|
-
|
|
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;
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
// src/core/islandPageContext.ts
|
|
638
|
-
var BOOTSTRAP_MANIFEST_KEY = "BootstrapClient", ISLAND_MARKER = 'data-island="true"', MANIFEST_MARKER = "__ABSOLUTE_MANIFEST__", ISLAND_STATE_MARKER = "__ABS_ISLAND_STATE__", CLOSING_HEAD_TAG2 = "</head>", buildIslandsHeadMarkup = (manifest) => {
|
|
639
|
-
const manifestScript = `<script>window.__ABSOLUTE_MANIFEST__ = ${JSON.stringify(manifest)}</script>`;
|
|
640
|
-
const islandStateScript = `<script>window.__ABS_ISLAND_STATE__ = ${JSON.stringify(globalThis.__ABS_ISLAND_STATE__ ?? {})}</script>`;
|
|
641
|
-
const bootstrapPath = manifest[BOOTSTRAP_MANIFEST_KEY];
|
|
642
|
-
const bootstrapScript = bootstrapPath ? `<script type="module" src="${bootstrapPath}"></script>` : "";
|
|
643
|
-
return `${manifestScript}${islandStateScript}${bootstrapScript}`;
|
|
644
|
-
}, injectHeadMarkup = (html, markup) => {
|
|
645
|
-
const closingHeadIndex = html.indexOf("</head>");
|
|
646
|
-
if (closingHeadIndex >= 0) {
|
|
647
|
-
return `${html.slice(0, closingHeadIndex)}${markup}${html.slice(closingHeadIndex)}`;
|
|
648
|
-
}
|
|
649
|
-
const openingBodyIndex = html.indexOf("<body");
|
|
650
|
-
if (openingBodyIndex >= 0) {
|
|
651
|
-
const bodyStart = html.indexOf(">", openingBodyIndex);
|
|
652
|
-
if (bodyStart >= 0) {
|
|
653
|
-
return `${html.slice(0, openingBodyIndex)}<head>${markup}</head>${html.slice(openingBodyIndex)}`;
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
return `<!DOCTYPE html><html><head>${markup}</head><body>${html}</body></html>`;
|
|
657
|
-
}, streamChunkToString2 = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true }), pipeStreamWithHeadInjection = (stream, markup) => {
|
|
658
|
-
const encoder = new TextEncoder;
|
|
659
|
-
const decoder = new TextDecoder;
|
|
660
|
-
const lookbehind = CLOSING_HEAD_TAG2.length - 1;
|
|
661
|
-
return new ReadableStream({
|
|
662
|
-
async start(controller) {
|
|
663
|
-
const reader = stream.getReader();
|
|
664
|
-
let injected = false;
|
|
665
|
-
let pending = "";
|
|
666
|
-
try {
|
|
667
|
-
for (;; ) {
|
|
668
|
-
const { done, value } = await reader.read();
|
|
669
|
-
if (done)
|
|
670
|
-
break;
|
|
671
|
-
if (!value)
|
|
672
|
-
continue;
|
|
673
|
-
pending += streamChunkToString2(value, decoder);
|
|
674
|
-
if (injected) {
|
|
675
|
-
controller.enqueue(encoder.encode(pending));
|
|
676
|
-
pending = "";
|
|
677
|
-
continue;
|
|
678
|
-
}
|
|
679
|
-
const headIndex = pending.indexOf(CLOSING_HEAD_TAG2);
|
|
680
|
-
if (headIndex >= 0) {
|
|
681
|
-
const next = `${pending.slice(0, headIndex)}${markup}${pending.slice(headIndex)}`;
|
|
682
|
-
controller.enqueue(encoder.encode(next));
|
|
683
|
-
pending = "";
|
|
684
|
-
injected = true;
|
|
685
|
-
continue;
|
|
686
|
-
}
|
|
687
|
-
if (pending.length > lookbehind) {
|
|
688
|
-
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
689
|
-
controller.enqueue(encoder.encode(safeText));
|
|
690
|
-
pending = pending.slice(-lookbehind);
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
pending += decoder.decode();
|
|
694
|
-
if (!injected) {
|
|
695
|
-
pending = injectHeadMarkup(pending, markup);
|
|
696
|
-
}
|
|
697
|
-
if (pending.length > 0) {
|
|
698
|
-
controller.enqueue(encoder.encode(pending));
|
|
699
|
-
}
|
|
700
|
-
controller.close();
|
|
701
|
-
} catch (error) {
|
|
702
|
-
controller.error(error);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
});
|
|
706
|
-
}, pipeStreamWithIslandMarkerDetection = (stream, markup) => {
|
|
707
|
-
const encoder = new TextEncoder;
|
|
708
|
-
const decoder = new TextDecoder;
|
|
709
|
-
const lookbehind = Math.max(ISLAND_MARKER.length, 1024);
|
|
710
|
-
return new ReadableStream({
|
|
711
|
-
async start(controller) {
|
|
712
|
-
const reader = stream.getReader();
|
|
713
|
-
let injected = false;
|
|
714
|
-
let pending = "";
|
|
715
|
-
try {
|
|
716
|
-
for (;; ) {
|
|
717
|
-
const { done, value } = await reader.read();
|
|
718
|
-
if (done)
|
|
719
|
-
break;
|
|
720
|
-
if (!value)
|
|
721
|
-
continue;
|
|
722
|
-
pending += streamChunkToString2(value, decoder);
|
|
723
|
-
if (injected) {
|
|
724
|
-
controller.enqueue(encoder.encode(pending));
|
|
725
|
-
pending = "";
|
|
726
|
-
continue;
|
|
727
|
-
}
|
|
728
|
-
const markerIndex = pending.indexOf(ISLAND_MARKER);
|
|
729
|
-
if (markerIndex >= 0) {
|
|
730
|
-
const tagStart = pending.lastIndexOf("<", markerIndex);
|
|
731
|
-
const injectAt = tagStart >= 0 ? tagStart : markerIndex;
|
|
732
|
-
const next = `${pending.slice(0, injectAt)}${markup}${pending.slice(injectAt)}`;
|
|
733
|
-
controller.enqueue(encoder.encode(next));
|
|
734
|
-
pending = "";
|
|
735
|
-
injected = true;
|
|
736
|
-
continue;
|
|
737
|
-
}
|
|
738
|
-
if (pending.length > lookbehind) {
|
|
739
|
-
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
740
|
-
controller.enqueue(encoder.encode(safeText));
|
|
741
|
-
pending = pending.slice(-lookbehind);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
pending += decoder.decode();
|
|
745
|
-
if (pending.length > 0) {
|
|
746
|
-
controller.enqueue(encoder.encode(pending));
|
|
747
|
-
}
|
|
748
|
-
controller.close();
|
|
749
|
-
} catch (error) {
|
|
750
|
-
controller.error(error);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
}, htmlContainsIslands = (html) => html.includes(ISLAND_MARKER), injectIslandPageContext = (html, options) => {
|
|
755
|
-
const manifest = globalThis.__absoluteManifest;
|
|
756
|
-
const hasIslands = options?.hasIslands ?? htmlContainsIslands(html);
|
|
757
|
-
if (!manifest || !hasIslands) {
|
|
758
|
-
return html;
|
|
759
|
-
}
|
|
760
|
-
if (html.includes(MANIFEST_MARKER) || html.includes(ISLAND_STATE_MARKER)) {
|
|
761
|
-
return html;
|
|
762
|
-
}
|
|
763
|
-
return injectHeadMarkup(html, buildIslandsHeadMarkup(manifest));
|
|
764
|
-
}, injectIslandPageContextStream = (stream, options) => {
|
|
765
|
-
const manifest = globalThis.__absoluteManifest;
|
|
766
|
-
if (!manifest)
|
|
767
|
-
return stream;
|
|
768
|
-
const markup = buildIslandsHeadMarkup(manifest);
|
|
769
|
-
if (options?.hasIslands === true) {
|
|
770
|
-
return pipeStreamWithHeadInjection(stream, markup);
|
|
771
|
-
}
|
|
772
|
-
if (options?.hasIslands === false) {
|
|
773
|
-
return stream;
|
|
774
|
-
}
|
|
775
|
-
return pipeStreamWithIslandMarkerDetection(stream, markup);
|
|
776
|
-
}, setCurrentIslandManifest = (manifest) => {
|
|
777
|
-
globalThis.__absoluteManifest = manifest;
|
|
240
|
+
if (options?.hasIslands === false) {
|
|
241
|
+
return stream;
|
|
242
|
+
}
|
|
243
|
+
return pipeStreamWithIslandMarkerDetection(stream, markup);
|
|
244
|
+
}, setCurrentIslandManifest = (manifest) => {
|
|
245
|
+
globalThis.__absoluteManifest = manifest;
|
|
778
246
|
};
|
|
779
247
|
|
|
780
248
|
// src/utils/ssrErrorPage.ts
|
|
@@ -11309,8 +10777,586 @@ var init_imageProcessing = __esm(() => {
|
|
|
11309
10777
|
// src/angular/index.ts
|
|
11310
10778
|
import"@angular/compiler";
|
|
11311
10779
|
|
|
10780
|
+
// src/client/streamSwap.ts
|
|
10781
|
+
var streamSwapRuntime = () => {
|
|
10782
|
+
if (window.__ABS_SLOT_RUNTIME__ === true)
|
|
10783
|
+
return;
|
|
10784
|
+
window.__ABS_SLOT_RUNTIME__ = true;
|
|
10785
|
+
window.__ABS_SLOT_PENDING__ = window.__ABS_SLOT_PENDING__ ?? {};
|
|
10786
|
+
const pending = window.__ABS_SLOT_PENDING__;
|
|
10787
|
+
const apply = (id, html) => {
|
|
10788
|
+
const node = document.getElementById(`slot-${id}`);
|
|
10789
|
+
if (!node) {
|
|
10790
|
+
pending[id] = html;
|
|
10791
|
+
return;
|
|
10792
|
+
}
|
|
10793
|
+
node.innerHTML = html;
|
|
10794
|
+
delete pending[id];
|
|
10795
|
+
};
|
|
10796
|
+
const flush = () => {
|
|
10797
|
+
for (const id in pending) {
|
|
10798
|
+
if (!Object.prototype.hasOwnProperty.call(pending, id))
|
|
10799
|
+
continue;
|
|
10800
|
+
apply(id, pending[id] ?? "");
|
|
10801
|
+
}
|
|
10802
|
+
};
|
|
10803
|
+
window.__ABS_SLOT_ENQUEUE__ = (id, html) => {
|
|
10804
|
+
apply(id, html);
|
|
10805
|
+
};
|
|
10806
|
+
if (typeof MutationObserver === "function") {
|
|
10807
|
+
const observer = new MutationObserver(flush);
|
|
10808
|
+
const root = document.documentElement ?? document.body ?? document;
|
|
10809
|
+
observer.observe(root, { childList: true, subtree: true });
|
|
10810
|
+
}
|
|
10811
|
+
if (document.readyState === "loading") {
|
|
10812
|
+
document.addEventListener("DOMContentLoaded", flush, { once: true });
|
|
10813
|
+
}
|
|
10814
|
+
flush();
|
|
10815
|
+
};
|
|
10816
|
+
var stripFunctionWrapper = (value) => {
|
|
10817
|
+
const start = value.indexOf("{");
|
|
10818
|
+
const end = value.lastIndexOf("}");
|
|
10819
|
+
if (start < 0 || end <= start)
|
|
10820
|
+
return "";
|
|
10821
|
+
return value.slice(start + 1, end);
|
|
10822
|
+
};
|
|
10823
|
+
var getStreamSwapRuntimeScript = () => `(function(){${stripFunctionWrapper(streamSwapRuntime.toString())}})();`;
|
|
10824
|
+
|
|
10825
|
+
// src/utils/streamingSlots.ts
|
|
10826
|
+
init_escapeScriptContent();
|
|
10827
|
+
var SLOT_ID_PREFIX = "abs-slot-";
|
|
10828
|
+
var SLOT_PLACEHOLDER_PREFIX = "slot-";
|
|
10829
|
+
var CLOSING_HEAD_TAG = "</head>";
|
|
10830
|
+
var CLOSING_HEAD_TAG_LENGTH = CLOSING_HEAD_TAG.length;
|
|
10831
|
+
var CLOSING_PAGE_TAG_REGEX = /<\/body>\s*<\/html>\s*$/i;
|
|
10832
|
+
var STREAMING_RUNTIME_GLOBAL = "__ABS_SLOT_ENQUEUE__";
|
|
10833
|
+
var STREAMING_PENDING_GLOBAL = "__ABS_SLOT_PENDING__";
|
|
10834
|
+
var STREAM_TAIL_LOOKBEHIND = 128;
|
|
10835
|
+
var STREAMING_SLOT_TIMEOUT_MS = 5000;
|
|
10836
|
+
var STREAMING_SLOT_MAX_PER_RESPONSE = 128;
|
|
10837
|
+
var STREAMING_SLOT_MAX_HTML_BYTES = 64000;
|
|
10838
|
+
var createSlotPlaceholderId = (id) => `${SLOT_PLACEHOLDER_PREFIX}${id}`;
|
|
10839
|
+
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)});`;
|
|
10840
|
+
var createNonceAttr = (nonce) => nonce ? ` nonce="${nonce}"` : "";
|
|
10841
|
+
var createStreamingSlotId = () => `${SLOT_ID_PREFIX}${Math.random().toString(36).slice(2, 10)}`;
|
|
10842
|
+
var getStreamingSlotsRuntimeScript = () => getStreamSwapRuntimeScript();
|
|
10843
|
+
var renderStreamingSlotsRuntimeTag = (nonce) => `<script${createNonceAttr(nonce)}>${escapeScriptContent(getStreamingSlotsRuntimeScript())}</script>`;
|
|
10844
|
+
var renderStreamingSlotPlaceholder = (id, fallbackHtml = "") => `<div id="${createSlotPlaceholderId(id)}" data-absolute-slot="true">${fallbackHtml}</div>`;
|
|
10845
|
+
var renderStreamingSlotPatchTag = (id, html, nonce) => `<script${createNonceAttr(nonce)}>${escapeScriptContent(createSlotPatchStatement(id, html))}</script>`;
|
|
10846
|
+
var injectHtmlIntoHead = (html, injection) => {
|
|
10847
|
+
const closingHeadIndex = html.indexOf(CLOSING_HEAD_TAG);
|
|
10848
|
+
if (closingHeadIndex >= 0) {
|
|
10849
|
+
return `${html.slice(0, closingHeadIndex)}${injection}${html.slice(closingHeadIndex)}`;
|
|
10850
|
+
}
|
|
10851
|
+
return `${html}${injection}`;
|
|
10852
|
+
};
|
|
10853
|
+
var toUint8 = (value, encoder) => encoder.encode(value);
|
|
10854
|
+
var currentStreamingSlotPolicy = {
|
|
10855
|
+
timeoutMs: STREAMING_SLOT_TIMEOUT_MS,
|
|
10856
|
+
fallbackHtml: "",
|
|
10857
|
+
errorHtml: undefined,
|
|
10858
|
+
maxSlotsPerResponse: STREAMING_SLOT_MAX_PER_RESPONSE,
|
|
10859
|
+
maxSlotHtmlSizeBytes: STREAMING_SLOT_MAX_HTML_BYTES
|
|
10860
|
+
};
|
|
10861
|
+
var clonePolicy = (policy) => ({
|
|
10862
|
+
...policy
|
|
10863
|
+
});
|
|
10864
|
+
var normalizeSlotBytes = (value, fallback) => {
|
|
10865
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
10866
|
+
return Math.floor(value);
|
|
10867
|
+
}
|
|
10868
|
+
return fallback;
|
|
10869
|
+
};
|
|
10870
|
+
var normalizeSlotText = (value, fallback) => typeof value === "string" ? value : fallback;
|
|
10871
|
+
var normalizeSlotError = (value, fallback) => typeof value === "string" ? value : fallback;
|
|
10872
|
+
var hasPolicyValue = (policy, key) => Object.prototype.hasOwnProperty.call(policy, key);
|
|
10873
|
+
var applyStreamingSlotPolicyOverrides = (base, overridePolicy = {}) => ({
|
|
10874
|
+
timeoutMs: hasPolicyValue(overridePolicy, "timeoutMs") ? normalizeSlotBytes(overridePolicy.timeoutMs, base.timeoutMs) : base.timeoutMs,
|
|
10875
|
+
fallbackHtml: hasPolicyValue(overridePolicy, "fallbackHtml") ? normalizeSlotText(overridePolicy.fallbackHtml, "") : base.fallbackHtml,
|
|
10876
|
+
errorHtml: hasPolicyValue(overridePolicy, "errorHtml") ? normalizeSlotError(overridePolicy.errorHtml) : base.errorHtml,
|
|
10877
|
+
maxSlotsPerResponse: hasPolicyValue(overridePolicy, "maxSlotsPerResponse") ? normalizeSlotBytes(overridePolicy.maxSlotsPerResponse, base.maxSlotsPerResponse) : base.maxSlotsPerResponse,
|
|
10878
|
+
maxSlotHtmlSizeBytes: hasPolicyValue(overridePolicy, "maxSlotHtmlSizeBytes") ? normalizeSlotBytes(overridePolicy.maxSlotHtmlSizeBytes, base.maxSlotHtmlSizeBytes) : base.maxSlotHtmlSizeBytes,
|
|
10879
|
+
onError: hasPolicyValue(overridePolicy, "onError") ? overridePolicy.onError : base.onError,
|
|
10880
|
+
onSlotMetric: hasPolicyValue(overridePolicy, "onSlotMetric") ? overridePolicy.onSlotMetric : base.onSlotMetric
|
|
10881
|
+
});
|
|
10882
|
+
var createCombinedSlotErrorHandler = (policyOnError, enhancerOnError) => {
|
|
10883
|
+
if (!policyOnError && !enhancerOnError)
|
|
10884
|
+
return;
|
|
10885
|
+
return (error, slot) => {
|
|
10886
|
+
policyOnError?.(error, slot);
|
|
10887
|
+
enhancerOnError?.(error, slot);
|
|
10888
|
+
};
|
|
10889
|
+
};
|
|
10890
|
+
var createCombinedSlotMetricHandler = (policyOnSlotMetric, callOnSlotMetric) => {
|
|
10891
|
+
if (!policyOnSlotMetric && !callOnSlotMetric)
|
|
10892
|
+
return;
|
|
10893
|
+
return (metric) => {
|
|
10894
|
+
policyOnSlotMetric?.(metric);
|
|
10895
|
+
callOnSlotMetric?.(metric);
|
|
10896
|
+
};
|
|
10897
|
+
};
|
|
10898
|
+
var resolveStreamingSlotPolicy = (overridePolicy = {}) => {
|
|
10899
|
+
const base = getStreamingSlotPolicy();
|
|
10900
|
+
return applyStreamingSlotPolicyOverrides(base, overridePolicy);
|
|
10901
|
+
};
|
|
10902
|
+
var getStreamingSlotPolicy = () => clonePolicy(currentStreamingSlotPolicy);
|
|
10903
|
+
var setStreamingSlotPolicy = (policy = {}) => {
|
|
10904
|
+
const base = getStreamingSlotPolicy();
|
|
10905
|
+
currentStreamingSlotPolicy = applyStreamingSlotPolicyOverrides(base, policy);
|
|
10906
|
+
};
|
|
10907
|
+
var withStreamingSlotPolicy = async (policy, callback) => {
|
|
10908
|
+
const previous = getStreamingSlotPolicy();
|
|
10909
|
+
setStreamingSlotPolicy(policy);
|
|
10910
|
+
try {
|
|
10911
|
+
return await callback();
|
|
10912
|
+
} finally {
|
|
10913
|
+
currentStreamingSlotPolicy = previous;
|
|
10914
|
+
}
|
|
10915
|
+
};
|
|
10916
|
+
var emitSlotMetric = (metric, onSlotMetric) => {
|
|
10917
|
+
onSlotMetric?.(metric);
|
|
10918
|
+
};
|
|
10919
|
+
var createTimeoutError = (slot, timeoutMs) => {
|
|
10920
|
+
const error = new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`);
|
|
10921
|
+
error.__absTimeout = true;
|
|
10922
|
+
return error;
|
|
10923
|
+
};
|
|
10924
|
+
var toStreamingSlot = (slot, policy) => ({
|
|
10925
|
+
errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
|
|
10926
|
+
fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
|
|
10927
|
+
id: slot.id ?? createStreamingSlotId(),
|
|
10928
|
+
timeoutMs: normalizeSlotBytes(slot.timeoutMs, policy.timeoutMs),
|
|
10929
|
+
resolve: slot.resolve
|
|
10930
|
+
});
|
|
10931
|
+
var prepareSlots = ({
|
|
10932
|
+
policy,
|
|
10933
|
+
slots,
|
|
10934
|
+
onError,
|
|
10935
|
+
onSlotMetric
|
|
10936
|
+
}) => {
|
|
10937
|
+
const preparedSlots = slots.map((slot) => toStreamingSlot(slot, policy));
|
|
10938
|
+
const maxSlotsPerResponse = policy.maxSlotsPerResponse;
|
|
10939
|
+
if (maxSlotsPerResponse === 0) {
|
|
10940
|
+
const error = new Error("Streaming slot limit is set to 0");
|
|
10941
|
+
for (const slot of preparedSlots) {
|
|
10942
|
+
onError?.(error, slot);
|
|
10943
|
+
emitSlotMetric({
|
|
10944
|
+
type: "dropped",
|
|
10945
|
+
slotId: slot.id,
|
|
10946
|
+
reason: "maxSlotsPerResponse is 0"
|
|
10947
|
+
}, onSlotMetric);
|
|
10948
|
+
}
|
|
10949
|
+
return [];
|
|
10950
|
+
}
|
|
10951
|
+
if (preparedSlots.length <= maxSlotsPerResponse) {
|
|
10952
|
+
preparedSlots.forEach((slot) => emitSlotMetric({
|
|
10953
|
+
type: "prepared",
|
|
10954
|
+
slotId: slot.id
|
|
10955
|
+
}, onSlotMetric));
|
|
10956
|
+
return preparedSlots;
|
|
10957
|
+
}
|
|
10958
|
+
const keptSlots = preparedSlots.slice(0, maxSlotsPerResponse);
|
|
10959
|
+
const droppedSlots = preparedSlots.slice(maxSlotsPerResponse);
|
|
10960
|
+
droppedSlots.forEach((slot) => {
|
|
10961
|
+
onError?.(new Error(`Streaming slot "${slot.id}" dropped because ${maxSlotsPerResponse} slots is the configured maximum`), slot);
|
|
10962
|
+
emitSlotMetric({
|
|
10963
|
+
type: "dropped",
|
|
10964
|
+
slotId: slot.id,
|
|
10965
|
+
reason: `maxSlotsPerResponse is ${maxSlotsPerResponse}`
|
|
10966
|
+
}, onSlotMetric);
|
|
10967
|
+
});
|
|
10968
|
+
keptSlots.forEach((slot) => emitSlotMetric({
|
|
10969
|
+
type: "prepared",
|
|
10970
|
+
slotId: slot.id
|
|
10971
|
+
}, onSlotMetric));
|
|
10972
|
+
return keptSlots;
|
|
10973
|
+
};
|
|
10974
|
+
var htmlByteLength = (value, encoder) => encoder.encode(value).length;
|
|
10975
|
+
var resolveSlot = async (slot, onError, policy, onSlotMetric) => {
|
|
10976
|
+
const safePolicy = policy ?? getStreamingSlotPolicy();
|
|
10977
|
+
const encoder = new TextEncoder;
|
|
10978
|
+
const start = Date.now();
|
|
10979
|
+
try {
|
|
10980
|
+
const maybeAsyncValue = Promise.resolve(slot.resolve());
|
|
10981
|
+
const resolved = typeof slot.timeoutMs === "number" && slot.timeoutMs > 0 ? await Promise.race([
|
|
10982
|
+
maybeAsyncValue,
|
|
10983
|
+
new Promise((_, reject) => setTimeout(() => {
|
|
10984
|
+
reject(createTimeoutError(slot, slot.timeoutMs ?? 0));
|
|
10985
|
+
}, slot.timeoutMs))
|
|
10986
|
+
]) : await maybeAsyncValue;
|
|
10987
|
+
const html = typeof resolved === "string" ? resolved : `${resolved}`;
|
|
10988
|
+
if (safePolicy.maxSlotHtmlSizeBytes > 0 && htmlByteLength(html, encoder) > safePolicy.maxSlotHtmlSizeBytes) {
|
|
10989
|
+
const bytes2 = htmlByteLength(html, encoder);
|
|
10990
|
+
const error = new Error(`Streaming slot "${slot.id}" exceeded max payload size of ${safePolicy.maxSlotHtmlSizeBytes} bytes`);
|
|
10991
|
+
const durationMs2 = Date.now() - start;
|
|
10992
|
+
onError?.(error, slot);
|
|
10993
|
+
emitSlotMetric({
|
|
10994
|
+
type: "size_exceeded",
|
|
10995
|
+
slotId: slot.id,
|
|
10996
|
+
durationMs: durationMs2,
|
|
10997
|
+
bytes: bytes2,
|
|
10998
|
+
error
|
|
10999
|
+
}, onSlotMetric);
|
|
11000
|
+
const fallbackHtml = typeof slot.errorHtml === "string" ? slot.errorHtml : null;
|
|
11001
|
+
return {
|
|
11002
|
+
html: fallbackHtml,
|
|
11003
|
+
id: slot.id,
|
|
11004
|
+
durationMs: durationMs2,
|
|
11005
|
+
bytes: fallbackHtml === null ? 0 : htmlByteLength(fallbackHtml, encoder)
|
|
11006
|
+
};
|
|
11007
|
+
}
|
|
11008
|
+
const durationMs = Date.now() - start;
|
|
11009
|
+
const bytes = htmlByteLength(html, encoder);
|
|
11010
|
+
emitSlotMetric({
|
|
11011
|
+
type: "resolved",
|
|
11012
|
+
slotId: slot.id,
|
|
11013
|
+
durationMs,
|
|
11014
|
+
bytes
|
|
11015
|
+
}, onSlotMetric);
|
|
11016
|
+
return {
|
|
11017
|
+
html,
|
|
11018
|
+
id: slot.id,
|
|
11019
|
+
durationMs,
|
|
11020
|
+
bytes
|
|
11021
|
+
};
|
|
11022
|
+
} catch (error) {
|
|
11023
|
+
const durationMs = Date.now() - start;
|
|
11024
|
+
onError?.(error, slot);
|
|
11025
|
+
emitSlotMetric({
|
|
11026
|
+
type: error?.__absTimeout === true ? "timeout" : "error",
|
|
11027
|
+
slotId: slot.id,
|
|
11028
|
+
durationMs,
|
|
11029
|
+
error
|
|
11030
|
+
}, onSlotMetric);
|
|
11031
|
+
if (typeof slot.errorHtml === "string") {
|
|
11032
|
+
const html = slot.errorHtml;
|
|
11033
|
+
return {
|
|
11034
|
+
html,
|
|
11035
|
+
id: slot.id,
|
|
11036
|
+
durationMs,
|
|
11037
|
+
bytes: htmlByteLength(html, encoder)
|
|
11038
|
+
};
|
|
11039
|
+
}
|
|
11040
|
+
return {
|
|
11041
|
+
html: null,
|
|
11042
|
+
id: slot.id,
|
|
11043
|
+
durationMs,
|
|
11044
|
+
bytes: 0
|
|
11045
|
+
};
|
|
11046
|
+
}
|
|
11047
|
+
};
|
|
11048
|
+
var nextResolvedSlot = async (pending) => {
|
|
11049
|
+
const wrapped = pending.map((promise) => promise.then((result) => ({
|
|
11050
|
+
original: promise,
|
|
11051
|
+
result
|
|
11052
|
+
})));
|
|
11053
|
+
return Promise.race(wrapped);
|
|
11054
|
+
};
|
|
11055
|
+
var streamChunkToString = (value, decoder) => typeof value === "string" ? value : decoder.decode(value, { stream: true });
|
|
11056
|
+
var streamOutOfOrderSlots = ({
|
|
11057
|
+
footerHtml = "",
|
|
11058
|
+
headerHtml = "",
|
|
11059
|
+
nonce,
|
|
11060
|
+
policy,
|
|
11061
|
+
onSlotMetric,
|
|
11062
|
+
onError,
|
|
11063
|
+
slots
|
|
11064
|
+
}) => {
|
|
11065
|
+
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
11066
|
+
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
11067
|
+
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
11068
|
+
const effectivePolicy = {
|
|
11069
|
+
...resolvedPolicy,
|
|
11070
|
+
onSlotMetric: combinedOnSlotMetric
|
|
11071
|
+
};
|
|
11072
|
+
const preparedSlots = prepareSlots({
|
|
11073
|
+
policy: effectivePolicy,
|
|
11074
|
+
slots,
|
|
11075
|
+
onError: combinedOnError,
|
|
11076
|
+
onSlotMetric: combinedOnSlotMetric
|
|
11077
|
+
});
|
|
11078
|
+
const encoder = new TextEncoder;
|
|
11079
|
+
return new ReadableStream({
|
|
11080
|
+
async start(controller) {
|
|
11081
|
+
try {
|
|
11082
|
+
let header = headerHtml;
|
|
11083
|
+
if (preparedSlots.length > 0 && !header.includes(STREAMING_RUNTIME_GLOBAL)) {
|
|
11084
|
+
header = injectHtmlIntoHead(header, renderStreamingSlotsRuntimeTag(nonce));
|
|
11085
|
+
}
|
|
11086
|
+
controller.enqueue(toUint8(header, encoder));
|
|
11087
|
+
const pending = preparedSlots.map((slot) => {
|
|
11088
|
+
const fallback = renderStreamingSlotPlaceholder(slot.id, slot.fallbackHtml ?? "");
|
|
11089
|
+
controller.enqueue(toUint8(fallback, encoder));
|
|
11090
|
+
return resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric);
|
|
11091
|
+
});
|
|
11092
|
+
while (pending.length > 0) {
|
|
11093
|
+
const { original, result } = await nextResolvedSlot(pending);
|
|
11094
|
+
const index = pending.indexOf(original);
|
|
11095
|
+
if (index >= 0)
|
|
11096
|
+
pending.splice(index, 1);
|
|
11097
|
+
if (result.html === null)
|
|
11098
|
+
continue;
|
|
11099
|
+
emitSlotMetric({
|
|
11100
|
+
type: "patched",
|
|
11101
|
+
slotId: result.id,
|
|
11102
|
+
durationMs: result.durationMs,
|
|
11103
|
+
bytes: result.bytes
|
|
11104
|
+
}, combinedOnSlotMetric);
|
|
11105
|
+
controller.enqueue(toUint8(renderStreamingSlotPatchTag(result.id, result.html, nonce), encoder));
|
|
11106
|
+
}
|
|
11107
|
+
if (footerHtml.length > 0) {
|
|
11108
|
+
controller.enqueue(toUint8(footerHtml, encoder));
|
|
11109
|
+
}
|
|
11110
|
+
controller.close();
|
|
11111
|
+
} catch (error) {
|
|
11112
|
+
controller.error(error);
|
|
11113
|
+
}
|
|
11114
|
+
}
|
|
11115
|
+
});
|
|
11116
|
+
};
|
|
11117
|
+
var injectStreamingRuntimeIntoStream = (stream, nonce) => {
|
|
11118
|
+
const runtimeTag = renderStreamingSlotsRuntimeTag(nonce);
|
|
11119
|
+
const encoder = new TextEncoder;
|
|
11120
|
+
const decoder = new TextDecoder;
|
|
11121
|
+
const lookbehind = CLOSING_HEAD_TAG_LENGTH - 1;
|
|
11122
|
+
return new ReadableStream({
|
|
11123
|
+
async start(controller) {
|
|
11124
|
+
const reader = stream.getReader();
|
|
11125
|
+
let injected = false;
|
|
11126
|
+
let pending = "";
|
|
11127
|
+
try {
|
|
11128
|
+
for (;; ) {
|
|
11129
|
+
const { done, value } = await reader.read();
|
|
11130
|
+
if (done)
|
|
11131
|
+
break;
|
|
11132
|
+
if (!value)
|
|
11133
|
+
continue;
|
|
11134
|
+
pending += streamChunkToString(value, decoder);
|
|
11135
|
+
if (injected) {
|
|
11136
|
+
controller.enqueue(encoder.encode(pending));
|
|
11137
|
+
pending = "";
|
|
11138
|
+
continue;
|
|
11139
|
+
}
|
|
11140
|
+
const headIndex = pending.indexOf(CLOSING_HEAD_TAG);
|
|
11141
|
+
if (headIndex >= 0) {
|
|
11142
|
+
const withRuntime = `${pending.slice(0, headIndex)}${runtimeTag}${pending.slice(headIndex)}`;
|
|
11143
|
+
controller.enqueue(encoder.encode(withRuntime));
|
|
11144
|
+
pending = "";
|
|
11145
|
+
injected = true;
|
|
11146
|
+
continue;
|
|
11147
|
+
}
|
|
11148
|
+
if (pending.length > lookbehind) {
|
|
11149
|
+
const safeText = pending.slice(0, pending.length - lookbehind);
|
|
11150
|
+
controller.enqueue(encoder.encode(safeText));
|
|
11151
|
+
pending = pending.slice(-lookbehind);
|
|
11152
|
+
}
|
|
11153
|
+
}
|
|
11154
|
+
pending += decoder.decode();
|
|
11155
|
+
if (!injected) {
|
|
11156
|
+
pending = injectHtmlIntoHead(pending, runtimeTag);
|
|
11157
|
+
}
|
|
11158
|
+
if (pending.length > 0) {
|
|
11159
|
+
controller.enqueue(encoder.encode(pending));
|
|
11160
|
+
}
|
|
11161
|
+
controller.close();
|
|
11162
|
+
} catch (error) {
|
|
11163
|
+
controller.error(error);
|
|
11164
|
+
}
|
|
11165
|
+
}
|
|
11166
|
+
});
|
|
11167
|
+
};
|
|
11168
|
+
var appendStreamingSlotPatchesToStream = (stream, slots = [], {
|
|
11169
|
+
injectRuntime = true,
|
|
11170
|
+
nonce,
|
|
11171
|
+
onError,
|
|
11172
|
+
onSlotMetric,
|
|
11173
|
+
policy
|
|
11174
|
+
} = {}) => {
|
|
11175
|
+
const resolvedPolicy = resolveStreamingSlotPolicy(policy);
|
|
11176
|
+
const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
|
|
11177
|
+
const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
|
|
11178
|
+
const effectivePolicy = {
|
|
11179
|
+
...resolvedPolicy,
|
|
11180
|
+
onSlotMetric: combinedOnSlotMetric
|
|
11181
|
+
};
|
|
11182
|
+
const preparedSlots = prepareSlots({
|
|
11183
|
+
policy: effectivePolicy,
|
|
11184
|
+
slots,
|
|
11185
|
+
onError: combinedOnError,
|
|
11186
|
+
onSlotMetric: combinedOnSlotMetric
|
|
11187
|
+
});
|
|
11188
|
+
if (preparedSlots.length === 0)
|
|
11189
|
+
return stream;
|
|
11190
|
+
const source = injectRuntime ? injectStreamingRuntimeIntoStream(stream, nonce) : stream;
|
|
11191
|
+
const encoder = new TextEncoder;
|
|
11192
|
+
const decoder = new TextDecoder;
|
|
11193
|
+
const reader = source.getReader();
|
|
11194
|
+
const pending = preparedSlots.map((slot) => resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric));
|
|
11195
|
+
return new ReadableStream({
|
|
11196
|
+
async start(controller) {
|
|
11197
|
+
let baseDone = false;
|
|
11198
|
+
let baseRead = reader.read();
|
|
11199
|
+
let tail = "";
|
|
11200
|
+
let footer = "";
|
|
11201
|
+
try {
|
|
11202
|
+
while (!baseDone || pending.length > 0) {
|
|
11203
|
+
const racers = [];
|
|
11204
|
+
if (!baseDone) {
|
|
11205
|
+
racers.push(baseRead.then(({ done, value }) => ({
|
|
11206
|
+
done,
|
|
11207
|
+
kind: "base",
|
|
11208
|
+
value
|
|
11209
|
+
})));
|
|
11210
|
+
}
|
|
11211
|
+
if (pending.length > 0) {
|
|
11212
|
+
racers.push(nextResolvedSlot(pending).then((resolved) => ({
|
|
11213
|
+
kind: "slot",
|
|
11214
|
+
...resolved
|
|
11215
|
+
})));
|
|
11216
|
+
}
|
|
11217
|
+
if (racers.length === 0)
|
|
11218
|
+
break;
|
|
11219
|
+
const winner = await Promise.race(racers);
|
|
11220
|
+
if (winner.kind === "base") {
|
|
11221
|
+
if (winner.done) {
|
|
11222
|
+
baseDone = true;
|
|
11223
|
+
tail += decoder.decode();
|
|
11224
|
+
const footerStart = tail.search(CLOSING_PAGE_TAG_REGEX);
|
|
11225
|
+
if (footerStart >= 0) {
|
|
11226
|
+
const content = tail.slice(0, footerStart);
|
|
11227
|
+
footer = tail.slice(footerStart);
|
|
11228
|
+
if (content.length > 0) {
|
|
11229
|
+
controller.enqueue(encoder.encode(content));
|
|
11230
|
+
}
|
|
11231
|
+
} else if (tail.length > 0) {
|
|
11232
|
+
controller.enqueue(encoder.encode(tail));
|
|
11233
|
+
}
|
|
11234
|
+
tail = "";
|
|
11235
|
+
} else if (winner.value) {
|
|
11236
|
+
tail += streamChunkToString(winner.value, decoder);
|
|
11237
|
+
if (tail.length > STREAM_TAIL_LOOKBEHIND) {
|
|
11238
|
+
const content = tail.slice(0, tail.length - STREAM_TAIL_LOOKBEHIND);
|
|
11239
|
+
controller.enqueue(encoder.encode(content));
|
|
11240
|
+
tail = tail.slice(-STREAM_TAIL_LOOKBEHIND);
|
|
11241
|
+
}
|
|
11242
|
+
baseRead = reader.read();
|
|
11243
|
+
}
|
|
11244
|
+
continue;
|
|
11245
|
+
}
|
|
11246
|
+
const index = pending.indexOf(winner.original);
|
|
11247
|
+
if (index >= 0)
|
|
11248
|
+
pending.splice(index, 1);
|
|
11249
|
+
if (winner.result.html === null)
|
|
11250
|
+
continue;
|
|
11251
|
+
emitSlotMetric({
|
|
11252
|
+
type: "patched",
|
|
11253
|
+
slotId: winner.result.id,
|
|
11254
|
+
durationMs: winner.result.durationMs,
|
|
11255
|
+
bytes: winner.result.bytes
|
|
11256
|
+
}, combinedOnSlotMetric);
|
|
11257
|
+
controller.enqueue(encoder.encode(renderStreamingSlotPatchTag(winner.result.id, winner.result.html, nonce)));
|
|
11258
|
+
}
|
|
11259
|
+
if (footer.length > 0)
|
|
11260
|
+
controller.enqueue(encoder.encode(footer));
|
|
11261
|
+
controller.close();
|
|
11262
|
+
} catch (error) {
|
|
11263
|
+
controller.error(error);
|
|
11264
|
+
}
|
|
11265
|
+
}
|
|
11266
|
+
});
|
|
11267
|
+
};
|
|
11268
|
+
|
|
11269
|
+
// src/core/streamingSlotRegistrar.ts
|
|
11270
|
+
var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
|
|
11271
|
+
var getRegistrarGlobal = () => globalThis;
|
|
11272
|
+
var setStreamingSlotRegistrar = (nextRegistrar) => {
|
|
11273
|
+
getRegistrarGlobal()[STREAMING_SLOT_REGISTRAR_KEY] = nextRegistrar;
|
|
11274
|
+
};
|
|
11275
|
+
var registerStreamingSlot = (slot) => {
|
|
11276
|
+
getRegistrarGlobal()[STREAMING_SLOT_REGISTRAR_KEY]?.(slot);
|
|
11277
|
+
};
|
|
11278
|
+
|
|
11279
|
+
// src/core/streamingSlotRegistry.ts
|
|
11280
|
+
var asyncLocalStorage;
|
|
11281
|
+
var isServerRuntime = () => typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
11282
|
+
var ensureAsyncLocalStorage = async () => {
|
|
11283
|
+
if (typeof asyncLocalStorage !== "undefined")
|
|
11284
|
+
return asyncLocalStorage;
|
|
11285
|
+
if (!isServerRuntime()) {
|
|
11286
|
+
asyncLocalStorage = null;
|
|
11287
|
+
return asyncLocalStorage;
|
|
11288
|
+
}
|
|
11289
|
+
const mod = await import("async_hooks");
|
|
11290
|
+
asyncLocalStorage = new mod.AsyncLocalStorage;
|
|
11291
|
+
return asyncLocalStorage;
|
|
11292
|
+
};
|
|
11293
|
+
var registerStreamingSlot2 = (slot) => {
|
|
11294
|
+
if (!asyncLocalStorage)
|
|
11295
|
+
return;
|
|
11296
|
+
const store = asyncLocalStorage.getStore();
|
|
11297
|
+
if (!store)
|
|
11298
|
+
return;
|
|
11299
|
+
store.set(slot.id, slot);
|
|
11300
|
+
};
|
|
11301
|
+
setStreamingSlotRegistrar(registerStreamingSlot2);
|
|
11302
|
+
var runWithStreamingSlotRegistry = async (task) => {
|
|
11303
|
+
const storage = await ensureAsyncLocalStorage();
|
|
11304
|
+
if (!storage) {
|
|
11305
|
+
return {
|
|
11306
|
+
result: await task(),
|
|
11307
|
+
slots: []
|
|
11308
|
+
};
|
|
11309
|
+
}
|
|
11310
|
+
return storage.run(new Map, async () => {
|
|
11311
|
+
const result = await task();
|
|
11312
|
+
const store = storage.getStore();
|
|
11313
|
+
return {
|
|
11314
|
+
result,
|
|
11315
|
+
slots: store ? [...store.values()] : []
|
|
11316
|
+
};
|
|
11317
|
+
});
|
|
11318
|
+
};
|
|
11319
|
+
|
|
11320
|
+
// src/core/responseEnhancers.ts
|
|
11321
|
+
var toResponse = async (responseLike) => await responseLike;
|
|
11322
|
+
var cloneHeaders = (response) => {
|
|
11323
|
+
const headers = new Headers(response.headers);
|
|
11324
|
+
return headers;
|
|
11325
|
+
};
|
|
11326
|
+
var enhanceHtmlResponseWithStreamingSlots = (response, { nonce, onError, streamingSlots = [], policy } = {}) => {
|
|
11327
|
+
if (!response.body || streamingSlots.length === 0) {
|
|
11328
|
+
return response;
|
|
11329
|
+
}
|
|
11330
|
+
const body = appendStreamingSlotPatchesToStream(response.body, streamingSlots, {
|
|
11331
|
+
nonce,
|
|
11332
|
+
onError,
|
|
11333
|
+
policy
|
|
11334
|
+
});
|
|
11335
|
+
return new Response(body, {
|
|
11336
|
+
headers: cloneHeaders(response),
|
|
11337
|
+
status: response.status,
|
|
11338
|
+
statusText: response.statusText
|
|
11339
|
+
});
|
|
11340
|
+
};
|
|
11341
|
+
var withStreamingSlots = async (responseLike, options = {}) => enhanceHtmlResponseWithStreamingSlots(await toResponse(responseLike), options);
|
|
11342
|
+
var mergeStreamingSlots = (registered, explicit) => {
|
|
11343
|
+
const merged = new Map;
|
|
11344
|
+
for (const slot of registered)
|
|
11345
|
+
merged.set(slot.id, slot);
|
|
11346
|
+
for (const slot of explicit)
|
|
11347
|
+
merged.set(slot.id, slot);
|
|
11348
|
+
return [...merged.values()];
|
|
11349
|
+
};
|
|
11350
|
+
var withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
|
|
11351
|
+
const { result, slots } = await runWithStreamingSlotRegistry(renderResponse);
|
|
11352
|
+
const explicit = options.streamingSlots ?? [];
|
|
11353
|
+
return withStreamingSlots(result, {
|
|
11354
|
+
...options,
|
|
11355
|
+
streamingSlots: mergeStreamingSlots(slots, explicit)
|
|
11356
|
+
});
|
|
11357
|
+
};
|
|
11358
|
+
|
|
11312
11359
|
// src/core/wrapPageHandlerWithStreamingSlots.ts
|
|
11313
|
-
init_responseEnhancers();
|
|
11314
11360
|
var wrapPageHandlerWithStreamingSlots = (handler) => (...args) => withRegisteredStreamingSlots(() => handler(...args));
|
|
11315
11361
|
|
|
11316
11362
|
// src/angular/index.ts
|
|
@@ -11737,5 +11783,5 @@ export {
|
|
|
11737
11783
|
DeferSlotComponent
|
|
11738
11784
|
};
|
|
11739
11785
|
|
|
11740
|
-
//# debugId=
|
|
11786
|
+
//# debugId=ADFC4B4BF6E33FDD64756E2164756E21
|
|
11741
11787
|
//# sourceMappingURL=index.js.map
|