@qwik.dev/core 2.0.0-beta.38 → 2.0.0-beta.39

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.38-dev+0339f17
3
+ * @qwik.dev/core 2.0.0-beta.39-dev+6fb620f
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
@@ -321,6 +321,7 @@ const VNodeDataChar = {
321
321
  CLOSE: /* ************* */ 125, // `}` is the end of the VNodeData for a virtual element.
322
322
  SCOPED_STYLE: /* ******* */ 59, // `;` - `q:sstyle` - Style attribute.
323
323
  RENDER_FN: /* ********** */ 60, // `<` - `q:renderFn' - Component QRL render function (body)
324
+ RENDER_HASH_PREFIX: /* **/ 95, // `_` after `<` identifies a component hash.
324
325
  ID: /* ***************** */ 61, // `=` - `q:id` - ID of the element.
325
326
  PROPS: /* ************** */ 62, // `>` - `q:props' - Component Props
326
327
  SLOT_PARENT: /* ******** */ 63, // `?` - `q:sparent` - Slot parent.
@@ -405,6 +406,7 @@ function decodeVNodeDataString(str) {
405
406
 
406
407
  /** State factory of the component. */
407
408
  const OnRenderProp = 'q:renderFn';
409
+ const QComponentHash = 'q:componentHash';
408
410
  /** Target DOM element for external projection rendering. */
409
411
  const QTargetElement = 'q:targetEl';
410
412
  /** Component style content prefix */
@@ -438,7 +440,6 @@ const QIgnore = 'q:ignore';
438
440
  const QIgnoreEnd = '/' + QIgnore;
439
441
  const QContainerAttr = 'q:container';
440
442
  const QContainerAttrEnd = '/' + QContainerAttr;
441
- const QCursorBoundary = 'q:cursorBoundary';
442
443
  const QTemplate = 'q:template';
443
444
  // the same selector should be inside the qwik loader
444
445
  // and the same selector should be inside the qwik router spa-shim and spa-init
@@ -479,6 +480,7 @@ const NON_SERIALIZABLE_MARKER_PREFIX = ':';
479
480
  const USE_ON_LOCAL = NON_SERIALIZABLE_MARKER_PREFIX + 'on';
480
481
  const USE_ON_LOCAL_SEQ_IDX = NON_SERIALIZABLE_MARKER_PREFIX + 'onIdx';
481
482
  const USE_ON_LOCAL_FLAGS = NON_SERIALIZABLE_MARKER_PREFIX + 'onFlags';
483
+ const QCursorBoundary = NON_SERIALIZABLE_MARKER_PREFIX + 'cursorBoundary';
482
484
  const NEAREST_CURSOR_BOUNDARY = NON_SERIALIZABLE_MARKER_PREFIX + 'nearestCursorBoundary';
483
485
  const Q_PROPS_SEPARATOR = ':';
484
486
  const dangerouslySetInnerHTML = 'dangerouslySetInnerHTML';
@@ -1264,7 +1266,7 @@ const COMMA = ',';
1264
1266
  *
1265
1267
  * @public
1266
1268
  */
1267
- const version = "2.0.0-beta.38-dev+0339f17";
1269
+ const version = "2.0.0-beta.39-dev+6fb620f";
1268
1270
 
1269
1271
  const isNode = (value) => {
1270
1272
  return value && typeof value.nodeType === 'number';
@@ -2314,7 +2316,7 @@ class Job {
2314
2316
  /** Backward compatible cache method for resource */
2315
2317
  cache() {
2316
2318
  isDev &&
2317
- console.error('useResource cache() method does not do anything. Use `useComputed$` instead of `useResource$`, use the `expires` option for polling behavior.');
2319
+ console.error('useResource cache() method does not do anything. Use `useComputed$` instead of `useResource$`; for polling use the `usePoll` hook from `@qwik.dev/utils`.');
2318
2320
  }
2319
2321
  get previous() {
2320
2322
  const val = this.$signal$.$untrackedValue$;
@@ -2333,7 +2335,7 @@ class Job {
2333
2335
  *
2334
2336
  * Sync compute functions resolve synchronously and every read they perform is auto-tracked. When
2335
2337
  * the compute function turns out to be async (it returned a promise), the signal lazily switches on
2336
- * the async engine — jobs, `loading`, `error`, polling — giving it the same API as an AsyncSignal.
2338
+ * the async engine — jobs, `loading`, `error` — giving it the same API as an AsyncSignal.
2337
2339
  * Auto-tracking only covers reads before the first await point (the invoke context is lost after
2338
2340
  * it); later reads must use the ComputeCtx `track()`.
2339
2341
  */
@@ -2381,20 +2383,11 @@ class ComputedSignalImpl extends SignalImpl {
2381
2383
  // clientOnly can never resolve during SSR, so it must be async from the start
2382
2384
  this.$flags$ |= 64 /* AsyncSignalFlags.CLIENT_ONLY */ | 512 /* AsyncSignalFlags.ASYNC_MODE */;
2383
2385
  }
2384
- if (options.allowStale === false) {
2385
- if (isDev && initial !== undefined) {
2386
- throw new Error('allowStale: false and initial cannot be used together. ' +
2387
- 'allowStale: false clears the value on invalidation, which conflicts with providing an initial value.');
2388
- }
2389
- this.$flags$ |= 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */;
2390
- }
2391
- const expires = options.expires ?? (options.interval ? Math.abs(options.interval) : undefined);
2392
- if (expires) {
2393
- this.expires = expires;
2394
- }
2395
- if (options.poll === false || (options.interval !== undefined && options.interval < 0)) {
2396
- this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
2397
- }
2386
+ }
2387
+ /** Clear the value so readers see the loading state, then recompute. */
2388
+ clear() {
2389
+ this.$untrackedValue$ = NEEDS_COMPUTATION;
2390
+ this.invalidate();
2398
2391
  }
2399
2392
  invalidate(info) {
2400
2393
  if (arguments.length > 0) {
@@ -2402,7 +2395,7 @@ class ComputedSignalImpl extends SignalImpl {
2402
2395
  this.$infoVersion$ = this.$infoVersion$ === undefined ? 1 : this.$infoVersion$ + 1;
2403
2396
  }
2404
2397
  if (this.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */) {
2405
- this.$setInvalid$(true, this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */);
2398
+ this.$setInvalid$(true);
2406
2399
  return;
2407
2400
  }
2408
2401
  this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
@@ -2450,9 +2443,7 @@ class ComputedSignalImpl extends SignalImpl {
2450
2443
  else if (this.$current$) {
2451
2444
  this.$current$.$canWrite$ = false;
2452
2445
  }
2453
- this.$clearNextPoll$();
2454
2446
  super.value = value;
2455
- this.$scheduleNextPoll$();
2456
2447
  return;
2457
2448
  }
2458
2449
  super.value = value;
@@ -2572,52 +2563,8 @@ class ComputedSignalImpl extends SignalImpl {
2572
2563
  }
2573
2564
  return this.$untrackedError$;
2574
2565
  }
2575
- get expires() {
2576
- return this.$expires$ || 0;
2577
- }
2578
- set expires(value) {
2579
- this.$clearNextPoll$();
2580
- this.$expires$ = value;
2581
- if (this.$expires$ && this.$hasSubscribers$()) {
2582
- this.$scheduleNextPoll$();
2583
- }
2584
- }
2585
- get poll() {
2586
- return !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
2587
- }
2588
- set poll(value) {
2589
- if (value) {
2590
- this.$flags$ &= -257 /* AsyncSignalFlags.NO_POLL */;
2591
- }
2592
- else {
2593
- this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
2594
- }
2595
- // Reschedule since poll behavior changed
2596
- if (this.$expires$ && this.$hasSubscribers$()) {
2597
- this.$clearNextPoll$();
2598
- this.$scheduleNextPoll$();
2599
- }
2600
- }
2601
- /** @deprecated Use `expires` and `poll` instead. */
2602
- get interval() {
2603
- const expires = this.$expires$ || 0;
2604
- return this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */ ? -expires : expires;
2605
- }
2606
- set interval(value) {
2607
- if (value < 0) {
2608
- this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
2609
- }
2610
- else {
2611
- this.$flags$ &= -257 /* AsyncSignalFlags.NO_POLL */;
2612
- }
2613
- this.expires = Math.abs(value);
2614
- }
2615
- $setInvalid$(allowRecalc, mustClear) {
2566
+ $setInvalid$(allowRecalc) {
2616
2567
  this.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
2617
- this.$clearNextPoll$();
2618
- if (mustClear) {
2619
- this.$untrackedValue$ = NEEDS_COMPUTATION;
2620
- }
2621
2568
  if (allowRecalc &&
2622
2569
  (this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size)) {
2623
2570
  // compute in next microtask
@@ -2742,7 +2689,6 @@ class ComputedSignalImpl extends SignalImpl {
2742
2689
  this.$container$?.serializationCtx.$eagerResume$.add(this);
2743
2690
  return;
2744
2691
  }
2745
- this.$clearNextPoll$();
2746
2692
  // Clear flag here to make sure the cleanups don't start another compute
2747
2693
  this.$flags$ &= -2 /* ComputedSignalFlags.INVALID */;
2748
2694
  const current = this.$current$;
@@ -2845,7 +2791,6 @@ class ComputedSignalImpl extends SignalImpl {
2845
2791
  }
2846
2792
  else {
2847
2793
  this.untrackedPending = false;
2848
- this.$scheduleNextPoll$();
2849
2794
  }
2850
2795
  }
2851
2796
  }
@@ -2868,7 +2813,6 @@ class ComputedSignalImpl extends SignalImpl {
2868
2813
  }
2869
2814
  /** Called after SSR/unmount */
2870
2815
  async $destroy$() {
2871
- this.$clearNextPoll$();
2872
2816
  clearTimeout(this.$computationTimeoutId$);
2873
2817
  const current = this.$current$;
2874
2818
  if (current) {
@@ -2881,24 +2825,6 @@ class ComputedSignalImpl extends SignalImpl {
2881
2825
  await current?.$promise$;
2882
2826
  }
2883
2827
  }
2884
- $clearNextPoll$() {
2885
- if (this.$pollTimeoutId$ !== undefined) {
2886
- clearTimeout(this.$pollTimeoutId$);
2887
- this.$pollTimeoutId$ = undefined;
2888
- }
2889
- }
2890
- $scheduleNextPoll$() {
2891
- if ((qTest ? isServerPlatform() : isServer) || !this.$expires$) {
2892
- return;
2893
- }
2894
- this.$clearNextPoll$();
2895
- const allowRecalc = !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
2896
- // Even when clear on invalidate, we don't clear if we're merely re-running due to polling
2897
- // We expect to get the new value soon, so we can avoid showing a loading state
2898
- const mustClear = this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */ && !allowRecalc;
2899
- this.$pollTimeoutId$ = setTimeout(() => this.$setInvalid$(allowRecalc, mustClear), this.$expires$);
2900
- this.$pollTimeoutId$?.unref?.();
2901
- }
2902
2828
  $hasSubscribers$() {
2903
2829
  return !!(this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size);
2904
2830
  }
@@ -3053,9 +2979,9 @@ class SerializerSignalImpl extends ComputedSignalImpl {
3053
2979
  *
3054
2980
  * # ================================
3055
2981
  *
3056
- * The async engine (jobs, loading, error, polling) lives in ComputedSignalImpl; this subclass
3057
- * configures it from options and switches the compute invocation to CTX_ARG mode: the compute fn
3058
- * receives the ComputeCtx argument and tracks only via its explicit `track()` (no auto-tracking).
2982
+ * The async engine (jobs, loading, error) lives in ComputedSignalImpl; this subclass configures it
2983
+ * from options and switches the compute invocation to CTX_ARG mode: the compute fn receives the
2984
+ * ComputeCtx argument and tracks only via its explicit `track()` (no auto-tracking).
3059
2985
  *
3060
2986
  * @internal
3061
2987
  */
@@ -4066,31 +3992,25 @@ const useConstant = (value, ...args) => {
4066
3992
  return set(value);
4067
3993
  };
4068
3994
 
4069
- const createCursorBoundary = () => {
4070
- return {
4071
- pending: createSignal(0),
4072
- version: createSignal(0),
4073
- };
4074
- };
4075
3995
  /** @internal */
4076
3996
  const useCursorBoundary = () => {
4077
3997
  if (!__EXPERIMENTAL__.suspense) {
4078
3998
  throw new Error('useCursorBoundary is experimental and must be enabled with `experimental: ["suspense"]` in the `qwikVite` plugin.');
4079
3999
  }
4080
- return useConstant(createCursorBoundary);
4000
+ return useSignal(0);
4081
4001
  };
4082
4002
  function addCursorBoundary(cursorData, vNode) {
4083
4003
  if (!__EXPERIMENTAL__.suspense) {
4084
4004
  return;
4085
4005
  }
4086
- const boundary = getNearestCursorBoundary(cursorData.container, vNode);
4006
+ const boundary = getNearestCursorBoundary(vNode);
4087
4007
  if (!boundary) {
4088
4008
  return;
4089
4009
  }
4090
4010
  const boundaries = (cursorData.boundaries ||= []);
4091
4011
  if (!boundaries.includes(boundary)) {
4092
4012
  boundaries.push(boundary);
4093
- boundary.pending.value++;
4013
+ boundary.value++;
4094
4014
  }
4095
4015
  }
4096
4016
  function resolveCursorBoundaries(cursorData) {
@@ -4104,40 +4024,35 @@ function resolveCursorBoundaries(cursorData) {
4104
4024
  cursorData.boundaries = null;
4105
4025
  for (let i = 0; i < boundaries.length; i++) {
4106
4026
  const boundary = boundaries[i];
4107
- boundary.pending.value = Math.max(0, boundary.pending.value - 1);
4108
- boundary.version.value++;
4027
+ boundary.value = Math.max(0, boundary.value - 1);
4109
4028
  }
4110
4029
  }
4111
- function getOwnCursorBoundary(container, vNode) {
4030
+ function getOwnCursorBoundary(vNode) {
4112
4031
  if (!__EXPERIMENTAL__.suspense) {
4113
4032
  return null;
4114
4033
  }
4115
- return container.getHostProp(vNode, QCursorBoundary);
4116
- }
4117
- function getNearestCursorBoundaryProp(vNode) {
4118
- if (!__EXPERIMENTAL__.suspense) {
4119
- return null;
4120
- }
4121
- return (vnode_getProp(vNode, NEAREST_CURSOR_BOUNDARY, null) ||
4122
- null);
4034
+ return vnode_getProp(vNode, QCursorBoundary, null) || null;
4123
4035
  }
4124
4036
  function clearNearestCursorBoundary(vNode) {
4125
- if (!__EXPERIMENTAL__.suspense) {
4126
- return;
4127
- }
4128
- vnode_setProp(vNode, NEAREST_CURSOR_BOUNDARY, null);
4037
+ setNearestCursorBoundary(vNode, null);
4129
4038
  }
4130
- function getNearestCursorBoundary(container, vNode) {
4039
+ function getNearestCursorBoundary(vNode) {
4131
4040
  if (!__EXPERIMENTAL__.suspense) {
4132
4041
  return null;
4133
4042
  }
4134
- return getNearestCursorBoundaryProp(vNode) || getOwnCursorBoundary(container, vNode);
4043
+ return (vnode_getProp(vNode, NEAREST_CURSOR_BOUNDARY, null) ||
4044
+ getOwnCursorBoundary(vNode));
4135
4045
  }
4136
4046
  function setNearestCursorBoundary(vNode, boundary) {
4137
4047
  __EXPERIMENTAL__.suspense && vnode_setProp(vNode, NEAREST_CURSOR_BOUNDARY, boundary);
4138
4048
  }
4049
+ function clearCursorBoundary(vNode) {
4050
+ if (__EXPERIMENTAL__.suspense && vNode.props && QCursorBoundary in vNode.props) {
4051
+ vnode_setProp(vNode, QCursorBoundary, null);
4052
+ }
4053
+ }
4139
4054
  /** Updates the nearest cursor boundary cache on a vnode and any already-dirty descendants. */
4140
- function updateDirtySubtreeCursorBoundary(container, vNode, boundary) {
4055
+ function updateDirtySubtreeCursorBoundary(vNode, boundary) {
4141
4056
  if (!__EXPERIMENTAL__.suspense) {
4142
4057
  return;
4143
4058
  }
@@ -4148,7 +4063,7 @@ function updateDirtySubtreeCursorBoundary(container, vNode, boundary) {
4148
4063
  }
4149
4064
  for (let i = 0; i < dirtyChildren.length; i++) {
4150
4065
  const child = dirtyChildren[i];
4151
- updateDirtySubtreeCursorBoundary(container, child, getOwnCursorBoundary(container, child) || boundary);
4066
+ updateDirtySubtreeCursorBoundary(child, getOwnCursorBoundary(child) || boundary);
4152
4067
  }
4153
4068
  }
4154
4069
 
@@ -4698,7 +4613,7 @@ function expectSlot(diffContext) {
4698
4613
  diffContext.$vNewNode$ = vnode_newVirtual();
4699
4614
  vnode_setProp(diffContext.$vNewNode$, QSlot, slotNameKey);
4700
4615
  vnode_setProp(diffContext.$vNewNode$, QCursorBoundary, cursorBoundary);
4701
- updateDirtySubtreeCursorBoundary(diffContext.$container$, diffContext.$vNewNode$, cursorBoundary);
4616
+ updateDirtySubtreeCursorBoundary(diffContext.$vNewNode$, cursorBoundary);
4702
4617
  vHost && vnode_setProp(vHost, slotNameKey, diffContext.$vNewNode$);
4703
4618
  isDev &&
4704
4619
  vnode_setProp(diffContext.$vNewNode$, DEBUG_TYPE, "P" /* VirtualType.Projection */); // Nothing to project, so render content of the slot.
@@ -4712,7 +4627,7 @@ function expectSlot(diffContext) {
4712
4627
  diffContext.$vNewNode$ = vProjectedNode;
4713
4628
  vnode_setProp(diffContext.$vNewNode$, QSlot, slotNameKey);
4714
4629
  vnode_setProp(diffContext.$vNewNode$, QCursorBoundary, cursorBoundary);
4715
- updateDirtySubtreeCursorBoundary(diffContext.$container$, diffContext.$vNewNode$, cursorBoundary);
4630
+ updateDirtySubtreeCursorBoundary(diffContext.$vNewNode$, cursorBoundary);
4716
4631
  vHost && vnode_setProp(vHost, slotNameKey, diffContext.$vNewNode$);
4717
4632
  isDev &&
4718
4633
  vnode_setProp(diffContext.$vNewNode$, DEBUG_TYPE, "P" /* VirtualType.Projection */);
@@ -5404,7 +5319,9 @@ function getComponentHash(vNode, getObject) {
5404
5319
  return null;
5405
5320
  }
5406
5321
  const qrl = vnode_getProp(vNode, OnRenderProp, getObject);
5407
- return qrl ? qrl.$hash$ : null;
5322
+ return qrl
5323
+ ? qrl.$hash$
5324
+ : vnode_getProp(vNode, QComponentHash, null);
5408
5325
  }
5409
5326
  /**
5410
5327
  * Marker class for JSX projection.
@@ -6029,8 +5946,8 @@ function findFirstElementNode(jsx) {
6029
5946
  function injectPlaceholderElement(jsx, placeholder) {
6030
5947
  // For regular JSX nodes, we can append the placeholder to its children.
6031
5948
  if (isJSXNode(jsx)) {
6032
- // Inline components don't always render children, so we wrap them in Fragment which does.
6033
- if (jsx.type !== Fragment && !isQwikComponent(jsx.type)) {
5949
+ // Inline components may ignore children, while component$ children become projections.
5950
+ if (jsx.type !== Fragment) {
6034
5951
  return _jsxSorted(Fragment, null, null, [jsx, placeholder], 0, null);
6035
5952
  }
6036
5953
  if (jsx.children == null) {
@@ -6994,6 +6911,7 @@ function finishWalk(container, cursor, cursorData, isServer) {
6994
6911
  executeFlushPhase(cursor, container);
6995
6912
  }
6996
6913
  resolveCursorBoundaries(cursorData);
6914
+ clearCursorBoundary(cursor);
6997
6915
  if (cursorData.extraPromises) {
6998
6916
  Promise.all(cursorData.extraPromises).then(() => {
6999
6917
  resolveCursor(container);
@@ -7094,12 +7012,7 @@ function getNextVNode(vNode, cursor, container) {
7094
7012
  return getNextVNode(parent, cursor, container);
7095
7013
  }
7096
7014
  function splitCursorBoundary(container, vNode) {
7097
- if (!__EXPERIMENTAL__.suspense) {
7098
- return false;
7099
- }
7100
- if (!vNode.props ||
7101
- !(QCursorBoundary in vNode.props) ||
7102
- !container.getHostProp(vNode, QCursorBoundary)) {
7015
+ if (!getOwnCursorBoundary(vNode)) {
7103
7016
  return false;
7104
7017
  }
7105
7018
  if (!isCursor(vNode)) {
@@ -7300,17 +7213,16 @@ function propagatePath(target) {
7300
7213
  * Propagates dirty bits from vNode up to the specified cursorRoot. Used during diff when we know
7301
7214
  * the cursor root to merge with. Also updates cursor position if we pass through any cursors.
7302
7215
  */
7303
- function propagateToCursorRoot(container, vNode, cursorRoot) {
7216
+ function propagateToCursorRoot(vNode, cursorRoot) {
7304
7217
  reusablePath.push(vNode);
7305
- let cursorBoundary = getOwnCursorBoundary(container, vNode);
7218
+ let cursorBoundary = getOwnCursorBoundary(vNode);
7306
7219
  let current = vNode.slotParent || vNode.parent;
7307
7220
  while (current) {
7308
7221
  const isDirty = current.dirty & 1023 /* ChoreBits.DIRTY_MASK */;
7309
7222
  const currentIsCursor = isCursor(current);
7310
7223
  if (__EXPERIMENTAL__.suspense) {
7311
7224
  cursorBoundary ||=
7312
- getOwnCursorBoundary(container, current) ||
7313
- (isDirty ? getNearestCursorBoundary(container, current) : null);
7225
+ getOwnCursorBoundary(current) || (isDirty ? getNearestCursorBoundary(current) : null);
7314
7226
  }
7315
7227
  // Stop when we reach the cursor root or a dirty ancestor
7316
7228
  if (current === cursorRoot || isDirty) {
@@ -7345,18 +7257,16 @@ function propagateToCursorRoot(container, vNode, cursorRoot) {
7345
7257
  * Finds a blocking cursor or dirty ancestor and propagates dirty bits to it. Returns true if found
7346
7258
  * and attached, false if a new cursor should be created.
7347
7259
  */
7348
- function findAndPropagateToBlockingCursor(container, vNode) {
7260
+ function findAndPropagateToBlockingCursor(vNode) {
7349
7261
  reusablePath.push(vNode);
7350
- let cursorBoundary = __EXPERIMENTAL__.suspense
7351
- ? getOwnCursorBoundary(container, vNode)
7352
- : null;
7262
+ let cursorBoundary = getOwnCursorBoundary(vNode);
7353
7263
  let current = vNode.slotParent || vNode.parent;
7354
7264
  while (current) {
7355
7265
  const currentIsCursor = isCursor(current);
7356
7266
  if (__EXPERIMENTAL__.suspense) {
7357
7267
  cursorBoundary ||=
7358
- getOwnCursorBoundary(container, current) ||
7359
- (currentIsCursor ? getNearestCursorBoundary(container, current) : null);
7268
+ getOwnCursorBoundary(current) ||
7269
+ (currentIsCursor ? getNearestCursorBoundary(current) : null);
7360
7270
  }
7361
7271
  if (currentIsCursor) {
7362
7272
  // Existing cursor case: attach this dirty vnode to the blocking cursor found above it and
@@ -7397,7 +7307,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
7397
7307
  ? container.$renderPromise$.then(() => result)
7398
7308
  : result;
7399
7309
  }
7400
- return;
7310
+ return result;
7401
7311
  }
7402
7312
  const isRealDirty = bits & 1023 /* ChoreBits.DIRTY_MASK */;
7403
7313
  // If already dirty, no need to propagate again
@@ -7407,14 +7317,14 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
7407
7317
  const parent = vNode.slotParent || vNode.parent;
7408
7318
  // If cursorRoot is provided, propagate up to it
7409
7319
  if (cursorRoot && isRealDirty && parent && !parent.dirty) {
7410
- propagateToCursorRoot(container, vNode, cursorRoot);
7320
+ propagateToCursorRoot(vNode, cursorRoot);
7411
7321
  return;
7412
7322
  }
7413
7323
  // We must attach to a cursor subtree if it exists
7414
7324
  if (parent && parent.dirty & 1023 /* ChoreBits.DIRTY_MASK */) {
7415
7325
  // Dirty parent case: this vnode joins an already scheduled subtree, so inherit the parent's
7416
7326
  // nearest boundary unless this vnode owns a boundary itself.
7417
- setNearestCursorBoundary(vNode, getOwnCursorBoundary(container, vNode) || getNearestCursorBoundary(container, parent));
7327
+ setNearestCursorBoundary(vNode, getOwnCursorBoundary(vNode) || getNearestCursorBoundary(parent));
7418
7328
  if (isRealDirty) {
7419
7329
  parent.dirty |= 64 /* ChoreBits.CHILDREN */;
7420
7330
  }
@@ -7446,7 +7356,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
7446
7356
  else if (!isCursor(vNode)) {
7447
7357
  // Check if there's an existing cursor that is blocking (executing a render-blocking task)
7448
7358
  // If so, merge with it instead of creating a new cursor (single-pass find + propagate)
7449
- if (!findAndPropagateToBlockingCursor(container, vNode)) {
7359
+ if (!findAndPropagateToBlockingCursor(vNode)) {
7450
7360
  // No blocking cursor found, create a new one
7451
7361
  addCursor(container, vNode, 0);
7452
7362
  }
@@ -7454,7 +7364,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
7454
7364
  else {
7455
7365
  // Existing cursor-root case: the vnode is already the scheduled cursor, so only its own
7456
7366
  // boundary can be authoritative here.
7457
- setNearestCursorBoundary(vNode, getOwnCursorBoundary(container, vNode));
7367
+ setNearestCursorBoundary(vNode, getOwnCursorBoundary(vNode));
7458
7368
  }
7459
7369
  }
7460
7370
  function addVNodeOperation(journal, operation) {
@@ -9132,8 +9042,14 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
9132
9042
  vnode_setProp(vParent, QScopedStyle, consumeValue());
9133
9043
  }
9134
9044
  else if (peek() === VNodeDataChar.RENDER_FN) {
9135
- (components ||= []).push(vParent);
9136
- vnode_setProp(vParent, OnRenderProp, consumeValue());
9045
+ const renderRef = consumeValue();
9046
+ if (renderRef.charCodeAt(0) === VNodeDataChar.RENDER_HASH_PREFIX) {
9047
+ vnode_setProp(vParent, QComponentHash, decodeURIComponent(decodeVNodeDataString(renderRef.slice(1))));
9048
+ }
9049
+ else {
9050
+ (components ||= []).push(vParent);
9051
+ vnode_setProp(vParent, OnRenderProp, renderRef);
9052
+ }
9137
9053
  }
9138
9054
  else if (peek() === VNodeDataChar.ID) {
9139
9055
  if (!container) {
@@ -9181,7 +9097,7 @@ function materializeFromVNodeData(vParent, vData, element, child, segmentId) {
9181
9097
  else if (peek() === VNodeDataChar.SEPARATOR) {
9182
9098
  // Custom attribute: |key|value
9183
9099
  const keyValue = consumeValue();
9184
- const key = decodeVNodeDataString(keyValue);
9100
+ const key = decodeURIComponent(decodeVNodeDataString(keyValue));
9185
9101
  const valueSeparatorIdx = dataIdx + keyValue.length + 1;
9186
9102
  const isEscapedValue = getChar(valueSeparatorIdx + 1) === VNodeDataChar.SEPARATOR;
9187
9103
  let value;
@@ -10776,7 +10692,6 @@ class Serializer {
10776
10692
  // async-mode computeds carry the same engine state and must round-trip like AsyncSignals
10777
10693
  const isAsync = !!(value.$flags$ & 512 /* AsyncSignalFlags.ASYNC_MODE */);
10778
10694
  const isErrored = isAsync && !!value.$untrackedError$;
10779
- const expires = isAsync && value.$expires$ !== 0 ? value.$expires$ : undefined;
10780
10695
  const concurrency = isAsync && value.$concurrency$ !== 1 ? value.$concurrency$ : undefined;
10781
10696
  const timeout = isAsync && value.$timeoutMs$ !== 0 ? value.$timeoutMs$ : undefined;
10782
10697
  // Send the flags but remove the serialization bits and default to 0 when undefined
@@ -10797,10 +10712,7 @@ class Serializer {
10797
10712
  out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedError$);
10798
10713
  out.push(asyncFlags || undefined);
10799
10714
  }
10800
- if (v !== NEEDS_COMPUTATION ||
10801
- expires !== undefined ||
10802
- concurrency !== undefined ||
10803
- timeout !== undefined) {
10715
+ if (v !== NEEDS_COMPUTATION || concurrency !== undefined || timeout !== undefined) {
10804
10716
  /**
10805
10717
  * If value is undefined, we need to keep it in the output. If we don't do that, later
10806
10718
  * during resuming, the value will be set to symbol(invalid) with flag invalid, and thats
@@ -10809,7 +10721,6 @@ class Serializer {
10809
10721
  out.push(v === undefined ? explicitUndefined : v);
10810
10722
  }
10811
10723
  if (isAsync) {
10812
- out.push(expires);
10813
10724
  out.push(concurrency);
10814
10725
  out.push(timeout);
10815
10726
  }
@@ -12137,6 +12048,16 @@ const applyQwikComponentBody = (ssr, jsx, component) => {
12137
12048
 
12138
12049
  class MaybeAsyncSignal {
12139
12050
  }
12051
+ const markPromiseHandled = (ssr, promise, host = null) => {
12052
+ promise.catch((reason) => {
12053
+ try {
12054
+ ssr.handleError(reason, host);
12055
+ }
12056
+ catch {
12057
+ // Original promise remains awaited later.
12058
+ }
12059
+ });
12060
+ };
12140
12061
  function setParentOptions(mutable, styleScoped, parentComponentFrame) {
12141
12062
  return () => {
12142
12063
  mutable.currentStyleScoped = styleScoped;
@@ -12147,6 +12068,11 @@ function setParentOptions(mutable, styleScoped, parentComponentFrame) {
12147
12068
  async function _walkJSX(ssr, value, options) {
12148
12069
  const stack = [value];
12149
12070
  const enqueue = (value) => stack.push(value);
12071
+ const enqueuePromise = (promise) => {
12072
+ markPromiseHandled(ssr, promise);
12073
+ stack.push(promise);
12074
+ stack.push(Promise);
12075
+ };
12150
12076
  const drain = async () => {
12151
12077
  while (stack.length) {
12152
12078
  try {
@@ -12169,7 +12095,7 @@ async function _walkJSX(ssr, value, options) {
12169
12095
  }
12170
12096
  continue;
12171
12097
  }
12172
- processJSXNode(ssr, enqueue, value, options);
12098
+ processJSXNode(ssr, enqueue, enqueuePromise, value, options);
12173
12099
  }
12174
12100
  finally {
12175
12101
  const pendingFlush = ssr.streamHandler.waitForPendingFlush();
@@ -12181,7 +12107,7 @@ async function _walkJSX(ssr, value, options) {
12181
12107
  };
12182
12108
  await drain();
12183
12109
  }
12184
- function processJSXNode(ssr, enqueue, value, options) {
12110
+ function processJSXNode(ssr, enqueue, enqueuePromise, value, options) {
12185
12111
  // console.log('processJSXNode', value);
12186
12112
  if (value == null) {
12187
12113
  ssr.textNode('');
@@ -12202,7 +12128,6 @@ function processJSXNode(ssr, enqueue, value, options) {
12202
12128
  }
12203
12129
  }
12204
12130
  else if (isSignal(value)) {
12205
- maybeAddPollingAsyncSignalToEagerResume(ssr.serializationCtx, value);
12206
12131
  ssr.openFragment(isDev ? { [DEBUG_TYPE]: "S" /* VirtualType.WrappedSignal */ } : EMPTY_OBJ);
12207
12132
  const signalNode = ssr.getOrCreateLastNode();
12208
12133
  const unwrappedSignal = value instanceof WrappedSignalImpl ? value.$unwrapIfSignal$() : value;
@@ -12213,8 +12138,7 @@ function processJSXNode(ssr, enqueue, value, options) {
12213
12138
  else if (isPromise(value)) {
12214
12139
  ssr.openFragment(isDev ? { [DEBUG_TYPE]: "A" /* VirtualType.Awaited */ } : EMPTY_OBJ);
12215
12140
  enqueue(ssr.closeFragment);
12216
- enqueue(value);
12217
- enqueue(Promise);
12141
+ enqueuePromise(value);
12218
12142
  enqueue(() => ssr.streamHandler.flush());
12219
12143
  }
12220
12144
  else if (isAsyncGenerator(value)) {
@@ -12285,11 +12209,9 @@ function processJSXNode(ssr, enqueue, value, options) {
12285
12209
  const componentFrame = options.parentComponentFrame;
12286
12210
  if (componentFrame) {
12287
12211
  const compId = componentFrame.componentNode.id || '';
12288
- const projectionAttrs = isDev ? { [DEBUG_TYPE]: "P" /* VirtualType.Projection */ } : {};
12289
- const cursorBoundary = directGetPropsProxyProp(jsx, QCursorBoundary);
12290
- if (cursorBoundary) {
12291
- projectionAttrs[QCursorBoundary] = cursorBoundary;
12292
- }
12212
+ const projectionAttrs = isDev
12213
+ ? { [DEBUG_TYPE]: "P" /* VirtualType.Projection */ }
12214
+ : {};
12293
12215
  projectionAttrs[QSlotParent] = compId;
12294
12216
  ssr.openProjection(projectionAttrs);
12295
12217
  const host = componentFrame.componentNode;
@@ -12337,8 +12259,12 @@ function processJSXNode(ssr, enqueue, value, options) {
12337
12259
  else {
12338
12260
  value = generator;
12339
12261
  }
12340
- enqueue(value);
12341
- isPromise(value) && enqueue(Promise);
12262
+ if (isPromise(value)) {
12263
+ enqueuePromise(value);
12264
+ }
12265
+ else {
12266
+ enqueue(value);
12267
+ }
12342
12268
  }
12343
12269
  else if (type === SSRRaw) {
12344
12270
  ssr.htmlNode(directGetPropsProxyProp(jsx, 'data'));
@@ -12362,6 +12288,7 @@ function processJSXNode(ssr, enqueue, value, options) {
12362
12288
  enqueue(setParentOptions(options, options.currentStyleScoped, options.parentComponentFrame));
12363
12289
  enqueue(() => ssr.closeComponent());
12364
12290
  if (isPromise(jsxOutput)) {
12291
+ markPromiseHandled(ssr, jsxOutput, host);
12365
12292
  // Defer reading QScopedStyle until after the promise resolves
12366
12293
  enqueue(async () => {
12367
12294
  await ssr.streamHandler.flush();
@@ -12386,27 +12313,17 @@ function processJSXNode(ssr, enqueue, value, options) {
12386
12313
  enqueue(ssr.closeFragment);
12387
12314
  const component = ssr.getParentComponentFrame();
12388
12315
  const jsxOutput = applyInlineComponent(ssr, component && component.componentNode, type, jsx);
12389
- enqueue(jsxOutput);
12390
- isPromise(jsxOutput) && enqueue(Promise);
12316
+ if (isPromise(jsxOutput)) {
12317
+ enqueuePromise(jsxOutput);
12318
+ }
12319
+ else {
12320
+ enqueue(jsxOutput);
12321
+ }
12391
12322
  }
12392
12323
  }
12393
12324
  }
12394
12325
  }
12395
12326
  }
12396
- function maybeAddPollingAsyncSignalToEagerResume(serializationCtx, signal) {
12397
- // Unwrap if it's a WrappedSignalImpl
12398
- const unwrappedSignal = signal instanceof WrappedSignalImpl ? signal.$unwrapIfSignal$() : signal;
12399
- if (unwrappedSignal instanceof ComputedSignalImpl) {
12400
- const expires = unwrappedSignal.$expires$;
12401
- // Don't check for $effects$ here - effects are added later during tracking.
12402
- // The AsyncSignal's polling mechanism will check for effects before scheduling.
12403
- // Only eager-resume for polling signals, not stale-only ones.
12404
- if (expires && !(unwrappedSignal.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */)) {
12405
- serializationCtx.$addRoot$(unwrappedSignal);
12406
- serializationCtx.$eagerResume$.add(unwrappedSignal);
12407
- }
12408
- }
12409
- }
12410
12327
  function appendQwikInspectorAttribute(jsx, qwikInspectorAttrValue) {
12411
12328
  if (qwikInspectorAttrValue && (!jsx.constProps || !(qwikInspectorAttr in jsx.constProps))) {
12412
12329
  (jsx.constProps ||= {})[qwikInspectorAttr] = qwikInspectorAttrValue;
@@ -12579,7 +12496,8 @@ function setEvent(serializationCtx, key, rawValue, hasMovedCaptures) {
12579
12496
  *
12580
12497
  * For internal qrls (starting with `_`) we assume that they do the right thing.
12581
12498
  */
12582
- if (!qrl.$symbol$.startsWith('_') && (Array.isArray(qrl.$captures$) || hasMovedCaptures)) {
12499
+ if (!qrl.$symbol$.startsWith('_') &&
12500
+ (Array.isArray(qrl.$captures$) || (hasMovedCaptures && qrl.$hasMovedCaptures$))) {
12583
12501
  qrl = createQRL(null, '_run', _run, null, [qrl]);
12584
12502
  }
12585
12503
  return qrlToChunks(serializationCtx, qrl);
@@ -13123,17 +13041,11 @@ function* inflateIterator(container, target, typeId, data) {
13123
13041
  if (asyncSignal.$untrackedValue$ === NEEDS_COMPUTATION) {
13124
13042
  asyncSignal.$flags$ |= 1 /* ComputedSignalFlags.INVALID */;
13125
13043
  }
13126
- // Handle old format (negative = no poll) and new format (always positive, flag in d[5])
13127
- const rawExpires = (d[7] ?? 0);
13128
- asyncSignal.expires = Math.abs(rawExpires);
13129
- if (rawExpires < 0) {
13130
- asyncSignal.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
13131
- }
13132
- if (d[8] !== undefined && d[8] !== 1) {
13133
- asyncSignal.$concurrency$ = (d[8] ?? 1);
13044
+ if (d[7] !== undefined && d[7] !== 1) {
13045
+ asyncSignal.$concurrency$ = (d[7] ?? 1);
13134
13046
  asyncSignal.$jobs$ = [];
13135
13047
  }
13136
- asyncSignal.$timeoutMs$ = (d[9] ?? 0);
13048
+ asyncSignal.$timeoutMs$ = (d[8] ?? 0);
13137
13049
  restoreEffectBackRefForEffects(asyncSignal.$effects$, asyncSignal);
13138
13050
  restoreEffectBackRefForEffects(asyncSignal.$loadingEffects$, asyncSignal);
13139
13051
  restoreEffectBackRefForEffects(asyncSignal.$errorEffects$, asyncSignal);
@@ -13915,7 +13827,7 @@ const isRecoverable = (err) => {
13915
13827
  };
13916
13828
 
13917
13829
  /** @internal */
13918
- const canRevealRegistration = (registration, isPending = (item) => item.boundary.pending.untrackedValue > 0) => {
13830
+ const canRevealRegistration = (registration, isPending = (item) => item.boundary.untrackedValue > 0) => {
13919
13831
  if (registration === null) {
13920
13832
  return true;
13921
13833
  }
@@ -13992,15 +13904,9 @@ class OutOfOrderRevealCoordinator {
13992
13904
  }
13993
13905
  /** @internal */
13994
13906
  const createOutOfOrderRevealCoordinator = (order, collapsed) => {
13995
- if (!isOutOfOrderStreaming()) {
13996
- return null;
13997
- }
13998
- const container = tryGetInvokeContext()?.$container$;
13999
- let id = 0;
14000
- if (container) {
14001
- id = (outOfOrderRevealIds.get(container) || 0) + 1;
14002
- outOfOrderRevealIds.set(container, id);
14003
- }
13907
+ const container = tryGetInvokeContext().$container$;
13908
+ const id = (outOfOrderRevealIds.get(container) || 0) + 1;
13909
+ outOfOrderRevealIds.set(container, id);
14004
13910
  return new OutOfOrderRevealCoordinator(id, order, collapsed);
14005
13911
  };
14006
13912
  const getOutOfOrderRevealOrderCode = (order) => {
@@ -14024,16 +13930,7 @@ const isOutOfOrderStreaming = () => {
14024
13930
  return container?.outOfOrderStreaming === true && !isOutOfOrderSegmentContainer(container);
14025
13931
  };
14026
13932
  /** @internal */
14027
- const nextOutOfOrderSuspenseId = () => {
14028
- if (!__EXPERIMENTAL__.suspense) {
14029
- return 0;
14030
- }
14031
- const container = tryGetInvokeContext()?.$container$;
14032
- if (container?.outOfOrderStreaming !== true) {
14033
- return 0;
14034
- }
14035
- return container?.nextOutOfOrderId?.() ?? 0;
14036
- };
13933
+ const nextOutOfOrderSuspenseId = () => tryGetInvokeContext().$container$.nextOutOfOrderId();
14037
13934
  /** @internal */
14038
13935
  const applySubscriptionPatches = (container, patches) => {
14039
13936
  if (!__EXPERIMENTAL__.suspense || !patches) {
@@ -14972,7 +14869,6 @@ class DomContainer extends _SharedContainer {
14972
14869
  case OnRenderProp:
14973
14870
  case QCtxAttr:
14974
14871
  case QBackRefs:
14975
- case QCursorBoundary:
14976
14872
  getObjectById = this.$getObjectById$;
14977
14873
  break;
14978
14874
  case ELEMENT_SEQ_IDX:
@@ -15398,6 +15294,7 @@ const setupHmr = (LazyRefClass, setGetLazyRef) => {
15398
15294
  };
15399
15295
 
15400
15296
  // keep these imports above the rest to prevent circular dep issues
15297
+ let reportedChunkFailures;
15401
15298
  let getLazyRef = (chunk, symbol, symbolFn, ref, container) => {
15402
15299
  return new LazyRef(chunk, symbol, symbolFn, ref, container);
15403
15300
  };
@@ -15438,7 +15335,25 @@ class LazyRef {
15438
15335
  this.$ref$ = ref;
15439
15336
  if (isPromise(ref)) {
15440
15337
  ref.then((r) => (this.$ref$ = r), (err) => {
15441
- console.error(`qrl ${this.$symbol$} failed to load`, err);
15338
+ const errorMessage = `qrl ${this.$symbol$} failed to load`;
15339
+ if (qTest ? isServerPlatform() : isServer) {
15340
+ console.error(errorMessage, err);
15341
+ }
15342
+ else if (qTest ? !isServerPlatform() : isBrowser$1) {
15343
+ const failureKey = this.$chunk$ === null ? `symbol:${this.$symbol$}` : `chunk:${this.$chunk$}`;
15344
+ const container = this.$container$;
15345
+ let containerFailures = container && reportedChunkFailures?.get(container);
15346
+ if (!containerFailures?.has(failureKey)) {
15347
+ if (container) {
15348
+ if (!containerFailures) {
15349
+ containerFailures = new Set();
15350
+ (reportedChunkFailures ||= new WeakMap()).set(container, containerFailures);
15351
+ }
15352
+ containerFailures.add(failureKey);
15353
+ }
15354
+ console.error(errorMessage, err);
15355
+ }
15356
+ }
15442
15357
  // We shouldn't cache rejections, we can try again later
15443
15358
  this.$ref$ = null;
15444
15359
  });
@@ -15531,6 +15446,10 @@ const qrlWithCaptures = function (captures) {
15531
15446
  const newQrl = new QRLClass(qrl.$lazy$, captures, qrl.$captures$ ? qrl.$container$ : undefined);
15532
15447
  return makeQrlFn(newQrl);
15533
15448
  };
15449
+ const qrlWithMovedCaptures = function () {
15450
+ this[QRL_STATE].$lazy$.$hasMovedCaptures$ = true;
15451
+ return this;
15452
+ };
15534
15453
  const qrlSetRef = function (ref) {
15535
15454
  const qrl = getInstance(this);
15536
15455
  qrl.$lazy$.$setRef$(ref);
@@ -15586,6 +15505,11 @@ const QRL_FUNCTION_PROTO = Object.create(Function.prototype, {
15586
15505
  this[QRL_STATE].$captures$ = value;
15587
15506
  },
15588
15507
  },
15508
+ $hasMovedCaptures$: {
15509
+ get() {
15510
+ return this[QRL_STATE].$lazy$.$hasMovedCaptures$;
15511
+ },
15512
+ },
15589
15513
  $container$: {
15590
15514
  get() {
15591
15515
  return this[QRL_STATE].$container$;
@@ -15634,6 +15558,9 @@ const QRL_FUNCTION_PROTO = Object.create(Function.prototype, {
15634
15558
  w: {
15635
15559
  value: qrlWithCaptures,
15636
15560
  },
15561
+ m: {
15562
+ value: qrlWithMovedCaptures,
15563
+ },
15637
15564
  s: {
15638
15565
  value: qrlSetRef,
15639
15566
  },
@@ -16971,10 +16898,10 @@ const eachCmpTask = async ({ track }) => {
16971
16898
  const context = tryGetInvokeContext();
16972
16899
  const host = context.$hostElement$;
16973
16900
  const container = context.$container$;
16974
- markVNodeDirty(container, host, 256 /* ChoreBits.RECONCILE */);
16901
+ const renderPromise = markVNodeDirty(container, host, 256 /* ChoreBits.RECONCILE */);
16975
16902
  const isSsr = qTest ? isServerPlatform() : isServer;
16976
16903
  if (isSsr) {
16977
- await container.$renderPromise$;
16904
+ await renderPromise;
16978
16905
  }
16979
16906
  };
16980
16907
  /** @internal */
@@ -17133,19 +17060,19 @@ const _hf0 = (p0, p1, p2, p3) => ({
17133
17060
  display: p1.value === 'fallback' &&
17134
17061
  p0.fallback != null &&
17135
17062
  p0.fallback !== false &&
17136
- (p2 === null || p2.value || !p3.reveal.collapsed)
17063
+ (p2.value || !p3.reveal.collapsed)
17137
17064
  ? 'contents'
17138
17065
  : 'none',
17139
17066
  });
17140
- const _hf0_str = '{display:p1.value==="fallback"&&p0.fallback!=null&&p0.fallback!==false&&(p2===null||p2.value||!p3.reveal.collapsed)?"contents":"none"}';
17141
- const _hf1 = (p0, p1, p2) => ({
17142
- display: (p1.value === 'content' || p0.showStale) && (p2 === null || p2.value) ? 'contents' : 'none',
17067
+ const _hf0_str = '{display:p1.value==="fallback"&&p0.fallback!=null&&p0.fallback!==false&&(p2.value||!p3.reveal.collapsed)?"contents":"none"}';
17068
+ const _hf1 = (p0, p1) => ({
17069
+ display: p0.value === 'content' && p1.value ? 'contents' : 'none',
17143
17070
  });
17144
- const _hf1_str = '{display:(p1.value==="content"||p0.showStale)&&(p2===null||p2.value)?"contents":"none"}';
17071
+ const _hf1_str = '{display:p0.value==="content"&&p1.value?"contents":"none"}';
17145
17072
  /** @internal */
17146
17073
  const suspenseTask = ({ track, cleanup }) => {
17147
17074
  const cursorBoundary = _captures[0], props = _captures[1], state = _captures[2], revealRegistration = _captures[3];
17148
- const pendingCount = track(cursorBoundary.pending);
17075
+ const pendingCount = track(cursorBoundary);
17149
17076
  const isBrowserEnv = qTest ? !isServerPlatform() : isBrowser$1;
17150
17077
  if (revealRegistration !== null && isBrowserEnv) {
17151
17078
  revealRegistration.reveal.version.value++;
@@ -17155,7 +17082,7 @@ const suspenseTask = ({ track, cleanup }) => {
17155
17082
  return;
17156
17083
  }
17157
17084
  const delayTimer = setTimeout(() => {
17158
- if (cursorBoundary.pending.value > 0) {
17085
+ if (cursorBoundary.value > 0) {
17159
17086
  state.value = 'fallback';
17160
17087
  }
17161
17088
  }, props.delay ?? 0);
@@ -17184,19 +17111,17 @@ const suspenseCmp = (props) => {
17184
17111
  const outOfOrderRevealBoundary = isServerOutOfOrder
17185
17112
  ? (revealRegistration?.reveal.ooos?.register(revealRegistration) ?? null)
17186
17113
  : null;
17187
- const showOutOfOrderFallback = isServerOutOfOrder && shouldRenderFallback(props.fallback, outOfOrderRevealBoundary);
17114
+ const showOutOfOrderFallback = isServerOutOfOrder &&
17115
+ untrack(() => props.fallback != null && props.fallback !== false) &&
17116
+ (outOfOrderRevealBoundary === null || outOfOrderRevealBoundary.showFallback);
17188
17117
  const outOfOrderBoundaryState = showOutOfOrderFallback && isPositiveDelay(props.delay)
17189
- ? { contentResolved: false, delayTimer: null }
17118
+ ? { contentResolved: false, delay: props.delay, delayTimer: null }
17190
17119
  : null;
17191
- const outOfOrderFallbackStyle = isServerOutOfOrder
17192
- ? /*#__PURE__*/ _fnSignal(_hf0, [props, state, canReveal, revealRegistration], _hf0_str)
17193
- : null;
17194
- const contentStyle = /*#__PURE__*/ _fnSignal(_hf1, [props, state, canReveal], _hf1_str);
17120
+ const contentStyle = /*#__PURE__*/ _fnSignal(_hf1, [state, canReveal], _hf1_str);
17195
17121
  const fallbackHost = (isServerOutOfOrder
17196
17122
  ? /*#__PURE__*/ _jsxSorted(SSRFallback, {
17197
17123
  boundary: outOfOrderBoundaryState,
17198
- delay: props.delay,
17199
- fallbackStyle: outOfOrderFallbackStyle,
17124
+ fallbackStyle: _fnSignal(_hf0, [props, state, canReveal, revealRegistration], _hf0_str),
17200
17125
  showFallback: showOutOfOrderFallback,
17201
17126
  state,
17202
17127
  }, null, _wrapProp(props, 'fallback'), 1, null)
@@ -17232,15 +17157,16 @@ const Suspense = /*#__PURE__*/ componentQrl(
17232
17157
  const SSRFallback = __EXPERIMENTAL__.suspense
17233
17158
  ? /*#__PURE__*/ createInternalServerComponent((ssr, jsx, _options, enqueue) => {
17234
17159
  const boundaryState = jsx.varProps.boundary;
17235
- const delay = jsx.varProps.delay;
17236
17160
  const fallbackStyle = jsx.varProps.fallbackStyle;
17237
17161
  const showFallback = jsx.varProps.showFallback === true;
17238
17162
  const state = jsx.varProps.state;
17239
- if (showFallback && !isPositiveDelay(delay)) {
17240
- state.value = 'fallback';
17241
- }
17242
- else if (boundaryState && showFallback && isPositiveDelay(delay)) {
17243
- enqueue(() => scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state, delay));
17163
+ if (showFallback) {
17164
+ if (boundaryState) {
17165
+ enqueue(() => scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state));
17166
+ }
17167
+ else {
17168
+ state.value = 'fallback';
17169
+ }
17244
17170
  }
17245
17171
  enqueue(
17246
17172
  /*#__PURE__*/ _jsxSorted('div', {
@@ -17250,13 +17176,13 @@ const SSRFallback = __EXPERIMENTAL__.suspense
17250
17176
  : null;
17251
17177
  const SSRDeferredSlot = __EXPERIMENTAL__.suspense
17252
17178
  ? /*#__PURE__*/ createInternalServerComponent(async (ssr, jsx, options) => {
17253
- const boundaryId = jsx.varProps.boundaryId ?? ssr.nextOutOfOrderId();
17179
+ const boundaryId = jsx.varProps.boundaryId;
17254
17180
  const contentSegment = `${boundaryId}`;
17255
17181
  const boundaryState = jsx.varProps.boundary;
17256
17182
  const contentStyle = jsx.varProps.contentStyle;
17257
17183
  const revealBoundary = jsx.varProps.reveal;
17258
17184
  const content = ssr.segment(contentSegment, createClaimedDeferredSlot(ssr, jsx, options), options);
17259
- writeOutOfOrderPlaceholder(ssr, boundaryId);
17185
+ ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"></template>`);
17260
17186
  ssr.emitOutOfOrderExecutorIfNeeded();
17261
17187
  ssr.queueOutOfOrderSegment(content.then((rendered) => emitRenderedOutOfOrderSegment(ssr, boundaryId, contentSegment, rendered, contentStyle, revealBoundary, boundaryState)));
17262
17188
  })
@@ -17275,29 +17201,27 @@ function createClaimedDeferredSlot(ssr, jsx, options) {
17275
17201
  return /*#__PURE__*/ _jsxSorted(Slot, jsx.varProps, jsx.constProps, slotChildren, jsx.flags, jsx.key);
17276
17202
  }
17277
17203
  async function emitRenderedOutOfOrderSegment(ssr, boundaryId, segmentId, rendered, contentStyle, revealBoundary, boundaryState) {
17278
- markOutOfOrderContentResolved(boundaryState);
17204
+ if (boundaryState) {
17205
+ boundaryState.contentResolved = true;
17206
+ if (boundaryState.delayTimer) {
17207
+ clearTimeout(boundaryState.delayTimer);
17208
+ boundaryState.delayTimer = null;
17209
+ }
17210
+ }
17279
17211
  revealBoundary?.resolve();
17280
17212
  await ssr.$runQueuedRender$(async () => {
17281
17213
  ssr.addRoot(contentStyle);
17282
17214
  const result = await rendered.container.$finalizeOutOfOrderSegment$(segmentId, rendered);
17283
- writeOutOfOrderResolvedTemplate(ssr, boundaryId, result.html, revealBoundary);
17215
+ ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"${revealBoundary?.attrs ?? ''}>`);
17216
+ ssr.write(result.html);
17217
+ ssr.write('</template>');
17284
17218
  ssr.emitOutOfOrderSegmentScripts(result.scripts);
17285
17219
  ssr.emitInlineScript(`qO(${boundaryId})`);
17286
17220
  // qO() is the browser-visible handoff for this segment, so flush it immediately.
17287
17221
  await ssr.streamHandler.flush();
17288
17222
  });
17289
17223
  }
17290
- function markOutOfOrderContentResolved(boundaryState) {
17291
- if (!boundaryState) {
17292
- return;
17293
- }
17294
- boundaryState.contentResolved = true;
17295
- if (boundaryState.delayTimer) {
17296
- clearTimeout(boundaryState.delayTimer);
17297
- boundaryState.delayTimer = null;
17298
- }
17299
- }
17300
- function scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state, delay) {
17224
+ function scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state) {
17301
17225
  boundaryState.delayTimer = setTimeout(() => {
17302
17226
  boundaryState.delayTimer = null;
17303
17227
  void ssr.$runQueuedRender$(async () => {
@@ -17308,24 +17232,11 @@ function scheduleOutOfOrderFallbackDelay(ssr, boundaryState, state, delay) {
17308
17232
  ssr.emitBackpatchDataAndExecutorIfNeeded();
17309
17233
  await ssr.streamHandler.flush();
17310
17234
  });
17311
- }, delay);
17235
+ }, boundaryState.delay);
17312
17236
  }
17313
17237
  function isPositiveDelay(delay) {
17314
17238
  return typeof delay === 'number' && Number.isFinite(delay) && delay > 0;
17315
17239
  }
17316
- function shouldRenderFallback(fallback, revealBoundary) {
17317
- return (fallback != null &&
17318
- fallback !== false &&
17319
- (revealBoundary === null || revealBoundary.showFallback));
17320
- }
17321
- function writeOutOfOrderPlaceholder(ssr, boundaryId) {
17322
- ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"></template>`);
17323
- }
17324
- function writeOutOfOrderResolvedTemplate(ssr, boundaryId, html, revealBoundary) {
17325
- ssr.write(`<template ${QSuspenseResolved}="${boundaryId}"${revealBoundary?.attrs ?? ''}>`);
17326
- ssr.write(html);
17327
- ssr.write('</template>');
17328
- }
17329
17240
 
17330
17241
  // keep this import from core/build so the cjs build works
17331
17242
  /**