@qwik.dev/core 2.0.0-beta.41 → 2.0.0-beta.42

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/core.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * @qwik.dev/core 2.0.0-beta.41-dev+4d04076
3
+ * @qwik.dev/core 2.0.0-beta.42-dev+3473a49
4
4
  * Copyright QwikDev. All Rights Reserved.
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://github.com/QwikDev/qwik/blob/main/LICENSE
@@ -29,6 +29,9 @@ const STYLE = qDev
29
29
  const logError = (message, ...optionalParams) => {
30
30
  return createAndLogError(false, message, ...optionalParams);
31
31
  };
32
+ const logErrorAndThrowAsync = (message, ...optionalParams) => {
33
+ return createAndLogError(true, message, ...optionalParams);
34
+ };
32
35
  const throwErrorAndStop = (message, ...optionalParams) => {
33
36
  const error = createAndLogError(false, message, ...optionalParams);
34
37
  // eslint-disable-next-line no-debugger
@@ -418,6 +421,8 @@ const QSlotS = 'q:s';
418
421
  const QStatePatchAttrSelector = '[q\\:patch]';
419
422
  const QSuspenseResolved = 'q:r';
420
423
  const QSuspenseResultParent = 'q:rp';
424
+ const QErrorContentHost = 'q:ebc';
425
+ const QErrorFallbackHost = 'q:ebf';
421
426
  const QStyle = 'q:style';
422
427
  const QStyleSelector = 'style[q\\:style]';
423
428
  const QStyleSSelector = 'style[q\\:sstyle]';
@@ -489,8 +494,13 @@ const debugStyleScopeIdPrefixAttr = '__scopedStyleIdPrefix__';
489
494
 
490
495
  const MAX_RETRY_ON_PROMISE_COUNT = 100;
491
496
  const isPromise = (value) => {
492
- // not using "value instanceof Promise" to have zone.js support
493
- return !!value && typeof value == 'object' && typeof value.then === 'function';
497
+ try {
498
+ // not using "value instanceof Promise" to have zone.js support
499
+ return !!value && typeof value == 'object' && typeof value.then === 'function';
500
+ }
501
+ catch {
502
+ return false;
503
+ }
494
504
  };
495
505
  const safeCall = (call, thenFn, rejectFn) => {
496
506
  try {
@@ -518,8 +528,13 @@ const delay = (timeout) => {
518
528
  });
519
529
  };
520
530
  const checkError = (e) => {
521
- if (isServer && e instanceof ReferenceError && e.message.includes('window')) {
522
- e.message = 'It seems like you forgot to add "if (isBrowser) {...}" here:' + e.message;
531
+ try {
532
+ if (isServer && e instanceof ReferenceError && e.message.includes('window')) {
533
+ e.message = 'It seems like you forgot to add "if (isBrowser) {...}" here:' + e.message;
534
+ }
535
+ }
536
+ catch {
537
+ // ignore
523
538
  }
524
539
  };
525
540
  const justThrow = (e) => {
@@ -1266,7 +1281,7 @@ const COMMA = ',';
1266
1281
  *
1267
1282
  * @public
1268
1283
  */
1269
- const version = "2.0.0-beta.41-dev+4d04076";
1284
+ const version = "2.0.0-beta.42-dev+3473a49";
1270
1285
 
1271
1286
  const isNode = (value) => {
1272
1287
  return value && typeof value.nodeType === 'number';
@@ -3780,6 +3795,16 @@ const _propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
3780
3795
  function isSlotProp(prop) {
3781
3796
  return !prop.startsWith('q:') && !prop.startsWith(NON_SERIALIZABLE_MARKER_PREFIX);
3782
3797
  }
3798
+ function hasSlotProps(props) {
3799
+ if (props) {
3800
+ for (const prop in props) {
3801
+ if (isSlotProp(prop)) {
3802
+ return true;
3803
+ }
3804
+ }
3805
+ }
3806
+ return false;
3807
+ }
3783
3808
  /** @internal */
3784
3809
  const _restProps = (props, omit = [], target = {}) => {
3785
3810
  // The optimizer can apply this transform to plain, non-component objects and
@@ -4022,7 +4047,12 @@ function addCursorBoundary(cursorData, vNode) {
4022
4047
  if (!__EXPERIMENTAL__.suspense) {
4023
4048
  return;
4024
4049
  }
4025
- const boundary = getNearestCursorBoundary(vNode);
4050
+ let boundary = null;
4051
+ let current = vNode;
4052
+ while (current && !boundary) {
4053
+ boundary = getNearestCursorBoundary(current);
4054
+ current = current.slotParent || current.parent;
4055
+ }
4026
4056
  if (!boundary) {
4027
4057
  return;
4028
4058
  }
@@ -4169,7 +4199,7 @@ function runEventHandlerQRL(handler, event, element, ctx) {
4169
4199
  if (!(hostElement.flags & 32 /* VNodeFlags.Deleted */)) {
4170
4200
  return invokeApply(ctx, realHandler, [event, element]);
4171
4201
  }
4172
- }, (err) => container.handleError(err, hostElement));
4202
+ }, (err) => container.handleError(err, hostElement, "event" /* ErrorBoundaryPhase.Event */));
4173
4203
  }
4174
4204
  /**
4175
4205
  * This is called by qwik-loader to run a QRL. It has to be synchronous when possible.
@@ -9335,7 +9365,10 @@ const runTask = (task, container, host) => {
9335
9365
  return pendingTask;
9336
9366
  }
9337
9367
  task.$flags$ &= -5 /* TaskFlags.DIRTY */;
9338
- const handleError = (reason) => container.handleError(reason, host);
9368
+ const handleError = (reason) => {
9369
+ tagErrorPhase(reason, "hook" /* ErrorBoundaryPhase.Hook */);
9370
+ container.handleError(reason, host, "hook" /* ErrorBoundaryPhase.Hook */);
9371
+ };
9339
9372
  let taskPromise = null;
9340
9373
  const result = maybeThen(cleanupAsyncDestroyable(task, handleError), () => {
9341
9374
  const iCtx = newInvokeContext(container.$locale$, host, TaskEvent);
@@ -9405,6 +9438,10 @@ function scheduleTask(_event, element) {
9405
9438
  setCaptures(deserializeCaptureDeltas(container, this));
9406
9439
  }
9407
9440
  const task = _captures[0];
9441
+ if (!task.$el$) {
9442
+ // An ErrorBoundary tore the host down; the task has nothing left to run against.
9443
+ return;
9444
+ }
9408
9445
  task.$flags$ |= 4 /* TaskFlags.DIRTY */;
9409
9446
  markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
9410
9447
  });
@@ -9669,7 +9706,12 @@ const getStoreHandler = (value) => {
9669
9706
  return value[STORE_HANDLER];
9670
9707
  };
9671
9708
  const getStoreTarget = (value) => {
9672
- return value?.[STORE_TARGET] || null;
9709
+ try {
9710
+ return value?.[STORE_TARGET] || null;
9711
+ }
9712
+ catch {
9713
+ return null;
9714
+ }
9673
9715
  };
9674
9716
  /**
9675
9717
  * Force a store to recompute and schedule effects.
@@ -9770,11 +9812,17 @@ class StoreHandler {
9770
9812
  return this.toString;
9771
9813
  }
9772
9814
  const flags = this.$flags$;
9773
- if (flags & 1 /* StoreFlags.RECURSIVE */ &&
9774
- isObject(value) &&
9775
- !Object.isFrozen(value) &&
9776
- !isStore(value) &&
9777
- !Object.isFrozen(target)) {
9815
+ let shouldWrapRecursively = false;
9816
+ if (flags & 1 /* StoreFlags.RECURSIVE */ && isObject(value)) {
9817
+ try {
9818
+ shouldWrapRecursively =
9819
+ !Object.isFrozen(value) && !isStore(value) && !Object.isFrozen(target);
9820
+ }
9821
+ catch {
9822
+ // ignore
9823
+ }
9824
+ }
9825
+ if (shouldWrapRecursively) {
9778
9826
  return getOrCreateStore(value, this.$flags$, this.$container$);
9779
9827
  }
9780
9828
  return value;
@@ -10727,8 +10775,9 @@ class Serializer {
10727
10775
  }
10728
10776
  const out = [value.$computeQrl$, value.$effects$];
10729
10777
  if (isAsync) {
10778
+ const untrackedError = value.$untrackedError$;
10730
10779
  // After SSR, the signal is never loading, so no need to send it
10731
- out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedError$);
10780
+ out.push(value.$loadingEffects$, value.$errorEffects$, untrackedError === undefined || isDev ? untrackedError : redactToGeneric(untrackedError));
10732
10781
  out.push(asyncFlags || undefined);
10733
10782
  }
10734
10783
  if (v !== NEEDS_COMPUTATION || concurrency !== undefined || timeout !== undefined) {
@@ -10765,8 +10814,9 @@ class Serializer {
10765
10814
  }
10766
10815
  else if (value instanceof Error) {
10767
10816
  const out = [value.message];
10768
- // flatten gives us the right output
10769
- out.push(...Object.entries(value).flat());
10817
+ for (const entry of Object.entries(value)) {
10818
+ out.push(entry[0], entry[1]);
10819
+ }
10770
10820
  /// In production we don't want to leak the stack trace.
10771
10821
  if (isDev) {
10772
10822
  out.push('stack', value.stack);
@@ -10774,15 +10824,20 @@ class Serializer {
10774
10824
  this.output(23 /* TypeIds.Error */, out);
10775
10825
  }
10776
10826
  else if (this.$serializationContext$.$isSsrNode$(value)) {
10827
+ // Paired with ssr-container's vnode-data INERT skip: drop the state root AND the path together.
10828
+ if (value.vnodeData &&
10829
+ value.vnodeData[0] & 32 /* VNodeDataFlag.INERT */ &&
10830
+ /[A-Za-z]/.test(value.id)) {
10831
+ this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
10832
+ return;
10833
+ }
10777
10834
  const rootIndex = this.$serializationContext$.$addRoot$(value);
10778
10835
  this.$serializationContext$.$setProp$(value, ELEMENT_ID, rootIndex);
10779
10836
  // we need to output before the vnode overwrites its values
10780
10837
  this.output(10 /* TypeIds.VNode */, value.id);
10781
10838
  const vNodeData = value.vnodeData;
10782
10839
  if (vNodeData) {
10783
- discoverValuesForVNodeData(vNodeData, (vNodeDataValue) => {
10784
- this.$serializationContext$.$addRoot$(vNodeDataValue);
10785
- });
10840
+ discoverValuesForVNodeData(vNodeData, this.$serializationContext$);
10786
10841
  this.$serializationContext$.$markSsrNodeForSerialization$(value, 16 /* VNodeDataFlag.SERIALIZE */);
10787
10842
  }
10788
10843
  if (value.children) {
@@ -11066,9 +11121,9 @@ function getCustomSerializerPromise(signal, value) {
11066
11121
  return data;
11067
11122
  });
11068
11123
  }
11069
- const discoverValuesForVNodeData = (vnodeData, callback) => {
11124
+ const discoverValuesForVNodeData = (vnodeData, serializationContext) => {
11070
11125
  const length = vnodeData.length;
11071
- for (let i = 0; i < length; i++) {
11126
+ for (let i = 1; i < length; i++) {
11072
11127
  const value = vnodeData[i];
11073
11128
  if (isSsrAttrs(value)) {
11074
11129
  for (const key in value) {
@@ -11081,7 +11136,7 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
11081
11136
  shouldSkipComponentProps(value, attrValue)))) {
11082
11137
  continue;
11083
11138
  }
11084
- callback(attrValue);
11139
+ serializationContext.$addRoot$(attrValue);
11085
11140
  }
11086
11141
  }
11087
11142
  }
@@ -12067,15 +12122,23 @@ const applyQwikComponentBody = (ssr, jsx, component) => {
12067
12122
 
12068
12123
  class MaybeAsyncSignal {
12069
12124
  }
12070
- const markPromiseHandled = (ssr, promise, host = null) => {
12071
- promise.catch((reason) => {
12072
- try {
12073
- ssr.handleError(reason, host);
12074
- }
12075
- catch {
12076
- // Original promise remains awaited later.
12077
- }
12078
- });
12125
+ // we need to differentiate between JSX functions and ssr container functions for error boundary
12126
+ // JSX functions need to be skipped after error boundary catch an error
12127
+ class InvokeJSXFunction {
12128
+ }
12129
+ const openBoundaryContentScope = (ssr, contentHost) => {
12130
+ const enclosing = ssr.$errorContentHost$;
12131
+ ssr.$errorContentHost$ = contentHost;
12132
+ return () => {
12133
+ ssr.$errorContentHost$ = enclosing;
12134
+ };
12135
+ };
12136
+ const isInsideFailedBoundaryContent = (ssr) => {
12137
+ const contentHost = ssr.$errorContentHost$;
12138
+ return !!contentHost && (contentHost.vnodeData[0] & 32 /* VNodeDataFlag.INERT */) !== 0;
12139
+ };
12140
+ const markPromiseHandled = (promise) => {
12141
+ promise.catch(() => { });
12079
12142
  };
12080
12143
  function setParentOptions(mutable, styleScoped, parentComponentFrame) {
12081
12144
  return () => {
@@ -12088,23 +12151,43 @@ async function _walkJSX(ssr, value, options) {
12088
12151
  const stack = [value];
12089
12152
  const enqueue = (value) => stack.push(value);
12090
12153
  const enqueuePromise = (promise) => {
12091
- markPromiseHandled(ssr, promise);
12154
+ markPromiseHandled(promise);
12092
12155
  stack.push(promise);
12093
12156
  stack.push(Promise);
12094
12157
  };
12095
12158
  const drain = async () => {
12096
12159
  while (stack.length) {
12160
+ let phase = "render" /* ErrorBoundaryPhase.Render */;
12097
12161
  try {
12098
12162
  const value = stack.pop();
12099
12163
  // Reference equality first (no prototype walk), then typeof
12100
12164
  if (value === MaybeAsyncSignal) {
12101
12165
  const trackFn = stack.pop();
12166
+ if (__EXPERIMENTAL__.errorBoundary && isInsideFailedBoundaryContent(ssr)) {
12167
+ continue;
12168
+ }
12169
+ phase = "hook" /* ErrorBoundaryPhase.Hook */;
12102
12170
  await retryOnPromise(() => stack.push(trackFn()));
12103
12171
  continue;
12104
12172
  }
12173
+ if (__EXPERIMENTAL__.errorBoundary && value === InvokeJSXFunction) {
12174
+ const fnChild = stack.pop();
12175
+ if (isInsideFailedBoundaryContent(ssr)) {
12176
+ continue;
12177
+ }
12178
+ const result = fnChild.apply(ssr);
12179
+ if (isPromise(result)) {
12180
+ await result;
12181
+ }
12182
+ continue;
12183
+ }
12105
12184
  if (typeof value === 'function') {
12106
12185
  if (value === Promise) {
12107
- stack.push(await stack.pop());
12186
+ const pending = stack.pop();
12187
+ if (__EXPERIMENTAL__.errorBoundary && isInsideFailedBoundaryContent(ssr)) {
12188
+ continue;
12189
+ }
12190
+ stack.push(await pending);
12108
12191
  }
12109
12192
  else {
12110
12193
  const result = value.apply(ssr);
@@ -12114,8 +12197,17 @@ async function _walkJSX(ssr, value, options) {
12114
12197
  }
12115
12198
  continue;
12116
12199
  }
12200
+ if (__EXPERIMENTAL__.errorBoundary && isInsideFailedBoundaryContent(ssr)) {
12201
+ if (isPromise(value)) {
12202
+ value.catch(() => { });
12203
+ }
12204
+ continue;
12205
+ }
12117
12206
  processJSXNode(ssr, enqueue, enqueuePromise, value, options);
12118
12207
  }
12208
+ catch (err) {
12209
+ ssr.handleError(err, ssr.getOrCreateLastNode(), phase);
12210
+ }
12119
12211
  finally {
12120
12212
  const pendingFlush = ssr.streamHandler.waitForPendingFlush();
12121
12213
  if (isPromise(pendingFlush)) {
@@ -12126,6 +12218,12 @@ async function _walkJSX(ssr, value, options) {
12126
12218
  };
12127
12219
  await drain();
12128
12220
  }
12221
+ function enqueueJSX(enqueue, value) {
12222
+ enqueue(value);
12223
+ if (__EXPERIMENTAL__.errorBoundary && typeof value === 'function') {
12224
+ enqueue(InvokeJSXFunction);
12225
+ }
12226
+ }
12129
12227
  function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12130
12228
  // console.log('processJSXNode', value);
12131
12229
  if (value == null) {
@@ -12143,7 +12241,7 @@ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12143
12241
  else if (typeof value === 'object') {
12144
12242
  if (Array.isArray(value)) {
12145
12243
  for (let i = value.length - 1; i >= 0; i--) {
12146
- enqueue(value[i]);
12244
+ enqueueJSX(enqueue, value[i]);
12147
12245
  }
12148
12246
  }
12149
12247
  else if (isSignal(value)) {
@@ -12162,19 +12260,28 @@ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12162
12260
  }
12163
12261
  else if (isAsyncGenerator(value)) {
12164
12262
  enqueue(async () => {
12165
- for await (const chunk of value) {
12166
- await _walkJSX(ssr, chunk, {
12167
- currentStyleScoped: options.currentStyleScoped,
12168
- parentComponentFrame: options.parentComponentFrame,
12169
- });
12170
- await ssr.streamHandler.flush();
12263
+ if (__EXPERIMENTAL__.errorBoundary && isInsideFailedBoundaryContent(ssr)) {
12264
+ return;
12265
+ }
12266
+ const freshWalkOptions = () => ({
12267
+ currentStyleScoped: options.currentStyleScoped,
12268
+ parentComponentFrame: options.parentComponentFrame,
12269
+ });
12270
+ try {
12271
+ for await (const chunk of value) {
12272
+ await _walkJSX(ssr, chunk, freshWalkOptions());
12273
+ await ssr.streamHandler.flush();
12274
+ }
12275
+ }
12276
+ catch (err) {
12277
+ ssr.handleError(err, ssr.getOrCreateLastNode(), "render" /* ErrorBoundaryPhase.Render */);
12278
+ await _walkJSX(ssr, null, freshWalkOptions());
12171
12279
  }
12172
12280
  });
12173
12281
  }
12174
12282
  else {
12175
12283
  const jsx = value;
12176
12284
  const type = jsx.type;
12177
- // Below, JSXChildren allows functions and regexes, but we assume the dev only uses those as appropriate.
12178
12285
  if (typeof type === 'string') {
12179
12286
  appendClassIfScopedStyleExists(jsx, options.currentStyleScoped);
12180
12287
  let qwikInspectorAttrValue = null;
@@ -12188,6 +12295,9 @@ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12188
12295
  if (innerHTML) {
12189
12296
  ssr.htmlNode(innerHTML);
12190
12297
  }
12298
+ if (__EXPERIMENTAL__.errorBoundary && directGetPropsProxyProp(jsx, QErrorContentHost)) {
12299
+ enqueue(openBoundaryContentScope(ssr, ssr.getOrCreateLastNode()));
12300
+ }
12191
12301
  enqueue(ssr.closeElement);
12192
12302
  if (type === 'head') {
12193
12303
  ssr.emitQwikLoaderAtTopIfNeeded();
@@ -12206,10 +12316,11 @@ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12206
12316
  }
12207
12317
  }
12208
12318
  const children = jsx.children;
12209
- children != null && enqueue(children);
12319
+ children != null && enqueueJSX(enqueue, children);
12210
12320
  }
12211
12321
  else if (isFunction(type)) {
12212
- if (__EXPERIMENTAL__.suspense && isInternalServerComponent(type)) {
12322
+ if ((__EXPERIMENTAL__.suspense || __EXPERIMENTAL__.errorBoundary) &&
12323
+ isInternalServerComponent(type)) {
12213
12324
  enqueue(() => getInternalServerComponentHandler(type)(ssr, jsx, options, enqueue));
12214
12325
  return;
12215
12326
  }
@@ -12220,9 +12331,8 @@ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12220
12331
  }
12221
12332
  ssr.openFragment(attrs);
12222
12333
  enqueue(ssr.closeFragment);
12223
- // In theory we could get functions or regexes, but we assume all is well
12224
12334
  const children = jsx.children;
12225
- children != null && enqueue(children);
12335
+ children != null && enqueueJSX(enqueue, children);
12226
12336
  }
12227
12337
  else if (type === Slot) {
12228
12338
  const componentFrame = options.parentComponentFrame;
@@ -12244,7 +12354,7 @@ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12244
12354
  if (slotDefaultChildren && slotChildren !== slotDefaultChildren) {
12245
12355
  ssr.addUnclaimedProjection(componentFrame, QDefaultSlot, slotDefaultChildren);
12246
12356
  }
12247
- enqueue(slotChildren);
12357
+ enqueueJSX(enqueue, slotChildren);
12248
12358
  enqueue(setParentOptions(options, componentFrame.projectionScopedStyle, componentFrame.projectionComponentFrame));
12249
12359
  }
12250
12360
  else {
@@ -12291,7 +12401,7 @@ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12291
12401
  else if (type === SSRStreamBlock) {
12292
12402
  ssr.streamHandler.streamBlockStart();
12293
12403
  enqueue(() => ssr.streamHandler.streamBlockEnd());
12294
- enqueue(jsx.children);
12404
+ enqueueJSX(enqueue, jsx.children);
12295
12405
  }
12296
12406
  else if (isQwikComponent(type)) {
12297
12407
  // prod: use new instance of an object for props, we always modify props for a component
@@ -12301,13 +12411,13 @@ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12301
12411
  }
12302
12412
  ssr.openComponent(componentAttrs);
12303
12413
  const host = ssr.getOrCreateLastNode();
12414
+ enqueue(setParentOptions(options, options.currentStyleScoped, options.parentComponentFrame));
12415
+ enqueue(() => ssr.closeComponent());
12304
12416
  const componentFrame = ssr.getParentComponentFrame();
12305
12417
  componentFrame.distributeChildrenIntoSlots(jsx.children, options.currentStyleScoped, options.parentComponentFrame);
12306
12418
  const jsxOutput = applyQwikComponentBody(ssr, jsx, type);
12307
- enqueue(setParentOptions(options, options.currentStyleScoped, options.parentComponentFrame));
12308
- enqueue(() => ssr.closeComponent());
12309
12419
  if (isPromise(jsxOutput)) {
12310
- markPromiseHandled(ssr, jsxOutput, host);
12420
+ markPromiseHandled(jsxOutput);
12311
12421
  // Defer reading QScopedStyle until after the promise resolves
12312
12422
  enqueue(async () => {
12313
12423
  await ssr.streamHandler.flush();
@@ -12359,6 +12469,99 @@ function appendClassIfScopedStyleExists(jsx, styleScoped) {
12359
12469
  }
12360
12470
  }
12361
12471
 
12472
+ /** @internal */
12473
+ function handleSSRError(container, err, host, phase) {
12474
+ if (!__EXPERIMENTAL__.errorBoundary || (qDev && !isRecoverable(err))) {
12475
+ throw err;
12476
+ }
12477
+ for (let boundaryNode = host; boundaryNode; boundaryNode = boundaryNode.parentComponent) {
12478
+ const errorStore = getOwnSSRErrorBoundaryStore(boundaryNode);
12479
+ if (!errorStore || !errorStore.$fallback$) {
12480
+ continue;
12481
+ }
12482
+ if (container.$isOutOfOrderSegment$ && errorStore.$emitFallback$) {
12483
+ throw err;
12484
+ }
12485
+ markBoundaryErrored(errorStore, err, phase);
12486
+ getRootContainer(container).$hasBoundaryError$ = true;
12487
+ if (container.$isOutOfOrderSegment$) {
12488
+ markErrorFromDeferredSegment(errorStore);
12489
+ }
12490
+ markErrorBoundaryContentInert(container, boundaryNode, errorStore);
12491
+ return;
12492
+ }
12493
+ throw err;
12494
+ }
12495
+ function markErrorBoundaryContentInert(container, boundaryNode, errorStore) {
12496
+ const ancestorOwners = new Map();
12497
+ let boundaryContentOwner = null;
12498
+ let depth = 0;
12499
+ for (let node = boundaryNode; node; node = node.parentComponent) {
12500
+ if (node.id) {
12501
+ ancestorOwners.set(node.id, { node, depth: depth++ });
12502
+ }
12503
+ if (node !== boundaryNode && !boundaryContentOwner) {
12504
+ const store = getOwnSSRErrorBoundaryStore(node);
12505
+ if (store?.error !== undefined || !hasSlotProps(node.getProp(ELEMENT_PROPS))) {
12506
+ boundaryContentOwner = node;
12507
+ }
12508
+ }
12509
+ }
12510
+ const topmostSevered = { node: null, depth: -1 };
12511
+ const children = boundaryNode.children;
12512
+ if (children) {
12513
+ for (let i = 0; i < children.length; i++) {
12514
+ markErrorSubtreeInert(container, children[i], ancestorOwners, topmostSevered);
12515
+ }
12516
+ }
12517
+ if (topmostSevered.node) {
12518
+ const immediateContentOwner = topmostSevered.node.parentComponent;
12519
+ if (topmostSevered.node === boundaryNode) {
12520
+ container.$retainForResume$(boundaryContentOwner);
12521
+ }
12522
+ else if (immediateContentOwner?.id) {
12523
+ container.$retainForResume$(immediateContentOwner);
12524
+ errorStore.projectedContentOwner = immediateContentOwner;
12525
+ }
12526
+ }
12527
+ }
12528
+ function getOwnSSRErrorBoundaryStore(node) {
12529
+ const ctx = node.getProp(QCtxAttr);
12530
+ return ctx ? mapArray_get(ctx, ERROR_CONTEXT.id, 0) : null;
12531
+ }
12532
+ function markErrorSubtreeInert(container, node, ancestorOwners, topmostSevered) {
12533
+ node.vnodeData[0] |= 32 /* VNodeDataFlag.INERT */;
12534
+ const ownerId = node.getProp(QSlotParent);
12535
+ if (ownerId) {
12536
+ const owner = ancestorOwners.get(ownerId);
12537
+ if (owner) {
12538
+ owner.node.removeProp(node.getProp(QSlot) ?? QDefaultSlot);
12539
+ if (owner.depth > topmostSevered.depth) {
12540
+ topmostSevered.node = owner.node;
12541
+ topmostSevered.depth = owner.depth;
12542
+ }
12543
+ }
12544
+ }
12545
+ // Element consumers keep materializing when inert, so their bindings would keep patching hidden
12546
+ // DOM; virtual ones can't materialize and would leave producers pointing at a dead node.
12547
+ clearAllEffects(container, node);
12548
+ const seq = node.getProp(ELEMENT_SEQ);
12549
+ if (seq) {
12550
+ for (let i = 0; i < seq.length; i++) {
12551
+ const item = seq[i];
12552
+ if (isTask(item)) {
12553
+ clearAllEffects(container, item);
12554
+ }
12555
+ }
12556
+ }
12557
+ const children = node.children;
12558
+ if (children) {
12559
+ for (let i = 0; i < children.length; i++) {
12560
+ markErrorSubtreeInert(container, children[i], ancestorOwners, topmostSevered);
12561
+ }
12562
+ }
12563
+ }
12564
+
12362
12565
  // <docs markdown="../readme.md#useLexicalScope">
12363
12566
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
12364
12567
  // (edit ../readme.md#useLexicalScope instead and run `pnpm docs.sync`)
@@ -13836,14 +14039,179 @@ const _resolveContextWithoutSequentialScope = (context) => {
13836
14039
  };
13837
14040
 
13838
14041
  const ERROR_CONTEXT = /*#__PURE__*/ createContextId('qk-error');
13839
- const isRecoverable = (err) => {
13840
- if (err && err instanceof Error) {
13841
- if ('plugin' in err) {
13842
- return false;
14042
+ const ERROR_BOUNDARY_QRL_SYMBOL = '_ebC';
14043
+ const safeRead = (read, fallback) => {
14044
+ try {
14045
+ return read();
14046
+ }
14047
+ catch {
14048
+ return fallback;
14049
+ }
14050
+ };
14051
+ const isRecoverable = (err) => safeRead(() => !(err instanceof Error && 'plugin' in err), true);
14052
+ const GENERIC_BOUNDARY_ERROR_MESSAGE = 'An error occurred';
14053
+ const errorBoundaryDigest = (err) => hashCode(safeRead(() => err instanceof Error ? `${err.name}: ${err.message}\n${err.stack ?? ''}` : String(err), 'unknown'));
14054
+ const REDACTED = /*#__PURE__*/ Symbol();
14055
+ const redactToGeneric = (err) => {
14056
+ const redacted = new Error(GENERIC_BOUNDARY_ERROR_MESSAGE);
14057
+ redacted.digest = errorBoundaryDigest(err);
14058
+ Object.defineProperty(redacted, REDACTED, { value: true });
14059
+ return redacted;
14060
+ };
14061
+ const toBoundaryError = (raw) => {
14062
+ if (raw instanceof Error) {
14063
+ return raw;
14064
+ }
14065
+ let message;
14066
+ try {
14067
+ message = String(raw);
14068
+ }
14069
+ catch {
14070
+ try {
14071
+ message = Object.prototype.toString.call(raw);
14072
+ }
14073
+ catch {
14074
+ message = GENERIC_BOUNDARY_ERROR_MESSAGE;
13843
14075
  }
13844
14076
  }
14077
+ const wrapped = new Error(message);
14078
+ wrapped.cause = raw;
14079
+ return wrapped;
14080
+ };
14081
+ const isReadableProjection = (projected) => safeRead(() => {
14082
+ void projected.message;
14083
+ void projected.name;
14084
+ for (const key in projected) {
14085
+ void projected[key];
14086
+ }
13845
14087
  return true;
14088
+ }, false);
14089
+ const redactBoundaryErrorForDisplay = (error, showRaw, transformError) => {
14090
+ try {
14091
+ if (transformError) {
14092
+ const projected = transformError(error);
14093
+ if (projected instanceof Error) {
14094
+ return isReadableProjection(projected) ? projected : redactToGeneric(error);
14095
+ }
14096
+ if (projected != null) {
14097
+ if (showRaw && isPromise(projected)) {
14098
+ logWarn('transformError must return synchronously; an async one redacts every error.');
14099
+ }
14100
+ return redactToGeneric(error);
14101
+ }
14102
+ }
14103
+ if (safeRead(() => error instanceof Error && REDACTED in error, false)) {
14104
+ return error;
14105
+ }
14106
+ if (!showRaw) {
14107
+ return redactToGeneric(error);
14108
+ }
14109
+ if (error instanceof Error) {
14110
+ return error;
14111
+ }
14112
+ const rawMessage = error?.message;
14113
+ if (typeof rawMessage === 'string') {
14114
+ const wrapped = new Error(rawMessage);
14115
+ wrapped.cause = error;
14116
+ return wrapped;
14117
+ }
14118
+ return toBoundaryError(error);
14119
+ }
14120
+ catch {
14121
+ return redactToGeneric(error);
14122
+ }
14123
+ };
14124
+ const fireOnError = (onError, error, phase, boundaryId) => {
14125
+ if (!onError) {
14126
+ return;
14127
+ }
14128
+ try {
14129
+ const digest = errorBoundaryDigest(error);
14130
+ void Promise.resolve(onError(toBoundaryError(error), { phase, boundaryId, digest })).catch(logError);
14131
+ }
14132
+ catch (e) {
14133
+ logError(e);
14134
+ }
14135
+ };
14136
+ const boundariesWithDeferredError = /*#__PURE__*/ new WeakSet();
14137
+ const markErrorFromDeferredSegment = (store) => {
14138
+ boundariesWithDeferredError.add(store);
14139
+ };
14140
+ const isErrorFromDeferredSegment = (store) => boundariesWithDeferredError.has(store);
14141
+ const ERROR_PHASE = /*#__PURE__*/ Symbol('qErrorPhase');
14142
+ const tagErrorPhase = (err, phase) => {
14143
+ try {
14144
+ Object.defineProperty(err, ERROR_PHASE, { value: phase, configurable: true });
14145
+ }
14146
+ catch {
14147
+ // ignore
14148
+ }
14149
+ };
14150
+ const getTaggedErrorPhase = (err) => safeRead(() => err?.[ERROR_PHASE], undefined);
14151
+ const markBoundaryErrored = (store, error, phase = "render" /* ErrorBoundaryPhase.Render */) => {
14152
+ // `null` would collide with the capture-only sentinel, so wrap every nullish throw.
14153
+ store.error = error == null ? toBoundaryError(error) : error;
14154
+ const onError = store.$onError$;
14155
+ if (onError) {
14156
+ fireOnError(onError, error, getTaggedErrorPhase(error) ?? phase, store.boundaryId ?? '');
14157
+ }
14158
+ };
14159
+ const handleQError = (e) => {
14160
+ const detail = e
14161
+ .detail;
14162
+ if (detail?.importError) {
14163
+ return;
14164
+ }
14165
+ const source = detail.element;
14166
+ // The listener is document-wide, so only this document's elements may route through it.
14167
+ if (!source || source.ownerDocument !== e.currentTarget) {
14168
+ return;
14169
+ }
14170
+ // A destroyed container clears this back-pointer, so a stale target resolves to nothing.
14171
+ const container = source.closest(QContainerSelector)?.qContainer;
14172
+ const host = container?.vNodeLocate(source);
14173
+ if (!container || !host) {
14174
+ return;
14175
+ }
14176
+ try {
14177
+ container.handleError(detail.error, host, "event" /* ErrorBoundaryPhase.Event */);
14178
+ }
14179
+ catch (handlerError) {
14180
+ logError(handlerError);
14181
+ }
13846
14182
  };
14183
+ /**
14184
+ * One listener per document, routed by target, so no container is retained by the document. The
14185
+ * marker lives on the document so a second bundle on the page reuses it instead of
14186
+ * double-handling.
14187
+ */
14188
+ function installQErrorListener(doc) {
14189
+ if (!doc.qErrorHandler) {
14190
+ doc.qErrorHandler = handleQError;
14191
+ doc.addEventListener?.('qerror', handleQError);
14192
+ }
14193
+ }
14194
+ function handleDevError(container, err, host) {
14195
+ if (typeof document !== 'undefined') {
14196
+ setErrorPayload(host, err);
14197
+ markVNodeDirty(container, host, 512 /* ChoreBits.ERROR_WRAP */);
14198
+ }
14199
+ try {
14200
+ if (err instanceof Error && !('hostElement' in err)) {
14201
+ err['hostElement'] = String(host);
14202
+ }
14203
+ }
14204
+ catch {
14205
+ // ignore
14206
+ }
14207
+ if (!isRecoverable(err)) {
14208
+ throw err;
14209
+ }
14210
+ }
14211
+ function getOwnErrorBoundaryStore(container, host) {
14212
+ const ctx = container.getHostProp(host, QCtxAttr);
14213
+ return ctx ? mapArray_get(ctx, ERROR_CONTEXT.id, 0) : null;
14214
+ }
13847
14215
 
13848
14216
  /** @internal */
13849
14217
  const canRevealRegistration = (registration, isPending = (item) => item.boundary.untrackedValue > 0) => {
@@ -14721,6 +15089,9 @@ class DomContainer extends _SharedContainer {
14721
15089
  this.$setServerData$();
14722
15090
  element.qContainer = this;
14723
15091
  element.qDestroy = () => this.$destroy$();
15092
+ if (__EXPERIMENTAL__.errorBoundary) {
15093
+ installQErrorListener(this.document);
15094
+ }
14724
15095
  this.$containerDataProcessState$ = 1 /* ContainerDataProcessState.ProcessingVNode */;
14725
15096
  processVNodeData(document, element);
14726
15097
  onVNodeDataReady(document, () => {
@@ -14816,29 +15187,48 @@ class DomContainer extends _SharedContainer {
14816
15187
  this.$stateData$[id] = vParent;
14817
15188
  }
14818
15189
  parseQRL(qrlStr) {
14819
- const qrl = parseQRL(qrlStr, this);
14820
- return qrl;
15190
+ return parseQRL(qrlStr, this);
14821
15191
  }
14822
- handleError(err, host) {
15192
+ handleError(err, host, phase = "render" /* ErrorBoundaryPhase.Render */) {
14823
15193
  if (qDev && host) {
14824
- if (typeof document !== 'undefined') {
14825
- setErrorPayload(host, err);
14826
- markVNodeDirty(this, host, 512 /* ChoreBits.ERROR_WRAP */);
14827
- }
14828
- if (err && err instanceof Error) {
14829
- if (!('hostElement' in err)) {
14830
- err['hostElement'] = String(host);
14831
- }
14832
- }
14833
- if (!isRecoverable(err)) {
15194
+ handleDevError(this, err, host);
15195
+ }
15196
+ if (!__EXPERIMENTAL__.errorBoundary) {
15197
+ const errorStore = host && this.resolveContext(host, ERROR_CONTEXT);
15198
+ if (!errorStore) {
14834
15199
  throw err;
14835
15200
  }
15201
+ errorStore.error = err;
15202
+ return;
14836
15203
  }
14837
- const errorStore = host && this.resolveContext(host, ERROR_CONTEXT);
14838
- if (!errorStore) {
14839
- throw err;
15204
+ // `null` would collide with the capture-only sentinel, so wrap every nullish throw.
15205
+ const storedError = err == null ? toBoundaryError(err) : err;
15206
+ let current = host;
15207
+ while (current) {
15208
+ const boundaryHost = this.resolveContextHost(current, ERROR_CONTEXT);
15209
+ if (!boundaryHost) {
15210
+ break;
15211
+ }
15212
+ const store = getOwnErrorBoundaryStore(this, boundaryHost);
15213
+ if (store && store.error === undefined) {
15214
+ store.error = storedError;
15215
+ const boundaryProps = this.getHostProp(boundaryHost, ELEMENT_PROPS);
15216
+ fireOnError(boundaryProps?.onError$, err, phase, store.boundaryId ?? '');
15217
+ markVNodeDirty(this, boundaryHost, 4 /* ChoreBits.COMPONENT */);
15218
+ return;
15219
+ }
15220
+ // Capture-only sentinel for the ErrorProvider test spy; folds away in prod builds.
15221
+ if (qTest && store && store.error === null) {
15222
+ store.error = storedError;
15223
+ return;
15224
+ }
15225
+ if (boundaryHost.dirty & 4 /* ChoreBits.COMPONENT */) {
15226
+ logError(err);
15227
+ return;
15228
+ }
15229
+ current = this.getParentHost(boundaryHost);
14840
15230
  }
14841
- errorStore.error = err;
15231
+ logErrorAndThrowAsync(err);
14842
15232
  }
14843
15233
  setContext(host, context, value) {
14844
15234
  let ctx = this.getHostProp(host, QCtxAttr);
@@ -14848,14 +15238,20 @@ class DomContainer extends _SharedContainer {
14848
15238
  mapArray_set(ctx, context.id, value, 0, true);
14849
15239
  }
14850
15240
  resolveContext(host, contextId) {
15241
+ const found = this.resolveContextHost(host, contextId);
15242
+ return found
15243
+ ? mapArray_get(this.getHostProp(found, QCtxAttr), contextId.id, 0)
15244
+ : undefined;
15245
+ }
15246
+ resolveContextHost(host, contextId) {
14851
15247
  while (host) {
14852
15248
  const ctx = this.getHostProp(host, QCtxAttr);
14853
15249
  if (ctx != null && mapArray_has(ctx, contextId.id, 0)) {
14854
- return mapArray_get(ctx, contextId.id, 0);
15250
+ return host;
14855
15251
  }
14856
15252
  host = this.getParentHost(host);
14857
15253
  }
14858
- return undefined;
15254
+ return null;
14859
15255
  }
14860
15256
  getParentHost(host) {
14861
15257
  let vNode = host.parent;
@@ -16867,13 +17263,217 @@ const useTask$ = /*#__PURE__*/ implicit$FirstArg(useTaskQrl);
16867
17263
  // We need to cast to help out the api extractor
16868
17264
  const useVisibleTask$ = /*#__PURE__*/ implicit$FirstArg(useVisibleTaskQrl);
16869
17265
 
16870
- /** @public */
16871
- const useErrorBoundary = () => {
16872
- const error = useStore({ error: undefined });
17266
+ const createErrorBoundaryStore = () => Object.defineProperty({ error: undefined }, 'error', { enumerable: false });
17267
+ /** @internal */
17268
+ const useErrorBoundaryStore = () => {
17269
+ const error = useStore(createErrorBoundaryStore);
16873
17270
  useContextProvider(ERROR_CONTEXT, error);
16874
17271
  return error;
16875
17272
  };
16876
17273
 
17274
+ /** Finalizes a deferred segment and emits its swap scripts; shared by Suspense and ErrorBoundary. */
17275
+ async function finalizeAndSwapOutOfOrderSegment(ssr, boundaryId, rendered, revealBoundary) {
17276
+ const segmentId = String(boundaryId);
17277
+ const result = await rendered.container.$finalizeOutOfOrderSegment$(segmentId, rendered);
17278
+ ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"${revealBoundary?.attrs ?? ''}>`);
17279
+ ssr.write(result.html);
17280
+ ssr.write('</template>');
17281
+ ssr.emitOutOfOrderSegmentScripts(result.scripts);
17282
+ ssr.emitOutOfOrderExecutorIfNeeded();
17283
+ ssr.emitInlineScript(`qO(${boundaryId})`);
17284
+ const errorSwapIds = rendered.container.$errorSwapIds$;
17285
+ if (__EXPERIMENTAL__.errorBoundary && errorSwapIds?.length) {
17286
+ ssr.emitErrorSwapExecutorIfNeeded();
17287
+ for (let i = 0; i < errorSwapIds.length; i++) {
17288
+ ssr.emitInlineScript(`qErr(${errorSwapIds[i]})`);
17289
+ }
17290
+ }
17291
+ // qO() is the browser-visible handoff for this segment, so flush it immediately.
17292
+ await ssr.streamHandler.flush();
17293
+ }
17294
+
17295
+ /** @internal */
17296
+ const errorBoundaryReset = () => {
17297
+ const [host] = _captures;
17298
+ // this is executed only on client
17299
+ const container = tryGetInvokeContext()?.$container$;
17300
+ const isBrowserEnv = qTest ? !isServerPlatform() : isBrowser$1;
17301
+ if (isBrowserEnv && host && container) {
17302
+ resetErrorBoundary(container, host);
17303
+ }
17304
+ };
17305
+ const RESET_KEY_SUFFIX = '\0';
17306
+ /** @internal */
17307
+ function resetErrorBoundary(container, host) {
17308
+ const boundaryHost = container.resolveContextHost(host, ERROR_CONTEXT);
17309
+ if (!boundaryHost) {
17310
+ return;
17311
+ }
17312
+ const store = getOwnErrorBoundaryStore(container, boundaryHost);
17313
+ if (!store) {
17314
+ return;
17315
+ }
17316
+ scheduleBoundaryContentReset(container, boundaryHost, store.projectedContentOwner ?? null);
17317
+ store.error = undefined;
17318
+ }
17319
+ function scheduleBoundaryContentReset(container, boundaryHost, recordedContentOwner) {
17320
+ let resetHost = boundaryHost;
17321
+ let contentOwner = null;
17322
+ let vNode = vnode_getProjectionParentOrParent(boundaryHost);
17323
+ let crossedProjection = false;
17324
+ while (vNode) {
17325
+ if (vnode_isVirtualVNode(vNode)) {
17326
+ if (vnode_getProp(vNode, QSlot, null) !== null) {
17327
+ crossedProjection = true;
17328
+ }
17329
+ else if (vnode_getProp(vNode, OnRenderProp, null) !== null) {
17330
+ if (!crossedProjection) {
17331
+ const ownerBoundary = getOwnErrorBoundaryStore(container, vNode);
17332
+ if (!ownerBoundary || ownerBoundary.error !== undefined) {
17333
+ if (contentOwner) {
17334
+ resetHost = contentOwner;
17335
+ }
17336
+ contentOwner = vNode;
17337
+ if (ownerBoundary?.error !== undefined || !hasSlotProps(vNode.props)) {
17338
+ break;
17339
+ }
17340
+ }
17341
+ }
17342
+ crossedProjection = false;
17343
+ }
17344
+ }
17345
+ vNode = vnode_getProjectionParentOrParent(vNode);
17346
+ }
17347
+ if (recordedContentOwner && recordedContentOwner !== contentOwner) {
17348
+ resetHost = contentOwner ?? resetHost;
17349
+ contentOwner = recordedContentOwner;
17350
+ }
17351
+ if (contentOwner) {
17352
+ // Force keyed diff to recreate emptied projected content.
17353
+ resetHost.key = `${resetHost.key ?? ''}${RESET_KEY_SUFFIX}`;
17354
+ markVNodeDirty(container, contentOwner, 4 /* ChoreBits.COMPONENT */);
17355
+ }
17356
+ else {
17357
+ markVNodeDirty(container, boundaryHost, 4 /* ChoreBits.COMPONENT */);
17358
+ }
17359
+ }
17360
+ const renderFallbackOrLastResort = (fallbackQrl, error, reset) => {
17361
+ return fallbackQrl(error, reset).catch((err) => {
17362
+ if (fallbackQrl.resolved !== undefined) {
17363
+ throw err;
17364
+ }
17365
+ return /*#__PURE__*/ _jsxSorted('div', { role: 'alert' }, null, 'Something went wrong.', 0, null);
17366
+ });
17367
+ };
17368
+ const buildSSRErrorBoundaryHosts = (store, container) => {
17369
+ const boundaryId = container?.nextOutOfOrderId(false) ?? 0;
17370
+ return [
17371
+ /*#__PURE__*/ _jsxSorted('div', {
17372
+ [QErrorContentHost]: String(boundaryId),
17373
+ style: 'display:contents',
17374
+ }, null,
17375
+ /*#__PURE__*/ _jsxSorted(Slot, null, null, null, 0, null), 1, null),
17376
+ /*#__PURE__*/ _jsxSorted(SSRErrorFallbackHost, {
17377
+ boundaryId,
17378
+ store,
17379
+ }, null, null, 1, null),
17380
+ ];
17381
+ };
17382
+ /** @internal */
17383
+ const errorBoundaryCmp = (props) => {
17384
+ if (!__EXPERIMENTAL__.errorBoundary) {
17385
+ throw new Error('<ErrorBoundary> requires the `errorBoundary` experimental feature. Enable it in your Qwik Vite config: qwikVite({ experimental: ["errorBoundary"] }).');
17386
+ }
17387
+ const store = useErrorBoundaryStore();
17388
+ const invokeCtx = tryGetInvokeContext();
17389
+ const container = invokeCtx?.$container$;
17390
+ if (container && (getStoreTarget(store) ?? store).boundaryId === undefined) {
17391
+ store.boundaryId = getNextUniqueIndex(container);
17392
+ }
17393
+ const isServerEnv = qTest ? isServerPlatform() : !isBrowser$1;
17394
+ if (!isServerEnv && store.error === undefined) {
17395
+ return /*#__PURE__*/ _jsxSorted(Slot, null, null, null, 0, null);
17396
+ }
17397
+ const reset = /*#__PURE__*/ inlinedQrl(errorBoundaryReset, '_ebR', [invokeCtx?.$hostElement$]);
17398
+ if (isServerEnv) {
17399
+ const fallbackQrl = props.fallback$;
17400
+ store.$fallback$ = noSerialize((error) => fallbackQrl(error, reset));
17401
+ const onErrorQrl = props.onError$;
17402
+ if (onErrorQrl) {
17403
+ store.$onError$ = noSerialize((error, info) => onErrorQrl(error, info));
17404
+ }
17405
+ return buildSSRErrorBoundaryHosts(store, container);
17406
+ }
17407
+ const displayError = redactBoundaryErrorForDisplay(store.error, true);
17408
+ return /*#__PURE__*/ _jsxSorted(Fragment, null, null, renderFallbackOrLastResort(props.fallback$, displayError, reset), 0, null);
17409
+ };
17410
+ /** Renders `fallback$` instead of its children when a descendant throws. @public @experimental */
17411
+ const ErrorBoundary =
17412
+ /*#__PURE__*/ componentQrl(
17413
+ /*#__PURE__*/ inlinedQrl(errorBoundaryCmp, ERROR_BOUNDARY_QRL_SYMBOL));
17414
+ const consumeSSRErrorFallback = (ssr, store) => {
17415
+ const fallback = store.$fallback$;
17416
+ delete store.$fallback$;
17417
+ const projected = redactBoundaryErrorForDisplay(store.error, isDev, ssr.$transformError$);
17418
+ return fallback(projected);
17419
+ };
17420
+ const SSRErrorFallbackRenderer = __EXPERIMENTAL__.errorBoundary
17421
+ ? /*#__PURE__*/ createInternalServerComponent((ssr, jsx, options, enqueue) => {
17422
+ const boundaryId = jsx.varProps.boundaryId;
17423
+ const store = jsx.varProps.store;
17424
+ if (jsx.varProps.deliverLate) {
17425
+ const streamFallback = async (error) => {
17426
+ if (!store.$fallback$) {
17427
+ return;
17428
+ }
17429
+ // The catch site already recorded it; marking again refires onError$.
17430
+ if (store.error !== error) {
17431
+ markBoundaryErrored(store, error, "render" /* ErrorBoundaryPhase.Render */);
17432
+ }
17433
+ const segment = await ssr.segment(`${boundaryId}`, consumeSSRErrorFallback(ssr, store), options);
17434
+ // qErr hides the errored content host and strips its broadcast handlers.
17435
+ segment.container.$registerErrorSwap$(boundaryId);
17436
+ await ssr.$runQueuedRender$(() => finalizeAndSwapOutOfOrderSegment(ssr, boundaryId, segment, null));
17437
+ };
17438
+ store.$emitFallback$ = noSerialize(streamFallback);
17439
+ ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"></template>`);
17440
+ if (store.error !== undefined) {
17441
+ return streamFallback(store.error);
17442
+ }
17443
+ return;
17444
+ }
17445
+ if (store.error === undefined || !store.$fallback$) {
17446
+ return;
17447
+ }
17448
+ if (isOutOfOrderSegmentContainer(ssr)) {
17449
+ ssr.$registerErrorSwap$(boundaryId);
17450
+ }
17451
+ else {
17452
+ enqueue(() => {
17453
+ ssr.emitErrorSwapExecutorIfNeeded();
17454
+ ssr.emitInlineScript(`qErr(${boundaryId})`);
17455
+ });
17456
+ }
17457
+ enqueue(consumeSSRErrorFallback(ssr, store));
17458
+ })
17459
+ : null;
17460
+ const SSRErrorFallbackHost = __EXPERIMENTAL__.errorBoundary
17461
+ ? /*#__PURE__*/ createInternalServerComponent((ssr, jsx, _options, enqueue) => {
17462
+ const boundaryId = jsx.varProps.boundaryId;
17463
+ const store = jsx.varProps.store;
17464
+ const deliverLate = __EXPERIMENTAL__.suspense &&
17465
+ ssr.outOfOrderStreaming &&
17466
+ !isOutOfOrderSegmentContainer(ssr) &&
17467
+ (store.error === undefined || isErrorFromDeferredSegment(store));
17468
+ enqueue(
17469
+ /*#__PURE__*/ _jsxSorted('div', {
17470
+ [deliverLate ? QSuspenseResultParent : QErrorFallbackHost]: String(boundaryId),
17471
+ style: 'display:none',
17472
+ }, null,
17473
+ /*#__PURE__*/ _jsxSorted(SSRErrorFallbackRenderer, { boundaryId, store, deliverLate }, null, null, 1, null), 1, null));
17474
+ })
17475
+ : null;
17476
+
16877
17477
  /** @internal */
16878
17478
  const eachCmpTask = async ({ track }) => {
16879
17479
  const props = _captures[0];
@@ -17164,10 +17764,23 @@ const SSRDeferredSlot = __EXPERIMENTAL__.suspense
17164
17764
  const boundaryState = jsx.varProps.boundary;
17165
17765
  const contentStyle = jsx.varProps.contentStyle;
17166
17766
  const revealBoundary = jsx.varProps.reveal;
17767
+ const errorBoundaryStore = __EXPERIMENTAL__.errorBoundary && options.parentComponentFrame
17768
+ ? ssr.resolveContext(options.parentComponentFrame.componentNode, ERROR_CONTEXT)
17769
+ : undefined;
17167
17770
  const content = ssr.segment(contentSegment, createClaimedDeferredSlot(ssr, jsx, options), options);
17168
17771
  ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"></template>`);
17169
17772
  ssr.emitOutOfOrderExecutorIfNeeded();
17170
- ssr.queueOutOfOrderSegment(content.then((rendered) => emitRenderedOutOfOrderSegment(ssr, boundaryId, contentSegment, rendered, contentStyle, revealBoundary, boundaryState)));
17773
+ ssr.queueOutOfOrderSegment(content
17774
+ .then((rendered) => emitRenderedOutOfOrderSegment(ssr, boundaryId, rendered, contentStyle, revealBoundary, boundaryState))
17775
+ .catch((error) => {
17776
+ if (errorBoundaryStore?.$emitFallback$) {
17777
+ return errorBoundaryStore.$emitFallback$(error);
17778
+ }
17779
+ if (errorBoundaryStore?.error !== undefined) {
17780
+ return;
17781
+ }
17782
+ throw error;
17783
+ }));
17171
17784
  })
17172
17785
  : null;
17173
17786
  function createClaimedDeferredSlot(ssr, jsx, options) {
@@ -17183,7 +17796,7 @@ function createClaimedDeferredSlot(ssr, jsx, options) {
17183
17796
  }
17184
17797
  return /*#__PURE__*/ _jsxSorted(Slot, jsx.varProps, jsx.constProps, slotChildren, jsx.flags, jsx.key);
17185
17798
  }
17186
- async function emitRenderedOutOfOrderSegment(ssr, boundaryId, segmentId, rendered, contentStyle, revealBoundary, boundaryState) {
17799
+ async function emitRenderedOutOfOrderSegment(ssr, boundaryId, rendered, contentStyle, revealBoundary, boundaryState) {
17187
17800
  if (boundaryState) {
17188
17801
  boundaryState.contentResolved = true;
17189
17802
  if (boundaryState.delayTimer) {
@@ -17194,14 +17807,7 @@ async function emitRenderedOutOfOrderSegment(ssr, boundaryId, segmentId, rendere
17194
17807
  revealBoundary?.resolve();
17195
17808
  await ssr.$runQueuedRender$(async () => {
17196
17809
  ssr.addRoot(contentStyle);
17197
- const result = await rendered.container.$finalizeOutOfOrderSegment$(segmentId, rendered);
17198
- ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"${revealBoundary?.attrs ?? ''}>`);
17199
- ssr.write(result.html);
17200
- ssr.write('</template>');
17201
- ssr.emitOutOfOrderSegmentScripts(result.scripts);
17202
- ssr.emitInlineScript(`qO(${boundaryId})`);
17203
- // qO() is the browser-visible handoff for this segment, so flush it immediately.
17204
- await ssr.streamHandler.flush();
17810
+ await finalizeAndSwapOutOfOrderSegment(ssr, boundaryId, rendered, revealBoundary);
17205
17811
  });
17206
17812
  }
17207
17813
  function scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state) {
@@ -17316,5 +17922,5 @@ if (import.meta.hot) {
17316
17922
  });
17317
17923
  }
17318
17924
 
17319
- export { $, Each, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, Reveal, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, Show, SkipRender, Slot, Suspense, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, ELEMENT_SEQ as _ELEMENT_SEQ, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, SubscriptionPatch as _SubscriptionPatch, Task as _Task, _UNINITIALIZED, _VAR_PROPS, _addProjection, _captures, _chk, _createDeserializeContainer, createQRL as _createQRL, createStore as _createStore, delay as _delay, _deserialize, _dumpState, eachCmp as _eaC, eachCmpTask as _eaT, _executeSsrChores, _fnSignal, getAsyncLocalStorage as _getAsyncLocalStorage, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, getSubscriber as _getSubscriber, _getVarProps, _hasStoreEffects, _hmr, _injectAsyncSignalValue, invoke as _invoke, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, _markSignalAsExternallyOwned, newInvokeContext as _newInvokeContext, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _qrlWithChunk, _qrlWithChunkDEV, revealCmp as _reC, revealCanReveal as _reR, revealCleanupTask as _reT, _regSymbol, _removeProjection, _res, _resolveContextWithoutSequentialScope, _restProps, retryOnPromise as _retryOnPromise, _rsc, _run, _serialize, setEvent as _setEvent, _setProjectionTarget, showCmp as _shC, showCmpTask as _shT, suspenseCmp as _suC, suspenseTask as _suT, scheduleTask as _task, _updateProjectionProps, _useHmr, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getElementName as _vnode_getElementName, vnode_getFirstChild as _vnode_getFirstChild, vnode_getProp as _vnode_getProp, vnode_getVNodeForChildNode as _vnode_getVNodeForChildNode, vnode_insertBefore as _vnode_insertBefore, vnode_isElementVNode as _vnode_isElementVNode, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_newVirtual as _vnode_newVirtual, vnode_remove as _vnode_remove, vnode_setProp as _vnode_setProp, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsyncSignal as createAsyncQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getClientManifest, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useComputed$, useComputedQrl, useConstant, useContext, useContextProvider, useErrorBoundary, useId, useLexicalScope, useOn, useOnDocument, useOnWindow, useResource$, useResourceQrl, useSerializer$, useSerializerQrl, useServerData, useSignal, useStore, useStyles$, useStylesQrl, useStylesScoped$, useStylesScopedQrl, useTask$, useTaskQrl, useVisibleTask$, useVisibleTaskQrl, version, withLocale };
17925
+ export { $, Each, ErrorBoundary, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, Reveal, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, Show, SkipRender, Slot, Suspense, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, ELEMENT_SEQ as _ELEMENT_SEQ, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, SubscriptionPatch as _SubscriptionPatch, Task as _Task, _UNINITIALIZED, _VAR_PROPS, _addProjection, _captures, _chk, _createDeserializeContainer, createQRL as _createQRL, createStore as _createStore, delay as _delay, _deserialize, _dumpState, eachCmp as _eaC, eachCmpTask as _eaT, errorBoundaryCmp as _ebC, errorBoundaryReset as _ebR, _executeSsrChores, _fnSignal, getAsyncLocalStorage as _getAsyncLocalStorage, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, getSubscriber as _getSubscriber, _getVarProps, handleSSRError as _handleSSRError, _hasStoreEffects, _hmr, _injectAsyncSignalValue, invoke as _invoke, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, _markSignalAsExternallyOwned, newInvokeContext as _newInvokeContext, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _qrlWithChunk, _qrlWithChunkDEV, revealCmp as _reC, revealCanReveal as _reR, revealCleanupTask as _reT, _regSymbol, _removeProjection, _res, _resolveContextWithoutSequentialScope, _restProps, retryOnPromise as _retryOnPromise, _rsc, _run, _serialize, setEvent as _setEvent, _setProjectionTarget, showCmp as _shC, showCmpTask as _shT, suspenseCmp as _suC, suspenseTask as _suT, scheduleTask as _task, _updateProjectionProps, _useHmr, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getElementName as _vnode_getElementName, vnode_getFirstChild as _vnode_getFirstChild, vnode_getProp as _vnode_getProp, vnode_getVNodeForChildNode as _vnode_getVNodeForChildNode, vnode_insertBefore as _vnode_insertBefore, vnode_isElementVNode as _vnode_isElementVNode, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_newVirtual as _vnode_newVirtual, vnode_remove as _vnode_remove, vnode_setProp as _vnode_setProp, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsyncSignal as createAsyncQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getClientManifest, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useComputed$, useComputedQrl, useConstant, useContext, useContextProvider, useId, useLexicalScope, useOn, useOnDocument, useOnWindow, useResource$, useResourceQrl, useSerializer$, useSerializerQrl, useServerData, useSignal, useStore, useStyles$, useStylesQrl, useStylesScoped$, useStylesScopedQrl, useTask$, useTaskQrl, useVisibleTask$, useVisibleTaskQrl, version, withLocale };
17320
17926
  //# sourceMappingURL=core.mjs.map