@qwik.dev/core 2.0.0-beta.1 → 2.0.0-beta.10

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.
Files changed (99) hide show
  1. package/bindings/qwik.darwin-arm64.node +0 -0
  2. package/bindings/qwik.darwin-x64.node +0 -0
  3. package/bindings/qwik.linux-x64-gnu.node +0 -0
  4. package/bindings/qwik.win32-x64-msvc.node +0 -0
  5. package/bindings/qwik_wasm_bg.wasm +0 -0
  6. package/dist/backpatch/index.cjs +6 -0
  7. package/dist/backpatch/index.d.ts +2 -0
  8. package/dist/backpatch/index.mjs +5 -0
  9. package/dist/backpatch/package.json +8 -0
  10. package/dist/backpatch-executor.debug.js +34 -0
  11. package/dist/backpatch-executor.js +1 -0
  12. package/dist/build/package.json +1 -1
  13. package/dist/cli.cjs +3031 -763
  14. package/dist/core-internal.d.ts +253 -78
  15. package/dist/core.cjs +1770 -957
  16. package/dist/core.cjs.map +1 -1
  17. package/dist/core.min.mjs +1 -1
  18. package/dist/core.mjs +1745 -955
  19. package/dist/core.mjs.map +1 -1
  20. package/dist/core.prod.cjs +1368 -949
  21. package/dist/core.prod.mjs +1435 -951
  22. package/dist/insights/vite/index.cjs +1 -1
  23. package/dist/insights/vite/index.mjs +10 -10
  24. package/dist/loader/index.cjs +2 -2
  25. package/dist/loader/index.mjs +2 -2
  26. package/dist/loader/package.json +1 -1
  27. package/dist/optimizer.cjs +201 -4016
  28. package/dist/optimizer.d.ts +12 -37
  29. package/dist/optimizer.mjs +2539 -3715
  30. package/dist/preloader.cjs +8 -11
  31. package/dist/preloader.mjs +8 -11
  32. package/dist/qwikloader.debug.js +1 -15
  33. package/dist/qwikloader.js +1 -1
  34. package/dist/server.cjs +309 -116
  35. package/dist/server.d.ts +17 -2
  36. package/dist/server.mjs +291 -103
  37. package/dist/starters/adapters/aws-lambda/adapters/aws-lambda/vite.config.mts +1 -1
  38. package/dist/starters/adapters/aws-lambda/package.json +1 -1
  39. package/dist/starters/adapters/aws-lambda/src/entry_aws-lambda.tsx +2 -6
  40. package/dist/starters/adapters/azure-swa/adapters/azure-swa/vite.config.mts +1 -1
  41. package/dist/starters/adapters/azure-swa/package.json +1 -1
  42. package/dist/starters/adapters/azure-swa/src/entry.azure-swa.tsx +2 -3
  43. package/dist/starters/adapters/bun/adapters/bun/vite.config.mts +2 -2
  44. package/dist/starters/adapters/bun/package.json +1 -1
  45. package/dist/starters/adapters/bun/src/entry.bun.ts +0 -2
  46. package/dist/starters/adapters/cloud-run/adapters/cloud-run/vite.config.mts +1 -1
  47. package/dist/starters/adapters/cloud-run/package.json +1 -1
  48. package/dist/starters/adapters/cloud-run/src/entry.cloud-run.tsx +1 -3
  49. package/dist/starters/adapters/cloudflare-pages/adapters/cloudflare-pages/vite.config.mts +1 -1
  50. package/dist/starters/adapters/cloudflare-pages/package.json +1 -1
  51. package/dist/starters/adapters/cloudflare-pages/src/entry.cloudflare-pages.tsx +2 -3
  52. package/dist/starters/adapters/deno/adapters/deno/vite.config.mts +1 -1
  53. package/dist/starters/adapters/deno/package.json +1 -1
  54. package/dist/starters/adapters/deno/src/entry.deno.ts +0 -2
  55. package/dist/starters/adapters/express/adapters/express/vite.config.mts +1 -1
  56. package/dist/starters/adapters/express/package.json +1 -1
  57. package/dist/starters/adapters/express/src/entry.express.tsx +1 -3
  58. package/dist/starters/adapters/fastify/adapters/fastify/vite.config.mts +1 -1
  59. package/dist/starters/adapters/fastify/package.json +1 -1
  60. package/dist/starters/adapters/fastify/src/entry.fastify.tsx +1 -1
  61. package/dist/starters/adapters/fastify/src/plugins/fastify-qwik.ts +1 -2
  62. package/dist/starters/adapters/firebase/adapters/firebase/vite.config.mts +1 -1
  63. package/dist/starters/adapters/firebase/package.json +1 -1
  64. package/dist/starters/adapters/firebase/src/entry-firebase.tsx +2 -3
  65. package/dist/starters/adapters/netlify-edge/adapters/netlify-edge/vite.config.mts +1 -1
  66. package/dist/starters/adapters/netlify-edge/package.json +1 -1
  67. package/dist/starters/adapters/netlify-edge/src/entry.netlify-edge.tsx +2 -3
  68. package/dist/starters/adapters/node-server/adapters/node-server/vite.config.mts +1 -1
  69. package/dist/starters/adapters/node-server/package.json +1 -1
  70. package/dist/starters/adapters/node-server/src/entry.node-server.tsx +0 -2
  71. package/dist/starters/adapters/{static/adapters/static → ssg/adapters/ssg}/vite.config.mts +2 -2
  72. package/dist/starters/adapters/ssg/package.json +19 -0
  73. package/dist/starters/adapters/vercel-edge/adapters/vercel-edge/vite.config.mts +1 -1
  74. package/dist/starters/adapters/vercel-edge/package.json +1 -1
  75. package/dist/starters/adapters/vercel-edge/src/entry.vercel-edge.tsx +2 -3
  76. package/dist/starters/adapters/vercel-edge/vercel.json +1 -1
  77. package/dist/starters/features/auth/package.json +1 -1
  78. package/dist/starters/features/csr/index.html +23 -0
  79. package/dist/starters/features/csr/package.json +29 -0
  80. package/dist/starters/features/csr/src/root.tsx +15 -0
  81. package/dist/starters/features/csr/vite.config.mts +13 -0
  82. package/dist/starters/features/localize/package.json +3 -3
  83. package/dist/starters/features/localize/src/entry.ssr.tsx +17 -21
  84. package/dist/starters/features/pandacss/package.json +1 -1
  85. package/dist/starters/features/playwright/playwright-report/index.html +953 -911
  86. package/dist/starters/features/postcss/postcss.config.js +1 -1
  87. package/dist/starters/features/tailwind/package.json +2 -2
  88. package/dist/starters/features/tailwind/prettier.config.js +10 -0
  89. package/dist/starters/features/tailwind-v3/package.json +1 -1
  90. package/dist/starters/features/tailwind-v3/prettier.config.js +10 -0
  91. package/dist/testing/index.cjs +7556 -5229
  92. package/dist/testing/index.d.ts +972 -1
  93. package/dist/testing/index.mjs +7456 -5140
  94. package/dist/testing/package.json +1 -1
  95. package/package.json +16 -10
  96. package/public.d.ts +1 -0
  97. package/dist/starters/adapters/static/package.json +0 -19
  98. package/dist/starters/features/tailwind/.prettierrc.js +0 -3
  99. /package/dist/starters/adapters/{static → ssg}/README.md +0 -0
package/dist/core.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * @qwik.dev/core 2.0.0-beta.1-dev+495e8d9
3
+ * @qwik.dev/core 2.0.0-beta.10-dev+4669425
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
@@ -9,6 +9,13 @@ import { isDev, isServer, isBrowser } from '@qwik.dev/core/build';
9
9
  export { isBrowser, isDev, isServer } from '@qwik.dev/core/build';
10
10
  import { p } from '@qwik.dev/core/preloader';
11
11
 
12
+ /**
13
+ * QWIK_VERSION
14
+ *
15
+ * @public
16
+ */
17
+ const version = "2.0.0-beta.10-dev+4669425";
18
+
12
19
  // same as isDev but separate so we can test
13
20
  const qDev = globalThis.qDev !== false;
14
21
  const qInspector = globalThis.qInspector === true;
@@ -72,6 +79,30 @@ const createAndLogError = (asyncThrow, message, ...optionalParams) => {
72
79
  return err;
73
80
  };
74
81
 
82
+ /** @private */
83
+ const isSerializableObject = (v) => {
84
+ const proto = Object.getPrototypeOf(v);
85
+ return proto === Object.prototype || proto === Array.prototype || proto === null;
86
+ };
87
+ const isObject = (v) => {
88
+ return typeof v === 'object' && v !== null;
89
+ };
90
+ const isArray = (v) => {
91
+ return Array.isArray(v);
92
+ };
93
+ const isString = (v) => {
94
+ return typeof v === 'string';
95
+ };
96
+ const isNumber$1 = (v) => {
97
+ return typeof v === 'number';
98
+ };
99
+ const isFunction = (v) => {
100
+ return typeof v === 'function';
101
+ };
102
+ const isPrimitive = (v) => {
103
+ return typeof v !== 'object' && typeof v !== 'function' && v !== null && v !== undefined;
104
+ };
105
+
75
106
  const codeToText = (code, ...parts) => {
76
107
  if (qDev) {
77
108
  // Keep one error, one line to make it easier to search for the error message.
@@ -116,7 +147,7 @@ const codeToText = (code, ...parts) => {
116
147
  if (parts.length) {
117
148
  text = text.replaceAll(/{{(\d+)}}/g, (_, index) => {
118
149
  let v = parts[index];
119
- if (v && typeof v === 'object' && v.constructor === Object) {
150
+ if (v && isObject(v) && v.constructor === Object) {
120
151
  v = JSON.stringify(v).slice(0, 50);
121
152
  }
122
153
  return v;
@@ -195,9 +226,13 @@ const QContainerSelector = '[q\\:container]:not([q\\:container=' +
195
226
  ']):not([q\\:container=' +
196
227
  "text" /* QContainerValue.TEXT */ +
197
228
  '])';
229
+ // Node namespaces
198
230
  const HTML_NS = 'http://www.w3.org/1999/xhtml';
199
231
  const SVG_NS = 'http://www.w3.org/2000/svg';
200
232
  const MATH_NS = 'http://www.w3.org/1998/Math/MathML';
233
+ // Attributes namespaces
234
+ const XLINK_NS = 'http://www.w3.org/1999/xlink';
235
+ const XML_NS = 'http://www.w3.org/XML/1998/namespace';
201
236
  const ResourceEvent = 'qResource';
202
237
  const RenderEvent = 'qRender';
203
238
  const TaskEvent = 'qTask';
@@ -263,13 +298,6 @@ const createPlatform = () => {
263
298
  });
264
299
  });
265
300
  },
266
- nextTick: (fn) => {
267
- return new Promise((resolve) => {
268
- setTimeout(() => {
269
- resolve(fn());
270
- });
271
- });
272
- },
273
301
  chunkForSymbol(symbolName, chunk) {
274
302
  return [symbolName, chunk ?? '_'];
275
303
  },
@@ -377,7 +405,7 @@ const delay = (timeout) => {
377
405
  setTimeout(resolve, timeout);
378
406
  });
379
407
  };
380
- // Retries a function that throws a promise.
408
+ /** Retries a function that throws a promise. */
381
409
  function retryOnPromise(fn, retryCount = 0) {
382
410
  const retryOrThrow = (e) => {
383
411
  if (isPromise(e) && retryCount < MAX_RETRY_ON_PROMISE_COUNT) {
@@ -402,24 +430,6 @@ function retryOnPromise(fn, retryCount = 0) {
402
430
  }
403
431
  }
404
432
 
405
- /** @private */
406
- const isSerializableObject = (v) => {
407
- const proto = Object.getPrototypeOf(v);
408
- return proto === Object.prototype || proto === Array.prototype || proto === null;
409
- };
410
- const isObject = (v) => {
411
- return !!v && typeof v === 'object';
412
- };
413
- const isArray = (v) => {
414
- return Array.isArray(v);
415
- };
416
- const isString = (v) => {
417
- return typeof v === 'string';
418
- };
419
- const isFunction = (v) => {
420
- return typeof v === 'function';
421
- };
422
-
423
433
  const ASSERT_DISCLAIMER = 'Internal assert, this is likely caused by a bug in Qwik: ';
424
434
  function assertDefined(value, text, ...parts) {
425
435
  if (qDev) {
@@ -545,6 +555,13 @@ class SignalImpl {
545
555
  this.$container$ = container;
546
556
  this.$untrackedValue$ = value;
547
557
  }
558
+ /**
559
+ * Use this to force running subscribers, for example when the calculated value has mutated but
560
+ * remained the same object
561
+ */
562
+ force() {
563
+ this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
564
+ }
548
565
  get untrackedValue() {
549
566
  return this.$untrackedValue$;
550
567
  }
@@ -558,14 +575,7 @@ class SignalImpl {
558
575
  set value(value) {
559
576
  if (value !== this.$untrackedValue$) {
560
577
  this.$untrackedValue$ = value;
561
- // TODO: move this to the scheduler
562
- triggerEffects(this.$container$, this, this.$effects$);
563
- // this.$container$?.$scheduler$(
564
- // ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
565
- // null,
566
- // this,
567
- // this.$effects$
568
- // );
578
+ this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
569
579
  }
570
580
  }
571
581
  // prevent accidental use as value
@@ -627,23 +637,19 @@ class WrappedSignalImpl extends SignalImpl {
627
637
  $funcStr$;
628
638
  $flags$;
629
639
  $hostElement$ = null;
630
- $forceRunEffects$ = false;
631
640
  [_EFFECT_BACK_REF] = null;
632
641
  constructor(container, fn, args, fnStr,
633
642
  // We need a separate flag to know when the computation needs running because
634
643
  // we need the old value to know if effects need running after computation
635
- flags = 1 /* SignalFlags.INVALID */ | 2 /* WrappedSignalFlags.UNWRAP */) {
644
+ flags = 1 /* SignalFlags.INVALID */ | 4 /* WrappedSignalFlags.UNWRAP */) {
636
645
  super(container, NEEDS_COMPUTATION);
637
646
  this.$args$ = args;
638
647
  this.$func$ = fn;
639
648
  this.$funcStr$ = fnStr;
640
649
  this.$flags$ = flags;
641
650
  }
642
- $invalidate$() {
651
+ invalidate() {
643
652
  this.$flags$ |= 1 /* SignalFlags.INVALID */;
644
- this.$forceRunEffects$ = false;
645
- // We should only call subscribers if the calculation actually changed.
646
- // Therefore, we need to calculate the value now.
647
653
  this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
648
654
  }
649
655
  /**
@@ -651,30 +657,26 @@ class WrappedSignalImpl extends SignalImpl {
651
657
  * remained the same object.
652
658
  */
653
659
  force() {
654
- this.$flags$ |= 1 /* SignalFlags.INVALID */;
655
- this.$forceRunEffects$ = false;
656
- triggerEffects(this.$container$, this, this.$effects$);
660
+ this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
661
+ this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
657
662
  }
658
663
  get untrackedValue() {
659
- const didChange = this.$computeIfNeeded$();
660
- if (didChange) {
661
- this.$forceRunEffects$ = didChange;
662
- }
664
+ this.$computeIfNeeded$();
663
665
  assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
664
666
  return this.$untrackedValue$;
665
667
  }
666
668
  $computeIfNeeded$() {
667
669
  if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
668
- return false;
670
+ return;
669
671
  }
670
672
  const untrackedValue = trackSignal(() => this.$func$(...this.$args$), this, "." /* EffectProperty.VNODE */, this.$container$);
671
- // TODO: we should remove invalid flag here
673
+ // TODO: we should remove invalid flag here, but some tests are failing
672
674
  // this.$flags$ &= ~SignalFlags.INVALID;
673
675
  const didChange = untrackedValue !== this.$untrackedValue$;
674
676
  if (didChange) {
677
+ this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
675
678
  this.$untrackedValue$ = untrackedValue;
676
679
  }
677
- return didChange;
678
680
  }
679
681
  // Make this signal read-only
680
682
  set value(_) {
@@ -711,7 +713,6 @@ function isSsrNode(value) {
711
713
  }
712
714
 
713
715
  let _context;
714
- /** @public */
715
716
  const tryGetInvokeContext = () => {
716
717
  if (!_context) {
717
718
  const context = typeof document !== 'undefined' && document && document.__q_context__;
@@ -732,6 +733,7 @@ const getInvokeContext = () => {
732
733
  }
733
734
  return ctx;
734
735
  };
736
+ /** @internal */
735
737
  const useInvokeContext = () => {
736
738
  const ctx = tryGetInvokeContext();
737
739
  if (!ctx || ctx.$event$ !== RenderEvent) {
@@ -777,7 +779,7 @@ const newInvokeContextFromTuple = ([element, event, url]) => {
777
779
  // TODO how about putting url and locale (and event/custom?) in to a "static" object
778
780
  const newInvokeContext = (locale, hostElement, element, event, url) => {
779
781
  // ServerRequestEvent has .locale, but it's not always defined.
780
- const $locale$ = locale || (typeof event === 'object' && event && 'locale' in event ? event.locale : undefined);
782
+ const $locale$ = locale || (event && isObject(event) && 'locale' in event ? event.locale : undefined);
781
783
  const ctx = {
782
784
  $url$: url,
783
785
  $i$: 0,
@@ -857,17 +859,38 @@ const _getContextEvent = () => {
857
859
  }
858
860
  };
859
861
  /** @internal */
862
+ const _getContextContainer = () => {
863
+ const iCtx = tryGetInvokeContext();
864
+ if (iCtx) {
865
+ return iCtx.$container$;
866
+ }
867
+ };
868
+ /** @internal */
860
869
  const _jsxBranch = (input) => {
861
870
  return input;
862
871
  };
863
872
  /** @internal */
864
873
  const _waitUntilRendered = (elm) => {
865
- const containerEl = _getQContainerElement(elm);
866
- if (!containerEl) {
874
+ const container = _getQContainerElement(elm)?.qContainer;
875
+ if (!container) {
867
876
  return Promise.resolve();
868
877
  }
869
- const container = containerEl.qContainer;
870
- return container?.renderDone ?? Promise.resolve();
878
+ // Multi-cycle idle: loop WAIT_FOR_QUEUE until the flush epoch stays stable
879
+ // across an extra microtask, which signals that no new work re-scheduled.
880
+ return (async () => {
881
+ for (;;) {
882
+ await container.$scheduler$(255 /* ChoreType.WAIT_FOR_QUEUE */).$returnValue$;
883
+ const firstEpoch = container.$flushEpoch$ || 0;
884
+ // Give a microtask for any immediate follow-up scheduling to enqueue
885
+ await Promise.resolve();
886
+ const secondEpoch = container.$flushEpoch$ || 0;
887
+ // If no epoch change occurred during and after WAIT_FOR_QUEUE, we are idle.
888
+ if (firstEpoch === secondEpoch) {
889
+ return;
890
+ }
891
+ // Continue loop if epoch advanced, meaning more work flushed.
892
+ }
893
+ })();
871
894
  };
872
895
 
873
896
  /**
@@ -945,7 +968,7 @@ function jsxEventToHtmlAttribute(jsxEvent) {
945
968
  }
946
969
  return null; // Return null if not matching expected format
947
970
  }
948
- function eventNameToJsxEvent(eventName, prefix, startIdx = 0) {
971
+ function eventNameToJsxEvent(eventName, prefix) {
949
972
  eventName = eventName.charAt(0).toUpperCase() + eventName.substring(1);
950
973
  return prefix + eventName + EVENT_SUFFIX;
951
974
  }
@@ -1214,6 +1237,15 @@ const validateContext = (context) => {
1214
1237
  throw qError(11 /* QError.invalidContext */, [context]);
1215
1238
  }
1216
1239
  };
1240
+ /** @internal */
1241
+ const _resolveContextWithoutSequentialScope = (context) => {
1242
+ const iCtx = getInvokeContext();
1243
+ const hostElement = iCtx.$hostElement$;
1244
+ if (!hostElement) {
1245
+ return undefined;
1246
+ }
1247
+ return iCtx.$container$?.resolveContext(hostElement, context);
1248
+ };
1217
1249
 
1218
1250
  const ERROR_CONTEXT = /*#__PURE__*/ createContextId('qk-error');
1219
1251
  const isRecoverable = (err) => {
@@ -1225,13 +1257,6 @@ const isRecoverable = (err) => {
1225
1257
  return true;
1226
1258
  };
1227
1259
 
1228
- /**
1229
- * QWIK_VERSION
1230
- *
1231
- * @public
1232
- */
1233
- const version = "2.0.0-beta.1-dev+495e8d9";
1234
-
1235
1260
  /** @internal */
1236
1261
  const EMPTY_ARRAY = [];
1237
1262
  const EMPTY_OBJ = {};
@@ -1372,7 +1397,7 @@ const useLexicalScope = () => {
1372
1397
  *
1373
1398
  * @internal
1374
1399
  */
1375
- const queueQRL = (...args) => {
1400
+ const _run = (...args) => {
1376
1401
  // This will already check container
1377
1402
  const [runQrl] = useLexicalScope();
1378
1403
  const context = getInvokeContext();
@@ -1386,7 +1411,58 @@ const queueQRL = (...args) => {
1386
1411
  if (!scheduler) {
1387
1412
  throw qError(1 /* QError.schedulerNotFound */);
1388
1413
  }
1389
- return scheduler(2 /* ChoreType.RUN_QRL */, hostElement, runQrl, args);
1414
+ // We don't return anything, the scheduler is in charge now
1415
+ const chore = scheduler(2 /* ChoreType.RUN_QRL */, hostElement, runQrl, args);
1416
+ return getChorePromise(chore);
1417
+ };
1418
+
1419
+ /** @internal */
1420
+ const mapApp_findIndx = (array, key, start) => {
1421
+ assertTrue(start % 2 === 0, 'Expecting even number.');
1422
+ let bottom = start >> 1;
1423
+ let top = (array.length - 2) >> 1;
1424
+ while (bottom <= top) {
1425
+ const mid = bottom + ((top - bottom) >> 1);
1426
+ const midKey = array[mid << 1];
1427
+ if (midKey === key) {
1428
+ return mid << 1;
1429
+ }
1430
+ if (midKey < key) {
1431
+ bottom = mid + 1;
1432
+ }
1433
+ else {
1434
+ top = mid - 1;
1435
+ }
1436
+ }
1437
+ return (bottom << 1) ^ -1;
1438
+ };
1439
+ /** @internal */
1440
+ const mapArray_set = (array, key, value, start, allowNullValue = false) => {
1441
+ const indx = mapApp_findIndx(array, key, start);
1442
+ if (indx >= 0) {
1443
+ if (value == null && !allowNullValue) {
1444
+ array.splice(indx, 2);
1445
+ }
1446
+ else {
1447
+ array[indx + 1] = value;
1448
+ }
1449
+ }
1450
+ else if (value != null || allowNullValue) {
1451
+ array.splice(indx ^ -1, 0, key, value);
1452
+ }
1453
+ };
1454
+ /** @internal */
1455
+ const mapArray_get = (array, key, start) => {
1456
+ const indx = mapApp_findIndx(array, key, start);
1457
+ if (indx >= 0) {
1458
+ return array[indx + 1];
1459
+ }
1460
+ else {
1461
+ return null;
1462
+ }
1463
+ };
1464
+ const mapArray_has = (array, key, start) => {
1465
+ return mapApp_findIndx(array, key, start) >= 0;
1390
1466
  };
1391
1467
 
1392
1468
  /** @internal */
@@ -1395,6 +1471,8 @@ const _CONST_PROPS = Symbol('CONST');
1395
1471
  const _VAR_PROPS = Symbol('VAR');
1396
1472
  /** @internal @deprecated v1 compat */
1397
1473
  const _IMMUTABLE = Symbol('IMMUTABLE');
1474
+ /** @internal */
1475
+ const _UNINITIALIZED = Symbol('UNINITIALIZED');
1398
1476
 
1399
1477
  // <docs markdown="../../readme.md#implicit$FirstArg">
1400
1478
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
@@ -1459,21 +1537,20 @@ class ComputedSignalImpl extends SignalImpl {
1459
1537
  */
1460
1538
  $computeQrl$;
1461
1539
  $flags$;
1462
- $forceRunEffects$ = false;
1463
1540
  [_EFFECT_BACK_REF] = null;
1464
1541
  constructor(container, fn,
1465
1542
  // We need a separate flag to know when the computation needs running because
1466
1543
  // we need the old value to know if effects need running after computation
1467
- flags = 1 /* SignalFlags.INVALID */) {
1544
+ flags = 1 /* SignalFlags.INVALID */ |
1545
+ 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */) {
1468
1546
  // The value is used for comparison when signals trigger, which can only happen
1469
1547
  // when it was calculated before. Therefore we can pass whatever we like.
1470
1548
  super(container, NEEDS_COMPUTATION);
1471
1549
  this.$computeQrl$ = fn;
1472
1550
  this.$flags$ = flags;
1473
1551
  }
1474
- $invalidate$() {
1552
+ invalidate() {
1475
1553
  this.$flags$ |= 1 /* SignalFlags.INVALID */;
1476
- this.$forceRunEffects$ = false;
1477
1554
  this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
1478
1555
  }
1479
1556
  /**
@@ -1481,20 +1558,17 @@ class ComputedSignalImpl extends SignalImpl {
1481
1558
  * remained the same object
1482
1559
  */
1483
1560
  force() {
1484
- this.$forceRunEffects$ = true;
1485
- this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
1561
+ this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
1562
+ super.force();
1486
1563
  }
1487
1564
  get untrackedValue() {
1488
- const didChange = this.$computeIfNeeded$();
1489
- if (didChange) {
1490
- this.$forceRunEffects$ = didChange;
1491
- }
1565
+ this.$computeIfNeeded$();
1492
1566
  assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
1493
1567
  return this.$untrackedValue$;
1494
1568
  }
1495
1569
  $computeIfNeeded$() {
1496
1570
  if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
1497
- return false;
1571
+ return;
1498
1572
  }
1499
1573
  const computeQrl = this.$computeQrl$;
1500
1574
  throwIfQRLNotResolved(computeQrl);
@@ -1513,9 +1587,12 @@ class ComputedSignalImpl extends SignalImpl {
1513
1587
  this.$flags$ &= ~1 /* SignalFlags.INVALID */;
1514
1588
  const didChange = untrackedValue !== this.$untrackedValue$;
1515
1589
  if (didChange) {
1590
+ // skip first computation when value is not changed
1591
+ if (this.$untrackedValue$ !== NEEDS_COMPUTATION) {
1592
+ this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
1593
+ }
1516
1594
  this.$untrackedValue$ = untrackedValue;
1517
1595
  }
1518
- return didChange;
1519
1596
  }
1520
1597
  finally {
1521
1598
  if (ctx) {
@@ -1541,12 +1618,12 @@ class ComputedSignalImpl extends SignalImpl {
1541
1618
  */
1542
1619
  class SerializerSignalImpl extends ComputedSignalImpl {
1543
1620
  constructor(container, argQrl) {
1544
- super(container, argQrl);
1621
+ super(container, argQrl, 1 /* SignalFlags.INVALID */ | 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */);
1545
1622
  }
1546
1623
  $didInitialize$ = false;
1547
1624
  $computeIfNeeded$() {
1548
1625
  if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
1549
- return false;
1626
+ return;
1550
1627
  }
1551
1628
  throwIfQRLNotResolved(this.$computeQrl$);
1552
1629
  let arg = this.$computeQrl$.resolved;
@@ -1557,16 +1634,16 @@ class SerializerSignalImpl extends ComputedSignalImpl {
1557
1634
  const update = arg.update;
1558
1635
  const currentValue = this.$untrackedValue$ === NEEDS_COMPUTATION ? initial : this.$untrackedValue$;
1559
1636
  const untrackedValue = trackSignal(() => this.$didInitialize$
1560
- ? update?.(currentValue)
1637
+ ? update?.(currentValue) || currentValue
1561
1638
  : deserialize(currentValue), this, "." /* EffectProperty.VNODE */, this.$container$);
1562
1639
  const didChange = (this.$didInitialize$ && untrackedValue !== 'undefined') ||
1563
1640
  untrackedValue !== this.$untrackedValue$;
1564
1641
  this.$flags$ &= -2 /* SignalFlags.INVALID */;
1565
1642
  this.$didInitialize$ = true;
1566
1643
  if (didChange) {
1644
+ this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
1567
1645
  this.$untrackedValue$ = untrackedValue;
1568
1646
  }
1569
- return didChange;
1570
1647
  }
1571
1648
  }
1572
1649
 
@@ -1576,6 +1653,28 @@ const getStoreHandler = (value) => {
1576
1653
  const getStoreTarget = (value) => {
1577
1654
  return value?.[STORE_TARGET] || null;
1578
1655
  };
1656
+ /**
1657
+ * Force a store to recompute and schedule effects.
1658
+ *
1659
+ * @public
1660
+ */
1661
+ const forceStoreEffects = (value, prop) => {
1662
+ const handler = getStoreHandler(value);
1663
+ if (handler) {
1664
+ handler.force(prop);
1665
+ }
1666
+ };
1667
+ /**
1668
+ * @returns True if the store has effects for the given prop
1669
+ * @internal
1670
+ */
1671
+ const _hasStoreEffects = (value, prop) => {
1672
+ const handler = getStoreHandler(value);
1673
+ if (handler) {
1674
+ return (handler.$effects$?.get(prop)?.size ?? 0) > 0;
1675
+ }
1676
+ return false;
1677
+ };
1579
1678
  /**
1580
1679
  * Get the original object that was wrapped by the store. Useful if you want to clone a store
1581
1680
  * (structuredClone, IndexedDB,...)
@@ -1585,6 +1684,7 @@ const getStoreTarget = (value) => {
1585
1684
  const unwrapStore = (value) => {
1586
1685
  return getStoreTarget(value) || value;
1587
1686
  };
1687
+ /** @internal */
1588
1688
  const isStore = (value) => {
1589
1689
  return STORE_TARGET in value;
1590
1690
  };
@@ -1613,7 +1713,12 @@ class StoreHandler {
1613
1713
  toString() {
1614
1714
  return '[Store]';
1615
1715
  }
1716
+ force(prop) {
1717
+ const target = getStoreTarget(this);
1718
+ this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, getEffects(target, prop, this.$effects$));
1719
+ }
1616
1720
  get(target, prop) {
1721
+ // TODO(perf): handle better `slice` calls
1617
1722
  if (typeof prop === 'symbol') {
1618
1723
  if (prop === STORE_TARGET) {
1619
1724
  return target;
@@ -1646,8 +1751,7 @@ class StoreHandler {
1646
1751
  }
1647
1752
  const flags = this.$flags$;
1648
1753
  if (flags & 1 /* StoreFlags.RECURSIVE */ &&
1649
- typeof value === 'object' &&
1650
- value !== null &&
1754
+ isObject(value) &&
1651
1755
  !Object.isFrozen(value) &&
1652
1756
  !isStore(value) &&
1653
1757
  !Object.isFrozen(target)) {
@@ -1677,7 +1781,11 @@ class StoreHandler {
1677
1781
  if (typeof prop != 'string' || !delete target[prop]) {
1678
1782
  return false;
1679
1783
  }
1680
- triggerEffects(this.$container$, this, getEffects(target, prop, this.$effects$));
1784
+ if (!Array.isArray(target)) {
1785
+ // If the target is an array, we don't need to trigger effects.
1786
+ // Changing the length property will trigger effects.
1787
+ this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, getEffects(target, prop, this.$effects$));
1788
+ }
1681
1789
  return true;
1682
1790
  }
1683
1791
  has(target, prop) {
@@ -1736,8 +1844,10 @@ function addStoreEffect(target, prop, store, effectSubscription) {
1736
1844
  }
1737
1845
  function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
1738
1846
  target[prop] = value;
1739
- // TODO: trigger effects through the scheduler
1740
- triggerEffects(currentStore.$container$, currentStore, getEffects(target, prop, currentStore.$effects$));
1847
+ const effects = getEffects(target, prop, currentStore.$effects$);
1848
+ if (effects) {
1849
+ currentStore.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, currentStore, effects);
1850
+ }
1741
1851
  }
1742
1852
  function getEffects(target, prop, storeEffects) {
1743
1853
  let effectsToTrigger;
@@ -1825,7 +1935,7 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
1825
1935
  $loadingEffects$ = null;
1826
1936
  $errorEffects$ = null;
1827
1937
  $destroy$;
1828
- $promiseValue$ = null;
1938
+ $promiseValue$ = NEEDS_COMPUTATION;
1829
1939
  [_EFFECT_BACK_REF] = null;
1830
1940
  constructor(container, fn, flags = 1 /* SignalFlags.INVALID */) {
1831
1941
  super(container, fn, flags);
@@ -1859,18 +1969,23 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
1859
1969
  get untrackedError() {
1860
1970
  return this.$untrackedError$;
1861
1971
  }
1972
+ invalidate() {
1973
+ super.invalidate();
1974
+ this.$promiseValue$ = NEEDS_COMPUTATION;
1975
+ }
1862
1976
  $computeIfNeeded$() {
1863
1977
  if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
1864
- return false;
1978
+ return;
1865
1979
  }
1866
1980
  const computeQrl = this.$computeQrl$;
1867
1981
  throwIfQRLNotResolved(computeQrl);
1868
1982
  const [cleanup] = cleanupFn(this, (err) => this.$container$?.handleError(err, null));
1869
- const untrackedValue = this.$promiseValue$ ??
1870
- computeQrl.getFn()({
1983
+ const untrackedValue = this.$promiseValue$ === NEEDS_COMPUTATION
1984
+ ? computeQrl.getFn()({
1871
1985
  track: trackFn(this, this.$container$),
1872
1986
  cleanup,
1873
- });
1987
+ })
1988
+ : this.$promiseValue$;
1874
1989
  if (isPromise(untrackedValue)) {
1875
1990
  this.untrackedLoading = true;
1876
1991
  this.untrackedError = null;
@@ -1881,14 +1996,16 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
1881
1996
  this.untrackedError = null;
1882
1997
  })
1883
1998
  .catch((err) => {
1999
+ this.$promiseValue$ = err;
1884
2000
  this.untrackedLoading = false;
1885
2001
  this.untrackedError = err;
1886
2002
  });
1887
2003
  }
1888
- this.$promiseValue$ = null;
2004
+ this.$promiseValue$ = NEEDS_COMPUTATION;
1889
2005
  this.$flags$ &= -2 /* SignalFlags.INVALID */;
1890
2006
  const didChange = untrackedValue !== this.$untrackedValue$;
1891
2007
  if (didChange) {
2008
+ this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
1892
2009
  this.$untrackedValue$ = untrackedValue;
1893
2010
  }
1894
2011
  return didChange;
@@ -1900,13 +2017,15 @@ const createSignal$1 = (value) => {
1900
2017
  return new SignalImpl(null, value);
1901
2018
  };
1902
2019
  /** @internal */
1903
- const createComputedSignal = (qrl) => {
1904
- throwIfQRLNotResolved(qrl);
1905
- return new ComputedSignalImpl(null, qrl);
2020
+ const createComputedSignal = (qrl, options) => {
2021
+ return new ComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'always'));
2022
+ };
2023
+ /** @internal */
2024
+ const createAsyncComputedSignal = (qrl, options) => {
2025
+ return new AsyncComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'never'));
1906
2026
  };
1907
2027
  /** @internal */
1908
2028
  const createSerializerSignal = (arg) => {
1909
- throwIfQRLNotResolved(arg);
1910
2029
  return new SerializerSignalImpl(null, arg);
1911
2030
  };
1912
2031
 
@@ -1925,11 +2044,22 @@ const createSignal = createSignal$1;
1925
2044
  * The QRL must be a function which returns the value of the signal. The function must not have side
1926
2045
  * effects, and it must be synchronous.
1927
2046
  *
1928
- * If you need the function to be async, use `useSignal` and `useTask$` instead.
2047
+ * If you need the function to be async, use `useAsyncComputed$` instead.
1929
2048
  *
1930
2049
  * @public
1931
2050
  */
1932
2051
  const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedSignal);
2052
+ /**
2053
+ * Create an async computed signal which is calculated from the given QRL. A computed signal is a
2054
+ * signal which is calculated from other signals or async operation. When the signals change, the
2055
+ * computed signal is recalculated.
2056
+ *
2057
+ * The QRL must be a function which returns the value of the signal. The function must not have side
2058
+ * effects, and it can be async.
2059
+ *
2060
+ * @public
2061
+ */
2062
+ const createAsyncComputed$ = /*#__PURE__*/ implicit$FirstArg(createAsyncComputedSignal);
1933
2063
  /**
1934
2064
  * Create a signal that holds a custom serializable value. See {@link useSerializer$} for more
1935
2065
  * details.
@@ -1963,7 +2093,7 @@ const _wrapProp = (...args) => {
1963
2093
  if (!(obj instanceof AsyncComputedSignalImpl)) {
1964
2094
  assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
1965
2095
  }
1966
- if (obj instanceof WrappedSignalImpl && obj.flags & 2 /* WrappedSignalFlags.UNWRAP */) {
2096
+ if (obj instanceof WrappedSignalImpl && obj.flags & 4 /* WrappedSignalFlags.UNWRAP */) {
1967
2097
  return obj;
1968
2098
  }
1969
2099
  return getWrapped(args);
@@ -1989,17 +2119,6 @@ const _wrapProp = (...args) => {
1989
2119
  // the object is not reactive, so we can just return the value
1990
2120
  return obj[prop];
1991
2121
  };
1992
- /** @internal */
1993
- const _wrapStore = (obj, prop) => {
1994
- const target = getStoreTarget(obj);
1995
- const value = target[prop];
1996
- if (isSignal(value)) {
1997
- return value;
1998
- }
1999
- else {
2000
- return new WrappedSignalImpl(null, getProp, [obj, prop], null, 1 /* SignalFlags.INVALID */);
2001
- }
2002
- };
2003
2122
  /** @internal @deprecated v1 compat */
2004
2123
  const _wrapSignal = (obj, prop) => {
2005
2124
  const r = _wrapProp(obj, prop);
@@ -2035,7 +2154,7 @@ function isSlotProp(prop) {
2035
2154
  return !prop.startsWith('q:') && !prop.startsWith(NON_SERIALIZABLE_MARKER_PREFIX);
2036
2155
  }
2037
2156
  /** @internal */
2038
- const _restProps = (props, omit, target = {}) => {
2157
+ const _restProps = (props, omit = [], target = {}) => {
2039
2158
  let constPropsTarget = null;
2040
2159
  const constProps = props[_CONST_PROPS];
2041
2160
  if (constProps) {
@@ -2421,7 +2540,6 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
2421
2540
  if (!isInlineComponent) {
2422
2541
  container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
2423
2542
  container.setHostProp(renderHost, USE_ON_LOCAL_SEQ_IDX, null);
2424
- container.setHostProp(renderHost, ELEMENT_PROPS, props);
2425
2543
  }
2426
2544
  if (vnode_isVNode(renderHost)) {
2427
2545
  clearAllEffects(container, renderHost);
@@ -2435,75 +2553,83 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
2435
2553
  return jsx;
2436
2554
  }, (err) => {
2437
2555
  if (isPromise(err) && retryCount < MAX_RETRY_ON_PROMISE_COUNT) {
2438
- return err.then(() => executeComponentWithPromiseExceptionRetry(retryCount++));
2556
+ return err.then(() => executeComponentWithPromiseExceptionRetry(++retryCount));
2439
2557
  }
2440
2558
  else {
2559
+ if (retryCount >= MAX_RETRY_ON_PROMISE_COUNT) {
2560
+ throw new Error(`Max retry count of component execution reached`);
2561
+ }
2441
2562
  throw err;
2442
2563
  }
2443
2564
  });
2444
2565
  return executeComponentWithPromiseExceptionRetry();
2445
2566
  };
2446
2567
  /**
2447
- * Stores the JSX output of the last execution of the component.
2448
- *
2449
- * Component can execute multiple times because:
2450
- *
2451
- * - Component can have multiple tasks
2452
- * - Tasks can track signals
2453
- * - Task A can change signal which causes Task B to rerun.
2568
+ * Adds `useOn` events to the JSX output.
2454
2569
  *
2455
- * So when executing a component we only care about its last JSX Output.
2570
+ * @param jsx The JSX output to modify.
2571
+ * @param useOnEvents The `useOn` events to add.
2572
+ * @returns The modified JSX output.
2456
2573
  */
2457
2574
  function addUseOnEvents(jsx, useOnEvents) {
2458
- const jsxElement = findFirstStringJSX(jsx);
2575
+ const jsxElement = findFirstElementNode(jsx);
2459
2576
  let jsxResult = jsx;
2577
+ const qVisibleEvent = 'onQvisible$';
2460
2578
  return maybeThen(jsxElement, (jsxElement) => {
2461
- let isInvisibleComponent = false;
2462
- if (!jsxElement) {
2463
- /**
2464
- * We did not find any jsx node with a string tag. This means that we should append:
2465
- *
2466
- * ```html
2467
- * <script type="placeholder" hidden on-document:qinit="..."></script>
2468
- * ```
2469
- *
2470
- * This is needed because use on events should have a node to attach them to.
2471
- */
2472
- isInvisibleComponent = true;
2473
- }
2579
+ // headless components are components that don't render a real DOM element
2580
+ const isHeadless = !jsxElement;
2581
+ // placeholder element is a <script> element that is used to add events to the document or window
2582
+ let placeholderElement = null;
2474
2583
  for (const key in useOnEvents) {
2475
2584
  if (Object.prototype.hasOwnProperty.call(useOnEvents, key)) {
2476
- if (isInvisibleComponent) {
2477
- if (key === 'onQvisible$') {
2478
- const [jsxElement, jsx] = addScriptNodeForInvisibleComponents(jsxResult);
2479
- jsxResult = jsx;
2480
- if (jsxElement) {
2481
- addUseOnEvent(jsxElement, 'document:onQinit$', useOnEvents[key]);
2585
+ let targetElement = jsxElement;
2586
+ let eventKey = key;
2587
+ if (isHeadless) {
2588
+ // if the component is headless, we need to add the event to the placeholder element
2589
+ if (key === qVisibleEvent ||
2590
+ key.startsWith("document:on" /* EventNameJSXScope.document */) ||
2591
+ key.startsWith("window:on" /* EventNameJSXScope.window */)) {
2592
+ if (!placeholderElement) {
2593
+ const [createdElement, newJsx] = injectPlaceholderElement(jsxResult);
2594
+ jsxResult = newJsx;
2595
+ placeholderElement = createdElement;
2482
2596
  }
2597
+ targetElement = placeholderElement;
2483
2598
  }
2484
- else if (key.startsWith('document:') || key.startsWith('window:')) {
2485
- const [jsxElement, jsx] = addScriptNodeForInvisibleComponents(jsxResult);
2486
- jsxResult = jsx;
2487
- if (jsxElement) {
2488
- addUseOnEvent(jsxElement, key, useOnEvents[key]);
2599
+ else {
2600
+ if (isDev) {
2601
+ logWarn('You are trying to add an event "' +
2602
+ key +
2603
+ '" using `useOn` hook, ' +
2604
+ 'but a node to which you can add an event is not found. ' +
2605
+ 'Please make sure that the component has a valid element node. ');
2489
2606
  }
2607
+ continue;
2490
2608
  }
2491
- else if (isDev) {
2609
+ }
2610
+ if (targetElement) {
2611
+ if (targetElement.type === 'script' && key === qVisibleEvent) {
2612
+ eventKey = 'document:onQInit$';
2492
2613
  logWarn('You are trying to add an event "' +
2493
2614
  key +
2494
- '" using `useOn` hook, ' +
2615
+ '" using `useVisibleTask$` hook, ' +
2495
2616
  'but a node to which you can add an event is not found. ' +
2496
- 'Please make sure that the component has a valid element node. ');
2617
+ 'Using document:onQInit$ instead.');
2497
2618
  }
2498
- }
2499
- else if (jsxElement) {
2500
- addUseOnEvent(jsxElement, key, useOnEvents[key]);
2619
+ addUseOnEvent(targetElement, eventKey, useOnEvents[key]);
2501
2620
  }
2502
2621
  }
2503
2622
  }
2504
2623
  return jsxResult;
2505
2624
  });
2506
2625
  }
2626
+ /**
2627
+ * Adds an event to the JSX element.
2628
+ *
2629
+ * @param jsxElement The JSX element to add the event to.
2630
+ * @param key The event name.
2631
+ * @param value The event value.
2632
+ */
2507
2633
  function addUseOnEvent(jsxElement, key, value) {
2508
2634
  let props = jsxElement.props;
2509
2635
  if (props === EMPTY_OBJ) {
@@ -2519,7 +2645,13 @@ function addUseOnEvent(jsxElement, key, value) {
2519
2645
  propValue.push(...value);
2520
2646
  props[key] = propValue;
2521
2647
  }
2522
- function findFirstStringJSX(jsx) {
2648
+ /**
2649
+ * Finds the first element node in the JSX output.
2650
+ *
2651
+ * @param jsx The JSX output to search.
2652
+ * @returns The first element node or null if no element node is found.
2653
+ */
2654
+ function findFirstElementNode(jsx) {
2523
2655
  const queue = [jsx];
2524
2656
  while (queue.length) {
2525
2657
  const jsx = queue.shift();
@@ -2529,44 +2661,69 @@ function findFirstStringJSX(jsx) {
2529
2661
  }
2530
2662
  queue.push(jsx.children);
2531
2663
  }
2532
- else if (Array.isArray(jsx)) {
2664
+ else if (isArray(jsx)) {
2533
2665
  queue.push(...jsx);
2534
2666
  }
2535
2667
  else if (isPromise(jsx)) {
2536
- return maybeThen(jsx, (jsx) => findFirstStringJSX(jsx));
2668
+ return maybeThen(jsx, (jsx) => findFirstElementNode(jsx));
2537
2669
  }
2538
2670
  else if (isSignal(jsx)) {
2539
- return findFirstStringJSX(untrack(() => jsx.value));
2671
+ return findFirstElementNode(untrack(() => jsx.value));
2540
2672
  }
2541
2673
  }
2542
2674
  return null;
2543
2675
  }
2544
- function addScriptNodeForInvisibleComponents(jsx) {
2676
+ /**
2677
+ * Injects a placeholder <script> element into the JSX output.
2678
+ *
2679
+ * This is necessary for headless components (components that don't render a real DOM element) to
2680
+ * have an anchor point for `useOn` event listeners that target the document or window.
2681
+ *
2682
+ * @param jsx The JSX output to modify.
2683
+ * @returns A tuple containing the created placeholder element and the modified JSX output.
2684
+ */
2685
+ function injectPlaceholderElement(jsx) {
2686
+ // For regular JSX nodes, we can append the placeholder to its children.
2545
2687
  if (isJSXNode(jsx)) {
2546
- const jsxElement = new JSXNodeImpl('script', {}, {
2547
- type: 'placeholder',
2548
- hidden: '',
2549
- }, null, 3);
2688
+ const placeholder = createPlaceholderScriptNode();
2689
+ // For slots, we can't add children, so we wrap them in a fragment.
2550
2690
  if (jsx.type === Slot) {
2551
- return [jsxElement, _jsxSorted(Fragment, null, null, [jsx, jsxElement], 0, null)];
2691
+ return [placeholder, _jsxSorted(Fragment, null, null, [jsx, placeholder], 0, null)];
2552
2692
  }
2553
2693
  if (jsx.children == null) {
2554
- jsx.children = jsxElement;
2694
+ jsx.children = placeholder;
2555
2695
  }
2556
- else if (Array.isArray(jsx.children)) {
2557
- jsx.children.push(jsxElement);
2696
+ else if (isArray(jsx.children)) {
2697
+ jsx.children.push(placeholder);
2558
2698
  }
2559
2699
  else {
2560
- jsx.children = [jsx.children, jsxElement];
2700
+ jsx.children = [jsx.children, placeholder];
2561
2701
  }
2562
- return [jsxElement, jsx];
2702
+ return [placeholder, jsx];
2703
+ }
2704
+ // For primitives, we can't add children, so we wrap them in a fragment.
2705
+ if (isPrimitive(jsx)) {
2706
+ const placeholder = createPlaceholderScriptNode();
2707
+ return [placeholder, _jsxSorted(Fragment, null, null, [jsx, placeholder], 0, null)];
2563
2708
  }
2564
- else if (Array.isArray(jsx) && jsx.length) {
2565
- // get first element
2566
- const [jsxElement, _] = addScriptNodeForInvisibleComponents(jsx[0]);
2567
- return [jsxElement, jsx];
2709
+ // For an array of nodes, we inject the placeholder into the first element.
2710
+ if (isArray(jsx) && jsx.length > 0) {
2711
+ const [createdElement, _] = injectPlaceholderElement(jsx[0]);
2712
+ return [createdElement, jsx];
2568
2713
  }
2569
- return [null, null];
2714
+ // For anything else we do nothing.
2715
+ return [null, jsx];
2716
+ }
2717
+ /**
2718
+ * Creates a <script> element with a placeholder type.
2719
+ *
2720
+ * @returns A <script> element with a placeholder type.
2721
+ */
2722
+ function createPlaceholderScriptNode() {
2723
+ return new JSXNodeImpl('script', {}, {
2724
+ type: 'placeholder',
2725
+ hidden: '',
2726
+ }, null, 3);
2570
2727
  }
2571
2728
 
2572
2729
  const applyInlineComponent = (ssr, componentHost, inlineComponentFunction, jsx) => {
@@ -2580,13 +2737,13 @@ const applyQwikComponentBody = (ssr, jsx, component) => {
2580
2737
  if (srcProps && srcProps.children) {
2581
2738
  delete srcProps.children;
2582
2739
  }
2583
- const scheduler = ssr.$scheduler$;
2584
2740
  host.setProp(OnRenderProp, componentQrl);
2585
2741
  host.setProp(ELEMENT_PROPS, srcProps);
2586
2742
  if (jsx.key !== null) {
2587
2743
  host.setProp(ELEMENT_KEY, jsx.key);
2588
2744
  }
2589
- return scheduler(6 /* ChoreType.COMPONENT */, host, componentQrl, srcProps);
2745
+ const componentChore = ssr.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQrl, srcProps);
2746
+ return getChorePromise(componentChore);
2590
2747
  };
2591
2748
 
2592
2749
  class ParentComponentData {
@@ -2694,7 +2851,14 @@ function processJSXNode(ssr, enqueue, value, options) {
2694
2851
  appendQwikInspectorAttribute(jsx, qwikInspectorAttrValue);
2695
2852
  }
2696
2853
  }
2697
- const innerHTML = ssr.openElement(type, varPropsToSsrAttrs(jsx.varProps, jsx.constProps, ssr.serializationCtx, options.styleScoped, jsx.key), constPropsToSsrAttrs(jsx.constProps, jsx.varProps, ssr.serializationCtx, options.styleScoped), qwikInspectorAttrValue);
2854
+ const innerHTML = ssr.openElement(type, varPropsToSsrAttrs(jsx.varProps, jsx.constProps, {
2855
+ serializationCtx: ssr.serializationCtx,
2856
+ styleScopedId: options.styleScoped,
2857
+ key: jsx.key,
2858
+ }), constPropsToSsrAttrs(jsx.constProps, jsx.varProps, {
2859
+ serializationCtx: ssr.serializationCtx,
2860
+ styleScopedId: options.styleScoped,
2861
+ }), qwikInspectorAttrValue);
2698
2862
  if (innerHTML) {
2699
2863
  ssr.htmlNode(innerHTML);
2700
2864
  }
@@ -2810,16 +2974,17 @@ function processJSXNode(ssr, enqueue, value, options) {
2810
2974
  }
2811
2975
  }
2812
2976
  }
2813
- function varPropsToSsrAttrs(varProps, constProps, serializationCtx, styleScopedId, key) {
2814
- return toSsrAttrs(varProps, constProps, serializationCtx, true, styleScopedId, key);
2977
+ function varPropsToSsrAttrs(varProps, constProps, options) {
2978
+ return toSsrAttrs(varProps, constProps, false, options);
2815
2979
  }
2816
- function constPropsToSsrAttrs(constProps, varProps, serializationCtx, styleScopedId) {
2817
- return toSsrAttrs(constProps, varProps, serializationCtx, false, styleScopedId);
2980
+ function constPropsToSsrAttrs(constProps, varProps, options) {
2981
+ return toSsrAttrs(constProps, varProps, true, options);
2818
2982
  }
2819
- function toSsrAttrs(record, anotherRecord, serializationCtx, pushMergedEventProps, styleScopedId, key) {
2983
+ function toSsrAttrs(record, anotherRecord, isConst, options) {
2820
2984
  if (record == null) {
2821
2985
  return null;
2822
2986
  }
2987
+ const pushMergedEventProps = !isConst;
2823
2988
  const ssrAttrs = [];
2824
2989
  for (const key in record) {
2825
2990
  let value = record[key];
@@ -2856,7 +3021,7 @@ function toSsrAttrs(record, anotherRecord, serializationCtx, pushMergedEventProp
2856
3021
  }
2857
3022
  }
2858
3023
  }
2859
- const eventValue = setEvent(serializationCtx, key, value);
3024
+ const eventValue = setEvent(options.serializationCtx, key, value);
2860
3025
  if (eventValue) {
2861
3026
  ssrAttrs.push(jsxEventToHtmlAttribute(key), eventValue);
2862
3027
  }
@@ -2866,7 +3031,7 @@ function toSsrAttrs(record, anotherRecord, serializationCtx, pushMergedEventProp
2866
3031
  // write signal as is. We will track this signal inside `writeAttrs`
2867
3032
  if (isClassAttr(key)) {
2868
3033
  // additionally append styleScopedId for class attr
2869
- ssrAttrs.push(key, [value, styleScopedId]);
3034
+ ssrAttrs.push(key, [value, options.styleScopedId]);
2870
3035
  }
2871
3036
  else {
2872
3037
  ssrAttrs.push(key, value);
@@ -2874,13 +3039,13 @@ function toSsrAttrs(record, anotherRecord, serializationCtx, pushMergedEventProp
2874
3039
  continue;
2875
3040
  }
2876
3041
  if (isPreventDefault(key)) {
2877
- addPreventDefaultEventToSerializationContext(serializationCtx, key);
3042
+ addPreventDefaultEventToSerializationContext(options.serializationCtx, key);
2878
3043
  }
2879
- value = serializeAttribute(key, value, styleScopedId);
3044
+ value = serializeAttribute(key, value, options.styleScopedId);
2880
3045
  ssrAttrs.push(key, value);
2881
3046
  }
2882
- if (key != null) {
2883
- ssrAttrs.push(ELEMENT_KEY, key);
3047
+ if (options.key != null) {
3048
+ ssrAttrs.push(ELEMENT_KEY, options.key);
2884
3049
  }
2885
3050
  return ssrAttrs;
2886
3051
  }
@@ -2929,7 +3094,7 @@ function setEvent(serializationCtx, key, rawValue) {
2929
3094
  * For internal qrls (starting with `_`) we assume that they do the right thing.
2930
3095
  */
2931
3096
  if (!qrl.$symbol$.startsWith('_') && (qrl.$captureRef$ || qrl.$capture$)) {
2932
- qrl = createQRL(null, '_run', queueQRL, null, null, [qrl]);
3097
+ qrl = createQRL(null, '_run', _run, null, null, [qrl]);
2933
3098
  }
2934
3099
  return qrlToString(serializationCtx, qrl);
2935
3100
  };
@@ -3009,10 +3174,9 @@ const useTaskQrl = (qrl) => {
3009
3174
  // deleted and we need to be able to release the task subscriptions.
3010
3175
  set(task);
3011
3176
  const container = iCtx.$container$;
3012
- const promise = container.$scheduler$(3 /* ChoreType.TASK */, task);
3013
- if (isPromise(promise)) {
3014
- // TODO: should we handle this differently?
3015
- promise.catch(() => { });
3177
+ const result = runTask(task, container, iCtx.$hostElement$);
3178
+ if (isPromise(result)) {
3179
+ throw result;
3016
3180
  }
3017
3181
  };
3018
3182
  const runTask = (task, container, host) => {
@@ -3024,7 +3188,7 @@ const runTask = (task, container, host) => {
3024
3188
  const track = trackFn(task, container);
3025
3189
  const [cleanup] = cleanupFn(task, (reason) => container.handleError(reason, host));
3026
3190
  const taskApi = { track, cleanup };
3027
- const result = safeCall(() => taskFn(taskApi), cleanup, (err) => {
3191
+ return safeCall(() => taskFn(taskApi), cleanup, (err) => {
3028
3192
  // If a Promise is thrown, that means we need to re-run the task.
3029
3193
  if (isPromise(err)) {
3030
3194
  return err.then(() => runTask(task, container, host));
@@ -3033,7 +3197,6 @@ const runTask = (task, container, host) => {
3033
3197
  throw err;
3034
3198
  }
3035
3199
  });
3036
- return result;
3037
3200
  };
3038
3201
  const cleanupTask = (task) => {
3039
3202
  const destroy = task.$destroy$;
@@ -3064,6 +3227,7 @@ class Task extends BackRef {
3064
3227
  this.$destroy$ = $destroy$;
3065
3228
  }
3066
3229
  }
3230
+ /** @internal */
3067
3231
  const isTask = (value) => {
3068
3232
  return value instanceof Task;
3069
3233
  };
@@ -3074,7 +3238,7 @@ const isTask = (value) => {
3074
3238
  */
3075
3239
  const scheduleTask = (_event, element) => {
3076
3240
  const [task] = useLexicalScope();
3077
- const type = task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */ ? 32 /* ChoreType.VISIBLE */ : 3 /* ChoreType.TASK */;
3241
+ const type = task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */ ? 16 /* ChoreType.VISIBLE */ : 3 /* ChoreType.TASK */;
3078
3242
  const container = getDomContainer(element);
3079
3243
  container.$scheduler$(type, task);
3080
3244
  };
@@ -3326,7 +3490,7 @@ class PropsProxyHandler {
3326
3490
  ? this.$constProps$[prop]
3327
3491
  : this.$varProps$[prop];
3328
3492
  // a proxied value that the optimizer made
3329
- return value instanceof WrappedSignalImpl && value.$flags$ & 2 /* WrappedSignalFlags.UNWRAP */
3493
+ return value instanceof WrappedSignalImpl && value.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */
3330
3494
  ? value.value
3331
3495
  : value;
3332
3496
  }
@@ -3402,48 +3566,23 @@ class PropsProxyHandler {
3402
3566
  const directGetPropsProxyProp = (jsx, prop) => {
3403
3567
  return (jsx.constProps && prop in jsx.constProps ? jsx.constProps[prop] : jsx.varProps[prop]);
3404
3568
  };
3405
-
3406
- const mapApp_findIndx = (array, key, start) => {
3407
- assertTrue(start % 2 === 0, 'Expecting even number.');
3408
- let bottom = start >> 1;
3409
- let top = (array.length - 2) >> 1;
3410
- while (bottom <= top) {
3411
- const mid = bottom + ((top - bottom) >> 1);
3412
- const midKey = array[mid << 1];
3413
- if (midKey === key) {
3414
- return mid << 1;
3415
- }
3416
- if (midKey < key) {
3417
- bottom = mid + 1;
3418
- }
3419
- else {
3420
- top = mid - 1;
3421
- }
3422
- }
3423
- return (bottom << 1) ^ -1;
3424
- };
3425
- const mapArray_set = (array, key, value, start) => {
3426
- const indx = mapApp_findIndx(array, key, start);
3427
- if (indx >= 0) {
3428
- if (value == null) {
3429
- array.splice(indx, 2);
3430
- }
3431
- else {
3432
- array[indx + 1] = value;
3433
- }
3434
- }
3435
- else if (value != null) {
3436
- array.splice(indx ^ -1, 0, key, value);
3569
+ /** @internal */
3570
+ const _getVarProps = (props) => {
3571
+ if (!props) {
3572
+ return null;
3437
3573
  }
3574
+ return _VAR_PROPS in props
3575
+ ? 'children' in props
3576
+ ? { ...props[_VAR_PROPS], children: props.children }
3577
+ : props[_VAR_PROPS]
3578
+ : props;
3438
3579
  };
3439
- const mapArray_get = (array, key, start) => {
3440
- const indx = mapApp_findIndx(array, key, start);
3441
- if (indx >= 0) {
3442
- return array[indx + 1];
3443
- }
3444
- else {
3580
+ /** @internal */
3581
+ const _getConstProps = (props) => {
3582
+ if (!props) {
3445
3583
  return null;
3446
3584
  }
3585
+ return _CONST_PROPS in props ? props[_CONST_PROPS] : null;
3447
3586
  };
3448
3587
 
3449
3588
  const isForeignObjectElement = (elementName) => {
@@ -3649,6 +3788,24 @@ function getNewElementNamespaceData(domParentVNode, tagOrVNode) {
3649
3788
  elementNamespaceFlag,
3650
3789
  };
3651
3790
  }
3791
+ function getAttributeNamespace(attributeName) {
3792
+ switch (attributeName) {
3793
+ case 'xlink:href':
3794
+ case 'xlink:actuate':
3795
+ case 'xlink:arcrole':
3796
+ case 'xlink:role':
3797
+ case 'xlink:show':
3798
+ case 'xlink:title':
3799
+ case 'xlink:type':
3800
+ return XLINK_NS;
3801
+ case 'xml:base':
3802
+ case 'xml:lang':
3803
+ case 'xml:space':
3804
+ return XML_NS;
3805
+ default:
3806
+ return null;
3807
+ }
3808
+ }
3652
3809
 
3653
3810
  function escapeHTML(html) {
3654
3811
  let escapedHTML = '';
@@ -3747,6 +3904,10 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
3747
3904
  vNewNode = null;
3748
3905
  vCurrent = vnode_getFirstChild(vStartNode);
3749
3906
  stackPush(jsxNode, true);
3907
+ if (vParent[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */) {
3908
+ // Ignore diff if the parent is deleted.
3909
+ return;
3910
+ }
3750
3911
  while (stack.length) {
3751
3912
  while (jsxIdx < jsxCount) {
3752
3913
  assertFalse(vParent === vCurrent, "Parent and current can't be the same");
@@ -4175,8 +4336,10 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
4175
4336
  value = trackSignalAndAssignHost(value, vNewNode, key, container, signalData);
4176
4337
  }
4177
4338
  if (key === dangerouslySetInnerHTML) {
4178
- element.innerHTML = value;
4179
- element.setAttribute(QContainerAttr, "html" /* QContainerValue.HTML */);
4339
+ if (value) {
4340
+ element.innerHTML = String(value);
4341
+ element.setAttribute(QContainerAttr, "html" /* QContainerValue.HTML */);
4342
+ }
4180
4343
  continue;
4181
4344
  }
4182
4345
  if (elementName === 'textarea' && key === 'value') {
@@ -4191,6 +4354,14 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
4191
4354
  }
4192
4355
  value = serializeAttribute(key, value, scopedStyleIdPrefix);
4193
4356
  if (value != null) {
4357
+ if (vNewNode[0 /* VNodeProps.flags */] & 64 /* VNodeFlags.NS_svg */) {
4358
+ // only svg elements can have namespace attributes
4359
+ const namespace = getAttributeNamespace(key);
4360
+ if (namespace) {
4361
+ element.setAttributeNS(namespace, key, String(value));
4362
+ continue;
4363
+ }
4364
+ }
4194
4365
  element.setAttribute(key, String(value));
4195
4366
  }
4196
4367
  }
@@ -4269,8 +4440,13 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
4269
4440
  let returnValue = false;
4270
4441
  qrls.flat(2).forEach((qrl) => {
4271
4442
  if (qrl) {
4272
- const value = container.$scheduler$(2 /* ChoreType.RUN_QRL */, vNode, qrl, [event, element]);
4273
- returnValue = returnValue || value === true;
4443
+ if (isSyncQrl(qrl)) {
4444
+ qrl(event, element);
4445
+ }
4446
+ else {
4447
+ const value = container.$scheduler$(2 /* ChoreType.RUN_QRL */, vNode, qrl, [event, element]);
4448
+ returnValue = returnValue || value === true;
4449
+ }
4274
4450
  }
4275
4451
  });
4276
4452
  return returnValue;
@@ -4540,16 +4716,36 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
4540
4716
  shouldRender = true;
4541
4717
  }
4542
4718
  if (host) {
4543
- const vNodeProps = vnode_getProp(host, ELEMENT_PROPS, container.$getObjectById$);
4544
- shouldRender = shouldRender || propsDiffer(jsxProps, vNodeProps);
4719
+ let vNodeProps = vnode_getProp(host, ELEMENT_PROPS, container.$getObjectById$);
4720
+ const propsAreDifferent = propsDiffer(jsxProps, vNodeProps);
4721
+ shouldRender = shouldRender || propsAreDifferent;
4545
4722
  if (shouldRender) {
4723
+ if (propsAreDifferent) {
4724
+ if (vNodeProps) {
4725
+ // Reuse the same props instance, qrls can use the current props instance
4726
+ // as a capture ref, so we can't change it.
4727
+ // We need to do this directly, because normally we would subscribe to the signals
4728
+ // if any signal is there.
4729
+ vNodeProps[_CONST_PROPS] = jsxProps[_CONST_PROPS];
4730
+ vNodeProps[_VAR_PROPS] = jsxProps[_VAR_PROPS];
4731
+ }
4732
+ else if (jsxProps) {
4733
+ // If there is no props instance, create a new one.
4734
+ // We can do this because we are not using the props instance for anything else.
4735
+ vnode_setProp(host, ELEMENT_PROPS, jsxProps);
4736
+ vNodeProps = jsxProps;
4737
+ }
4738
+ }
4739
+ // Assign the new QRL instance to the host.
4740
+ // Unfortunately it is created every time, something to fix in the optimizer.
4741
+ vnode_setProp(host, OnRenderProp, componentQRL);
4546
4742
  /**
4547
4743
  * Mark host as not deleted. The host could have been marked as deleted if it there was a
4548
4744
  * cleanup run. Now we found it and want to reuse it, so we need to mark it as not
4549
4745
  * deleted.
4550
4746
  */
4551
4747
  host[0 /* VNodeProps.flags */] &= -33 /* VNodeFlags.Deleted */;
4552
- container.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQRL, jsxProps);
4748
+ container.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQRL, vNodeProps);
4553
4749
  }
4554
4750
  }
4555
4751
  descendContentToProject(jsxNode.children, host);
@@ -4752,7 +4948,7 @@ function cleanup(container, vNode) {
4752
4948
  const task = obj;
4753
4949
  clearAllEffects(container, task);
4754
4950
  if (task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */) {
4755
- container.$scheduler$(48 /* ChoreType.CLEANUP_VISIBLE */, task);
4951
+ container.$scheduler$(32 /* ChoreType.CLEANUP_VISIBLE */, task);
4756
4952
  }
4757
4953
  else {
4758
4954
  cleanupTask(task);
@@ -4803,7 +4999,16 @@ function cleanup(container, vNode) {
4803
4999
  */
4804
5000
  const vFirstChild = vnode_getFirstChild(vCursor);
4805
5001
  if (vFirstChild) {
4806
- vnode_walkVNode(vFirstChild);
5002
+ vnode_walkVNode(vFirstChild, (vNode) => {
5003
+ /**
5004
+ * Instead of an ID, we store a direct reference to the VNode. This is necessary to
5005
+ * locate the slot's parent in a detached subtree, as the ID would become invalid.
5006
+ */
5007
+ if (vNode[0 /* VNodeProps.flags */] & 2 /* VNodeFlags.Virtual */) {
5008
+ // The QSlotParent is used to find the slot parent during scheduling
5009
+ vnode_getProp(vNode, QSlotParent, (id) => vnode_locate(container.rootVNode, id));
5010
+ }
5011
+ });
4807
5012
  return;
4808
5013
  }
4809
5014
  }
@@ -4880,8 +5085,8 @@ const useResourceQrl = (qrl, opts) => {
4880
5085
  const resource = createResourceReturn(container, opts);
4881
5086
  const el = iCtx.$hostElement$;
4882
5087
  const task = new Task(8 /* TaskFlags.DIRTY */ | 4 /* TaskFlags.RESOURCE */, i, el, qrl, resource, null);
4883
- container.$scheduler$(3 /* ChoreType.TASK */, task);
4884
5088
  set(resource);
5089
+ runResource(task, container, el);
4885
5090
  return resource;
4886
5091
  };
4887
5092
  // <docs markdown="../readme.md#useResource">
@@ -4949,10 +5154,10 @@ const Resource = (props) => {
4949
5154
  function getResourceValueAsPromise(props) {
4950
5155
  const resource = props.value;
4951
5156
  if (isResourceReturn(resource)) {
5157
+ // create a subscription for the resource._state changes
5158
+ const state = resource._state;
4952
5159
  const isBrowser = !isServerPlatform();
4953
5160
  if (isBrowser) {
4954
- // create a subscription for the resource._state changes
4955
- const state = resource._state;
4956
5161
  if (state === 'pending' && props.onPending) {
4957
5162
  return Promise.resolve().then(useBindInvokeContext(props.onPending));
4958
5163
  }
@@ -4967,30 +5172,25 @@ function getResourceValueAsPromise(props) {
4967
5172
  }
4968
5173
  }
4969
5174
  }
4970
- const value = resource.value;
4971
- if (value) {
4972
- return value.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
4973
- }
4974
- else {
4975
- // this is temporary value until the `runResource` is executed and promise is assigned to the value
4976
- return Promise.resolve(undefined);
4977
- }
5175
+ return untrack(() => resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
4978
5176
  }
4979
5177
  else if (isPromise(resource)) {
4980
5178
  return resource.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
4981
5179
  }
4982
5180
  else if (isSignal(resource)) {
4983
- return Promise.resolve(resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
5181
+ const value = retryOnPromise(() => resource.value);
5182
+ const promise = isPromise(value) ? value : Promise.resolve(value);
5183
+ return promise.then(useBindInvokeContext(props.onResolved));
4984
5184
  }
4985
5185
  else {
4986
- return Promise.resolve(resource).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
5186
+ return Promise.resolve(resource).then(useBindInvokeContext(props.onResolved));
4987
5187
  }
4988
5188
  }
4989
5189
  const _createResourceReturn = (opts) => {
4990
5190
  const resource = {
4991
5191
  __brand: 'resource',
4992
5192
  value: undefined,
4993
- loading: isServerPlatform() ? false : true,
5193
+ loading: !isServerPlatform(),
4994
5194
  _resolved: undefined,
4995
5195
  _error: undefined,
4996
5196
  _state: 'pending',
@@ -5041,19 +5241,22 @@ const runResource = (task, container, host) => {
5041
5241
  done = true;
5042
5242
  if (resolved) {
5043
5243
  done = true;
5044
- resource.loading = false;
5045
- resource._state = 'resolved';
5046
- resource._resolved = value;
5047
- resource._error = undefined;
5244
+ resourceTarget.loading = false;
5245
+ resourceTarget._state = 'resolved';
5246
+ resourceTarget._resolved = value;
5247
+ resourceTarget._error = undefined;
5048
5248
  resolve(value);
5049
5249
  }
5050
5250
  else {
5051
5251
  done = true;
5052
- resource.loading = false;
5053
- resource._state = 'rejected';
5054
- resource._error = value;
5252
+ resourceTarget.loading = false;
5253
+ resourceTarget._state = 'rejected';
5254
+ resourceTarget._error = value;
5055
5255
  reject(value);
5056
5256
  }
5257
+ if (!isServerPlatform()) {
5258
+ forceStoreEffects(resource, '_state');
5259
+ }
5057
5260
  return true;
5058
5261
  }
5059
5262
  return false;
@@ -5069,17 +5272,17 @@ const runResource = (task, container, host) => {
5069
5272
  }
5070
5273
  });
5071
5274
  // Execute mutation inside empty invocation
5275
+ // TODO: is it right? why we need to invoke inside context and trigger effects?
5072
5276
  invoke(iCtx, () => {
5073
5277
  // console.log('RESOURCE.pending: ');
5074
5278
  resource._state = 'pending';
5075
5279
  resource.loading = !isServerPlatform();
5076
- const promise = (resource.value = new Promise((r, re) => {
5280
+ resource.value = new Promise((r, re) => {
5077
5281
  resolve = r;
5078
5282
  reject = re;
5079
- }));
5080
- promise.catch(ignoreErrorToPreventNodeFromCrashing);
5283
+ });
5081
5284
  });
5082
- const promise = safeCall(() => Promise.resolve(taskFn(opts)), (value) => {
5285
+ const promise = safeCall(() => taskFn(opts), (value) => {
5083
5286
  setState(true, value);
5084
5287
  }, (err) => {
5085
5288
  if (isPromise(err)) {
@@ -5102,10 +5305,6 @@ const runResource = (task, container, host) => {
5102
5305
  }
5103
5306
  return promise;
5104
5307
  };
5105
- const ignoreErrorToPreventNodeFromCrashing = (err) => {
5106
- // ignore error to prevent node from crashing
5107
- // node will crash in promise is rejected and no one is listening to the rejection.
5108
- };
5109
5308
 
5110
5309
  /// These global variables are used to avoid creating new arrays for each call to `vnode_documentPosition`.
5111
5310
  const aVNodePath = [];
@@ -5188,11 +5387,11 @@ const ssrNodeDocumentPosition = (a, b) => {
5188
5387
  let bDepth = -1;
5189
5388
  while (a) {
5190
5389
  const ssrNode = (aSsrNodePath[++aDepth] = a);
5191
- a = ssrNode.parentSsrNode;
5390
+ a = ssrNode.parentComponent;
5192
5391
  }
5193
5392
  while (b) {
5194
5393
  const ssrNode = (bSsrNodePath[++bDepth] = b);
5195
- b = ssrNode.parentSsrNode;
5394
+ b = ssrNode.parentComponent;
5196
5395
  }
5197
5396
  while (aDepth >= 0 && bDepth >= 0) {
5198
5397
  a = aSsrNodePath[aDepth];
@@ -5209,6 +5408,210 @@ const ssrNodeDocumentPosition = (a, b) => {
5209
5408
  return aDepth < bDepth ? -1 : 1;
5210
5409
  };
5211
5410
 
5411
+ /**
5412
+ * Rules for determining if a chore is blocked by another chore. Some chores can block other chores.
5413
+ * They cannot run until the blocking chore has completed.
5414
+ *
5415
+ * The match function is used to determine if the blocked chore is blocked by the blocking chore.
5416
+ * The match function is called with the blocked chore, the blocking chore, and the container.
5417
+ */
5418
+ const VISIBLE_BLOCKING_RULES = [
5419
+ // NODE_DIFF blocks VISIBLE on same host,
5420
+ // if the blocked chore is a child of the blocking chore
5421
+ // or the blocked chore is a sibling of the blocking chore
5422
+ {
5423
+ blockedType: 16 /* ChoreType.VISIBLE */,
5424
+ blockingType: 4 /* ChoreType.NODE_DIFF */,
5425
+ match: (blocked, blocking, container) => isDescendant(blocked, blocking, container) || isDescendant(blocking, blocked, container),
5426
+ },
5427
+ // COMPONENT blocks VISIBLE on same host
5428
+ // if the blocked chore is a child of the blocking chore
5429
+ // or the blocked chore is a sibling of the blocking chore
5430
+ {
5431
+ blockedType: 16 /* ChoreType.VISIBLE */,
5432
+ blockingType: 6 /* ChoreType.COMPONENT */,
5433
+ match: (blocked, blocking, container) => isDescendant(blocked, blocking, container) || isDescendant(blocking, blocked, container),
5434
+ },
5435
+ ];
5436
+ const BLOCKING_RULES = [
5437
+ // QRL_RESOLVE blocks RUN_QRL, TASK, VISIBLE on same host
5438
+ {
5439
+ blockedType: 2 /* ChoreType.RUN_QRL */,
5440
+ blockingType: 1 /* ChoreType.QRL_RESOLVE */,
5441
+ match: (blocked, blocking) => {
5442
+ const blockedQrl = blocked.$target$;
5443
+ const blockingQrl = blocking.$target$;
5444
+ return isSameHost(blocked, blocking) && isSameQrl(blockedQrl, blockingQrl);
5445
+ },
5446
+ },
5447
+ {
5448
+ blockedType: 3 /* ChoreType.TASK */,
5449
+ blockingType: 1 /* ChoreType.QRL_RESOLVE */,
5450
+ match: (blocked, blocking) => {
5451
+ const blockedTask = blocked.$payload$;
5452
+ const blockingQrl = blocking.$target$;
5453
+ return isSameHost(blocked, blocking) && isSameQrl(blockedTask.$qrl$, blockingQrl);
5454
+ },
5455
+ },
5456
+ {
5457
+ blockedType: 16 /* ChoreType.VISIBLE */,
5458
+ blockingType: 1 /* ChoreType.QRL_RESOLVE */,
5459
+ match: (blocked, blocking) => {
5460
+ const blockedTask = blocked.$payload$;
5461
+ const blockingQrl = blocking.$target$;
5462
+ return isSameHost(blocked, blocking) && isSameQrl(blockedTask.$qrl$, blockingQrl);
5463
+ },
5464
+ },
5465
+ // COMPONENT blocks NODE_DIFF, NODE_PROP on same host
5466
+ {
5467
+ blockedType: 4 /* ChoreType.NODE_DIFF */,
5468
+ blockingType: 6 /* ChoreType.COMPONENT */,
5469
+ match: (blocked, blocking) => blocked.$host$ === blocking.$host$,
5470
+ },
5471
+ {
5472
+ blockedType: 5 /* ChoreType.NODE_PROP */,
5473
+ blockingType: 6 /* ChoreType.COMPONENT */,
5474
+ match: (blocked, blocking) => blocked.$host$ === blocking.$host$,
5475
+ },
5476
+ ...VISIBLE_BLOCKING_RULES,
5477
+ // TASK blocks subsequent TASKs in the same component
5478
+ {
5479
+ blockedType: 3 /* ChoreType.TASK */,
5480
+ blockingType: 3 /* ChoreType.TASK */,
5481
+ match: (blocked, blocking, container) => {
5482
+ if (blocked.$host$ !== blocking.$host$) {
5483
+ return false;
5484
+ }
5485
+ const blockedIdx = blocked.$idx$;
5486
+ if (!isNumber$1(blockedIdx) || blockedIdx <= 0) {
5487
+ return false;
5488
+ }
5489
+ const previousTask = findPreviousTaskInComponent(blocked.$host$, blockedIdx, container);
5490
+ return previousTask === blocking.$payload$;
5491
+ },
5492
+ },
5493
+ ];
5494
+ function isDescendant(descendantChore, ancestorChore, container) {
5495
+ const descendantHost = descendantChore.$host$;
5496
+ const ancestorHost = ancestorChore.$host$;
5497
+ if (!vnode_isVNode(descendantHost) || !vnode_isVNode(ancestorHost)) {
5498
+ return false;
5499
+ }
5500
+ return vnode_isDescendantOf(descendantHost, ancestorHost, container.rootVNode);
5501
+ }
5502
+ function isSameHost(a, b) {
5503
+ return a.$host$ === b.$host$;
5504
+ }
5505
+ function isSameQrl(a, b) {
5506
+ return a.$symbol$ === b.$symbol$;
5507
+ }
5508
+ function findBlockingChoreInQueue(chore, choreQueue, container) {
5509
+ for (const candidate of choreQueue) {
5510
+ // everything after VISIBLE is not blocking. Visible task, task and resource should not block anything in this rule.
5511
+ if (candidate.$type$ >= 16 /* ChoreType.VISIBLE */ || candidate.$type$ === 3 /* ChoreType.TASK */) {
5512
+ continue;
5513
+ }
5514
+ if (isDescendant(chore, candidate, container)) {
5515
+ return candidate;
5516
+ }
5517
+ }
5518
+ return null;
5519
+ }
5520
+ function findBlockingChore(chore, choreQueue, blockedChores, runningChores, container) {
5521
+ const blockingChoreInChoreQueue = findBlockingChoreInQueue(chore, choreQueue, container);
5522
+ if (blockingChoreInChoreQueue) {
5523
+ return blockingChoreInChoreQueue;
5524
+ }
5525
+ const blockingChoreInBlockedChores = findBlockingChoreInQueue(chore, Array.from(blockedChores), container);
5526
+ if (blockingChoreInBlockedChores) {
5527
+ return blockingChoreInBlockedChores;
5528
+ }
5529
+ const blockingChoreInRunningChores = findBlockingChoreInQueue(chore, Array.from(runningChores), container);
5530
+ if (blockingChoreInRunningChores) {
5531
+ return blockingChoreInRunningChores;
5532
+ }
5533
+ for (const rule of BLOCKING_RULES) {
5534
+ if (chore.$type$ !== rule.blockedType) {
5535
+ continue;
5536
+ }
5537
+ // Check in choreQueue
5538
+ // TODO(perf): better to iterate in reverse order?
5539
+ for (const candidate of choreQueue) {
5540
+ if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
5541
+ return candidate;
5542
+ }
5543
+ }
5544
+ // Check in blockedChores
5545
+ for (const candidate of blockedChores) {
5546
+ if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
5547
+ return candidate;
5548
+ }
5549
+ }
5550
+ // Check in runningChores
5551
+ for (const candidate of runningChores) {
5552
+ if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
5553
+ return candidate;
5554
+ }
5555
+ }
5556
+ }
5557
+ return null;
5558
+ }
5559
+ function findPreviousTaskInComponent(host, currentTaskIdx, container) {
5560
+ const elementSeq = container.getHostProp(host, ELEMENT_SEQ);
5561
+ if (!elementSeq || elementSeq.length <= currentTaskIdx) {
5562
+ return null;
5563
+ }
5564
+ for (let i = currentTaskIdx - 1; i >= 0; i--) {
5565
+ const candidate = elementSeq[i];
5566
+ if (candidate instanceof Task && candidate.$flags$ & 2 /* TaskFlags.TASK */) {
5567
+ return candidate;
5568
+ }
5569
+ }
5570
+ return null;
5571
+ }
5572
+ function findBlockingChoreForVisible(chore, runningChores, container) {
5573
+ for (const rule of VISIBLE_BLOCKING_RULES) {
5574
+ if (chore.$type$ !== rule.blockedType) {
5575
+ continue;
5576
+ }
5577
+ for (const candidate of runningChores) {
5578
+ if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
5579
+ return candidate;
5580
+ }
5581
+ }
5582
+ }
5583
+ return null;
5584
+ }
5585
+
5586
+ // This can't be in platform.ts because it uses MessageChannel which cannot post messages with functions
5587
+ // TODO: move this to platform.ts somehow
5588
+ const createNextTick = (fn) => {
5589
+ let nextTick;
5590
+ // according to the https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate#notes
5591
+ if (typeof setImmediate === 'function') {
5592
+ // setImmediate is the fastest way to schedule a task, but works only in node.js
5593
+ nextTick = () => {
5594
+ setImmediate(fn);
5595
+ };
5596
+ }
5597
+ else if (typeof MessageChannel !== 'undefined') {
5598
+ const channel = new MessageChannel();
5599
+ channel.port1.onmessage = () => {
5600
+ fn();
5601
+ };
5602
+ nextTick = () => {
5603
+ channel.port2.postMessage(null);
5604
+ };
5605
+ }
5606
+ else {
5607
+ // setTimeout is a fallback, creates 4ms delay
5608
+ nextTick = () => {
5609
+ setTimeout(fn);
5610
+ };
5611
+ }
5612
+ return nextTick;
5613
+ };
5614
+
5212
5615
  /**
5213
5616
  * Scheduler is responsible for running application code in predictable order.
5214
5617
  *
@@ -5292,29 +5695,43 @@ const ssrNodeDocumentPosition = (a, b) => {
5292
5695
  */
5293
5696
  // Turn this on to get debug output of what the scheduler is doing.
5294
5697
  const DEBUG = false;
5295
- const getPromise = (chore) => (chore.$promise$ ||= new Promise((resolve) => {
5296
- chore.$resolve$ = resolve;
5297
- }));
5298
- const createScheduler = (container, scheduleDrain, journalFlush) => {
5299
- const choreQueue = [];
5300
- const qrlRuns = [];
5301
- let currentChore = null;
5698
+ var ChoreState;
5699
+ (function (ChoreState) {
5700
+ ChoreState[ChoreState["NONE"] = 0] = "NONE";
5701
+ ChoreState[ChoreState["RUNNING"] = 1] = "RUNNING";
5702
+ ChoreState[ChoreState["FAILED"] = 2] = "FAILED";
5703
+ ChoreState[ChoreState["DONE"] = 3] = "DONE";
5704
+ })(ChoreState || (ChoreState = {}));
5705
+ const getChorePromise = (chore) => chore.$state$ === ChoreState.NONE
5706
+ ? (chore.$returnValue$ ||= new Promise((resolve, reject) => {
5707
+ chore.$resolve$ = resolve;
5708
+ chore.$reject$ = reject;
5709
+ }))
5710
+ : chore.$returnValue$;
5711
+ const createScheduler = (container, journalFlush, choreQueue = [], blockedChores = new Set(), runningChores = new Set()) => {
5712
+ let drainChore = null;
5302
5713
  let drainScheduled = false;
5714
+ let isDraining = false;
5715
+ let isJournalFlushRunning = false;
5716
+ let flushBudgetStart = 0;
5717
+ let currentTime = performance.now();
5718
+ const nextTick = createNextTick(drainChoreQueue);
5719
+ function drainInNextTick() {
5720
+ if (!drainScheduled) {
5721
+ drainScheduled = true;
5722
+ nextTick();
5723
+ }
5724
+ }
5725
+ // Drain for ~16.67ms, then apply journal flush for ~16.67ms, then repeat
5726
+ // We divide by 60 because we want to run at 60fps
5727
+ const FREQUENCY_MS = Math.floor(1000 / 60);
5303
5728
  return schedule;
5304
5729
  ///// IMPLEMENTATION /////
5305
5730
  function schedule(type, hostOrTask = null, targetOrQrl = null, payload = null) {
5306
- const isServer = !isDomContainer(container);
5307
- const isComponentSsr = isServer && type === 6 /* ChoreType.COMPONENT */;
5308
- const runLater = type !== 255 /* ChoreType.WAIT_FOR_ALL */ && !isComponentSsr && type !== 2 /* ChoreType.RUN_QRL */;
5309
- const isTask = type === 3 /* ChoreType.TASK */ || type === 32 /* ChoreType.VISIBLE */ || type === 48 /* ChoreType.CLEANUP_VISIBLE */;
5310
- const isClientOnly = type === 16 /* ChoreType.JOURNAL_FLUSH */ ||
5311
- type === 4 /* ChoreType.NODE_DIFF */ ||
5312
- type === 5 /* ChoreType.NODE_PROP */ ||
5313
- type === 1 /* ChoreType.QRL_RESOLVE */ ||
5314
- type === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */;
5315
- if (isServer && isClientOnly) {
5316
- return;
5731
+ if (type === 255 /* ChoreType.WAIT_FOR_QUEUE */ && drainChore) {
5732
+ return drainChore;
5317
5733
  }
5734
+ const isTask = type === 3 /* ChoreType.TASK */ || type === 16 /* ChoreType.VISIBLE */ || type === 32 /* ChoreType.CLEANUP_VISIBLE */;
5318
5735
  if (isTask) {
5319
5736
  hostOrTask.$flags$ |= 8 /* TaskFlags.DIRTY */;
5320
5737
  }
@@ -5328,167 +5745,310 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5328
5745
  $host$: isTask ? hostOrTask.$el$ : hostOrTask,
5329
5746
  $target$: targetOrQrl,
5330
5747
  $payload$: isTask ? hostOrTask : payload,
5331
- $resolve$: null,
5332
- $promise$: null,
5748
+ $state$: ChoreState.NONE,
5749
+ $blockedChores$: null,
5750
+ $startTime$: undefined,
5751
+ $endTime$: undefined,
5752
+ $resolve$: undefined,
5753
+ $reject$: undefined,
5333
5754
  $returnValue$: null,
5334
- $executed$: false,
5335
5755
  };
5336
- chore = sortedInsert(choreQueue, chore, container.rootVNode || null);
5337
- if (!drainScheduled && runLater) {
5338
- // If we are not currently draining, we need to schedule a drain.
5339
- drainScheduled = true;
5340
- schedule(16 /* ChoreType.JOURNAL_FLUSH */);
5341
- // Catch here to avoid unhandled promise rejection
5342
- scheduleDrain()?.catch?.(() => { });
5756
+ if (type === 255 /* ChoreType.WAIT_FOR_QUEUE */) {
5757
+ getChorePromise(chore);
5758
+ drainChore = chore;
5759
+ drainInNextTick();
5760
+ return chore;
5761
+ }
5762
+ const isServer = isServerPlatform();
5763
+ const isClientOnly = type === 4 /* ChoreType.NODE_DIFF */ || type === 1 /* ChoreType.QRL_RESOLVE */;
5764
+ if (isServer && isClientOnly) {
5765
+ // Mark skipped client-only chores as completed on the server
5766
+ finishChore(chore, undefined);
5767
+ return chore;
5768
+ }
5769
+ if (isServer && chore.$host$ && isSsrNode(chore.$host$)) {
5770
+ const isUpdatable = !!(chore.$host$.flags & 1 /* SsrNodeFlags.Updatable */);
5771
+ if (!isUpdatable) {
5772
+ if (
5773
+ // backpatching exceptions:
5774
+ // - node prop is allowed because it is used to update the node property
5775
+ // - recompute and schedule effects because it triggers effects (so node prop too)
5776
+ chore.$type$ !== 5 /* ChoreType.NODE_PROP */ &&
5777
+ chore.$type$ !== 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */) {
5778
+ // We are running on the server.
5779
+ // On server we can't schedule task for a different host!
5780
+ // Server is SSR, and therefore scheduling for anything but the current host
5781
+ // implies that things need to be re-run and that is not supported because of streaming.
5782
+ const warningMessage = `A '${choreTypeToName(chore.$type$)}' chore was scheduled on a host element that has already been streamed to the client.
5783
+ This can lead to inconsistencies between Server-Side Rendering (SSR) and Client-Side Rendering (CSR).
5784
+
5785
+ Problematic chore:
5786
+ - Type: ${choreTypeToName(chore.$type$)}
5787
+ - Host: ${chore.$host$.toString()}
5788
+ - Nearest element location: ${chore.$host$.currentFile}
5789
+
5790
+ This is often caused by modifying a signal in an already rendered component during SSR.`;
5791
+ logWarn(warningMessage);
5792
+ return chore;
5793
+ }
5794
+ }
5343
5795
  }
5344
- // TODO figure out what to do with chore errors
5345
- if (runLater) {
5346
- return getPromise(chore);
5796
+ const blockingChore = findBlockingChore(chore, choreQueue, blockedChores, runningChores, container);
5797
+ if (blockingChore) {
5798
+ addBlockedChore(chore, blockingChore, blockedChores);
5799
+ return chore;
5800
+ }
5801
+ chore = sortedInsert(choreQueue, chore, container.rootVNode || null);
5802
+ const runImmediately = (isServer && type === 6 /* ChoreType.COMPONENT */) || type === 2 /* ChoreType.RUN_QRL */;
5803
+ if (runImmediately && !isDraining) {
5804
+ immediateDrain();
5347
5805
  }
5348
5806
  else {
5349
- return drainUpTo(chore, isServer);
5350
- }
5351
- }
5352
- /** Execute all of the chores up to and including the given chore. */
5353
- function drainUpTo(runUptoChore, isServer) {
5354
- let maxRetries = 5000;
5355
- while (choreQueue.length) {
5356
- if (maxRetries-- < 0) {
5357
- throw new Error('drainUpTo: max retries reached');
5358
- }
5359
- if (currentChore) {
5360
- // Already running chore, which means we're waiting for async completion
5361
- return getPromise(currentChore)
5362
- .then(() => drainUpTo(runUptoChore, isServer))
5363
- .catch((e) => {
5364
- container.handleError(e, currentChore?.$host$);
5365
- });
5807
+ drainInNextTick();
5808
+ }
5809
+ return chore;
5810
+ }
5811
+ function immediateDrain() {
5812
+ drainScheduled = true;
5813
+ drainChoreQueue();
5814
+ }
5815
+ ////////////////////////////////////////////////////////////////////////////////
5816
+ // Drain queue helpers
5817
+ ////////////////////////////////////////////////////////////////////////////////
5818
+ function applyJournalFlush() {
5819
+ if (!isJournalFlushRunning) {
5820
+ // prevent multiple journal flushes from running at the same time
5821
+ isJournalFlushRunning = true;
5822
+ journalFlush();
5823
+ isJournalFlushRunning = false;
5824
+ flushBudgetStart = performance.now();
5825
+ }
5826
+ }
5827
+ function shouldApplyJournalFlush(isServer) {
5828
+ return !isServer && currentTime - flushBudgetStart >= FREQUENCY_MS;
5829
+ }
5830
+ function drainChoreQueue() {
5831
+ const isServer = isServerPlatform();
5832
+ drainScheduled = false;
5833
+ if (isDraining) {
5834
+ return;
5835
+ }
5836
+ // early return if the queue is empty
5837
+ if (!choreQueue.length) {
5838
+ applyJournalFlush();
5839
+ if (drainChore && !runningChores.size) {
5840
+ // resolve drainChore only if there are no running chores, because
5841
+ // we are sure that we are done
5842
+ drainChore.$resolve$(null);
5843
+ drainChore = null;
5366
5844
  }
5367
- const nextChore = choreQueue[0];
5368
- if (nextChore.$executed$) {
5369
- choreQueue.shift();
5370
- if (nextChore === runUptoChore) {
5371
- break;
5845
+ return;
5846
+ }
5847
+ isDraining = true;
5848
+ flushBudgetStart = performance.now();
5849
+ const maybeFinishDrain = () => {
5850
+ if (choreQueue.length) {
5851
+ drainInNextTick();
5852
+ return false;
5853
+ }
5854
+ if (drainChore && runningChores.size) {
5855
+ if (shouldApplyJournalFlush(isServer)) {
5856
+ // apply journal flush even if we are not finished draining the queue
5857
+ applyJournalFlush();
5372
5858
  }
5373
- continue;
5859
+ return false;
5374
5860
  }
5375
- if (vNodeAlreadyDeleted(nextChore) &&
5376
- // we need to process cleanup tasks for deleted nodes
5377
- nextChore.$type$ !== 48 /* ChoreType.CLEANUP_VISIBLE */) {
5378
- choreQueue.shift();
5379
- continue;
5861
+ currentChore = null;
5862
+ applyJournalFlush();
5863
+ drainChore?.$resolve$(null);
5864
+ drainChore = null;
5865
+ return true;
5866
+ };
5867
+ const scheduleBlockedChoresAndDrainIfNeeded = (chore) => {
5868
+ let blockedChoresScheduled = false;
5869
+ if (chore.$blockedChores$) {
5870
+ for (const blockedChore of chore.$blockedChores$) {
5871
+ const blockingChore = findBlockingChore(blockedChore, choreQueue, blockedChores, runningChores, container);
5872
+ if (blockingChore) {
5873
+ addBlockedChore(blockedChore, blockingChore, blockedChores);
5874
+ }
5875
+ else {
5876
+ blockedChores.delete(blockedChore);
5877
+ sortedInsert(choreQueue, blockedChore, container.rootVNode || null);
5878
+ blockedChoresScheduled = true;
5879
+ }
5880
+ }
5881
+ chore.$blockedChores$ = null;
5380
5882
  }
5381
- executeChore(nextChore, isServer);
5382
- }
5383
- return runUptoChore.$returnValue$;
5384
- }
5385
- function executeChore(chore, isServer) {
5386
- const host = chore.$host$;
5387
- assertEqual(currentChore, null, 'Chore already running.');
5388
- currentChore = chore;
5389
- let returnValue = null;
5883
+ if (blockedChoresScheduled && !isDraining) {
5884
+ drainInNextTick();
5885
+ }
5886
+ };
5887
+ let currentChore = null;
5390
5888
  try {
5391
- switch (chore.$type$) {
5392
- case 255 /* ChoreType.WAIT_FOR_ALL */:
5393
- {
5394
- if (isServer) {
5395
- drainScheduled = false;
5396
- }
5397
- }
5398
- break;
5399
- case 16 /* ChoreType.JOURNAL_FLUSH */:
5400
- {
5401
- returnValue = journalFlush();
5402
- drainScheduled = false;
5889
+ while (choreQueue.length) {
5890
+ currentTime = performance.now();
5891
+ const chore = (currentChore = choreQueue.shift());
5892
+ if (chore.$state$ !== ChoreState.NONE) {
5893
+ continue;
5894
+ }
5895
+ if (vNodeAlreadyDeleted(chore) &&
5896
+ // we need to process cleanup tasks for deleted nodes
5897
+ chore.$type$ !== 32 /* ChoreType.CLEANUP_VISIBLE */) {
5898
+ // skip deleted chore
5899
+ DEBUG && debugTrace('skip chore', chore, choreQueue, blockedChores);
5900
+ continue;
5901
+ }
5902
+ if (chore.$type$ === 16 /* ChoreType.VISIBLE */) {
5903
+ // ensure that the journal flush is applied before the visible chore is executed
5904
+ // so that the visible chore can see the latest DOM changes
5905
+ applyJournalFlush();
5906
+ const blockingChore = findBlockingChoreForVisible(chore, runningChores, container);
5907
+ if (blockingChore && blockingChore.$state$ === ChoreState.RUNNING) {
5908
+ addBlockedChore(chore, blockingChore, blockedChores);
5909
+ continue;
5403
5910
  }
5404
- break;
5405
- case 6 /* ChoreType.COMPONENT */:
5406
- {
5407
- returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
5408
- if (isServer) {
5409
- return jsx;
5911
+ }
5912
+ // Note that this never throws
5913
+ chore.$startTime$ = performance.now();
5914
+ const result = executeChore(chore, isServer);
5915
+ chore.$returnValue$ = result;
5916
+ if (isPromise(result)) {
5917
+ runningChores.add(chore);
5918
+ chore.$state$ = ChoreState.RUNNING;
5919
+ result
5920
+ .then((value) => {
5921
+ finishChore(chore, value);
5922
+ })
5923
+ .catch((e) => {
5924
+ if (chore.$state$ !== ChoreState.RUNNING) {
5925
+ // we already handled the error
5926
+ return;
5927
+ }
5928
+ handleError(chore, e);
5929
+ })
5930
+ .finally(() => {
5931
+ runningChores.delete(chore);
5932
+ // Note that we ignore failed chores so the app keeps working
5933
+ // TODO decide if this is ok and document it
5934
+ scheduleBlockedChoresAndDrainIfNeeded(chore);
5935
+ // If drainChore is not null, we are waiting for it to finish.
5936
+ // If there are no running chores, we can finish the drain.
5937
+ if (!runningChores.size) {
5938
+ let finished = false;
5939
+ if (drainChore) {
5940
+ finished = maybeFinishDrain();
5410
5941
  }
5411
- else {
5412
- const styleScopedId = container.getHostProp(host, QScopedStyle);
5413
- return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
5942
+ if (!finished && !isDraining) {
5943
+ // if finished, then journal flush is already applied
5944
+ applyJournalFlush();
5414
5945
  }
5415
- }, (err) => container.handleError(err, host));
5416
- }
5417
- break;
5418
- case 2 /* ChoreType.RUN_QRL */:
5419
- {
5420
- const fn = chore.$target$.getFn();
5421
- const result = retryOnPromise(() => fn(...chore.$payload$));
5422
- if (isPromise(result)) {
5423
- const handled = result
5424
- .finally(() => {
5425
- qrlRuns.splice(qrlRuns.indexOf(handled), 1);
5426
- })
5427
- .catch((error) => {
5428
- container.handleError(error, chore.$host$);
5429
- });
5430
- // Don't wait for the promise to resolve
5431
- // TODO come up with a better solution, we also want concurrent signal handling with tasks but serial tasks
5432
- qrlRuns.push(handled);
5433
- DEBUG &&
5434
- debugTrace('execute.DONE (but still running)', chore, currentChore, choreQueue);
5435
- chore.$returnValue$ = handled;
5436
- chore.$resolve$?.(handled);
5437
- currentChore = null;
5438
- chore.$executed$ = true;
5439
- // early out so we don't call after()
5440
- return;
5441
5946
  }
5442
- returnValue = null;
5443
- }
5444
- break;
5445
- case 3 /* ChoreType.TASK */:
5446
- case 32 /* ChoreType.VISIBLE */:
5447
- {
5448
- const payload = chore.$payload$;
5449
- if (payload.$flags$ & 4 /* TaskFlags.RESOURCE */) {
5450
- const result = runResource(payload, container, host);
5451
- // Don't await the return value of the resource, because async resources should not be awaited.
5452
- // The reason for this is that we should be able to update for example a node with loading
5453
- // text. If we await the resource, the loading text will not be displayed until the resource
5454
- // is loaded.
5455
- // Awaiting on the client also causes a deadlock.
5456
- // In any case, the resource will never throw.
5457
- returnValue = isServer ? result : null;
5947
+ });
5948
+ }
5949
+ else {
5950
+ finishChore(chore, result);
5951
+ scheduleBlockedChoresAndDrainIfNeeded(chore);
5952
+ }
5953
+ if (shouldApplyJournalFlush(isServer)) {
5954
+ applyJournalFlush();
5955
+ drainInNextTick();
5956
+ return;
5957
+ }
5958
+ }
5959
+ }
5960
+ catch (e) {
5961
+ handleError(currentChore, e);
5962
+ scheduleBlockedChoresAndDrainIfNeeded(currentChore);
5963
+ }
5964
+ finally {
5965
+ isDraining = false;
5966
+ maybeFinishDrain();
5967
+ }
5968
+ }
5969
+ function finishChore(chore, value) {
5970
+ chore.$endTime$ = performance.now();
5971
+ chore.$state$ = ChoreState.DONE;
5972
+ chore.$returnValue$ = value;
5973
+ chore.$resolve$?.(value);
5974
+ }
5975
+ function handleError(chore, e) {
5976
+ chore.$endTime$ = performance.now();
5977
+ chore.$state$ = ChoreState.FAILED;
5978
+ // If we used the result as promise, this won't exist
5979
+ chore.$reject$?.(e);
5980
+ container.handleError(e, chore.$host$);
5981
+ }
5982
+ function executeChore(chore, isServer) {
5983
+ const host = chore.$host$;
5984
+ let returnValue;
5985
+ switch (chore.$type$) {
5986
+ case 6 /* ChoreType.COMPONENT */:
5987
+ {
5988
+ returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
5989
+ if (isServer) {
5990
+ return jsx;
5458
5991
  }
5459
5992
  else {
5460
- returnValue = runTask(payload, container, host);
5993
+ const styleScopedId = container.getHostProp(host, QScopedStyle);
5994
+ return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
5461
5995
  }
5996
+ }, (err) => {
5997
+ handleError(chore, err);
5998
+ });
5999
+ }
6000
+ break;
6001
+ case 2 /* ChoreType.RUN_QRL */:
6002
+ {
6003
+ const fn = chore.$target$.getFn();
6004
+ returnValue = retryOnPromise(() => fn(...chore.$payload$));
6005
+ }
6006
+ break;
6007
+ case 3 /* ChoreType.TASK */:
6008
+ case 16 /* ChoreType.VISIBLE */:
6009
+ {
6010
+ const payload = chore.$payload$;
6011
+ if (payload.$flags$ & 4 /* TaskFlags.RESOURCE */) {
6012
+ returnValue = runResource(payload, container, host);
5462
6013
  }
5463
- break;
5464
- case 48 /* ChoreType.CLEANUP_VISIBLE */:
5465
- {
5466
- const task = chore.$payload$;
5467
- cleanupTask(task);
6014
+ else {
6015
+ returnValue = runTask(payload, container, host);
5468
6016
  }
5469
- break;
5470
- case 4 /* ChoreType.NODE_DIFF */:
5471
- {
5472
- const parentVirtualNode = chore.$target$;
5473
- let jsx = chore.$payload$;
5474
- if (isSignal(jsx)) {
5475
- jsx = jsx.value;
5476
- }
5477
- returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
6017
+ }
6018
+ break;
6019
+ case 32 /* ChoreType.CLEANUP_VISIBLE */:
6020
+ {
6021
+ const task = chore.$payload$;
6022
+ cleanupTask(task);
6023
+ }
6024
+ break;
6025
+ case 4 /* ChoreType.NODE_DIFF */:
6026
+ {
6027
+ const parentVirtualNode = chore.$target$;
6028
+ let jsx = chore.$payload$;
6029
+ if (isSignal(jsx)) {
6030
+ jsx = jsx.value;
5478
6031
  }
5479
- break;
5480
- case 5 /* ChoreType.NODE_PROP */:
5481
- {
5482
- const virtualNode = chore.$host$;
5483
- const payload = chore.$payload$;
5484
- let value = payload.$value$;
5485
- if (isSignal(value)) {
5486
- value = value.value;
5487
- }
5488
- const isConst = payload.$isConst$;
5489
- const journal = container.$journal$;
5490
- const property = chore.$idx$;
5491
- const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
6032
+ returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
6033
+ }
6034
+ break;
6035
+ case 5 /* ChoreType.NODE_PROP */:
6036
+ {
6037
+ const virtualNode = chore.$host$;
6038
+ const payload = chore.$payload$;
6039
+ let value = payload.$value$;
6040
+ if (isSignal(value)) {
6041
+ value = value.value;
6042
+ }
6043
+ const isConst = payload.$isConst$;
6044
+ const journal = container.$journal$;
6045
+ const property = chore.$idx$;
6046
+ const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
6047
+ if (isServer) {
6048
+ container.addBackpatchEntry(chore.$host$.id, property, serializedValue);
6049
+ returnValue = null;
6050
+ }
6051
+ else {
5492
6052
  if (isConst) {
5493
6053
  const element = virtualNode[6 /* ElementVNodeProps.element */];
5494
6054
  journal.push(2 /* VNodeJournalOpCode.SetAttribute */, element, property, serializedValue);
@@ -5496,63 +6056,49 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5496
6056
  else {
5497
6057
  vnode_setAttr(journal, virtualNode, property, serializedValue);
5498
6058
  }
6059
+ returnValue = undefined;
5499
6060
  }
5500
- break;
5501
- case 1 /* ChoreType.QRL_RESOLVE */: {
5502
- {
5503
- const target = chore.$target$;
5504
- returnValue = !target.resolved ? target.resolve() : null;
5505
- }
5506
- break;
5507
6061
  }
5508
- case 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */: {
5509
- {
5510
- const target = chore.$target$;
5511
- const effects = chore.$payload$;
5512
- if (target instanceof ComputedSignalImpl || target instanceof WrappedSignalImpl) {
5513
- const forceRunEffects = target.$forceRunEffects$;
5514
- target.$forceRunEffects$ = false;
5515
- if (!target.$effects$?.size) {
5516
- break;
6062
+ break;
6063
+ case 1 /* ChoreType.QRL_RESOLVE */: {
6064
+ {
6065
+ const target = chore.$target$;
6066
+ returnValue = (!target.resolved ? target.resolve() : null);
6067
+ }
6068
+ break;
6069
+ }
6070
+ case 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */: {
6071
+ {
6072
+ const target = chore.$target$;
6073
+ const effects = chore.$payload$;
6074
+ if (!effects?.size) {
6075
+ break;
6076
+ }
6077
+ let shouldCompute = target instanceof ComputedSignalImpl || target instanceof WrappedSignalImpl;
6078
+ if (target instanceof AsyncComputedSignalImpl && effects !== target.$effects$) {
6079
+ shouldCompute = false;
6080
+ }
6081
+ if (shouldCompute) {
6082
+ const ctx = newInvokeContext();
6083
+ ctx.$container$ = container;
6084
+ // needed for computed signals and throwing QRLs
6085
+ returnValue = maybeThen(retryOnPromise(() => invoke.call(target, ctx, target.$computeIfNeeded$)), () => {
6086
+ if (target.$flags$ & 2 /* SignalFlags.RUN_EFFECTS */) {
6087
+ target.$flags$ &= -3 /* SignalFlags.RUN_EFFECTS */;
6088
+ return retryOnPromise(() => triggerEffects(container, target, effects));
5517
6089
  }
5518
- returnValue = retryOnPromise(() => {
5519
- if (target.$computeIfNeeded$() || forceRunEffects) {
5520
- triggerEffects(container, target, effects);
5521
- }
5522
- });
5523
- }
5524
- else {
5525
- returnValue = retryOnPromise(() => {
5526
- triggerEffects(container, target, effects);
5527
- });
5528
- }
6090
+ });
6091
+ }
6092
+ else {
6093
+ returnValue = retryOnPromise(() => {
6094
+ triggerEffects(container, target, effects);
6095
+ });
5529
6096
  }
5530
- break;
5531
6097
  }
6098
+ break;
5532
6099
  }
5533
6100
  }
5534
- catch (e) {
5535
- returnValue = Promise.reject(e);
5536
- }
5537
- const after = (value, error) => {
5538
- currentChore = null;
5539
- chore.$executed$ = true;
5540
- if (error) {
5541
- container.handleError(error, host);
5542
- }
5543
- else {
5544
- chore.$returnValue$ = value;
5545
- chore.$resolve$?.(value);
5546
- }
5547
- };
5548
- if (isPromise(returnValue)) {
5549
- chore.$promise$ = returnValue.then(after, (error) => after(undefined, error));
5550
- chore.$resolve$?.(chore.$promise$);
5551
- chore.$resolve$ = undefined;
5552
- }
5553
- else {
5554
- after(returnValue);
5555
- }
6101
+ return returnValue;
5556
6102
  }
5557
6103
  /**
5558
6104
  * Compares two chores to determine their execution order in the scheduler's queue.
@@ -5581,15 +6127,6 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5581
6127
  else {
5582
6128
  assertFalse(vnode_isVNode(aHost), 'expected aHost to be SSRNode but it is a VNode');
5583
6129
  assertFalse(vnode_isVNode(bHost), 'expected bHost to be SSRNode but it is a VNode');
5584
- // we are running on the server.
5585
- // On server we can't schedule task for a different host!
5586
- // Server is SSR, and therefore scheduling for anything but the current host
5587
- // implies that things need to be re-run nad that is not supported because of streaming.
5588
- const errorMessage = `SERVER: during HTML streaming, re-running tasks on a different host is not allowed.
5589
- You are attempting to change a state that has already been streamed to the client.
5590
- This can lead to inconsistencies between Server-Side Rendering (SSR) and Client-Side Rendering (CSR).
5591
- Problematic Node: ${aHost.toString()}`;
5592
- logWarn(errorMessage);
5593
6130
  const hostDiff = ssrNodeDocumentPosition(aHost, bHost);
5594
6131
  if (hostDiff !== 0) {
5595
6132
  return hostDiff;
@@ -5606,12 +6143,21 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5606
6143
  return idxDiff;
5607
6144
  }
5608
6145
  // If the host is the same (or missing), and the type is the same, we need to compare the target.
5609
- if (a.$target$ !== b.$target$ || a.$payload$ !== b.$payload$) {
6146
+ if (a.$target$ !== b.$target$) {
6147
+ if (isQrl(a.$target$) && isQrl(b.$target$) && a.$target$.$hash$ === b.$target$.$hash$) {
6148
+ return 0;
6149
+ }
5610
6150
  // 1 means that we are going to process chores as FIFO
5611
6151
  return 1;
5612
6152
  }
5613
- // If the chore is the same as the current chore, we will run it again
5614
- if (b === currentChore) {
6153
+ // ensure that the effect chores are scheduled for the same target
6154
+ // TODO: can we do this better?
6155
+ if (a.$type$ === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */ &&
6156
+ b.$type$ === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */ &&
6157
+ ((a.$target$ instanceof StoreHandler && b.$target$ instanceof StoreHandler) ||
6158
+ (a.$target$ instanceof AsyncComputedSignalImpl &&
6159
+ b.$target$ instanceof AsyncComputedSignalImpl)) &&
6160
+ a.$payload$ !== b.$payload$) {
5615
6161
  return 1;
5616
6162
  }
5617
6163
  // The chores are the same and will run only once
@@ -5643,6 +6189,15 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5643
6189
  /// We need to ensure that the `queue` is sorted by priority.
5644
6190
  /// 1. Find a place where to insert into.
5645
6191
  const idx = sortedFindIndex(sortedArray, value, rootVNode);
6192
+ if (idx < 0 && runningChores.size) {
6193
+ // 1.1. Check if the chore is already running.
6194
+ for (const chore of runningChores) {
6195
+ const comp = choreComparator(value, chore, rootVNode);
6196
+ if (comp === 0) {
6197
+ return chore;
6198
+ }
6199
+ }
6200
+ }
5646
6201
  if (idx < 0) {
5647
6202
  /// 2. Insert the chore into the queue.
5648
6203
  sortedArray.splice(~idx, 0, value);
@@ -5654,12 +6209,9 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5654
6209
  * multiple times during component execution. For this reason it is necessary for us to update
5655
6210
  * the chore with the latest result of the signal.
5656
6211
  */
5657
- if (existing.$type$ === 4 /* ChoreType.NODE_DIFF */) {
6212
+ if (existing.$payload$ !== value.$payload$) {
5658
6213
  existing.$payload$ = value.$payload$;
5659
6214
  }
5660
- if (existing.$executed$) {
5661
- existing.$executed$ = false;
5662
- }
5663
6215
  return existing;
5664
6216
  }
5665
6217
  };
@@ -5671,6 +6223,25 @@ function vNodeAlreadyDeleted(chore) {
5671
6223
  vnode_isVNode(chore.$host$) &&
5672
6224
  chore.$host$[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */);
5673
6225
  }
6226
+ function addBlockedChore(blockedChore, blockingChore, blockedChores) {
6227
+ blockingChore.$blockedChores$ ||= [];
6228
+ blockingChore.$blockedChores$.push(blockedChore);
6229
+ blockedChores.add(blockedChore);
6230
+ }
6231
+ function choreTypeToName(type) {
6232
+ return ({
6233
+ [1 /* ChoreType.QRL_RESOLVE */]: 'Resolve QRL',
6234
+ [2 /* ChoreType.RUN_QRL */]: 'Run QRL',
6235
+ [3 /* ChoreType.TASK */]: 'Task',
6236
+ [4 /* ChoreType.NODE_DIFF */]: 'Changes diffing',
6237
+ [5 /* ChoreType.NODE_PROP */]: 'Updating node property',
6238
+ [6 /* ChoreType.COMPONENT */]: 'Component',
6239
+ [7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */]: 'Signal recompute',
6240
+ [16 /* ChoreType.VISIBLE */]: 'Visible',
6241
+ [32 /* ChoreType.CLEANUP_VISIBLE */]: 'Cleanup visible',
6242
+ [255 /* ChoreType.WAIT_FOR_QUEUE */]: 'Wait for queue',
6243
+ }[type] || 'Unknown: ' + type);
6244
+ }
5674
6245
  function debugChoreTypeToString(type) {
5675
6246
  return ({
5676
6247
  [1 /* ChoreType.QRL_RESOLVE */]: 'QRL_RESOLVE',
@@ -5680,31 +6251,87 @@ function debugChoreTypeToString(type) {
5680
6251
  [5 /* ChoreType.NODE_PROP */]: 'NODE_PROP',
5681
6252
  [6 /* ChoreType.COMPONENT */]: 'COMPONENT',
5682
6253
  [7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */]: 'RECOMPUTE_SIGNAL',
5683
- [16 /* ChoreType.JOURNAL_FLUSH */]: 'JOURNAL_FLUSH',
5684
- [32 /* ChoreType.VISIBLE */]: 'VISIBLE',
5685
- [48 /* ChoreType.CLEANUP_VISIBLE */]: 'CLEANUP_VISIBLE',
5686
- [255 /* ChoreType.WAIT_FOR_ALL */]: 'WAIT_FOR_ALL',
6254
+ [16 /* ChoreType.VISIBLE */]: 'VISIBLE',
6255
+ [32 /* ChoreType.CLEANUP_VISIBLE */]: 'CLEANUP_VISIBLE',
6256
+ [255 /* ChoreType.WAIT_FOR_QUEUE */]: 'WAIT_FOR_QUEUE',
5687
6257
  }[type] || 'UNKNOWN: ' + type);
5688
6258
  }
5689
- function debugChoreToString(chore) {
5690
- const type = debugChoreTypeToString(chore.$type$);
5691
- const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
5692
- const qrlTarget = chore.$target$?.$symbol$;
5693
- return `Chore(${type} ${chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */ ? qrlTarget : host} ${chore.$idx$})`;
5694
- }
5695
- function debugTrace(action, arg, currentChore, queue) {
5696
- const lines = ['===========================\nScheduler: ' + action];
5697
- if (arg && !('$type$' in arg)) {
5698
- lines.push(' arg: ' + String(arg).replaceAll(/\n.*/gim, ''));
5699
- }
5700
- if (queue) {
5701
- queue.forEach((chore) => {
5702
- const active = chore === arg ? '>>>' : ' ';
5703
- lines.push(` ${active} > ` +
5704
- (chore === currentChore ? '[running] ' : '') +
5705
- debugChoreToString(chore));
6259
+ function debugTrace(action, arg, queue, blockedChores) {
6260
+ const lines = [];
6261
+ // Header
6262
+ lines.push(`Scheduler: ${action}`);
6263
+ // Argument section
6264
+ if (arg) {
6265
+ lines.push('');
6266
+ if (arg && '$type$' in arg) {
6267
+ const chore = arg;
6268
+ const type = debugChoreTypeToString(chore.$type$);
6269
+ const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
6270
+ const qrlTarget = chore.$target$?.$symbol$;
6271
+ const targetOrHost = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
6272
+ ? qrlTarget
6273
+ : host;
6274
+ lines.push(`🎯 Current Chore:`);
6275
+ lines.push(` Type: ${type}`);
6276
+ lines.push(` Host: ${targetOrHost}`);
6277
+ // Show execution time if available
6278
+ if (chore.$startTime$ && chore.$endTime$) {
6279
+ const executionTime = chore.$endTime$ - chore.$startTime$;
6280
+ lines.push(` Time: ${executionTime.toFixed(2)}ms`);
6281
+ }
6282
+ else if (chore.$startTime$) {
6283
+ const elapsedTime = performance.now() - chore.$startTime$;
6284
+ lines.push(` Time: ${elapsedTime.toFixed(2)}ms (running)`);
6285
+ }
6286
+ // Show blocked chores for this chore
6287
+ if (chore.$blockedChores$ && chore.$blockedChores$.length > 0) {
6288
+ lines.push(` ⛔ Blocked Chores:`);
6289
+ chore.$blockedChores$.forEach((blockedChore, index) => {
6290
+ const blockedType = debugChoreTypeToString(blockedChore.$type$);
6291
+ const blockedTarget = String(blockedChore.$host$).replaceAll(/\n.*/gim, '');
6292
+ lines.push(` ${index + 1}. ${blockedType} ${blockedTarget} ${blockedChore.$idx$}`);
6293
+ });
6294
+ }
6295
+ }
6296
+ else {
6297
+ lines.push(`📝 Argument: ${String(arg).replaceAll(/\n.*/gim, '')}`);
6298
+ }
6299
+ }
6300
+ // Queue section
6301
+ if (queue && queue.length > 0) {
6302
+ lines.push('');
6303
+ lines.push(`📋 Queue (${queue.length} items):`);
6304
+ queue.forEach((chore, index) => {
6305
+ const isActive = chore === arg;
6306
+ const activeMarker = isActive ? `▶ ` : ' ';
6307
+ const type = debugChoreTypeToString(chore.$type$);
6308
+ const state = chore.$state$ ? `[${ChoreState[chore.$state$]}]` : '';
6309
+ const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
6310
+ const qrlTarget = chore.$target$?.$symbol$;
6311
+ const target = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
6312
+ ? qrlTarget
6313
+ : host;
6314
+ const line = `${activeMarker}${state} ${type} ${target} ${chore.$idx$}`;
6315
+ lines.push(line);
5706
6316
  });
5707
6317
  }
6318
+ // Blocked chores section
6319
+ if (blockedChores && blockedChores.size > 0) {
6320
+ lines.push('');
6321
+ lines.push(`🚫 Blocked Chores (${blockedChores.size} items):`);
6322
+ Array.from(blockedChores).forEach((chore, index) => {
6323
+ const type = debugChoreTypeToString(chore.$type$);
6324
+ const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
6325
+ const qrlTarget = chore.$target$?.$symbol$;
6326
+ const target = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
6327
+ ? qrlTarget
6328
+ : host;
6329
+ lines.push(` ${index + 1}. ${type} ${target} ${chore.$idx$}`);
6330
+ });
6331
+ }
6332
+ // Footer
6333
+ lines.push('');
6334
+ lines.push('─'.repeat(60));
5708
6335
  // eslint-disable-next-line no-console
5709
6336
  console.log(lines.join('\n') + '\n');
5710
6337
  }
@@ -5722,7 +6349,8 @@ class _SharedContainer {
5722
6349
  $currentUniqueId$ = 0;
5723
6350
  $instanceHash$ = null;
5724
6351
  $buildBase$ = null;
5725
- constructor(scheduleDrain, journalFlush, serverData, locale) {
6352
+ $flushEpoch$ = 0;
6353
+ constructor(journalFlush, serverData, locale) {
5726
6354
  this.$serverData$ = serverData;
5727
6355
  this.$locale$ = locale;
5728
6356
  this.$version$ = version;
@@ -5730,7 +6358,7 @@ class _SharedContainer {
5730
6358
  this.$getObjectById$ = (_id) => {
5731
6359
  throw Error('Not implemented');
5732
6360
  };
5733
- this.$scheduler$ = createScheduler(this, scheduleDrain, journalFlush);
6361
+ this.$scheduler$ = createScheduler(this, journalFlush);
5734
6362
  }
5735
6363
  trackSignalValue(signal, subscriber, property, data) {
5736
6364
  return trackSignalAndAssignHost(signal, subscriber, property, this, data);
@@ -5878,7 +6506,7 @@ function processVNodeData$1(document) {
5878
6506
  const qContainer = getAttribute.call(node, Q_CONTAINER);
5879
6507
  if (qContainer === null) {
5880
6508
  if (hasAttribute.call(node, Q_SHADOW_ROOT)) {
5881
- return 6 /* NodeType.ELEMENT_SHADOW_ROOT */;
6509
+ return 6 /* NodeType.ELEMENT_SHADOW_ROOT_WRAPPER */;
5882
6510
  }
5883
6511
  const isQElement = hasAttribute.call(node, Q_PROPS_SEPARATOR);
5884
6512
  return isQElement ? 2 /* NodeType.ELEMENT */ : 0 /* NodeType.OTHER */;
@@ -5896,10 +6524,10 @@ function processVNodeData$1(document) {
5896
6524
  return 16 /* NodeType.COMMENT_IGNORE_START */;
5897
6525
  }
5898
6526
  else if (nodeValue.startsWith(Q_CONTAINER)) {
5899
- return 5 /* NodeType.COMMENT_SKIP_START */;
6527
+ return 9 /* NodeType.COMMENT_SKIP_START */;
5900
6528
  }
5901
6529
  else if (nodeValue.startsWith(Q_CONTAINER_ISLAND_END)) {
5902
- return 128 /* NodeType.COMMENT_ISLAND_END */;
6530
+ return 64 /* NodeType.COMMENT_ISLAND_END */;
5903
6531
  }
5904
6532
  else if (nodeValue.startsWith(Q_IGNORE_END)) {
5905
6533
  return 32 /* NodeType.COMMENT_IGNORE_END */;
@@ -5946,11 +6574,6 @@ function processVNodeData$1(document) {
5946
6574
  while (node && (node = node.nextSibling) && getFastNodeType(node) === 0 /* NodeType.OTHER */) { }
5947
6575
  return node;
5948
6576
  };
5949
- const firstChild = (node) => {
5950
- // eslint-disable-next-line no-empty
5951
- while (node && (node = node.firstChild) && getFastNodeType(node) === 0 /* NodeType.OTHER */) { }
5952
- return node;
5953
- };
5954
6577
  /**
5955
6578
  * Process the container
5956
6579
  *
@@ -6011,7 +6634,7 @@ function processVNodeData$1(document) {
6011
6634
  } while (getFastNodeType(islandNode) !== 65 /* NodeType.COMMENT_ISLAND_START */);
6012
6635
  nextNode = null;
6013
6636
  }
6014
- else if (nodeType === 128 /* NodeType.COMMENT_ISLAND_END */) {
6637
+ else if (nodeType === 64 /* NodeType.COMMENT_ISLAND_END */) {
6015
6638
  nextNode = node;
6016
6639
  do {
6017
6640
  nextNode = walker.nextNode();
@@ -6021,7 +6644,7 @@ function processVNodeData$1(document) {
6021
6644
  } while (getFastNodeType(nextNode) !== 32 /* NodeType.COMMENT_IGNORE_END */);
6022
6645
  nextNode = null;
6023
6646
  }
6024
- else if (nodeType === 5 /* NodeType.COMMENT_SKIP_START */) {
6647
+ else if (nodeType === 9 /* NodeType.COMMENT_SKIP_START */) {
6025
6648
  // If we are in a container, we need to skip the children.
6026
6649
  nextNode = node;
6027
6650
  do {
@@ -6033,7 +6656,7 @@ function processVNodeData$1(document) {
6033
6656
  // console.log('EXIT', nextNode?.outerHTML);
6034
6657
  walkContainer(walker, node, node, nextNode, '', null);
6035
6658
  }
6036
- else if (nodeType === 6 /* NodeType.ELEMENT_SHADOW_ROOT */) {
6659
+ else if (nodeType === 6 /* NodeType.ELEMENT_SHADOW_ROOT_WRAPPER */) {
6037
6660
  // If we are in a shadow root, we need to get the shadow root element.
6038
6661
  nextNode = nextSibling(node);
6039
6662
  const shadowRootContainer = node;
@@ -6041,7 +6664,7 @@ function processVNodeData$1(document) {
6041
6664
  if (shadowRoot) {
6042
6665
  walkContainer(
6043
6666
  // we need to create a new walker for the shadow root
6044
- document.createTreeWalker(shadowRoot, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */), null, firstChild(shadowRoot), null, '', null);
6667
+ document.createTreeWalker(shadowRoot, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */), null, shadowRoot, null, '', null);
6045
6668
  }
6046
6669
  }
6047
6670
  if ((nodeType & 2 /* NodeType.ELEMENT */) === 2 /* NodeType.ELEMENT */) {
@@ -6098,6 +6721,7 @@ function processVNodeData$1(document) {
6098
6721
  }
6099
6722
 
6100
6723
  /** @file Public APIs for the SSR */
6724
+ // @ts-expect-error we don't have types for the preloader
6101
6725
  /** @public */
6102
6726
  function getDomContainer(element) {
6103
6727
  const qContainerElement = _getQContainerElement(element);
@@ -6117,7 +6741,7 @@ function getDomContainerFromQContainerElement(qContainerElement) {
6117
6741
  /** @internal */
6118
6742
  function _getQContainerElement(element) {
6119
6743
  const qContainerElement = Array.isArray(element)
6120
- ? vnode_getDomParent(element)
6744
+ ? vnode_getDomParent(element, true)
6121
6745
  : element;
6122
6746
  return qContainerElement.closest(QContainerSelector);
6123
6747
  }
@@ -6132,19 +6756,20 @@ class DomContainer extends _SharedContainer {
6132
6756
  rootVNode;
6133
6757
  document;
6134
6758
  $journal$;
6135
- renderDone = null;
6136
6759
  $rawStateData$;
6137
6760
  $storeProxyMap$ = new WeakMap();
6138
6761
  $qFuncs$;
6139
6762
  $instanceHash$;
6140
6763
  $forwardRefs$ = null;
6141
- $initialQRLsIndexes$ = null;
6764
+ $initialQRLs$ = null;
6142
6765
  vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
6143
6766
  $stateData$;
6144
6767
  $styleIds$ = null;
6145
- $renderCount$ = 0;
6146
6768
  constructor(element) {
6147
- super(() => this.scheduleRender(), () => vnode_applyJournal(this.$journal$), {}, element.getAttribute(QLocaleAttr));
6769
+ super(() => {
6770
+ this.$flushEpoch$++;
6771
+ vnode_applyJournal(this.$journal$);
6772
+ }, {}, element.getAttribute(QLocaleAttr));
6148
6773
  this.qContainer = element.getAttribute(QContainerAttr);
6149
6774
  if (!this.qContainer) {
6150
6775
  throw qError(25 /* QError.elementWithoutContainer */);
@@ -6186,20 +6811,17 @@ class DomContainer extends _SharedContainer {
6186
6811
  }
6187
6812
  handleError(err, host) {
6188
6813
  if (qDev && host) {
6189
- // Clean vdom
6190
6814
  if (typeof document !== 'undefined') {
6191
6815
  const vHost = host;
6192
- const errorDiv = document.createElement('errored-host');
6193
- if (err && err instanceof Error) {
6194
- errorDiv.props = { error: err };
6195
- }
6196
- errorDiv.setAttribute('q:key', '_error_');
6197
6816
  const journal = [];
6198
- const vErrorDiv = vnode_newElement(errorDiv, 'errored-host');
6199
- vnode_getDOMChildNodes(journal, vHost, true).forEach((child) => {
6200
- vnode_insertBefore(journal, vErrorDiv, child, null);
6201
- });
6202
- vnode_insertBefore(journal, vHost, vErrorDiv, null);
6817
+ const vHostParent = vnode_getParent(vHost);
6818
+ const vHostNextSibling = vnode_getNextSibling(vHost);
6819
+ const vErrorDiv = vnode_createErrorDiv(document, vHost, err, journal);
6820
+ // If the host is an element node, we need to insert the error div into its parent.
6821
+ const insertHost = vnode_isElementVNode(vHost) ? vHostParent || vHost : vHost;
6822
+ // If the host is different then we need to insert errored-host in the same position as the host.
6823
+ const insertBefore = insertHost === vHost ? null : vHostNextSibling;
6824
+ vnode_insertBefore(journal, insertHost, vErrorDiv, insertBefore);
6203
6825
  vnode_applyJournal(journal);
6204
6826
  }
6205
6827
  if (err && err instanceof Error) {
@@ -6219,19 +6841,16 @@ class DomContainer extends _SharedContainer {
6219
6841
  }
6220
6842
  setContext(host, context, value) {
6221
6843
  let ctx = this.getHostProp(host, QCtxAttr);
6222
- if (!ctx) {
6844
+ if (ctx == null) {
6223
6845
  this.setHostProp(host, QCtxAttr, (ctx = []));
6224
6846
  }
6225
- mapArray_set(ctx, context.id, value, 0);
6847
+ mapArray_set(ctx, context.id, value, 0, true);
6226
6848
  }
6227
6849
  resolveContext(host, contextId) {
6228
6850
  while (host) {
6229
6851
  const ctx = this.getHostProp(host, QCtxAttr);
6230
- if (ctx) {
6231
- const value = mapArray_get(ctx, contextId.id, 0);
6232
- if (value) {
6233
- return value;
6234
- }
6852
+ if (ctx != null && mapArray_has(ctx, contextId.id, 0)) {
6853
+ return mapArray_get(ctx, contextId.id, 0);
6235
6854
  }
6236
6855
  host = this.getParentHost(host);
6237
6856
  }
@@ -6277,29 +6896,6 @@ class DomContainer extends _SharedContainer {
6277
6896
  }
6278
6897
  return vnode_getProp(vNode, name, getObjectById);
6279
6898
  }
6280
- scheduleRender() {
6281
- this.$renderCount$++;
6282
- this.renderDone ||= getPlatform().nextTick(() => this.processChores());
6283
- return this.renderDone.finally(() => emitEvent('qrender', { instanceHash: this.$instanceHash$, renderCount: this.$renderCount$ }));
6284
- }
6285
- processChores() {
6286
- let renderCount = this.$renderCount$;
6287
- const result = this.$scheduler$(255 /* ChoreType.WAIT_FOR_ALL */);
6288
- if (isPromise(result)) {
6289
- return result.then(async () => {
6290
- while (renderCount !== this.$renderCount$) {
6291
- renderCount = this.$renderCount$;
6292
- await this.$scheduler$(255 /* ChoreType.WAIT_FOR_ALL */);
6293
- }
6294
- this.renderDone = null;
6295
- });
6296
- }
6297
- if (renderCount !== this.$renderCount$) {
6298
- this.processChores();
6299
- return;
6300
- }
6301
- this.renderDone = null;
6302
- }
6303
6899
  ensureProjectionResolved(vNode) {
6304
6900
  if ((vNode[0 /* VNodeProps.flags */] & 16 /* VNodeFlags.Resolved */) === 0) {
6305
6901
  vNode[0 /* VNodeProps.flags */] |= 16 /* VNodeFlags.Resolved */;
@@ -6309,7 +6905,9 @@ class DomContainer extends _SharedContainer {
6309
6905
  if (isSlotProp(prop)) {
6310
6906
  const value = props[i + 1];
6311
6907
  if (typeof value == 'string') {
6312
- props[i + 1] = this.vNodeLocate(value);
6908
+ const projection = this.vNodeLocate(value);
6909
+ props[i + 1] = projection;
6910
+ vnode_getProp(projection, QSlotParent, (id) => this.vNodeLocate(id));
6313
6911
  }
6314
6912
  }
6315
6913
  }
@@ -6378,11 +6976,14 @@ class DomContainer extends _SharedContainer {
6378
6976
  * ```
6379
6977
  */
6380
6978
  $scheduleInitialQRLs$() {
6381
- if (this.$initialQRLsIndexes$) {
6382
- for (const index of this.$initialQRLsIndexes$) {
6383
- this.$scheduler$(1 /* ChoreType.QRL_RESOLVE */, null, this.$getObjectById$(index));
6979
+ if (this.$initialQRLs$) {
6980
+ for (const qrl of this.$initialQRLs$) {
6981
+ const match = /#(.*)_([a-zA-Z0-9]+)(\[|$)/.exec(qrl);
6982
+ if (match) {
6983
+ p(match[2], 0.3);
6984
+ }
6384
6985
  }
6385
- this.$initialQRLsIndexes$ = null;
6986
+ this.$initialQRLs$ = null;
6386
6987
  }
6387
6988
  }
6388
6989
  }
@@ -6430,7 +7031,7 @@ const addQrlToSerializationCtx = (effectSubscriber, container) => {
6430
7031
  }
6431
7032
  };
6432
7033
  const triggerEffects = (container, signal, effects) => {
6433
- const isBrowser = isDomContainer(container);
7034
+ const isBrowser = !isServerPlatform();
6434
7035
  if (effects) {
6435
7036
  const scheduleEffect = (effectSubscription) => {
6436
7037
  const consumer = effectSubscription[0 /* EffectSubscriptionProp.CONSUMER */];
@@ -6440,7 +7041,7 @@ const triggerEffects = (container, signal, effects) => {
6440
7041
  consumer.$flags$ |= 8 /* TaskFlags.DIRTY */;
6441
7042
  let choreType = 3 /* ChoreType.TASK */;
6442
7043
  if (consumer.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */) {
6443
- choreType = 32 /* ChoreType.VISIBLE */;
7044
+ choreType = 16 /* ChoreType.VISIBLE */;
6444
7045
  }
6445
7046
  container.$scheduler$(choreType, consumer);
6446
7047
  }
@@ -6454,7 +7055,7 @@ const triggerEffects = (container, signal, effects) => {
6454
7055
  container.$scheduler$(1 /* ChoreType.QRL_RESOLVE */, null, consumer.$computeQrl$);
6455
7056
  }
6456
7057
  }
6457
- consumer.$invalidate$();
7058
+ consumer.invalidate();
6458
7059
  }
6459
7060
  else if (property === ":" /* EffectProperty.COMPONENT */) {
6460
7061
  const host = consumer;
@@ -6463,22 +7064,22 @@ const triggerEffects = (container, signal, effects) => {
6463
7064
  const props = container.getHostProp(host, ELEMENT_PROPS);
6464
7065
  container.$scheduler$(6 /* ChoreType.COMPONENT */, host, qrl, props);
6465
7066
  }
6466
- else if (isBrowser) {
6467
- if (property === "." /* EffectProperty.VNODE */) {
7067
+ else if (property === "." /* EffectProperty.VNODE */) {
7068
+ if (isBrowser) {
6468
7069
  const host = consumer;
6469
7070
  container.$scheduler$(4 /* ChoreType.NODE_DIFF */, host, host, signal);
6470
7071
  }
6471
- else {
6472
- const host = consumer;
6473
- const effectData = effectSubscription[3 /* EffectSubscriptionProp.DATA */];
6474
- if (effectData instanceof SubscriptionData) {
6475
- const data = effectData.data;
6476
- const payload = {
6477
- ...data,
6478
- $value$: signal,
6479
- };
6480
- container.$scheduler$(5 /* ChoreType.NODE_PROP */, host, property, payload);
6481
- }
7072
+ }
7073
+ else {
7074
+ const host = consumer;
7075
+ const effectData = effectSubscription[3 /* EffectSubscriptionProp.DATA */];
7076
+ if (effectData instanceof SubscriptionData) {
7077
+ const data = effectData.data;
7078
+ const payload = {
7079
+ ...data,
7080
+ $value$: signal,
7081
+ };
7082
+ container.$scheduler$(5 /* ChoreType.NODE_PROP */, host, property, payload);
6482
7083
  }
6483
7084
  }
6484
7085
  };
@@ -6489,7 +7090,23 @@ const triggerEffects = (container, signal, effects) => {
6489
7090
  };
6490
7091
  /** @internal */
6491
7092
  const isSerializerObj = (obj) => {
6492
- return (typeof obj === 'object' && obj !== null && typeof obj[SerializerSymbol] === 'function');
7093
+ return isObject(obj) && typeof obj[SerializerSymbol] === 'function';
7094
+ };
7095
+ const getComputedSignalFlags = (serializationStrategy) => {
7096
+ let flags = 1 /* SignalFlags.INVALID */;
7097
+ switch (serializationStrategy) {
7098
+ // TODO: implement this in the future
7099
+ // case 'auto':
7100
+ // flags |= ComputedSignalFlags.SERIALIZATION_STRATEGY_AUTO;
7101
+ // break;
7102
+ case 'never':
7103
+ flags |= 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
7104
+ break;
7105
+ case 'always':
7106
+ flags |= 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
7107
+ break;
7108
+ }
7109
+ return flags;
6493
7110
  };
6494
7111
 
6495
7112
  const stringifyPath = [];
@@ -6784,6 +7401,7 @@ const vnode_isElementOrTextVNode = (vNode) => {
6784
7401
  const flag = vNode[0 /* VNodeProps.flags */];
6785
7402
  return (flag & 5 /* VNodeFlags.ELEMENT_OR_TEXT_MASK */) !== 0;
6786
7403
  };
7404
+ /** @internal */
6787
7405
  const vnode_isMaterialized = (vNode) => {
6788
7406
  assertDefined(vNode, 'Missing vNode');
6789
7407
  const flag = vNode[0 /* VNodeProps.flags */];
@@ -6791,11 +7409,13 @@ const vnode_isMaterialized = (vNode) => {
6791
7409
  vNode[4 /* ElementVNodeProps.firstChild */] !== undefined &&
6792
7410
  vNode[5 /* ElementVNodeProps.lastChild */] !== undefined);
6793
7411
  };
7412
+ /** @internal */
6794
7413
  const vnode_isTextVNode = (vNode) => {
6795
7414
  assertDefined(vNode, 'Missing vNode');
6796
7415
  const flag = vNode[0 /* VNodeProps.flags */];
6797
7416
  return (flag & 4 /* VNodeFlags.Text */) === 4 /* VNodeFlags.Text */;
6798
7417
  };
7418
+ /** @internal */
6799
7419
  const vnode_isVirtualVNode = (vNode) => {
6800
7420
  assertDefined(vNode, 'Missing vNode');
6801
7421
  const flag = vNode[0 /* VNodeProps.flags */];
@@ -6833,6 +7453,7 @@ const vnode_getNodeTypeName = (vNode) => {
6833
7453
  }
6834
7454
  return '<unknown>';
6835
7455
  };
7456
+ /** @internal */
6836
7457
  const vnode_ensureElementInflated = (vnode) => {
6837
7458
  const flags = vnode[0 /* VNodeProps.flags */];
6838
7459
  if ((flags & 15 /* VNodeFlags.INFLATED_TYPE_MASK */) === 1 /* VNodeFlags.Element */) {
@@ -6874,6 +7495,9 @@ function vnode_walkVNode(vNode, callback) {
6874
7495
  }
6875
7496
  let vParent = null;
6876
7497
  do {
7498
+ if (callback?.(vCursor, vParent)) {
7499
+ return;
7500
+ }
6877
7501
  const vFirstChild = vnode_getFirstChild(vCursor);
6878
7502
  if (vFirstChild) {
6879
7503
  vCursor = vFirstChild;
@@ -7042,6 +7666,7 @@ const vnode_ensureTextInflated = (journal, vnode) => {
7042
7666
  const flags = textVNode[0 /* VNodeProps.flags */];
7043
7667
  if ((flags & 8 /* VNodeFlags.Inflated */) === 0) {
7044
7668
  const parentNode = vnode_getDomParent(vnode);
7669
+ assertDefined(parentNode, 'Missing parent node.');
7045
7670
  const sharedTextNode = textVNode[4 /* TextVNodeProps.node */];
7046
7671
  const doc = parentNode.ownerDocument;
7047
7672
  // Walk the previous siblings and inflate them.
@@ -7200,6 +7825,18 @@ const indexOfAlphanumeric = (id, length) => {
7200
7825
  }
7201
7826
  return length;
7202
7827
  };
7828
+ const vnode_createErrorDiv = (document, host, err, journal) => {
7829
+ const errorDiv = document.createElement('errored-host');
7830
+ if (err && err instanceof Error) {
7831
+ errorDiv.props = { error: err };
7832
+ }
7833
+ errorDiv.setAttribute('q:key', '_error_');
7834
+ const vErrorDiv = vnode_newElement(errorDiv, 'errored-host');
7835
+ vnode_getDOMChildNodes(journal, host, true).forEach((child) => {
7836
+ vnode_insertBefore(journal, vErrorDiv, child, null);
7837
+ });
7838
+ return vErrorDiv;
7839
+ };
7203
7840
  const parseBoolean = (value) => {
7204
7841
  if (value === 'false') {
7205
7842
  return false;
@@ -7338,7 +7975,7 @@ const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
7338
7975
  * unlink the previous or next sibling, we don't know that after "a" node is "b". So we need to
7339
7976
  * find children first (and inflate them).
7340
7977
  */
7341
- const domParentVNode = vnode_getDomParentVNode(parent);
7978
+ const domParentVNode = vnode_getDomParentVNode(parent, false);
7342
7979
  const parentNode = domParentVNode && domParentVNode[6 /* ElementVNodeProps.element */];
7343
7980
  let domChildren = null;
7344
7981
  if (domParentVNode) {
@@ -7387,27 +8024,31 @@ const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
7387
8024
  newChildCurrentParent !== parent)) {
7388
8025
  vnode_remove(journal, newChildCurrentParent, newChild, false);
7389
8026
  }
7390
- let adjustedInsertBefore = null;
7391
- if (insertBefore == null) {
7392
- if (vnode_isVirtualVNode(parent)) {
7393
- // If `insertBefore` is null, than we need to insert at the end of the list.
7394
- // Well, not quite. If the parent is a virtual node, our "last node" is not the same
7395
- // as the DOM "last node". So in that case we need to look for the "next node" from
7396
- // our parent.
7397
- adjustedInsertBefore = vnode_getDomSibling(parent, true, false);
8027
+ const parentIsDeleted = parent[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */;
8028
+ // if the parent is deleted, then we don't need to insert the new child
8029
+ if (!parentIsDeleted) {
8030
+ let adjustedInsertBefore = null;
8031
+ if (insertBefore == null) {
8032
+ if (vnode_isVirtualVNode(parent)) {
8033
+ // If `insertBefore` is null, than we need to insert at the end of the list.
8034
+ // Well, not quite. If the parent is a virtual node, our "last node" is not the same
8035
+ // as the DOM "last node". So in that case we need to look for the "next node" from
8036
+ // our parent.
8037
+ adjustedInsertBefore = vnode_getDomSibling(parent, true, false);
8038
+ }
8039
+ }
8040
+ else if (vnode_isVirtualVNode(insertBefore)) {
8041
+ // If the `insertBefore` is virtual, than we need to descend into the virtual and find e actual
8042
+ adjustedInsertBefore = vnode_getDomSibling(insertBefore, true, true);
8043
+ }
8044
+ else {
8045
+ adjustedInsertBefore = insertBefore;
8046
+ }
8047
+ adjustedInsertBefore && vnode_ensureInflatedIfText(journal, adjustedInsertBefore);
8048
+ // Here we know the insertBefore node
8049
+ if (domChildren && domChildren.length) {
8050
+ journal.push(5 /* VNodeJournalOpCode.Insert */, parentNode, vnode_getNode(adjustedInsertBefore), ...domChildren);
7398
8051
  }
7399
- }
7400
- else if (vnode_isVirtualVNode(insertBefore)) {
7401
- // If the `insertBefore` is virtual, than we need to descend into the virtual and find e actual
7402
- adjustedInsertBefore = vnode_getDomSibling(insertBefore, true, true);
7403
- }
7404
- else {
7405
- adjustedInsertBefore = insertBefore;
7406
- }
7407
- adjustedInsertBefore && vnode_ensureInflatedIfText(journal, adjustedInsertBefore);
7408
- // Here we know the insertBefore node
7409
- if (domChildren && domChildren.length) {
7410
- journal.push(5 /* VNodeJournalOpCode.Insert */, parentNode, vnode_getNode(adjustedInsertBefore), ...domChildren);
7411
8052
  }
7412
8053
  // link newChild into the previous/next list
7413
8054
  const vNext = insertBefore;
@@ -7429,14 +8070,22 @@ const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
7429
8070
  newChild[2 /* VNodeProps.previousSibling */] = vPrevious;
7430
8071
  newChild[3 /* VNodeProps.nextSibling */] = vNext;
7431
8072
  newChild[1 /* VNodeProps.parent */] = parent;
8073
+ if (parentIsDeleted) {
8074
+ // if the parent is deleted, then the new child is also deleted
8075
+ newChild[0 /* VNodeProps.flags */] |= 32 /* VNodeFlags.Deleted */;
8076
+ }
7432
8077
  };
7433
- const vnode_getDomParent = (vnode) => {
7434
- vnode = vnode_getDomParentVNode(vnode);
8078
+ const vnode_getDomParent = (vnode, includeProjection = true) => {
8079
+ vnode = vnode_getDomParentVNode(vnode, includeProjection);
7435
8080
  return (vnode && vnode[6 /* ElementVNodeProps.element */]);
7436
8081
  };
7437
- const vnode_getDomParentVNode = (vnode) => {
8082
+ const vnode_getDomParentVNode = (vnode, includeProjection = true) => {
7438
8083
  while (vnode && !vnode_isElementVNode(vnode)) {
7439
- vnode = vnode[1 /* VNodeProps.parent */];
8084
+ vnode =
8085
+ vnode[1 /* VNodeProps.parent */] ||
8086
+ (includeProjection
8087
+ ? vnode_getProp(vnode, QSlotParent, (id) => (vnode_isVNode(id) ? id : null))
8088
+ : null);
7440
8089
  }
7441
8090
  return vnode;
7442
8091
  };
@@ -7446,7 +8095,7 @@ const vnode_remove = (journal, vParent, vToRemove, removeDOM) => {
7446
8095
  vnode_ensureTextInflated(journal, vToRemove);
7447
8096
  }
7448
8097
  if (removeDOM) {
7449
- const domParent = vnode_getDomParent(vParent);
8098
+ const domParent = vnode_getDomParent(vParent, false);
7450
8099
  const isInnerHTMLParent = vnode_getAttr(vParent, dangerouslySetInnerHTML);
7451
8100
  if (isInnerHTMLParent) {
7452
8101
  // ignore children, as they are inserted via innerHTML
@@ -7511,6 +8160,7 @@ const vnode_setText = (journal, textVNode, text) => {
7511
8160
  const textNode = textVNode[4 /* TextVNodeProps.node */];
7512
8161
  journal.push(1 /* VNodeJournalOpCode.SetText */, textNode, (textVNode[5 /* TextVNodeProps.text */] = text));
7513
8162
  };
8163
+ /** @internal */
7514
8164
  const vnode_getFirstChild = (vnode) => {
7515
8165
  if (vnode_isTextVNode(vnode)) {
7516
8166
  return null;
@@ -7771,27 +8421,46 @@ const materializeFromDOM = (vParent, firstChild, vData) => {
7771
8421
  return vFirstChild;
7772
8422
  };
7773
8423
  function setEffectBackRefFromVNodeData(vParent, value, container) {
7774
- const deserializedSubMap = container.$getObjectById$(value);
7775
8424
  if (!vParent[_EFFECT_BACK_REF]) {
8425
+ // get data lazily
8426
+ // this is because effects back refs can point to vnodes which are not yet materialized
8427
+ // (are after the current vnode)
7776
8428
  Object.defineProperty(vParent, _EFFECT_BACK_REF, {
7777
- value: deserializedSubMap,
8429
+ get() {
8430
+ const subMap = container.$getObjectById$(value);
8431
+ vParent[_EFFECT_BACK_REF] = subMap;
8432
+ return subMap;
8433
+ },
8434
+ set(value) {
8435
+ Object.defineProperty(vParent, _EFFECT_BACK_REF, {
8436
+ value,
8437
+ writable: true,
8438
+ enumerable: true,
8439
+ configurable: true,
8440
+ });
8441
+ },
8442
+ enumerable: true,
8443
+ configurable: true,
7778
8444
  });
7779
8445
  }
7780
8446
  else {
7781
8447
  const subMap = vParent[_EFFECT_BACK_REF];
7782
- mergeMaps(subMap, deserializedSubMap);
8448
+ mergeMaps(subMap, container.$getObjectById$(value));
7783
8449
  }
7784
8450
  }
7785
8451
  const processVNodeData = (vData, callback) => {
7786
8452
  let nextToConsumeIdx = 0;
7787
8453
  let ch = 0;
7788
8454
  let peekCh = 0;
8455
+ const getChar = (idx) => {
8456
+ return idx < vData.length ? vData.charCodeAt(idx) : 0;
8457
+ };
7789
8458
  const peek = () => {
7790
8459
  if (peekCh !== 0) {
7791
8460
  return peekCh;
7792
8461
  }
7793
8462
  else {
7794
- return (peekCh = nextToConsumeIdx < vData.length ? vData.charCodeAt(nextToConsumeIdx) : 0);
8463
+ return (peekCh = getChar(nextToConsumeIdx));
7795
8464
  }
7796
8465
  };
7797
8466
  const consume = () => {
@@ -7812,15 +8481,17 @@ const processVNodeData = (vData, callback) => {
7812
8481
  return vData.substring(start, nextToConsumeIdx);
7813
8482
  };
7814
8483
  while (peek() !== 0) {
7815
- callback(peek, consumeValue, consume, nextToConsumeIdx);
8484
+ callback(peek, consumeValue, consume, getChar, nextToConsumeIdx);
7816
8485
  }
7817
8486
  };
8487
+ /** @internal */
7818
8488
  const vnode_getNextSibling = (vnode) => {
7819
8489
  return vnode[3 /* VNodeProps.nextSibling */];
7820
8490
  };
7821
8491
  const vnode_getPreviousSibling = (vnode) => {
7822
8492
  return vnode[2 /* VNodeProps.previousSibling */];
7823
8493
  };
8494
+ /** @internal */
7824
8495
  const vnode_getAttrKeys = (vnode) => {
7825
8496
  const type = vnode[0 /* VNodeProps.flags */];
7826
8497
  if ((type & 3 /* VNodeFlags.ELEMENT_OR_VIRTUAL_MASK */) !== 0) {
@@ -7866,6 +8537,7 @@ const vnode_setAttr = (journal, vnode, key, value) => {
7866
8537
  }
7867
8538
  }
7868
8539
  };
8540
+ /** @internal */
7869
8541
  const vnode_getAttr = (vnode, key) => {
7870
8542
  const type = vnode[0 /* VNodeProps.flags */];
7871
8543
  if ((type & 3 /* VNodeFlags.ELEMENT_OR_VIRTUAL_MASK */) !== 0) {
@@ -7902,6 +8574,7 @@ const vnode_setProp = (vnode, key, value) => {
7902
8574
  props.splice(idx ^ -1, 0, key, value);
7903
8575
  }
7904
8576
  };
8577
+ /** @internal */
7905
8578
  const vnode_getPropStartIndex = (vnode) => {
7906
8579
  const type = vnode[0 /* VNodeProps.flags */] & 7 /* VNodeFlags.TYPE_MASK */;
7907
8580
  if (type === 1 /* VNodeFlags.Element */) {
@@ -7912,12 +8585,33 @@ const vnode_getPropStartIndex = (vnode) => {
7912
8585
  }
7913
8586
  throw qError(26 /* QError.invalidVNodeType */, [type]);
7914
8587
  };
8588
+ /** @internal */
7915
8589
  const vnode_getProps = (vnode) => {
7916
8590
  return vnode[vnode_getPropStartIndex(vnode)];
7917
8591
  };
7918
8592
  const vnode_getParent = (vnode) => {
7919
8593
  return vnode[1 /* VNodeProps.parent */] || null;
7920
8594
  };
8595
+ const vnode_isDescendantOf = (vnode, ancestor, rootVNode) => {
8596
+ let parent = vnode_getParentOrProjectionParent(vnode, rootVNode);
8597
+ while (parent) {
8598
+ if (parent === ancestor) {
8599
+ return true;
8600
+ }
8601
+ parent = vnode_getParentOrProjectionParent(parent, rootVNode);
8602
+ }
8603
+ return false;
8604
+ };
8605
+ const vnode_getParentOrProjectionParent = (vnode, rootVNode) => {
8606
+ if (rootVNode) {
8607
+ const parentProjection = vnode_getProp(vnode, QSlotParent, (id) => vnode_locate(rootVNode, id));
8608
+ if (parentProjection) {
8609
+ // This is a projection, so we need to check the parent of the projection
8610
+ return parentProjection;
8611
+ }
8612
+ }
8613
+ return vnode_getParent(vnode);
8614
+ };
7921
8615
  const vnode_getNode = (vnode) => {
7922
8616
  if (vnode === null || vnode_isVirtualVNode(vnode)) {
7923
8617
  return null;
@@ -8026,21 +8720,19 @@ function materializeFromVNodeData(vParent, vData, element, child) {
8026
8720
  let textIdx = 0;
8027
8721
  let combinedText = null;
8028
8722
  let container = null;
8029
- processVNodeData(vData, (peek, consumeValue, consume, nextToConsumeIdx) => {
8723
+ processVNodeData(vData, (peek, consumeValue, consume, getChar, nextToConsumeIdx) => {
8030
8724
  if (isNumber(peek())) {
8031
8725
  // Element counts get encoded as numbers.
8032
- while (!isElement(child)) {
8726
+ while (!isElement(child) ||
8727
+ // We pretend that style element's don't exist as they can get moved out.
8728
+ // skip over style elements, as those need to be moved to the head
8729
+ // and are not included in the counts.
8730
+ isQStyleElement(child)) {
8033
8731
  child = fastNextSibling(child);
8034
8732
  if (!child) {
8035
8733
  throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), nextToConsumeIdx]);
8036
8734
  }
8037
8735
  }
8038
- // We pretend that style element's don't exist as they can get moved out.
8039
- while (isQStyleElement(child)) {
8040
- // skip over style elements, as those need to be moved to the head
8041
- // and are not included in the counts.
8042
- child = fastNextSibling(child);
8043
- }
8044
8736
  combinedText = null;
8045
8737
  previousTextNode = null;
8046
8738
  let value = 0;
@@ -8072,7 +8764,17 @@ function materializeFromVNodeData(vParent, vData, element, child) {
8072
8764
  vnode_setAttr(null, vParent, ELEMENT_PROPS, consumeValue());
8073
8765
  }
8074
8766
  else if (peek() === VNodeDataChar.KEY) {
8075
- vnode_setAttr(null, vParent, ELEMENT_KEY, consumeValue());
8767
+ const isEscapedValue = getChar(nextToConsumeIdx + 1) === VNodeDataChar.SEPARATOR;
8768
+ let value;
8769
+ if (isEscapedValue) {
8770
+ consume();
8771
+ value = decodeURI(consumeValue());
8772
+ consume();
8773
+ }
8774
+ else {
8775
+ value = consumeValue();
8776
+ }
8777
+ vnode_setAttr(null, vParent, ELEMENT_KEY, value);
8076
8778
  }
8077
8779
  else if (peek() === VNodeDataChar.SEQ) {
8078
8780
  vnode_setAttr(null, vParent, ELEMENT_SEQ, consumeValue());
@@ -8118,6 +8820,10 @@ function materializeFromVNodeData(vParent, vData, element, child) {
8118
8820
  vnode_setAttr(null, vParent, QSlot, consumeValue());
8119
8821
  }
8120
8822
  else {
8823
+ // skip over style elements in front of text nodes, where text node is the first child (except the style node)
8824
+ while (isQStyleElement(child)) {
8825
+ child = fastNextSibling(child);
8826
+ }
8121
8827
  const textNode = child && fastNodeType(child) === /* Node.TEXT_NODE */ 3 ? child : null;
8122
8828
  // must be alphanumeric
8123
8829
  if (combinedText === null) {
@@ -8212,9 +8918,11 @@ const VNodeArray = class VNode extends Array {
8212
8918
  };
8213
8919
 
8214
8920
  /** There's [documentation](./serialization.md) */
8921
+ /** Arrays/Objects are special-cased so their identifiers is a single digit. */
8922
+ const needsInflation = (typeId) => typeId >= 14 /* TypeIds.Error */ || typeId === 4 /* TypeIds.Array */ || typeId === 5 /* TypeIds.Object */;
8215
8923
  const deserializedProxyMap = new WeakMap();
8216
8924
  const isDeserializerProxy = (value) => {
8217
- return typeof value === 'object' && value !== null && SERIALIZER_PROXY_UNWRAP in value;
8925
+ return isObject(value) && SERIALIZER_PROXY_UNWRAP in value;
8218
8926
  };
8219
8927
  const SERIALIZER_PROXY_UNWRAP = Symbol('UNWRAP');
8220
8928
  /** Call this on the serialized root state */
@@ -8259,19 +8967,19 @@ class DeserializationHandler {
8259
8967
  const idx = i * 2;
8260
8968
  const typeId = this.$data$[idx];
8261
8969
  const value = this.$data$[idx + 1];
8262
- if (typeId === undefined) {
8970
+ if (typeId === 0 /* TypeIds.Plain */) {
8263
8971
  // The value is already cached
8264
8972
  return value;
8265
8973
  }
8266
8974
  const container = this.$container$;
8267
- let propValue = allocate(container, typeId, value);
8268
- /** We stored the reference, so now we can inflate, allowing cycles. */
8269
- if (typeId >= 14 /* TypeIds.Error */) {
8270
- propValue = inflate(container, propValue, typeId, value);
8271
- }
8975
+ const propValue = allocate(container, typeId, value);
8272
8976
  Reflect.set(target, property, propValue);
8273
- this.$data$[idx] = undefined;
8977
+ this.$data$[idx] = 0 /* TypeIds.Plain */;
8274
8978
  this.$data$[idx + 1] = propValue;
8979
+ /** We stored the reference, so now we can inflate, allowing cycles */
8980
+ if (needsInflation(typeId)) {
8981
+ inflate(container, propValue, typeId, value);
8982
+ }
8275
8983
  return propValue;
8276
8984
  }
8277
8985
  has(target, property) {
@@ -8290,7 +8998,7 @@ class DeserializationHandler {
8290
8998
  return out;
8291
8999
  }
8292
9000
  const idx = i * 2;
8293
- this.$data$[idx] = undefined;
9001
+ this.$data$[idx] = 0 /* TypeIds.Plain */;
8294
9002
  this.$data$[idx + 1] = value;
8295
9003
  return true;
8296
9004
  }
@@ -8308,51 +9016,33 @@ const _eagerDeserializeArray = (container, data) => {
8308
9016
  };
8309
9017
  const resolvers = new WeakMap();
8310
9018
  const inflate = (container, target, typeId, data) => {
8311
- if (typeId === undefined) {
9019
+ if (typeId === 0 /* TypeIds.Plain */) {
8312
9020
  // Already processed
8313
- return target;
9021
+ return;
8314
9022
  }
8315
- // restore the complex data, except for plain objects
8316
- if (typeId !== 15 /* TypeIds.Object */ && Array.isArray(data)) {
9023
+ // Restore the complex data
9024
+ if (Array.isArray(data)) {
8317
9025
  data = _eagerDeserializeArray(container, data);
8318
9026
  }
8319
9027
  switch (typeId) {
8320
- case 15 /* TypeIds.Object */:
8321
- // We use getters for making complex values lazy
8322
- for (let i = 0; i < data.length; i += 4) {
8323
- const key = deserializeData(container, data[i], data[i + 1]);
8324
- const valType = data[i + 2];
8325
- const valData = data[i + 3];
8326
- if (valType === 0 /* TypeIds.RootRef */ || valType >= 14 /* TypeIds.Error */) {
8327
- Object.defineProperty(target, key, {
8328
- get() {
8329
- const value = deserializeData(container, valType, valData);
8330
- // after first deserialize, we can replace the Object.defineProperty with the value
8331
- target[key] = value;
8332
- return value;
8333
- },
8334
- set(value) {
8335
- Object.defineProperty(target, key, {
8336
- value,
8337
- writable: true,
8338
- enumerable: true,
8339
- configurable: true,
8340
- });
8341
- },
8342
- enumerable: true,
8343
- configurable: true,
8344
- });
8345
- }
8346
- else {
8347
- target[key] = deserializeData(container, valType, valData);
8348
- }
9028
+ case 4 /* TypeIds.Array */:
9029
+ for (let i = 0; i < target.length; i++) {
9030
+ // read the value to trigger lazy deserialization
9031
+ target[i];
9032
+ }
9033
+ break;
9034
+ case 5 /* TypeIds.Object */:
9035
+ for (let i = 0; i < data.length; i += 2) {
9036
+ const key = data[i];
9037
+ const value = data[i + 1];
9038
+ target[key] = value;
8349
9039
  }
8350
9040
  break;
8351
- case 20 /* TypeIds.QRL */:
8352
- case 21 /* TypeIds.PreloadQRL */:
9041
+ case 19 /* TypeIds.QRL */:
9042
+ case 20 /* TypeIds.PreloadQRL */:
8353
9043
  inflateQRL(container, target);
8354
9044
  break;
8355
- case 22 /* TypeIds.Task */:
9045
+ case 21 /* TypeIds.Task */:
8356
9046
  const task = target;
8357
9047
  const v = data;
8358
9048
  task.$qrl$ = inflateQRL(container, v[0]);
@@ -8362,7 +9052,7 @@ const inflate = (container, target, typeId, data) => {
8362
9052
  task[_EFFECT_BACK_REF] = v[4];
8363
9053
  task.$state$ = v[5];
8364
9054
  break;
8365
- case 23 /* TypeIds.Resource */:
9055
+ case 22 /* TypeIds.Resource */:
8366
9056
  const [resolved, result, effects] = data;
8367
9057
  const resource = target;
8368
9058
  if (resolved) {
@@ -8377,26 +9067,31 @@ const inflate = (container, target, typeId, data) => {
8377
9067
  }
8378
9068
  getStoreHandler(target).$effects$ = effects;
8379
9069
  break;
8380
- case 24 /* TypeIds.Component */:
9070
+ case 23 /* TypeIds.Component */:
8381
9071
  target[SERIALIZABLE_STATE][0] = data[0];
8382
9072
  break;
8383
- case 30 /* TypeIds.Store */:
8384
- case 31 /* TypeIds.StoreArray */: {
8385
- const [value, flags, effects] = data;
8386
- const store = getOrCreateStore(value, flags, container);
8387
- const storeHandler = getStoreHandler(store);
9073
+ case 29 /* TypeIds.Store */: {
9074
+ /**
9075
+ * Note that cycles between stores and their targets can cause this inflation to happen on
9076
+ * already inflated stores, but that's ok because the flags and effects are still the same.
9077
+ *
9078
+ * Also note that we don't do anything with the innerstores we added during serialization,
9079
+ * because they are already inflated in the first step of inflate().
9080
+ */
9081
+ const [, flags, effects] = data;
9082
+ const storeHandler = getStoreHandler(target);
9083
+ storeHandler.$flags$ = flags;
8388
9084
  storeHandler.$effects$ = effects;
8389
- target = store;
8390
9085
  break;
8391
9086
  }
8392
- case 25 /* TypeIds.Signal */: {
9087
+ case 24 /* TypeIds.Signal */: {
8393
9088
  const signal = target;
8394
9089
  const d = data;
8395
9090
  signal.$untrackedValue$ = d[0];
8396
9091
  signal.$effects$ = new Set(d.slice(1));
8397
9092
  break;
8398
9093
  }
8399
- case 26 /* TypeIds.WrappedSignal */: {
9094
+ case 25 /* TypeIds.WrappedSignal */: {
8400
9095
  const signal = target;
8401
9096
  const d = data;
8402
9097
  signal.$func$ = container.getSyncFn(d[0]);
@@ -8409,7 +9104,7 @@ const inflate = (container, target, typeId, data) => {
8409
9104
  signal.$effects$ = new Set(d.slice(5));
8410
9105
  break;
8411
9106
  }
8412
- case 28 /* TypeIds.AsyncComputedSignal */: {
9107
+ case 27 /* TypeIds.AsyncComputedSignal */: {
8413
9108
  const asyncComputed = target;
8414
9109
  const d = data;
8415
9110
  asyncComputed.$computeQrl$ = d[0];
@@ -8422,14 +9117,12 @@ const inflate = (container, target, typeId, data) => {
8422
9117
  if (hasValue) {
8423
9118
  asyncComputed.$untrackedValue$ = d[6];
8424
9119
  }
8425
- else {
8426
- asyncComputed.$flags$ |= 1 /* SignalFlags.INVALID */;
8427
- }
9120
+ asyncComputed.$flags$ |= 1 /* SignalFlags.INVALID */;
8428
9121
  break;
8429
9122
  }
8430
9123
  // Inflating a SerializerSignal is the same as inflating a ComputedSignal
8431
- case 29 /* TypeIds.SerializerSignal */:
8432
- case 27 /* TypeIds.ComputedSignal */: {
9124
+ case 28 /* TypeIds.SerializerSignal */:
9125
+ case 26 /* TypeIds.ComputedSignal */: {
8433
9126
  const computed = target;
8434
9127
  const d = data;
8435
9128
  computed.$computeQrl$ = d[0];
@@ -8438,7 +9131,7 @@ const inflate = (container, target, typeId, data) => {
8438
9131
  if (hasValue) {
8439
9132
  computed.$untrackedValue$ = d[2];
8440
9133
  // The serialized signal is always invalid so it can recreate the custom object
8441
- if (typeId === 29 /* TypeIds.SerializerSignal */) {
9134
+ if (typeId === 28 /* TypeIds.SerializerSignal */) {
8442
9135
  computed.$flags$ |= 1 /* SignalFlags.INVALID */;
8443
9136
  }
8444
9137
  }
@@ -8452,7 +9145,7 @@ const inflate = (container, target, typeId, data) => {
8452
9145
  */
8453
9146
  // try to download qrl in this tick
8454
9147
  computed.$computeQrl$.resolve();
8455
- container.$scheduler$?.(1 /* ChoreType.QRL_RESOLVE */, null, computed.$computeQrl$);
9148
+ container.$scheduler$(1 /* ChoreType.QRL_RESOLVE */, null, computed.$computeQrl$);
8456
9149
  }
8457
9150
  break;
8458
9151
  }
@@ -8464,7 +9157,7 @@ const inflate = (container, target, typeId, data) => {
8464
9157
  }
8465
9158
  break;
8466
9159
  }
8467
- case 32 /* TypeIds.FormData */: {
9160
+ case 30 /* TypeIds.FormData */: {
8468
9161
  const formData = target;
8469
9162
  const d = data;
8470
9163
  for (let i = 0; i < d.length; i++) {
@@ -8472,7 +9165,7 @@ const inflate = (container, target, typeId, data) => {
8472
9165
  }
8473
9166
  break;
8474
9167
  }
8475
- case 33 /* TypeIds.JSXNode */: {
9168
+ case 31 /* TypeIds.JSXNode */: {
8476
9169
  const jsx = target;
8477
9170
  const [type, varProps, constProps, children, flags, key] = data;
8478
9171
  jsx.type = type;
@@ -8483,7 +9176,7 @@ const inflate = (container, target, typeId, data) => {
8483
9176
  jsx.key = key;
8484
9177
  break;
8485
9178
  }
8486
- case 17 /* TypeIds.Set */: {
9179
+ case 16 /* TypeIds.Set */: {
8487
9180
  const set = target;
8488
9181
  const d = data;
8489
9182
  for (let i = 0; i < d.length; i++) {
@@ -8491,7 +9184,7 @@ const inflate = (container, target, typeId, data) => {
8491
9184
  }
8492
9185
  break;
8493
9186
  }
8494
- case 18 /* TypeIds.Map */: {
9187
+ case 17 /* TypeIds.Map */: {
8495
9188
  const map = target;
8496
9189
  const d = data;
8497
9190
  for (let i = 0; i < d.length; i++) {
@@ -8499,7 +9192,7 @@ const inflate = (container, target, typeId, data) => {
8499
9192
  }
8500
9193
  break;
8501
9194
  }
8502
- case 16 /* TypeIds.Promise */: {
9195
+ case 15 /* TypeIds.Promise */: {
8503
9196
  const promise = target;
8504
9197
  const [resolved, result] = data;
8505
9198
  const [resolve, reject] = resolvers.get(promise);
@@ -8511,7 +9204,7 @@ const inflate = (container, target, typeId, data) => {
8511
9204
  }
8512
9205
  break;
8513
9206
  }
8514
- case 19 /* TypeIds.Uint8Array */:
9207
+ case 18 /* TypeIds.Uint8Array */:
8515
9208
  const bytes = target;
8516
9209
  const buf = atob(data);
8517
9210
  let i = 0;
@@ -8519,12 +9212,12 @@ const inflate = (container, target, typeId, data) => {
8519
9212
  bytes[i++] = s.charCodeAt(0);
8520
9213
  }
8521
9214
  break;
8522
- case 34 /* TypeIds.PropsProxy */:
9215
+ case 32 /* TypeIds.PropsProxy */:
8523
9216
  const propsProxy = target;
8524
9217
  propsProxy[_VAR_PROPS] = data === 0 ? {} : data[0];
8525
9218
  propsProxy[_CONST_PROPS] = data[1];
8526
9219
  break;
8527
- case 35 /* TypeIds.EffectData */: {
9220
+ case 33 /* TypeIds.SubscriptionData */: {
8528
9221
  const effectData = target;
8529
9222
  effectData.data.$scopedStyleIdPrefix$ = data[0];
8530
9223
  effectData.data.$isConst$ = data[1];
@@ -8533,7 +9226,6 @@ const inflate = (container, target, typeId, data) => {
8533
9226
  default:
8534
9227
  throw qError(16 /* QError.serializeErrorNotImplemented */, [typeId]);
8535
9228
  }
8536
- return target;
8537
9229
  };
8538
9230
  const _constants = [
8539
9231
  undefined,
@@ -8545,6 +9237,7 @@ const _constants = [
8545
9237
  EMPTY_OBJ,
8546
9238
  NEEDS_COMPUTATION,
8547
9239
  STORE_ALL_PROPS,
9240
+ _UNINITIALIZED,
8548
9241
  Slot,
8549
9242
  Fragment,
8550
9243
  NaN,
@@ -8564,6 +9257,7 @@ const _constantNames = [
8564
9257
  'EMPTY_OBJ',
8565
9258
  'NEEDS_COMPUTATION',
8566
9259
  'STORE_ALL_PROPS',
9260
+ '_UNINITIALIZED',
8567
9261
  'Slot',
8568
9262
  'Fragment',
8569
9263
  'NaN',
@@ -8574,84 +9268,96 @@ const _constantNames = [
8574
9268
  'MIN_SAFE_INTEGER',
8575
9269
  ];
8576
9270
  const allocate = (container, typeId, value) => {
8577
- if (value === undefined) {
8578
- // When a value was already processed, the result is stored in type
8579
- return typeId;
9271
+ if (typeId === 0 /* TypeIds.Plain */) {
9272
+ return value;
8580
9273
  }
8581
9274
  switch (typeId) {
8582
- case 0 /* TypeIds.RootRef */:
9275
+ case 1 /* TypeIds.RootRef */:
8583
9276
  return container.$getObjectById$(value);
8584
- case 1 /* TypeIds.ForwardRef */:
9277
+ case 2 /* TypeIds.ForwardRef */:
8585
9278
  if (!container.$forwardRefs$) {
8586
9279
  throw qError(18 /* QError.serializeErrorCannotAllocate */, ['forward ref']);
8587
9280
  }
8588
- return container.$getObjectById$(container.$forwardRefs$[value]);
8589
- case 2 /* TypeIds.ForwardRefs */:
9281
+ const rootRef = container.$forwardRefs$[value];
9282
+ if (rootRef === -1) {
9283
+ return _UNINITIALIZED;
9284
+ }
9285
+ else {
9286
+ return container.$getObjectById$(rootRef);
9287
+ }
9288
+ case 13 /* TypeIds.ForwardRefs */:
8590
9289
  return value;
8591
9290
  case 3 /* TypeIds.Constant */:
8592
9291
  return _constants[value];
8593
- case 4 /* TypeIds.Number */:
8594
- return value;
8595
- case 6 /* TypeIds.Array */:
9292
+ case 4 /* TypeIds.Array */:
9293
+ // Wrap while inflating so we can handle cyclic references
8596
9294
  return wrapDeserializerProxy(container, value);
8597
- case 15 /* TypeIds.Object */:
9295
+ case 5 /* TypeIds.Object */:
8598
9296
  return {};
8599
- case 20 /* TypeIds.QRL */:
8600
- case 21 /* TypeIds.PreloadQRL */:
9297
+ case 19 /* TypeIds.QRL */:
9298
+ case 20 /* TypeIds.PreloadQRL */:
8601
9299
  const qrl = typeof value === 'number'
8602
9300
  ? // root reference
8603
9301
  container.$getObjectById$(value)
8604
9302
  : value;
8605
9303
  return parseQRL(qrl);
8606
- case 22 /* TypeIds.Task */:
9304
+ case 21 /* TypeIds.Task */:
8607
9305
  return new Task(-1, -1, null, null, null, null);
8608
- case 23 /* TypeIds.Resource */: {
9306
+ case 22 /* TypeIds.Resource */: {
8609
9307
  const res = createResourceReturn(container,
8610
9308
  // we don't care about the timeout value
8611
9309
  undefined, undefined);
8612
9310
  res.loading = false;
8613
9311
  return res;
8614
9312
  }
8615
- case 7 /* TypeIds.URL */:
9313
+ case 6 /* TypeIds.URL */:
8616
9314
  return new URL(value);
8617
- case 8 /* TypeIds.Date */:
9315
+ case 7 /* TypeIds.Date */:
8618
9316
  return new Date(value);
8619
- case 9 /* TypeIds.Regex */:
9317
+ case 8 /* TypeIds.Regex */:
8620
9318
  const idx = value.lastIndexOf('/');
8621
9319
  return new RegExp(value.slice(1, idx), value.slice(idx + 1));
8622
9320
  case 14 /* TypeIds.Error */:
8623
9321
  return new Error();
8624
- case 24 /* TypeIds.Component */:
9322
+ case 23 /* TypeIds.Component */:
8625
9323
  return componentQrl(null);
8626
- case 25 /* TypeIds.Signal */:
9324
+ case 24 /* TypeIds.Signal */:
8627
9325
  return new SignalImpl(container, 0);
8628
- case 26 /* TypeIds.WrappedSignal */:
9326
+ case 25 /* TypeIds.WrappedSignal */:
8629
9327
  return new WrappedSignalImpl(container, null, null, null);
8630
- case 27 /* TypeIds.ComputedSignal */:
9328
+ case 26 /* TypeIds.ComputedSignal */:
8631
9329
  return new ComputedSignalImpl(container, null);
8632
- case 28 /* TypeIds.AsyncComputedSignal */:
9330
+ case 27 /* TypeIds.AsyncComputedSignal */:
8633
9331
  return new AsyncComputedSignalImpl(container, null);
8634
- case 29 /* TypeIds.SerializerSignal */:
9332
+ case 28 /* TypeIds.SerializerSignal */:
8635
9333
  return new SerializerSignalImpl(container, null);
8636
- case 30 /* TypeIds.Store */:
8637
- case 31 /* TypeIds.StoreArray */:
8638
- // ignore allocate, we need to assign target while creating store
8639
- return null;
8640
- case 13 /* TypeIds.URLSearchParams */:
9334
+ case 29 /* TypeIds.Store */:
9335
+ /**
9336
+ * We have a problem here: In theory, both the store and the target need to be present at
9337
+ * allocate time before inflation can happen. However, that makes the code really complex.
9338
+ * Instead, we deserialize the target here, which will already allocate and inflate this store
9339
+ * if there is a cycle (because the original allocation for the store didn't complete yet).
9340
+ * Because we have a map of target -> store, we will reuse the same store instance after
9341
+ * target deserialization. So in that case, we will be running inflation twice on the same
9342
+ * store, but that is not a problem, very little overhead and the code is way simpler.
9343
+ */
9344
+ const storeValue = deserializeData(container, value[0], value[1]);
9345
+ value[0] = 0 /* TypeIds.Plain */;
9346
+ value[1] = storeValue;
9347
+ return getOrCreateStore(storeValue, 0 /* StoreFlags.NONE */, container);
9348
+ case 12 /* TypeIds.URLSearchParams */:
8641
9349
  return new URLSearchParams(value);
8642
- case 32 /* TypeIds.FormData */:
9350
+ case 30 /* TypeIds.FormData */:
8643
9351
  return new FormData();
8644
- case 33 /* TypeIds.JSXNode */:
9352
+ case 31 /* TypeIds.JSXNode */:
8645
9353
  return new JSXNodeImpl(null, null, null, null, -1, null);
8646
- case 12 /* TypeIds.BigInt */:
9354
+ case 11 /* TypeIds.BigInt */:
8647
9355
  return BigInt(value);
8648
- case 17 /* TypeIds.Set */:
9356
+ case 16 /* TypeIds.Set */:
8649
9357
  return new Set();
8650
- case 18 /* TypeIds.Map */:
9358
+ case 17 /* TypeIds.Map */:
8651
9359
  return new Map();
8652
- case 5 /* TypeIds.String */:
8653
- return value;
8654
- case 16 /* TypeIds.Promise */:
9360
+ case 15 /* TypeIds.Promise */:
8655
9361
  let resolve;
8656
9362
  let reject;
8657
9363
  const promise = new Promise((res, rej) => {
@@ -8662,25 +9368,51 @@ const allocate = (container, typeId, value) => {
8662
9368
  // Don't leave unhandled promise rejections
8663
9369
  promise.catch(() => { });
8664
9370
  return promise;
8665
- case 19 /* TypeIds.Uint8Array */:
9371
+ case 18 /* TypeIds.Uint8Array */:
8666
9372
  const encodedLength = value.length;
8667
9373
  const blocks = encodedLength >>> 2;
8668
9374
  const rest = encodedLength & 3;
8669
9375
  const decodedLength = blocks * 3 + (rest ? rest - 1 : 0);
8670
9376
  return new Uint8Array(decodedLength);
8671
- case 34 /* TypeIds.PropsProxy */:
9377
+ case 32 /* TypeIds.PropsProxy */:
8672
9378
  return createPropsProxy(null, null);
8673
- case 10 /* TypeIds.VNode */:
9379
+ case 9 /* TypeIds.VNode */:
8674
9380
  return retrieveVNodeOrDocument(container, value);
8675
- case 11 /* TypeIds.RefVNode */:
9381
+ case 10 /* TypeIds.RefVNode */:
8676
9382
  const vNode = retrieveVNodeOrDocument(container, value);
8677
9383
  if (vnode_isVNode(vNode)) {
9384
+ /**
9385
+ * If we have a ref, we need to ensure the element is materialized.
9386
+ *
9387
+ * Example:
9388
+ *
9389
+ * ```
9390
+ * const Cmp = component$(() => {
9391
+ * const element = useSignal<HTMLDivElement>();
9392
+ *
9393
+ * useVisibleTask$(() => {
9394
+ * element.value!.innerHTML = 'I am the innerHTML content!';
9395
+ * });
9396
+ *
9397
+ * return (
9398
+ * <div ref={element} />
9399
+ * );
9400
+ * });
9401
+ * ```
9402
+ *
9403
+ * If we don't materialize early element with ref property, and change element innerHTML it
9404
+ * will be applied to a vnode tree during the lazy materialization, and it is wrong.
9405
+ *
9406
+ * Next if we rerender component it will remove applied innerHTML, because the system thinks
9407
+ * it is a part of the vnode tree.
9408
+ */
9409
+ ensureMaterialized(vNode);
8678
9410
  return vnode_getNode(vNode);
8679
9411
  }
8680
9412
  else {
8681
9413
  throw qError(17 /* QError.serializeErrorExpectedVNode */, [typeof vNode]);
8682
9414
  }
8683
- case 35 /* TypeIds.EffectData */:
9415
+ case 33 /* TypeIds.SubscriptionData */:
8684
9416
  return new SubscriptionData({});
8685
9417
  default:
8686
9418
  throw qError(18 /* QError.serializeErrorCannotAllocate */, [typeId]);
@@ -8742,7 +9474,7 @@ DomRefConstructor, symbolToChunkResolver, getProp, setProp, storeProxyMap, write
8742
9474
  };
8743
9475
  }
8744
9476
  const seenObjsMap = new Map();
8745
- const rootsPathMap = new Map();
9477
+ const objectPathStringCache = new Map();
8746
9478
  const syncFnMap = new Map();
8747
9479
  const syncFns = [];
8748
9480
  const roots = [];
@@ -8751,7 +9483,7 @@ DomRefConstructor, symbolToChunkResolver, getProp, setProp, storeProxyMap, write
8751
9483
  return seenObjsMap.set(obj, { $parent$: parent, $index$: index, $rootIndex$: -1 });
8752
9484
  };
8753
9485
  const $addRootPath$ = (obj) => {
8754
- const rootPath = rootsPathMap.get(obj);
9486
+ const rootPath = objectPathStringCache.get(obj);
8755
9487
  if (rootPath) {
8756
9488
  return rootPath;
8757
9489
  }
@@ -8770,7 +9502,7 @@ DomRefConstructor, symbolToChunkResolver, getProp, setProp, storeProxyMap, write
8770
9502
  current = seenObjsMap.get(current.$parent$);
8771
9503
  }
8772
9504
  const pathStr = path.length > 1 ? path.join(' ') : path.length ? path[0] : seen.$index$;
8773
- rootsPathMap.set(obj, pathStr);
9505
+ objectPathStringCache.set(obj, pathStr);
8774
9506
  return pathStr;
8775
9507
  };
8776
9508
  const $addRoot$ = (obj, parent = null) => {
@@ -8837,7 +9569,7 @@ DomRefConstructor, symbolToChunkResolver, getProp, setProp, storeProxyMap, write
8837
9569
  $storeProxyMap$: storeProxyMap,
8838
9570
  $getProp$: getProp,
8839
9571
  $setProp$: setProp,
8840
- $pathMap$: rootsPathMap,
9572
+ $objectPathStringCache$: objectPathStringCache,
8841
9573
  };
8842
9574
  };
8843
9575
  function $discoverRoots$(serializationContext, obj, parent, index) {
@@ -8861,7 +9593,8 @@ const discoverValuesForVNodeData = (vnodeData, callback) => {
8861
9593
  for (let i = 1; i < value.length; i += 2) {
8862
9594
  const keyValue = value[i - 1];
8863
9595
  const attrValue = value[i];
8864
- if (typeof attrValue === 'string' ||
9596
+ if (attrValue == null ||
9597
+ typeof attrValue === 'string' ||
8865
9598
  // skip empty props
8866
9599
  (keyValue === ELEMENT_PROPS &&
8867
9600
  Object.keys(attrValue).length === 0)) {
@@ -8886,6 +9619,14 @@ class PromiseResult {
8886
9619
  this.$qrl$ = $qrl$;
8887
9620
  }
8888
9621
  }
9622
+ class SerializationWeakRef {
9623
+ $obj$;
9624
+ constructor($obj$) {
9625
+ this.$obj$ = $obj$;
9626
+ }
9627
+ }
9628
+ /** @internal */
9629
+ const _serializationWeakRef = (obj) => new SerializationWeakRef(obj);
8889
9630
  /**
8890
9631
  * Format:
8891
9632
  *
@@ -8896,12 +9637,14 @@ class PromiseResult {
8896
9637
  * - Therefore root indexes need to be doubled to get the actual index.
8897
9638
  */
8898
9639
  async function serialize(serializationContext) {
8899
- const { $writer$, $isSsrNode$, $isDomRef$, $storeProxyMap$, $addRoot$, $pathMap$, $wasSeen$ } = serializationContext;
9640
+ const { $writer$, $isSsrNode$, $isDomRef$, $storeProxyMap$, $addRoot$, $objectPathStringCache$, $wasSeen$, } = serializationContext;
8900
9641
  let depth = 0;
9642
+ let rootIdx = 0;
8901
9643
  const forwardRefs = [];
8902
9644
  let forwardRefsId = 0;
8903
9645
  const promises = new Set();
8904
9646
  const preloadQrls = new Set();
9647
+ const s11nWeakRefs = new Map();
8905
9648
  let parent = null;
8906
9649
  const isRootObject = () => depth === 0;
8907
9650
  const outputArray = (value, writeFn) => {
@@ -8946,19 +9689,41 @@ async function serialize(serializationContext) {
8946
9689
  };
8947
9690
  const addPreloadQrl = (qrl) => {
8948
9691
  preloadQrls.add(qrl);
8949
- serializationContext.$addRoot$(qrl, null);
9692
+ serializationContext.$addRoot$(qrl);
8950
9693
  };
8951
- const outputRootRef = (value, rootDepth = 0) => {
9694
+ const outputAsRootRef = (value, rootDepth = 0) => {
8952
9695
  const seen = $wasSeen$(value);
8953
- const rootRefPath = $pathMap$.get(value);
9696
+ const rootRefPath = $objectPathStringCache$.get(value);
9697
+ // Objects are the only way to create circular dependencies.
9698
+ // So the first thing to to is to see if we have a circular dependency.
9699
+ // (NOTE: For root objects we need to serialize them regardless if we have seen
9700
+ // them before, otherwise the root object reference will point to itself.)
9701
+ // Also note that depth will be 1 for objects in root
8954
9702
  if (rootDepth === depth && seen && seen.$parent$ !== null && rootRefPath) {
8955
- output(0 /* TypeIds.RootRef */, rootRefPath);
9703
+ output(1 /* TypeIds.RootRef */, rootRefPath);
8956
9704
  return true;
8957
9705
  }
8958
9706
  else if (depth > rootDepth && seen && seen.$rootIndex$ !== -1) {
8959
- output(0 /* TypeIds.RootRef */, seen.$rootIndex$);
9707
+ // We have seen this object before, so we can serialize it as a reference.
9708
+ // Otherwise serialize as normal
9709
+ output(1 /* TypeIds.RootRef */, seen.$rootIndex$);
8960
9710
  return true;
8961
9711
  }
9712
+ else if (s11nWeakRefs.has(value)) {
9713
+ const forwardRefId = s11nWeakRefs.get(value);
9714
+ // We see the object again, we must now make it a root and update the forward ref
9715
+ if (rootDepth === depth) {
9716
+ // It's already a root
9717
+ forwardRefs[forwardRefId] = rootIdx;
9718
+ }
9719
+ else {
9720
+ // ref
9721
+ const rootRef = $addRoot$(value);
9722
+ output(1 /* TypeIds.RootRef */, rootRef);
9723
+ forwardRefs[forwardRefId] = rootRef;
9724
+ return true;
9725
+ }
9726
+ }
8962
9727
  return false;
8963
9728
  };
8964
9729
  const writeValue = (value) => {
@@ -8966,22 +9731,22 @@ async function serialize(serializationContext) {
8966
9731
  output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
8967
9732
  }
8968
9733
  else if (typeof value === 'bigint') {
8969
- output(12 /* TypeIds.BigInt */, value.toString());
9734
+ output(11 /* TypeIds.BigInt */, value.toString());
8970
9735
  }
8971
9736
  else if (typeof value === 'boolean') {
8972
9737
  output(3 /* TypeIds.Constant */, value ? 2 /* Constants.True */ : 3 /* Constants.False */);
8973
9738
  }
8974
9739
  else if (typeof value === 'function') {
8975
9740
  if (value === Slot) {
8976
- output(3 /* TypeIds.Constant */, 9 /* Constants.Slot */);
9741
+ output(3 /* TypeIds.Constant */, 10 /* Constants.Slot */);
8977
9742
  }
8978
9743
  else if (value === Fragment) {
8979
- output(3 /* TypeIds.Constant */, 10 /* Constants.Fragment */);
9744
+ output(3 /* TypeIds.Constant */, 11 /* Constants.Fragment */);
8980
9745
  }
8981
9746
  else if (isQrl(value)) {
8982
- if (!outputRootRef(value)) {
9747
+ if (!outputAsRootRef(value)) {
8983
9748
  const qrl = qrlToString(serializationContext, value);
8984
- const type = preloadQrls.has(value) ? 21 /* TypeIds.PreloadQRL */ : 20 /* TypeIds.QRL */;
9749
+ const type = preloadQrls.has(value) ? 20 /* TypeIds.PreloadQRL */ : 19 /* TypeIds.QRL */;
8985
9750
  if (isRootObject()) {
8986
9751
  output(type, qrl);
8987
9752
  }
@@ -8994,7 +9759,7 @@ async function serialize(serializationContext) {
8994
9759
  else if (isQwikComponent(value)) {
8995
9760
  const [qrl] = value[SERIALIZABLE_STATE];
8996
9761
  serializationContext.$renderSymbols$.add(qrl.$symbol$);
8997
- output(24 /* TypeIds.Component */, [qrl]);
9762
+ output(23 /* TypeIds.Component */, [qrl]);
8998
9763
  }
8999
9764
  else {
9000
9765
  throw qError(34 /* QError.serializeErrorCannotSerializeFunction */, [value.toString()]);
@@ -9002,22 +9767,22 @@ async function serialize(serializationContext) {
9002
9767
  }
9003
9768
  else if (typeof value === 'number') {
9004
9769
  if (Number.isNaN(value)) {
9005
- output(3 /* TypeIds.Constant */, 11 /* Constants.NaN */);
9770
+ output(3 /* TypeIds.Constant */, 12 /* Constants.NaN */);
9006
9771
  }
9007
9772
  else if (!Number.isFinite(value)) {
9008
- output(3 /* TypeIds.Constant */, value < 0 ? 13 /* Constants.NegativeInfinity */ : 12 /* Constants.PositiveInfinity */);
9773
+ output(3 /* TypeIds.Constant */, value < 0 ? 14 /* Constants.NegativeInfinity */ : 13 /* Constants.PositiveInfinity */);
9009
9774
  }
9010
9775
  else if (value === Number.MAX_SAFE_INTEGER) {
9011
- output(3 /* TypeIds.Constant */, 14 /* Constants.MaxSafeInt */);
9776
+ output(3 /* TypeIds.Constant */, 15 /* Constants.MaxSafeInt */);
9012
9777
  }
9013
9778
  else if (value === Number.MAX_SAFE_INTEGER - 1) {
9014
- output(3 /* TypeIds.Constant */, 15 /* Constants.AlmostMaxSafeInt */);
9779
+ output(3 /* TypeIds.Constant */, 16 /* Constants.AlmostMaxSafeInt */);
9015
9780
  }
9016
9781
  else if (value === Number.MIN_SAFE_INTEGER) {
9017
- output(3 /* TypeIds.Constant */, 16 /* Constants.MinSafeInt */);
9782
+ output(3 /* TypeIds.Constant */, 17 /* Constants.MinSafeInt */);
9018
9783
  }
9019
9784
  else {
9020
- output(4 /* TypeIds.Number */, value);
9785
+ output(0 /* TypeIds.Plain */, value);
9021
9786
  }
9022
9787
  }
9023
9788
  else if (typeof value === 'object') {
@@ -9044,8 +9809,8 @@ async function serialize(serializationContext) {
9044
9809
  output(3 /* TypeIds.Constant */, 4 /* Constants.EmptyString */);
9045
9810
  }
9046
9811
  else {
9047
- if (!outputRootRef(value)) {
9048
- output(5 /* TypeIds.String */, value);
9812
+ if (!outputAsRootRef(value)) {
9813
+ output(0 /* TypeIds.Plain */, value);
9049
9814
  }
9050
9815
  }
9051
9816
  }
@@ -9058,6 +9823,9 @@ async function serialize(serializationContext) {
9058
9823
  else if (value === STORE_ALL_PROPS) {
9059
9824
  output(3 /* TypeIds.Constant */, 8 /* Constants.STORE_ALL_PROPS */);
9060
9825
  }
9826
+ else if (value === _UNINITIALIZED) {
9827
+ output(3 /* TypeIds.Constant */, 9 /* Constants.UNINITIALIZED */);
9828
+ }
9061
9829
  else {
9062
9830
  throw qError(20 /* QError.serializeErrorUnknownType */, [typeof value]);
9063
9831
  }
@@ -9067,14 +9835,11 @@ async function serialize(serializationContext) {
9067
9835
  * The object writer outputs an array object (without type prefix) and this increases the depth
9068
9836
  * for the objects within (depth 1).
9069
9837
  */
9070
- // Objects are the only way to create circular dependencies.
9071
- // So the first thing to to is to see if we have a circular dependency.
9072
- // (NOTE: For root objects we need to serialize them regardless if we have seen
9073
- // them before, otherwise the root object reference will point to itself.)
9074
- // Also note that depth will be 1 for objects in root
9075
- if (outputRootRef(value, 1)) {
9838
+ if (outputAsRootRef(value, 1)) {
9076
9839
  return;
9077
9840
  }
9841
+ // handle custom serializers
9842
+ // add to the seen map
9078
9843
  if (isPropsProxy(value)) {
9079
9844
  const varProps = value[_VAR_PROPS];
9080
9845
  const constProps = value[_CONST_PROPS];
@@ -9083,10 +9848,10 @@ async function serialize(serializationContext) {
9083
9848
  : Object.keys(varProps).length
9084
9849
  ? [varProps]
9085
9850
  : 0;
9086
- output(34 /* TypeIds.PropsProxy */, out);
9851
+ output(32 /* TypeIds.PropsProxy */, out);
9087
9852
  }
9088
9853
  else if (value instanceof SubscriptionData) {
9089
- output(35 /* TypeIds.EffectData */, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
9854
+ output(33 /* TypeIds.SubscriptionData */, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
9090
9855
  }
9091
9856
  else if (isStore(value)) {
9092
9857
  if (isResource(value)) {
@@ -9094,38 +9859,38 @@ async function serialize(serializationContext) {
9094
9859
  serializationContext.$resources$.add(value);
9095
9860
  // TODO the effects include the resource return which has duplicate data
9096
9861
  const forwardRefId = $resolvePromise$(value.value, $addRoot$, (resolved, resolvedValue) => {
9097
- return new PromiseResult(23 /* TypeIds.Resource */, resolved, resolvedValue, getStoreHandler(value).$effects$);
9862
+ return new PromiseResult(22 /* TypeIds.Resource */, resolved, resolvedValue, getStoreHandler(value).$effects$);
9098
9863
  });
9099
- output(1 /* TypeIds.ForwardRef */, forwardRefId);
9864
+ output(2 /* TypeIds.ForwardRef */, forwardRefId);
9100
9865
  }
9101
9866
  else {
9102
9867
  const storeHandler = getStoreHandler(value);
9103
9868
  const storeTarget = getStoreTarget(value);
9104
9869
  const flags = storeHandler.$flags$;
9105
9870
  const effects = storeHandler.$effects$;
9871
+ // We need to retain the nested stores too, they won't be found from the target
9106
9872
  const innerStores = [];
9107
9873
  for (const prop in storeTarget) {
9108
9874
  const propValue = storeTarget[prop];
9109
- if ($storeProxyMap$.has(propValue)) {
9110
- const innerStore = $storeProxyMap$.get(propValue);
9875
+ const innerStore = $storeProxyMap$.get(propValue);
9876
+ if (innerStore) {
9111
9877
  innerStores.push(innerStore);
9112
- serializationContext.$addRoot$(innerStore);
9113
9878
  }
9114
9879
  }
9115
9880
  const out = [storeTarget, flags, effects, ...innerStores];
9116
9881
  while (out[out.length - 1] == null) {
9117
9882
  out.pop();
9118
9883
  }
9119
- output(Array.isArray(storeTarget) ? 31 /* TypeIds.StoreArray */ : 30 /* TypeIds.Store */, out);
9884
+ output(29 /* TypeIds.Store */, out);
9120
9885
  }
9121
9886
  }
9122
9887
  else if (isSerializerObj(value)) {
9123
9888
  const result = value[SerializerSymbol](value);
9124
9889
  if (isPromise(result)) {
9125
9890
  const forwardRef = $resolvePromise$(result, $addRoot$, (resolved, resolvedValue) => {
9126
- return new PromiseResult(29 /* TypeIds.SerializerSignal */, resolved, resolvedValue, null, null);
9891
+ return new PromiseResult(28 /* TypeIds.SerializerSignal */, resolved, resolvedValue, null, null);
9127
9892
  });
9128
- output(1 /* TypeIds.ForwardRef */, forwardRef);
9893
+ output(2 /* TypeIds.ForwardRef */, forwardRef);
9129
9894
  }
9130
9895
  else {
9131
9896
  depth--;
@@ -9135,7 +9900,7 @@ async function serialize(serializationContext) {
9135
9900
  }
9136
9901
  else if (isObjectLiteral(value)) {
9137
9902
  if (Array.isArray(value)) {
9138
- output(6 /* TypeIds.Array */, value);
9903
+ output(4 /* TypeIds.Array */, value);
9139
9904
  }
9140
9905
  else {
9141
9906
  const out = [];
@@ -9146,32 +9911,24 @@ async function serialize(serializationContext) {
9146
9911
  }
9147
9912
  }
9148
9913
  // TODO if !out.length, output 0 and restore as {}
9149
- output(15 /* TypeIds.Object */, out);
9914
+ output(5 /* TypeIds.Object */, out);
9150
9915
  }
9151
9916
  }
9152
9917
  else if ($isDomRef$(value)) {
9153
9918
  value.$ssrNode$.vnodeData[0] |= 16 /* VNodeDataFlag.SERIALIZE */;
9154
- output(11 /* TypeIds.RefVNode */, value.$ssrNode$.id);
9919
+ output(10 /* TypeIds.RefVNode */, value.$ssrNode$.id);
9155
9920
  }
9156
9921
  else if (value instanceof SignalImpl) {
9157
9922
  if (value instanceof SerializerSignalImpl) {
9158
9923
  addPreloadQrl(value.$computeQrl$);
9159
9924
  const forwardRefId = $resolvePromise$($getCustomSerializerPromise$(value, value.$untrackedValue$), $addRoot$, (resolved, resolvedValue) => {
9160
- return new PromiseResult(29 /* TypeIds.SerializerSignal */, resolved, resolvedValue, value.$effects$, value.$computeQrl$);
9925
+ return new PromiseResult(28 /* TypeIds.SerializerSignal */, resolved, resolvedValue, value.$effects$, value.$computeQrl$);
9161
9926
  });
9162
- output(1 /* TypeIds.ForwardRef */, forwardRefId);
9927
+ output(2 /* TypeIds.ForwardRef */, forwardRefId);
9163
9928
  return;
9164
9929
  }
9165
- /**
9166
- * Special case: when a Signal value is an SSRNode, it always needs to be a DOM ref instead.
9167
- * It can never be meant to become a vNode, because vNodes are internal only.
9168
- */
9169
- const v = value instanceof ComputedSignalImpl &&
9170
- (value.$flags$ & 1 /* SignalFlags.INVALID */ || fastSkipSerialize(value.$untrackedValue$))
9171
- ? NEEDS_COMPUTATION
9172
- : value.$untrackedValue$;
9173
9930
  if (value instanceof WrappedSignalImpl) {
9174
- output(26 /* TypeIds.WrappedSignal */, [
9931
+ output(25 /* TypeIds.WrappedSignal */, [
9175
9932
  ...serializeWrappingFn(serializationContext, value),
9176
9933
  filterEffectBackRefs(value[_EFFECT_BACK_REF]),
9177
9934
  value.$flags$,
@@ -9179,45 +9936,44 @@ async function serialize(serializationContext) {
9179
9936
  ...(value.$effects$ || []),
9180
9937
  ]);
9181
9938
  }
9182
- else if (value instanceof AsyncComputedSignalImpl) {
9183
- addPreloadQrl(value.$computeQrl$);
9184
- const out = [
9185
- value.$computeQrl$,
9186
- value.$effects$,
9187
- value.$loadingEffects$,
9188
- value.$errorEffects$,
9189
- value.$untrackedLoading$,
9190
- value.$untrackedError$,
9191
- ];
9192
- if (v !== NEEDS_COMPUTATION) {
9193
- out.push(v);
9194
- }
9195
- output(28 /* TypeIds.AsyncComputedSignal */, out);
9196
- }
9197
9939
  else if (value instanceof ComputedSignalImpl) {
9940
+ let v = value.$untrackedValue$;
9941
+ const shouldAlwaysSerialize = value.$flags$ & 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
9942
+ const shouldNeverSerialize = value.$flags$ & 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
9943
+ const isInvalid = value.$flags$ & 1 /* SignalFlags.INVALID */;
9944
+ const isSkippable = fastSkipSerialize(value.$untrackedValue$);
9945
+ if (shouldAlwaysSerialize) {
9946
+ v = value.$untrackedValue$;
9947
+ }
9948
+ else if (shouldNeverSerialize) {
9949
+ v = NEEDS_COMPUTATION;
9950
+ }
9951
+ else if (isInvalid || isSkippable) {
9952
+ v = NEEDS_COMPUTATION;
9953
+ }
9198
9954
  addPreloadQrl(value.$computeQrl$);
9199
- const out = [
9200
- value.$computeQrl$,
9201
- // TODO check if we can use domVRef for effects
9202
- value.$effects$,
9203
- ];
9955
+ const out = [value.$computeQrl$, value.$effects$];
9956
+ const isAsync = value instanceof AsyncComputedSignalImpl;
9957
+ if (isAsync) {
9958
+ out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedLoading$, value.$untrackedError$);
9959
+ }
9204
9960
  if (v !== NEEDS_COMPUTATION) {
9205
9961
  out.push(v);
9206
9962
  }
9207
- output(27 /* TypeIds.ComputedSignal */, out);
9963
+ output(isAsync ? 27 /* TypeIds.AsyncComputedSignal */ : 26 /* TypeIds.ComputedSignal */, out);
9208
9964
  }
9209
9965
  else {
9210
- output(25 /* TypeIds.Signal */, [v, ...(value.$effects$ || [])]);
9966
+ output(24 /* TypeIds.Signal */, [value.$untrackedValue$, ...(value.$effects$ || [])]);
9211
9967
  }
9212
9968
  }
9213
9969
  else if (value instanceof URL) {
9214
- output(7 /* TypeIds.URL */, value.href);
9970
+ output(6 /* TypeIds.URL */, value.href);
9215
9971
  }
9216
9972
  else if (value instanceof Date) {
9217
- output(8 /* TypeIds.Date */, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
9973
+ output(7 /* TypeIds.Date */, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
9218
9974
  }
9219
9975
  else if (value instanceof RegExp) {
9220
- output(9 /* TypeIds.Regex */, value.toString());
9976
+ output(8 /* TypeIds.Regex */, value.toString());
9221
9977
  }
9222
9978
  else if (value instanceof Error) {
9223
9979
  const out = [value.message];
@@ -9233,7 +9989,7 @@ async function serialize(serializationContext) {
9233
9989
  const rootIndex = $addRoot$(value);
9234
9990
  serializationContext.$setProp$(value, ELEMENT_ID, String(rootIndex));
9235
9991
  // we need to output before the vnode overwrites its values
9236
- output(10 /* TypeIds.VNode */, value.id);
9992
+ output(9 /* TypeIds.VNode */, value.id);
9237
9993
  const vNodeData = value.vnodeData;
9238
9994
  if (vNodeData) {
9239
9995
  discoverValuesForVNodeData(vNodeData, (vNodeDataValue) => $addRoot$(vNodeDataValue));
@@ -9269,23 +10025,23 @@ async function serialize(serializationContext) {
9269
10025
  array.push(key, value.name);
9270
10026
  }
9271
10027
  });
9272
- output(32 /* TypeIds.FormData */, array);
10028
+ output(30 /* TypeIds.FormData */, array);
9273
10029
  }
9274
10030
  else if (value instanceof URLSearchParams) {
9275
- output(13 /* TypeIds.URLSearchParams */, value.toString());
10031
+ output(12 /* TypeIds.URLSearchParams */, value.toString());
9276
10032
  }
9277
10033
  else if (value instanceof Set) {
9278
- output(17 /* TypeIds.Set */, [...value.values()]);
10034
+ output(16 /* TypeIds.Set */, [...value.values()]);
9279
10035
  }
9280
10036
  else if (value instanceof Map) {
9281
10037
  const combined = [];
9282
10038
  for (const [k, v] of value.entries()) {
9283
10039
  combined.push(k, v);
9284
10040
  }
9285
- output(18 /* TypeIds.Map */, combined);
10041
+ output(17 /* TypeIds.Map */, combined);
9286
10042
  }
9287
10043
  else if (isJSXNode(value)) {
9288
- output(33 /* TypeIds.JSXNode */, [
10044
+ output(31 /* TypeIds.JSXNode */, [
9289
10045
  value.type,
9290
10046
  value.varProps,
9291
10047
  value.constProps,
@@ -9306,21 +10062,21 @@ async function serialize(serializationContext) {
9306
10062
  while (out[out.length - 1] == null) {
9307
10063
  out.pop();
9308
10064
  }
9309
- output(22 /* TypeIds.Task */, out);
10065
+ output(21 /* TypeIds.Task */, out);
9310
10066
  }
9311
10067
  else if (isPromise(value)) {
9312
10068
  const forwardRefId = $resolvePromise$(value, $addRoot$, (resolved, resolvedValue) => {
9313
- return new PromiseResult(16 /* TypeIds.Promise */, resolved, resolvedValue);
10069
+ return new PromiseResult(15 /* TypeIds.Promise */, resolved, resolvedValue);
9314
10070
  });
9315
- output(1 /* TypeIds.ForwardRef */, forwardRefId);
10071
+ output(2 /* TypeIds.ForwardRef */, forwardRefId);
9316
10072
  }
9317
10073
  else if (value instanceof PromiseResult) {
9318
- if (value.$type$ === 23 /* TypeIds.Resource */) {
9319
- output(23 /* TypeIds.Resource */, [value.$resolved$, value.$value$, value.$effects$]);
10074
+ if (value.$type$ === 22 /* TypeIds.Resource */) {
10075
+ output(22 /* TypeIds.Resource */, [value.$resolved$, value.$value$, value.$effects$]);
9320
10076
  }
9321
- else if (value.$type$ === 29 /* TypeIds.SerializerSignal */) {
10077
+ else if (value.$type$ === 28 /* TypeIds.SerializerSignal */) {
9322
10078
  if (value.$qrl$) {
9323
- output(29 /* TypeIds.SerializerSignal */, [value.$qrl$, value.$effects$, value.$value$]);
10079
+ output(28 /* TypeIds.SerializerSignal */, [value.$qrl$, value.$effects$, value.$value$]);
9324
10080
  }
9325
10081
  else if (value.$resolved$) {
9326
10082
  writeValue(value.$value$);
@@ -9331,7 +10087,7 @@ async function serialize(serializationContext) {
9331
10087
  }
9332
10088
  }
9333
10089
  else {
9334
- output(16 /* TypeIds.Promise */, [value.$resolved$, value.$value$]);
10090
+ output(15 /* TypeIds.Promise */, [value.$resolved$, value.$value$]);
9335
10091
  }
9336
10092
  }
9337
10093
  else if (value instanceof Uint8Array) {
@@ -9340,7 +10096,13 @@ async function serialize(serializationContext) {
9340
10096
  buf += String.fromCharCode(c);
9341
10097
  }
9342
10098
  const out = btoa(buf).replace(/=+$/, '');
9343
- output(19 /* TypeIds.Uint8Array */, out);
10099
+ output(18 /* TypeIds.Uint8Array */, out);
10100
+ }
10101
+ else if (value instanceof SerializationWeakRef) {
10102
+ const forwardRefId = forwardRefsId++;
10103
+ s11nWeakRefs.set(value.$obj$, forwardRefId);
10104
+ forwardRefs[forwardRefId] = -1;
10105
+ output(2 /* TypeIds.ForwardRef */, forwardRefId);
9344
10106
  }
9345
10107
  else if (vnode_isVNode(value)) {
9346
10108
  output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
@@ -9365,21 +10127,20 @@ async function serialize(serializationContext) {
9365
10127
  }
9366
10128
  const outputRoots = async () => {
9367
10129
  $writer$.write('[');
9368
- let lastRootsLength = 0;
9369
10130
  let rootsLength = serializationContext.$roots$.length;
9370
- while (lastRootsLength < rootsLength || promises.size) {
9371
- if (lastRootsLength !== 0) {
10131
+ while (rootIdx < rootsLength || promises.size) {
10132
+ if (rootIdx !== 0) {
9372
10133
  $writer$.write(',');
9373
10134
  }
9374
10135
  let separator = false;
9375
- for (let i = lastRootsLength; i < rootsLength; i++) {
10136
+ for (; rootIdx < rootsLength; rootIdx++) {
9376
10137
  if (separator) {
9377
10138
  $writer$.write(',');
9378
10139
  }
9379
10140
  else {
9380
10141
  separator = true;
9381
10142
  }
9382
- writeValue(serializationContext.$roots$[i]);
10143
+ writeValue(serializationContext.$roots$[rootIdx]);
9383
10144
  }
9384
10145
  if (promises.size) {
9385
10146
  try {
@@ -9389,12 +10150,11 @@ async function serialize(serializationContext) {
9389
10150
  // ignore rejections, they will be serialized as rejected promises
9390
10151
  }
9391
10152
  }
9392
- lastRootsLength = rootsLength;
9393
10153
  rootsLength = serializationContext.$roots$.length;
9394
10154
  }
9395
10155
  if (forwardRefs.length) {
9396
10156
  $writer$.write(',');
9397
- $writer$.write(2 /* TypeIds.ForwardRefs */ + ',');
10157
+ $writer$.write(13 /* TypeIds.ForwardRefs */ + ',');
9398
10158
  outputArray(forwardRefs, (value) => {
9399
10159
  $writer$.write(String(value));
9400
10160
  });
@@ -9543,12 +10303,12 @@ function _deserialize(rawStateData, element) {
9543
10303
  return output;
9544
10304
  }
9545
10305
  function deserializeData(container, typeId, value) {
9546
- if (typeId === undefined) {
10306
+ if (typeId === 0 /* TypeIds.Plain */) {
9547
10307
  return value;
9548
10308
  }
9549
- let propValue = allocate(container, typeId, value);
9550
- if (typeId >= 14 /* TypeIds.Error */) {
9551
- propValue = inflate(container, propValue, typeId, value);
10309
+ const propValue = allocate(container, typeId, value);
10310
+ if (needsInflation(typeId)) {
10311
+ inflate(container, propValue, typeId, value);
9552
10312
  }
9553
10313
  return propValue;
9554
10314
  }
@@ -9571,7 +10331,7 @@ function _createDeserializeContainer(stateData, element) {
9571
10331
  $storeProxyMap$: new WeakMap(),
9572
10332
  element: null,
9573
10333
  $forwardRefs$: null,
9574
- $initialQRLsIndexes$: null,
10334
+ $initialQRLs$: null,
9575
10335
  $scheduler$: null,
9576
10336
  };
9577
10337
  preprocessState(stateData, container);
@@ -9631,18 +10391,18 @@ function _createDeserializeContainer(stateData, element) {
9631
10391
  */
9632
10392
  function preprocessState(data, container) {
9633
10393
  const isRootDeepRef = (type, value) => {
9634
- return type === 0 /* TypeIds.RootRef */ && typeof value === 'string';
10394
+ return type === 1 /* TypeIds.RootRef */ && typeof value === 'string';
9635
10395
  };
9636
10396
  const isForwardRefsMap = (type) => {
9637
- return type === 2 /* TypeIds.ForwardRefs */;
10397
+ return type === 13 /* TypeIds.ForwardRefs */;
9638
10398
  };
9639
10399
  const isPreloadQrlType = (type) => {
9640
- return type === 21 /* TypeIds.PreloadQRL */;
10400
+ return type === 20 /* TypeIds.PreloadQRL */;
9641
10401
  };
9642
10402
  const processRootRef = (index) => {
9643
10403
  const rootRefPath = data[index + 1].split(' ');
9644
10404
  let object = data;
9645
- let objectType = 0 /* TypeIds.RootRef */;
10405
+ let objectType = 1 /* TypeIds.RootRef */;
9646
10406
  let typeIndex = 0;
9647
10407
  let valueIndex = 0;
9648
10408
  let parent = null;
@@ -9652,7 +10412,7 @@ function preprocessState(data, container) {
9652
10412
  valueIndex = typeIndex + 1;
9653
10413
  objectType = object[typeIndex];
9654
10414
  object = object[valueIndex];
9655
- if (objectType === 0 /* TypeIds.RootRef */) {
10415
+ if (objectType === 1 /* TypeIds.RootRef */) {
9656
10416
  const rootRef = object;
9657
10417
  const rootRefTypeIndex = rootRef * 2;
9658
10418
  objectType = data[rootRefTypeIndex];
@@ -9660,7 +10420,7 @@ function preprocessState(data, container) {
9660
10420
  }
9661
10421
  }
9662
10422
  if (parent) {
9663
- parent[typeIndex] = 0 /* TypeIds.RootRef */;
10423
+ parent[typeIndex] = 1 /* TypeIds.RootRef */;
9664
10424
  parent[valueIndex] = index / 2;
9665
10425
  }
9666
10426
  data[index] = objectType;
@@ -9674,8 +10434,8 @@ function preprocessState(data, container) {
9674
10434
  container.$forwardRefs$ = data[i + 1];
9675
10435
  }
9676
10436
  else if (isPreloadQrlType(data[i])) {
9677
- container.$initialQRLsIndexes$ ||= [];
9678
- container.$initialQRLsIndexes$.push(i / 2);
10437
+ const qrl = data[i + 1];
10438
+ (container.$initialQRLs$ ||= []).push(qrl);
9679
10439
  }
9680
10440
  }
9681
10441
  }
@@ -9695,7 +10455,7 @@ function shouldTrackObj(obj) {
9695
10455
  return (
9696
10456
  // THINK: Not sure if we need to keep track of functions (QRLs) Let's skip them for now.
9697
10457
  // and see if we have a test case which requires them.
9698
- (typeof obj === 'object' && obj !== null) ||
10458
+ isObject(obj) ||
9699
10459
  /**
9700
10460
  * We track all strings greater than 1 character, because those take at least 6 bytes to encode
9701
10461
  * and even with 999 root objects it saves one byte per reference. Tracking more objects makes
@@ -9723,9 +10483,7 @@ function isResource(value) {
9723
10483
  return '__brand' in value && value.__brand === 'resource';
9724
10484
  }
9725
10485
  const frameworkType = (obj) => {
9726
- return ((typeof obj === 'object' &&
9727
- obj !== null &&
9728
- (obj instanceof SignalImpl || obj instanceof Task || isJSXNode(obj))) ||
10486
+ return ((isObject(obj) && (obj instanceof SignalImpl || obj instanceof Task || isJSXNode(obj))) ||
9729
10487
  isQrl(obj));
9730
10488
  };
9731
10489
  const canSerialize = (value, seen = new WeakSet()) => {
@@ -9811,17 +10569,19 @@ const canSerialize = (value, seen = new WeakSet()) => {
9811
10569
  return true;
9812
10570
  }
9813
10571
  }
10572
+ else if (value === _UNINITIALIZED) {
10573
+ return true;
10574
+ }
9814
10575
  return false;
9815
10576
  };
9816
10577
  const QRL_RUNTIME_CHUNK = 'mock-chunk';
9817
10578
  const _typeIdNames = [
10579
+ 'Plain',
9818
10580
  'RootRef',
9819
10581
  'ForwardRef',
9820
- 'ForwardRefs',
9821
10582
  'Constant',
9822
- 'Number',
9823
- 'String',
9824
10583
  'Array',
10584
+ 'Object',
9825
10585
  'URL',
9826
10586
  'Date',
9827
10587
  'Regex',
@@ -9829,8 +10589,8 @@ const _typeIdNames = [
9829
10589
  'RefVNode',
9830
10590
  'BigInt',
9831
10591
  'URLSearchParams',
10592
+ 'ForwardRefs',
9832
10593
  'Error',
9833
- 'Object',
9834
10594
  'Promise',
9835
10595
  'Set',
9836
10596
  'Map',
@@ -9846,16 +10606,15 @@ const _typeIdNames = [
9846
10606
  'AsyncComputedSignal',
9847
10607
  'SerializerSignal',
9848
10608
  'Store',
9849
- 'StoreArray',
9850
10609
  'FormData',
9851
10610
  'JSXNode',
9852
10611
  'PropsProxy',
9853
- 'EffectData',
10612
+ 'SubscriptionData',
9854
10613
  ];
9855
10614
  const circularProofJson = (obj, indent) => {
9856
10615
  const seen = new WeakSet();
9857
- return JSON.stringify(obj, (key, value) => {
9858
- if (typeof value === 'object' && value !== null) {
10616
+ return JSON.stringify(obj, (_, value) => {
10617
+ if (isObject(value)) {
9859
10618
  if (seen.has(value)) {
9860
10619
  return `[Circular ${value.constructor.name}]`;
9861
10620
  }
@@ -9890,9 +10649,15 @@ const dumpState = (state, color = false, prefix = '', limit = 20) => {
9890
10649
  }
9891
10650
  const key = state[i];
9892
10651
  let value = state[++i];
9893
- if (key === undefined) {
9894
- hasRaw = true;
9895
- out.push(`${RED}[raw${typeof value === 'object' && value ? ` ${value.constructor.name}` : ''}]${RESET} ${printRaw(value, `${prefix} `)}`);
10652
+ if (key === 0 /* TypeIds.Plain */) {
10653
+ const isRaw = typeof value !== 'number' && typeof value !== 'string';
10654
+ if (isRaw) {
10655
+ hasRaw = true;
10656
+ }
10657
+ const type = isRaw
10658
+ ? `[raw${isObject(value) ? ` ${value.constructor.name}` : ''}]`
10659
+ : typeIdToName(key);
10660
+ out.push(`${RED}${type}${RESET} ${printRaw(value, `${prefix} `)}`);
9896
10661
  }
9897
10662
  else {
9898
10663
  if (key === 3 /* TypeIds.Constant */) {
@@ -9904,7 +10669,7 @@ const dumpState = (state, color = false, prefix = '', limit = 20) => {
9904
10669
  value = value.slice(0, 120) + '"...';
9905
10670
  }
9906
10671
  }
9907
- else if (key === 2 /* TypeIds.ForwardRefs */) {
10672
+ else if (key === 13 /* TypeIds.ForwardRefs */) {
9908
10673
  value = '[' + `\n${prefix} ${value.join(`\n${prefix} `)}\n${prefix}]`;
9909
10674
  }
9910
10675
  else if (Array.isArray(value)) {
@@ -10006,7 +10771,6 @@ const _verifySerializable = (value, seen, ctx, preMessage) => {
10006
10771
  return value;
10007
10772
  };
10008
10773
  const noSerializeSet = /*#__PURE__*/ new WeakSet();
10009
- const weakSerializeSet = /*#__PURE__*/ new WeakSet();
10010
10774
  const shouldSerialize = (obj) => {
10011
10775
  if (isObject(obj) || isFunction(obj)) {
10012
10776
  return !noSerializeSet.has(obj);
@@ -10015,7 +10779,7 @@ const shouldSerialize = (obj) => {
10015
10779
  };
10016
10780
  const fastSkipSerialize = (obj) => {
10017
10781
  return (obj &&
10018
- (typeof obj === 'object' || typeof obj === 'function') &&
10782
+ (isObject(obj) || typeof obj === 'function') &&
10019
10783
  (NoSerializeSymbol in obj || noSerializeSet.has(obj)));
10020
10784
  };
10021
10785
  // <docs markdown="../../readme.md#noSerialize">
@@ -10040,16 +10804,11 @@ const fastSkipSerialize = (obj) => {
10040
10804
  // </docs>
10041
10805
  const noSerialize = (input) => {
10042
10806
  // only add supported values to the noSerializeSet, prevent console errors
10043
- if ((typeof input === 'object' && input !== null) || typeof input === 'function') {
10807
+ if ((isObject(input) && input !== null) || typeof input === 'function') {
10044
10808
  noSerializeSet.add(input);
10045
10809
  }
10046
10810
  return input;
10047
10811
  };
10048
- /** @internal */
10049
- const _weakSerialize = (input) => {
10050
- weakSerializeSet.add(input);
10051
- return input;
10052
- };
10053
10812
  /**
10054
10813
  * If an object has this property, it will not be serialized. Use this on prototypes to avoid having
10055
10814
  * to call `noSerialize()` on every object.
@@ -10076,6 +10835,7 @@ const NoSerializeSymbol = Symbol('noSerialize');
10076
10835
  const SerializerSymbol = Symbol('serialize');
10077
10836
 
10078
10837
  // keep these imports above the rest to prevent circular dep issues
10838
+ const resolvedSymbol = Symbol('resolved');
10079
10839
  const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10080
10840
  if (qDev && qSerialize) {
10081
10841
  if (captureRef) {
@@ -10128,9 +10888,6 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10128
10888
  };
10129
10889
  return bound;
10130
10890
  }
10131
- const resolveLazy = (containerEl) => {
10132
- return symbolRef !== null ? symbolRef : resolve(containerEl);
10133
- };
10134
10891
  // Wrap functions to provide their lexical scope
10135
10892
  const wrapFn = (fn) => {
10136
10893
  if (typeof fn !== 'function' || (!capture?.length && !captureRef?.length)) {
@@ -10159,45 +10916,58 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10159
10916
  return invoke.call(this, context, fn, ...args);
10160
10917
  };
10161
10918
  };
10162
- const resolve = async (containerEl) => {
10163
- if (symbolRef !== null) {
10164
- // Resolving (Promise) or already resolved (value)
10919
+ // Retrieve memoized result from symbolFn
10920
+ if (symbolFn && resolvedSymbol in symbolFn) {
10921
+ symbolRef = symbolFn[resolvedSymbol];
10922
+ }
10923
+ const resolve = symbolRef
10924
+ ? async () => symbolRef
10925
+ : async (containerEl) => {
10926
+ if (symbolRef !== null) {
10927
+ // Resolving (Promise) or already resolved (value)
10928
+ return symbolRef;
10929
+ }
10930
+ if (containerEl) {
10931
+ setContainer(containerEl);
10932
+ }
10933
+ if (chunk === '') {
10934
+ // Sync QRL
10935
+ assertDefined(_containerEl, 'Sync QRL must have container element');
10936
+ const hash = _containerEl.getAttribute(QInstanceAttr);
10937
+ const doc = _containerEl.ownerDocument;
10938
+ const qFuncs = getQFuncs(doc, hash);
10939
+ // No need to wrap, syncQRLs can't have captured scope
10940
+ return (qrl.resolved = symbolRef = qFuncs[Number(symbol)]);
10941
+ }
10942
+ if (isBrowser && chunk) {
10943
+ /** We run the QRL, so now the probability of the chunk is 100% */
10944
+ p(chunk, 1);
10945
+ }
10946
+ const start = now();
10947
+ const ctx = tryGetInvokeContext();
10948
+ if (symbolFn !== null) {
10949
+ symbolRef = symbolFn().then((module) => {
10950
+ const resolved = wrapFn((symbolRef = module[symbol]));
10951
+ // We memoize the result on the symbolFn
10952
+ symbolFn[resolvedSymbol] = resolved;
10953
+ qrl.resolved = resolved;
10954
+ return resolved;
10955
+ });
10956
+ }
10957
+ else {
10958
+ // TODO cache the imported symbol but watch out for dev mode
10959
+ const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
10960
+ symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
10961
+ }
10962
+ if (isPromise(symbolRef)) {
10963
+ symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
10964
+ console.error(`qrl ${symbol} failed to load`, err);
10965
+ // We shouldn't cache rejections, we can try again later
10966
+ symbolRef = null;
10967
+ });
10968
+ }
10165
10969
  return symbolRef;
10166
- }
10167
- if (containerEl) {
10168
- setContainer(containerEl);
10169
- }
10170
- if (chunk === '') {
10171
- // Sync QRL
10172
- assertDefined(_containerEl, 'Sync QRL must have container element');
10173
- const hash = _containerEl.getAttribute(QInstanceAttr);
10174
- const doc = _containerEl.ownerDocument;
10175
- const qFuncs = getQFuncs(doc, hash);
10176
- // No need to wrap, syncQRLs can't have captured scope
10177
- return (qrl.resolved = symbolRef = qFuncs[Number(symbol)]);
10178
- }
10179
- if (isBrowser && chunk) {
10180
- /** We run the QRL, so now the probability of the chunk is 100% */
10181
- p(chunk, 1);
10182
- }
10183
- const start = now();
10184
- const ctx = tryGetInvokeContext();
10185
- if (symbolFn !== null) {
10186
- symbolRef = symbolFn().then((module) => (qrl.resolved = wrapFn((symbolRef = module[symbol]))));
10187
- }
10188
- else {
10189
- const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
10190
- symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
10191
- }
10192
- if (typeof symbolRef === 'object' && isPromise(symbolRef)) {
10193
- symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
10194
- console.error(`qrl ${symbol} failed to load`, err);
10195
- // We shouldn't cache rejections, we can try again later
10196
- symbolRef = null;
10197
- });
10198
- }
10199
- return symbolRef;
10200
- };
10970
+ };
10201
10971
  const createOrReuseInvocationContext = (invoke) => {
10202
10972
  if (invoke == null) {
10203
10973
  return newInvokeContext();
@@ -10215,7 +10985,6 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10215
10985
  getHash: () => hash,
10216
10986
  getCaptured: () => captureRef,
10217
10987
  resolve,
10218
- $resolveLazy$: resolveLazy,
10219
10988
  $setContainer$: setContainer,
10220
10989
  $chunk$: chunk,
10221
10990
  $symbol$: symbol,
@@ -10516,7 +11285,7 @@ const render = async (parent, jsxNode, opts = {}) => {
10516
11285
  container.$serverData$ = opts.serverData || {};
10517
11286
  const host = container.rootVNode;
10518
11287
  container.$scheduler$(4 /* ChoreType.NODE_DIFF */, host, host, jsxNode);
10519
- await container.$scheduler$(255 /* ChoreType.WAIT_FOR_ALL */);
11288
+ await container.$scheduler$(255 /* ChoreType.WAIT_FOR_QUEUE */).$returnValue$;
10520
11289
  return {
10521
11290
  cleanup: () => {
10522
11291
  cleanup(container, container.rootVNode);
@@ -11056,13 +11825,13 @@ const _useStyles = (styleQrl, transform, scoped) => {
11056
11825
  const styleId = styleKey(styleQrl, i);
11057
11826
  const host = iCtx.$hostElement$;
11058
11827
  set(styleId);
11059
- const value = styleQrl.$resolveLazy$(iCtx.$element$);
11060
- if (isPromise(value)) {
11061
- value.then((val) => iCtx.$container$.$appendStyle$(transform(val, styleId), styleId, host, scoped));
11062
- throw value;
11828
+ if (styleQrl.resolved) {
11829
+ iCtx.$container$.$appendStyle$(transform(styleQrl.resolved, styleId), styleId, host, scoped);
11063
11830
  }
11064
11831
  else {
11065
- iCtx.$container$.$appendStyle$(transform(value, styleId), styleId, host, scoped);
11832
+ throw styleQrl
11833
+ .resolve()
11834
+ .then((val) => iCtx.$container$.$appendStyle$(transform(val, styleId), styleId, host, scoped));
11066
11835
  }
11067
11836
  return styleId;
11068
11837
  };
@@ -11243,13 +12012,13 @@ const useConstant = (value) => {
11243
12012
  return set(value);
11244
12013
  };
11245
12014
 
11246
- const useComputedCommon = (qrl, Class) => {
12015
+ const useComputedCommon = (qrl, createFn, options) => {
11247
12016
  const { val, set } = useSequentialScope();
11248
12017
  if (val) {
11249
12018
  return val;
11250
12019
  }
11251
12020
  assertQrl(qrl);
11252
- const signal = new Class(null, qrl);
12021
+ const signal = createFn(qrl, options);
11253
12022
  set(signal);
11254
12023
  // Note that we first save the signal
11255
12024
  // and then we throw to load the qrl
@@ -11258,8 +12027,8 @@ const useComputedCommon = (qrl, Class) => {
11258
12027
  return signal;
11259
12028
  };
11260
12029
  /** @internal */
11261
- const useComputedQrl = (qrl) => {
11262
- return useComputedCommon(qrl, ComputedSignalImpl);
12030
+ const useComputedQrl = (qrl, options) => {
12031
+ return useComputedCommon(qrl, createComputedSignal, options);
11263
12032
  };
11264
12033
  /**
11265
12034
  * Creates a computed signal which is calculated from the given function. A computed signal is a
@@ -11274,7 +12043,7 @@ const useComputedQrl = (qrl) => {
11274
12043
  const useComputed$ = implicit$FirstArg(useComputedQrl);
11275
12044
 
11276
12045
  /** @internal */
11277
- const useSerializerQrl = (qrl) => useComputedCommon(qrl, SerializerSignalImpl);
12046
+ const useSerializerQrl = (qrl) => useComputedCommon(qrl, createSerializerSignal);
11278
12047
  /**
11279
12048
  * Creates a signal which holds a custom serializable value. It requires that the value implements
11280
12049
  * the `CustomSerializable` type, which means having a function under the `[SerializeSymbol]`
@@ -11353,8 +12122,8 @@ const useVisibleTaskQrl = (qrl, opts) => {
11353
12122
  set(task);
11354
12123
  useRunTask(task, eagerness);
11355
12124
  if (!isServerPlatform()) {
11356
- qrl.$resolveLazy$(iCtx.$element$);
11357
- iCtx.$container$.$scheduler$(32 /* ChoreType.VISIBLE */, task);
12125
+ qrl.resolve(iCtx.$element$);
12126
+ iCtx.$container$.$scheduler$(16 /* ChoreType.VISIBLE */, task);
11358
12127
  }
11359
12128
  };
11360
12129
  const useRunTask = (task, eagerness) => {
@@ -11529,8 +12298,8 @@ const useTask$ = /*#__PURE__*/ implicit$FirstArg(useTaskQrl);
11529
12298
  const useVisibleTask$ = /*#__PURE__*/ implicit$FirstArg(useVisibleTaskQrl);
11530
12299
 
11531
12300
  /** @internal */
11532
- const useAsyncComputedQrl = (qrl) => {
11533
- return useComputedCommon(qrl, AsyncComputedSignalImpl);
12301
+ const useAsyncComputedQrl = (qrl, options) => {
12302
+ return useComputedCommon(qrl, createAsyncComputedSignal, options);
11534
12303
  };
11535
12304
  /**
11536
12305
  * Creates a computed signal which is calculated from the given function. A computed signal is a
@@ -11583,7 +12352,7 @@ const PrefetchServiceWorker = (opts) => {
11583
12352
  // the file 'qwik-prefetch-service-worker.js' is not located in /build/
11584
12353
  resolvedOpts.path = baseUrl + resolvedOpts.path;
11585
12354
  }
11586
- let code = PREFETCH_CODE.replace("'_URL_'", JSON.stringify(resolvedOpts.path));
12355
+ let code = PREFETCH_CODE.replace('"_URL_"', JSON.stringify(resolvedOpts.path.split('/').pop()));
11587
12356
  if (!isDev) {
11588
12357
  // consecutive spaces are indentation
11589
12358
  code = code.replaceAll(/\s\s+/gm, '');
@@ -11613,6 +12382,17 @@ const PREFETCH_CODE = /*#__PURE__*/ ((c // Service worker container
11613
12382
  });
11614
12383
  });
11615
12384
  }
12385
+ if ('caches' in window) {
12386
+ caches
12387
+ .keys()
12388
+ .then((names) => {
12389
+ const cacheName = names.find((name) => name.startsWith('QwikBundles'));
12390
+ if (cacheName) {
12391
+ caches.delete(cacheName).catch(console.error);
12392
+ }
12393
+ })
12394
+ .catch(console.error);
12395
+ }
11616
12396
  }).toString();
11617
12397
  /**
11618
12398
  * @deprecated This is no longer needed as the preloading happens automatically in qrl-class. You
@@ -11621,5 +12401,15 @@ const PREFETCH_CODE = /*#__PURE__*/ ((c // Service worker container
11621
12401
  */
11622
12402
  const PrefetchGraph = (_opts = {}) => null;
11623
12403
 
11624
- export { $, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, EMPTY_ARRAY as _EMPTY_ARRAY, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, _VAR_PROPS, _deserialize, dumpState as _dumpState, _fnSignal, _getContextElement, _getContextEvent, getDomContainer as _getDomContainer, _getQContainerElement, isJSXNode as _isJSXNode, isStringifiable as _isStringifiable, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, _regSymbol, _restProps, queueQRL as _run, _serialize, scheduleTask as _task, verifySerializable as _verifySerializable, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _weakSerialize, _wrapProp, _wrapSignal, _wrapStore, component$, componentQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsx as jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useAsyncComputed$, useAsyncComputedQrl, 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 };
12404
+ //////////////////////////////////////////////////////////////////////////////////////////
12405
+ // Protect against duplicate imports
12406
+ //////////////////////////////////////////////////////////////////////////////////////////
12407
+ if (globalThis.__qwik) {
12408
+ console.error(`==============================================\n` +
12409
+ `Qwik version ${globalThis.__qwik} already imported while importing ${version}. Verify external vs bundled imports etc. This can lead to issues due to duplicated shared structures.\n` +
12410
+ `==============================================\n`);
12411
+ }
12412
+ globalThis.__qwik = version;
12413
+
12414
+ export { $, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, EMPTY_ARRAY as _EMPTY_ARRAY, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, _UNINITIALIZED, _VAR_PROPS, _deserialize, dumpState as _dumpState, _fnSignal, _getConstProps, _getContextContainer, _getContextElement, _getContextEvent, getDomContainer as _getDomContainer, _getQContainerElement, _getVarProps, _hasStoreEffects, 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, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, _regSymbol, _resolveContextWithoutSequentialScope, _restProps, _run, _serializationWeakRef, _serialize, scheduleTask as _task, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttr as _vnode_getAttr, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getFirstChild as _vnode_getFirstChild, vnode_getNextSibling as _vnode_getNextSibling, vnode_getPropStartIndex as _vnode_getPropStartIndex, vnode_getProps as _vnode_getProps, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsyncComputed$, createAsyncComputedSignal as createAsyncComputedQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsx as jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useAsyncComputed$, useAsyncComputedQrl, 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 };
11625
12415
  //# sourceMappingURL=core.mjs.map