@absolutejs/absolute 0.19.0-beta.350 → 0.19.0-beta.351

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/index.js CHANGED
@@ -202365,7 +202365,7 @@ ${registrations}
202365
202365
  ({ tsLibDir } = cached);
202366
202366
  cached.lastUsed = Date.now();
202367
202367
  } else {
202368
- const tsPath = __require.resolve("typescript");
202368
+ const tsPath = __require.resolve("/home/alexkahn/abs/absolutejs/node_modules/typescript/lib/typescript.js");
202369
202369
  const tsRootDir = dirname9(tsPath);
202370
202370
  tsLibDir = tsRootDir.endsWith("lib") ? tsRootDir : resolve18(tsRootDir, "lib");
202371
202371
  const config = readConfiguration("./tsconfig.json");
@@ -209194,6 +209194,9 @@ var CLOSING_PAGE_TAG_REGEX = /<\/body>\s*<\/html>\s*$/i;
209194
209194
  var STREAMING_RUNTIME_GLOBAL = "__ABS_SLOT_ENQUEUE__";
209195
209195
  var STREAMING_PENDING_GLOBAL = "__ABS_SLOT_PENDING__";
209196
209196
  var STREAM_TAIL_LOOKBEHIND = 128;
209197
+ var STREAMING_SLOT_TIMEOUT_MS = 5000;
209198
+ var STREAMING_SLOT_MAX_PER_RESPONSE = 128;
209199
+ var STREAMING_SLOT_MAX_HTML_BYTES = 64000;
209197
209200
  var createSlotPlaceholderId = (id) => `${SLOT_PLACEHOLDER_PREFIX}${id}`;
209198
209201
  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)});`;
209199
209202
  var createNonceAttr = (nonce) => nonce ? ` nonce="${nonce}"` : "";
@@ -209210,32 +209213,197 @@ var injectHtmlIntoHead = (html, injection) => {
209210
209213
  return `${html}${injection}`;
209211
209214
  };
209212
209215
  var toUint8 = (value, encoder) => encoder.encode(value);
209213
- var toStreamingSlot = (slot) => ({
209214
- ...slot,
209215
- id: slot.id ?? createStreamingSlotId()
209216
+ var currentStreamingSlotPolicy = {
209217
+ timeoutMs: STREAMING_SLOT_TIMEOUT_MS,
209218
+ fallbackHtml: "",
209219
+ errorHtml: undefined,
209220
+ maxSlotsPerResponse: STREAMING_SLOT_MAX_PER_RESPONSE,
209221
+ maxSlotHtmlSizeBytes: STREAMING_SLOT_MAX_HTML_BYTES
209222
+ };
209223
+ var clonePolicy = (policy2) => ({
209224
+ ...policy2
209225
+ });
209226
+ var normalizeSlotBytes = (value, fallback) => {
209227
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
209228
+ return Math.floor(value);
209229
+ }
209230
+ return fallback;
209231
+ };
209232
+ var normalizeSlotText = (value, fallback) => typeof value === "string" ? value : fallback;
209233
+ var normalizeSlotError = (value, fallback) => typeof value === "string" ? value : fallback;
209234
+ var hasPolicyValue = (policy2, key) => Object.prototype.hasOwnProperty.call(policy2, key);
209235
+ var applyStreamingSlotPolicyOverrides = (base, overridePolicy = {}) => ({
209236
+ timeoutMs: hasPolicyValue(overridePolicy, "timeoutMs") ? normalizeSlotBytes(overridePolicy.timeoutMs, base.timeoutMs) : base.timeoutMs,
209237
+ fallbackHtml: hasPolicyValue(overridePolicy, "fallbackHtml") ? normalizeSlotText(overridePolicy.fallbackHtml, "") : base.fallbackHtml,
209238
+ errorHtml: hasPolicyValue(overridePolicy, "errorHtml") ? normalizeSlotError(overridePolicy.errorHtml) : base.errorHtml,
209239
+ maxSlotsPerResponse: hasPolicyValue(overridePolicy, "maxSlotsPerResponse") ? normalizeSlotBytes(overridePolicy.maxSlotsPerResponse, base.maxSlotsPerResponse) : base.maxSlotsPerResponse,
209240
+ maxSlotHtmlSizeBytes: hasPolicyValue(overridePolicy, "maxSlotHtmlSizeBytes") ? normalizeSlotBytes(overridePolicy.maxSlotHtmlSizeBytes, base.maxSlotHtmlSizeBytes) : base.maxSlotHtmlSizeBytes,
209241
+ onError: hasPolicyValue(overridePolicy, "onError") ? overridePolicy.onError : base.onError,
209242
+ onSlotMetric: hasPolicyValue(overridePolicy, "onSlotMetric") ? overridePolicy.onSlotMetric : base.onSlotMetric
209243
+ });
209244
+ var createCombinedSlotErrorHandler = (policyOnError, enhancerOnError) => {
209245
+ if (!policyOnError && !enhancerOnError)
209246
+ return;
209247
+ return (error, slot) => {
209248
+ policyOnError?.(error, slot);
209249
+ enhancerOnError?.(error, slot);
209250
+ };
209251
+ };
209252
+ var createCombinedSlotMetricHandler = (policyOnSlotMetric, callOnSlotMetric) => {
209253
+ if (!policyOnSlotMetric && !callOnSlotMetric)
209254
+ return;
209255
+ return (metric) => {
209256
+ policyOnSlotMetric?.(metric);
209257
+ callOnSlotMetric?.(metric);
209258
+ };
209259
+ };
209260
+ var resolveStreamingSlotPolicy = (overridePolicy = {}) => {
209261
+ const base = getStreamingSlotPolicy();
209262
+ return applyStreamingSlotPolicyOverrides(base, overridePolicy);
209263
+ };
209264
+ var getStreamingSlotPolicy = () => clonePolicy(currentStreamingSlotPolicy);
209265
+ var setStreamingSlotPolicy = (policy2 = {}) => {
209266
+ const base = getStreamingSlotPolicy();
209267
+ currentStreamingSlotPolicy = applyStreamingSlotPolicyOverrides(base, policy2);
209268
+ };
209269
+ var withStreamingSlotPolicy = async (policy2, callback) => {
209270
+ const previous = getStreamingSlotPolicy();
209271
+ setStreamingSlotPolicy(policy2);
209272
+ try {
209273
+ return await callback();
209274
+ } finally {
209275
+ currentStreamingSlotPolicy = previous;
209276
+ }
209277
+ };
209278
+ var emitSlotMetric = (metric, onSlotMetric) => {
209279
+ onSlotMetric?.(metric);
209280
+ };
209281
+ var createTimeoutError = (slot, timeoutMs) => {
209282
+ const error = new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`);
209283
+ error.__absTimeout = true;
209284
+ return error;
209285
+ };
209286
+ var toStreamingSlot = (slot, policy2) => ({
209287
+ errorHtml: slot.errorHtml === undefined ? policy2.errorHtml : slot.errorHtml,
209288
+ fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy2.fallbackHtml),
209289
+ id: slot.id ?? createStreamingSlotId(),
209290
+ timeoutMs: normalizeSlotBytes(slot.timeoutMs, policy2.timeoutMs),
209291
+ resolve: slot.resolve
209216
209292
  });
209217
- var resolveSlot = async (slot, onError) => {
209293
+ var prepareSlots = ({
209294
+ policy: policy2,
209295
+ slots,
209296
+ onError,
209297
+ onSlotMetric
209298
+ }) => {
209299
+ const preparedSlots = slots.map((slot) => toStreamingSlot(slot, policy2));
209300
+ const maxSlotsPerResponse = policy2.maxSlotsPerResponse;
209301
+ if (maxSlotsPerResponse === 0) {
209302
+ const error = new Error("Streaming slot limit is set to 0");
209303
+ for (const slot of preparedSlots) {
209304
+ onError?.(error, slot);
209305
+ emitSlotMetric({
209306
+ type: "dropped",
209307
+ slotId: slot.id,
209308
+ reason: "maxSlotsPerResponse is 0"
209309
+ }, onSlotMetric);
209310
+ }
209311
+ return [];
209312
+ }
209313
+ if (preparedSlots.length <= maxSlotsPerResponse) {
209314
+ preparedSlots.forEach((slot) => emitSlotMetric({
209315
+ type: "prepared",
209316
+ slotId: slot.id
209317
+ }, onSlotMetric));
209318
+ return preparedSlots;
209319
+ }
209320
+ const keptSlots = preparedSlots.slice(0, maxSlotsPerResponse);
209321
+ const droppedSlots = preparedSlots.slice(maxSlotsPerResponse);
209322
+ droppedSlots.forEach((slot) => {
209323
+ onError?.(new Error(`Streaming slot "${slot.id}" dropped because ${maxSlotsPerResponse} slots is the configured maximum`), slot);
209324
+ emitSlotMetric({
209325
+ type: "dropped",
209326
+ slotId: slot.id,
209327
+ reason: `maxSlotsPerResponse is ${maxSlotsPerResponse}`
209328
+ }, onSlotMetric);
209329
+ });
209330
+ keptSlots.forEach((slot) => emitSlotMetric({
209331
+ type: "prepared",
209332
+ slotId: slot.id
209333
+ }, onSlotMetric));
209334
+ return keptSlots;
209335
+ };
209336
+ var htmlByteLength = (value, encoder) => encoder.encode(value).length;
209337
+ var resolveSlot = async (slot, onError, policy2, onSlotMetric) => {
209338
+ const safePolicy = policy2 ?? getStreamingSlotPolicy();
209339
+ const encoder = new TextEncoder;
209340
+ const start = Date.now();
209218
209341
  try {
209219
- const resolved = slot.resolve();
209220
- const html = typeof slot.timeoutMs === "number" && slot.timeoutMs > 0 ? await Promise.race([
209221
- Promise.resolve(resolved),
209222
- new Promise((_, reject) => setTimeout(() => reject(new Error(`Streaming slot "${slot.id}" timed out after ${slot.timeoutMs}ms`)), slot.timeoutMs))
209223
- ]) : await resolved;
209342
+ const maybeAsyncValue = Promise.resolve(slot.resolve());
209343
+ const resolved = typeof slot.timeoutMs === "number" && slot.timeoutMs > 0 ? await Promise.race([
209344
+ maybeAsyncValue,
209345
+ new Promise((_, reject) => setTimeout(() => {
209346
+ reject(createTimeoutError(slot, slot.timeoutMs ?? 0));
209347
+ }, slot.timeoutMs))
209348
+ ]) : await maybeAsyncValue;
209349
+ const html = typeof resolved === "string" ? resolved : `${resolved}`;
209350
+ if (safePolicy.maxSlotHtmlSizeBytes > 0 && htmlByteLength(html, encoder) > safePolicy.maxSlotHtmlSizeBytes) {
209351
+ const bytes2 = htmlByteLength(html, encoder);
209352
+ const error = new Error(`Streaming slot "${slot.id}" exceeded max payload size of ${safePolicy.maxSlotHtmlSizeBytes} bytes`);
209353
+ const durationMs2 = Date.now() - start;
209354
+ onError?.(error, slot);
209355
+ emitSlotMetric({
209356
+ type: "size_exceeded",
209357
+ slotId: slot.id,
209358
+ durationMs: durationMs2,
209359
+ bytes: bytes2,
209360
+ error
209361
+ }, onSlotMetric);
209362
+ const fallbackHtml = typeof slot.errorHtml === "string" ? slot.errorHtml : null;
209363
+ return {
209364
+ html: fallbackHtml,
209365
+ id: slot.id,
209366
+ durationMs: durationMs2,
209367
+ bytes: fallbackHtml === null ? 0 : htmlByteLength(fallbackHtml, encoder)
209368
+ };
209369
+ }
209370
+ const durationMs = Date.now() - start;
209371
+ const bytes = htmlByteLength(html, encoder);
209372
+ emitSlotMetric({
209373
+ type: "resolved",
209374
+ slotId: slot.id,
209375
+ durationMs,
209376
+ bytes
209377
+ }, onSlotMetric);
209224
209378
  return {
209225
209379
  html,
209226
- id: slot.id
209380
+ id: slot.id,
209381
+ durationMs,
209382
+ bytes
209227
209383
  };
209228
209384
  } catch (error) {
209385
+ const durationMs = Date.now() - start;
209229
209386
  onError?.(error, slot);
209387
+ emitSlotMetric({
209388
+ type: error?.__absTimeout === true ? "timeout" : "error",
209389
+ slotId: slot.id,
209390
+ durationMs,
209391
+ error
209392
+ }, onSlotMetric);
209230
209393
  if (typeof slot.errorHtml === "string") {
209394
+ const html = slot.errorHtml;
209231
209395
  return {
209232
- html: slot.errorHtml,
209233
- id: slot.id
209396
+ html,
209397
+ id: slot.id,
209398
+ durationMs,
209399
+ bytes: htmlByteLength(html, encoder)
209234
209400
  };
209235
209401
  }
209236
209402
  return {
209237
209403
  html: null,
209238
- id: slot.id
209404
+ id: slot.id,
209405
+ durationMs,
209406
+ bytes: 0
209239
209407
  };
209240
209408
  }
209241
209409
  };
@@ -209251,23 +209419,37 @@ var streamOutOfOrderSlots = ({
209251
209419
  footerHtml = "",
209252
209420
  headerHtml = "",
209253
209421
  nonce,
209422
+ policy: policy2,
209423
+ onSlotMetric,
209254
209424
  onError,
209255
209425
  slots
209256
209426
  }) => {
209427
+ const resolvedPolicy = resolveStreamingSlotPolicy(policy2);
209428
+ const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
209429
+ const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
209430
+ const effectivePolicy = {
209431
+ ...resolvedPolicy,
209432
+ onSlotMetric: combinedOnSlotMetric
209433
+ };
209434
+ const preparedSlots = prepareSlots({
209435
+ policy: effectivePolicy,
209436
+ slots,
209437
+ onError: combinedOnError,
209438
+ onSlotMetric: combinedOnSlotMetric
209439
+ });
209257
209440
  const encoder = new TextEncoder;
209258
209441
  return new ReadableStream({
209259
209442
  async start(controller) {
209260
209443
  try {
209261
209444
  let header = headerHtml;
209262
- if (!header.includes(STREAMING_RUNTIME_GLOBAL)) {
209445
+ if (preparedSlots.length > 0 && !header.includes(STREAMING_RUNTIME_GLOBAL)) {
209263
209446
  header = injectHtmlIntoHead(header, renderStreamingSlotsRuntimeTag(nonce));
209264
209447
  }
209265
209448
  controller.enqueue(toUint8(header, encoder));
209266
- const pending = slots.map((slot) => {
209267
- const resolvedSlot = toStreamingSlot(slot);
209268
- const fallback = renderStreamingSlotPlaceholder(resolvedSlot.id, resolvedSlot.fallbackHtml ?? "");
209449
+ const pending = preparedSlots.map((slot) => {
209450
+ const fallback = renderStreamingSlotPlaceholder(slot.id, slot.fallbackHtml ?? "");
209269
209451
  controller.enqueue(toUint8(fallback, encoder));
209270
- return resolveSlot(resolvedSlot, onError);
209452
+ return resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric);
209271
209453
  });
209272
209454
  while (pending.length > 0) {
209273
209455
  const { original, result } = await nextResolvedSlot(pending);
@@ -209276,6 +209458,12 @@ var streamOutOfOrderSlots = ({
209276
209458
  pending.splice(index, 1);
209277
209459
  if (result.html === null)
209278
209460
  continue;
209461
+ emitSlotMetric({
209462
+ type: "patched",
209463
+ slotId: result.id,
209464
+ durationMs: result.durationMs,
209465
+ bytes: result.bytes
209466
+ }, combinedOnSlotMetric);
209279
209467
  controller.enqueue(toUint8(renderStreamingSlotPatchTag(result.id, result.html, nonce), encoder));
209280
209468
  }
209281
209469
  if (footerHtml.length > 0) {
@@ -209339,12 +209527,33 @@ var injectStreamingRuntimeIntoStream = (stream, nonce) => {
209339
209527
  }
209340
209528
  });
209341
209529
  };
209342
- var appendStreamingSlotPatchesToStream = (stream, slots = [], { injectRuntime = true, nonce, onError } = {}) => {
209530
+ var appendStreamingSlotPatchesToStream = (stream, slots = [], {
209531
+ injectRuntime = true,
209532
+ nonce,
209533
+ onError,
209534
+ onSlotMetric,
209535
+ policy: policy2
209536
+ } = {}) => {
209537
+ const resolvedPolicy = resolveStreamingSlotPolicy(policy2);
209538
+ const combinedOnError = createCombinedSlotErrorHandler(resolvedPolicy.onError, onError);
209539
+ const combinedOnSlotMetric = createCombinedSlotMetricHandler(resolvedPolicy.onSlotMetric, onSlotMetric);
209540
+ const effectivePolicy = {
209541
+ ...resolvedPolicy,
209542
+ onSlotMetric: combinedOnSlotMetric
209543
+ };
209544
+ const preparedSlots = prepareSlots({
209545
+ policy: effectivePolicy,
209546
+ slots,
209547
+ onError: combinedOnError,
209548
+ onSlotMetric: combinedOnSlotMetric
209549
+ });
209550
+ if (preparedSlots.length === 0)
209551
+ return stream;
209343
209552
  const source = injectRuntime ? injectStreamingRuntimeIntoStream(stream, nonce) : stream;
209344
209553
  const encoder = new TextEncoder;
209345
209554
  const decoder = new TextDecoder;
209346
209555
  const reader = source.getReader();
209347
- const pending = slots.map((slot) => resolveSlot(slot, onError));
209556
+ const pending = preparedSlots.map((slot) => resolveSlot(slot, combinedOnError, effectivePolicy, combinedOnSlotMetric));
209348
209557
  return new ReadableStream({
209349
209558
  async start(controller) {
209350
209559
  let baseDone = false;
@@ -209401,6 +209610,12 @@ var appendStreamingSlotPatchesToStream = (stream, slots = [], { injectRuntime =
209401
209610
  pending.splice(index, 1);
209402
209611
  if (winner.result.html === null)
209403
209612
  continue;
209613
+ emitSlotMetric({
209614
+ type: "patched",
209615
+ slotId: winner.result.id,
209616
+ durationMs: winner.result.durationMs,
209617
+ bytes: winner.result.bytes
209618
+ }, combinedOnSlotMetric);
209404
209619
  controller.enqueue(encoder.encode(renderStreamingSlotPatchTag(winner.result.id, winner.result.html, nonce)));
209405
209620
  }
209406
209621
  if (footer.length > 0)
@@ -209459,13 +209674,14 @@ var cloneHeaders = (response) => {
209459
209674
  const headers = new Headers(response.headers);
209460
209675
  return headers;
209461
209676
  };
209462
- var enhanceHtmlResponseWithStreamingSlots = (response, { nonce, onError, streamingSlots = [] } = {}) => {
209677
+ var enhanceHtmlResponseWithStreamingSlots = (response, { nonce, onError, streamingSlots = [], policy: policy2 } = {}) => {
209463
209678
  if (!response.body || streamingSlots.length === 0) {
209464
209679
  return response;
209465
209680
  }
209466
209681
  const body = appendStreamingSlotPatchesToStream(response.body, streamingSlots, {
209467
209682
  nonce,
209468
- onError
209683
+ onError,
209684
+ policy: policy2
209469
209685
  });
209470
209686
  return new Response(body, {
209471
209687
  headers: cloneHeaders(response),
@@ -216071,11 +216287,70 @@ var getEnv = (key) => {
216071
216287
 
216072
216288
  // src/utils/index.ts
216073
216289
  init_registerClientScript();
216290
+
216291
+ // src/utils/streamingSlotMetricSink.ts
216292
+ var shouldEmitType = (metric, includeTypes, excludeTypes) => {
216293
+ if (Array.isArray(includeTypes) && includeTypes.length > 0 && !includeTypes.includes(metric.type)) {
216294
+ return false;
216295
+ }
216296
+ if (Array.isArray(excludeTypes) && excludeTypes.includes(metric.type)) {
216297
+ return false;
216298
+ }
216299
+ return true;
216300
+ };
216301
+ var shouldSample = (sampleRate = 1) => {
216302
+ if (!Number.isFinite(sampleRate) || sampleRate <= 0)
216303
+ return false;
216304
+ if (sampleRate >= 1)
216305
+ return true;
216306
+ return Math.random() < sampleRate;
216307
+ };
216308
+ var asAsyncReporter = (reporter, onError) => {
216309
+ return (metric) => {
216310
+ try {
216311
+ const result = reporter(metric);
216312
+ if (result && typeof result === "object" && "catch" in result && typeof result.catch === "function") {
216313
+ result.catch((error) => onError(error, metric));
216314
+ }
216315
+ } catch (error) {
216316
+ onError(error, metric);
216317
+ }
216318
+ };
216319
+ };
216320
+ var createStreamingSlotMetricSink = ({
216321
+ excludeTypes,
216322
+ includeTypes,
216323
+ metadata: metadata2,
216324
+ onReport,
216325
+ onError = () => {},
216326
+ route,
216327
+ sampleRate = 1
216328
+ } = {}) => {
216329
+ if (typeof onReport !== "function") {
216330
+ return () => {};
216331
+ }
216332
+ const emit = asAsyncReporter(onReport, onError);
216333
+ const safeMetadata = metadata2 ?? {};
216334
+ return (metric) => {
216335
+ if (!shouldSample(sampleRate))
216336
+ return;
216337
+ if (!shouldEmitType(metric, includeTypes, excludeTypes))
216338
+ return;
216339
+ emit({
216340
+ ...metric,
216341
+ at: Date.now(),
216342
+ route,
216343
+ metadata: safeMetadata
216344
+ });
216345
+ };
216346
+ };
216074
216347
  export {
216075
216348
  wrapPageHandlerWithStreamingSlots,
216076
216349
  withStreamingSlots,
216350
+ withStreamingSlotPolicy,
216077
216351
  withRegisteredStreamingSlots,
216078
216352
  streamOutOfOrderSlots,
216353
+ setStreamingSlotPolicy,
216079
216354
  setSsrContextGetter,
216080
216355
  serializeIslandProps,
216081
216356
  renderStreamingSlotsRuntimeTag,
@@ -216100,6 +216375,7 @@ export {
216100
216375
  handleHTMXPageRequest,
216101
216376
  handleHTMLPageRequest,
216102
216377
  getStreamingSlotsRuntimeScript,
216378
+ getStreamingSlotPolicy,
216103
216379
  getSsrContextId,
216104
216380
  getLocalIPAddress,
216105
216381
  getIslandManifestKey,
@@ -216116,6 +216392,7 @@ export {
216116
216392
  defineIslandComponent,
216117
216393
  defineEnv,
216118
216394
  defineConfig,
216395
+ createStreamingSlotMetricSink,
216119
216396
  createStreamingSlotId,
216120
216397
  clearAllClientScripts,
216121
216398
  asset,
@@ -216171,5 +216448,5 @@ export {
216171
216448
  ANGULAR_INIT_TIMEOUT_MS
216172
216449
  };
216173
216450
 
216174
- //# debugId=FCBDCB12C760F79464756E2164756E21
216451
+ //# debugId=7D3D069CAEA08EF564756E2164756E21
216175
216452
  //# sourceMappingURL=index.js.map