@qwik.dev/core 2.0.0-beta.2 → 2.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * @qwik.dev/core 2.0.0-beta.2-dev+3ddc6c7
3
+ * @qwik.dev/core 2.0.0-beta.4-dev+9849dcf
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
@@ -74,6 +74,24 @@
74
74
  return err;
75
75
  };
76
76
 
77
+ /** @private */
78
+ const isSerializableObject = (v) => {
79
+ const proto = Object.getPrototypeOf(v);
80
+ return proto === Object.prototype || proto === Array.prototype || proto === null;
81
+ };
82
+ const isObject = (v) => {
83
+ return typeof v === 'object' && v !== null;
84
+ };
85
+ const isArray = (v) => {
86
+ return Array.isArray(v);
87
+ };
88
+ const isString = (v) => {
89
+ return typeof v === 'string';
90
+ };
91
+ const isFunction = (v) => {
92
+ return typeof v === 'function';
93
+ };
94
+
77
95
  const codeToText = (code, ...parts) => {
78
96
  if (qDev) {
79
97
  // Keep one error, one line to make it easier to search for the error message.
@@ -118,7 +136,7 @@
118
136
  if (parts.length) {
119
137
  text = text.replaceAll(/{{(\d+)}}/g, (_, index) => {
120
138
  let v = parts[index];
121
- if (v && typeof v === 'object' && v.constructor === Object) {
139
+ if (v && isObject(v) && v.constructor === Object) {
122
140
  v = JSON.stringify(v).slice(0, 50);
123
141
  }
124
142
  return v;
@@ -379,7 +397,7 @@
379
397
  setTimeout(resolve, timeout);
380
398
  });
381
399
  };
382
- // Retries a function that throws a promise.
400
+ /** Retries a function that throws a promise. */
383
401
  function retryOnPromise(fn, retryCount = 0) {
384
402
  const retryOrThrow = (e) => {
385
403
  if (isPromise(e) && retryCount < MAX_RETRY_ON_PROMISE_COUNT) {
@@ -404,24 +422,6 @@
404
422
  }
405
423
  }
406
424
 
407
- /** @private */
408
- const isSerializableObject = (v) => {
409
- const proto = Object.getPrototypeOf(v);
410
- return proto === Object.prototype || proto === Array.prototype || proto === null;
411
- };
412
- const isObject = (v) => {
413
- return !!v && typeof v === 'object';
414
- };
415
- const isArray = (v) => {
416
- return Array.isArray(v);
417
- };
418
- const isString = (v) => {
419
- return typeof v === 'string';
420
- };
421
- const isFunction = (v) => {
422
- return typeof v === 'function';
423
- };
424
-
425
425
  const ASSERT_DISCLAIMER = 'Internal assert, this is likely caused by a bug in Qwik: ';
426
426
  function assertDefined(value, text, ...parts) {
427
427
  if (qDev) {
@@ -641,11 +641,9 @@
641
641
  this.$funcStr$ = fnStr;
642
642
  this.$flags$ = flags;
643
643
  }
644
- $invalidate$() {
644
+ invalidate() {
645
645
  this.$flags$ |= 1 /* SignalFlags.INVALID */;
646
646
  this.$forceRunEffects$ = false;
647
- // We should only call subscribers if the calculation actually changed.
648
- // Therefore, we need to calculate the value now.
649
647
  this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
650
648
  }
651
649
  /**
@@ -653,9 +651,8 @@
653
651
  * remained the same object.
654
652
  */
655
653
  force() {
656
- this.$flags$ |= 1 /* SignalFlags.INVALID */;
657
- this.$forceRunEffects$ = false;
658
- triggerEffects(this.$container$, this, this.$effects$);
654
+ this.$forceRunEffects$ = true;
655
+ this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
659
656
  }
660
657
  get untrackedValue() {
661
658
  const didChange = this.$computeIfNeeded$();
@@ -713,7 +710,6 @@
713
710
  }
714
711
 
715
712
  let _context;
716
- /** @public */
717
713
  const tryGetInvokeContext = () => {
718
714
  if (!_context) {
719
715
  const context = typeof document !== 'undefined' && document && document.__q_context__;
@@ -734,6 +730,7 @@
734
730
  }
735
731
  return ctx;
736
732
  };
733
+ /** @internal */
737
734
  const useInvokeContext = () => {
738
735
  const ctx = tryGetInvokeContext();
739
736
  if (!ctx || ctx.$event$ !== RenderEvent) {
@@ -779,7 +776,7 @@
779
776
  // TODO how about putting url and locale (and event/custom?) in to a "static" object
780
777
  const newInvokeContext = (locale, hostElement, element, event, url) => {
781
778
  // ServerRequestEvent has .locale, but it's not always defined.
782
- const $locale$ = locale || (typeof event === 'object' && event && 'locale' in event ? event.locale : undefined);
779
+ const $locale$ = locale || (event && isObject(event) && 'locale' in event ? event.locale : undefined);
783
780
  const ctx = {
784
781
  $url$: url,
785
782
  $i$: 0,
@@ -859,6 +856,13 @@
859
856
  }
860
857
  };
861
858
  /** @internal */
859
+ const _getContextContainer = () => {
860
+ const iCtx = tryGetInvokeContext();
861
+ if (iCtx) {
862
+ return iCtx.$container$;
863
+ }
864
+ };
865
+ /** @internal */
862
866
  const _jsxBranch = (input) => {
863
867
  return input;
864
868
  };
@@ -1232,7 +1236,7 @@
1232
1236
  *
1233
1237
  * @public
1234
1238
  */
1235
- const version = "2.0.0-beta.2-dev+3ddc6c7";
1239
+ const version = "2.0.0-beta.4-dev+9849dcf";
1236
1240
 
1237
1241
  /** @internal */
1238
1242
  const EMPTY_ARRAY = [];
@@ -1397,6 +1401,8 @@
1397
1401
  const _VAR_PROPS = Symbol('VAR');
1398
1402
  /** @internal @deprecated v1 compat */
1399
1403
  const _IMMUTABLE = Symbol('IMMUTABLE');
1404
+ /** @internal */
1405
+ const _UNINITIALIZED = Symbol('UNINITIALIZED');
1400
1406
 
1401
1407
  // <docs markdown="../../readme.md#implicit$FirstArg">
1402
1408
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
@@ -1466,14 +1472,15 @@
1466
1472
  constructor(container, fn,
1467
1473
  // We need a separate flag to know when the computation needs running because
1468
1474
  // we need the old value to know if effects need running after computation
1469
- flags = 1 /* SignalFlags.INVALID */) {
1475
+ flags = 1 /* SignalFlags.INVALID */ |
1476
+ 16 /* ComputedSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */) {
1470
1477
  // The value is used for comparison when signals trigger, which can only happen
1471
1478
  // when it was calculated before. Therefore we can pass whatever we like.
1472
1479
  super(container, NEEDS_COMPUTATION);
1473
1480
  this.$computeQrl$ = fn;
1474
1481
  this.$flags$ = flags;
1475
1482
  }
1476
- $invalidate$() {
1483
+ invalidate() {
1477
1484
  this.$flags$ |= 1 /* SignalFlags.INVALID */;
1478
1485
  this.$forceRunEffects$ = false;
1479
1486
  this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
@@ -1543,7 +1550,7 @@
1543
1550
  */
1544
1551
  class SerializerSignalImpl extends ComputedSignalImpl {
1545
1552
  constructor(container, argQrl) {
1546
- super(container, argQrl);
1553
+ super(container, argQrl, 1 /* SignalFlags.INVALID */ | 16 /* ComputedSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */);
1547
1554
  }
1548
1555
  $didInitialize$ = false;
1549
1556
  $computeIfNeeded$() {
@@ -1559,7 +1566,7 @@
1559
1566
  const update = arg.update;
1560
1567
  const currentValue = this.$untrackedValue$ === NEEDS_COMPUTATION ? initial : this.$untrackedValue$;
1561
1568
  const untrackedValue = trackSignal(() => this.$didInitialize$
1562
- ? update?.(currentValue)
1569
+ ? update?.(currentValue) || currentValue
1563
1570
  : deserialize(currentValue), this, "." /* EffectProperty.VNODE */, this.$container$);
1564
1571
  const didChange = (this.$didInitialize$ && untrackedValue !== 'undefined') ||
1565
1572
  untrackedValue !== this.$untrackedValue$;
@@ -1648,8 +1655,7 @@
1648
1655
  }
1649
1656
  const flags = this.$flags$;
1650
1657
  if (flags & 1 /* StoreFlags.RECURSIVE */ &&
1651
- typeof value === 'object' &&
1652
- value !== null &&
1658
+ isObject(value) &&
1653
1659
  !Object.isFrozen(value) &&
1654
1660
  !isStore(value) &&
1655
1661
  !Object.isFrozen(target)) {
@@ -1827,7 +1833,7 @@
1827
1833
  $loadingEffects$ = null;
1828
1834
  $errorEffects$ = null;
1829
1835
  $destroy$;
1830
- $promiseValue$ = null;
1836
+ $promiseValue$ = NEEDS_COMPUTATION;
1831
1837
  [_EFFECT_BACK_REF] = null;
1832
1838
  constructor(container, fn, flags = 1 /* SignalFlags.INVALID */) {
1833
1839
  super(container, fn, flags);
@@ -1861,6 +1867,10 @@
1861
1867
  get untrackedError() {
1862
1868
  return this.$untrackedError$;
1863
1869
  }
1870
+ invalidate() {
1871
+ super.invalidate();
1872
+ this.$promiseValue$ = NEEDS_COMPUTATION;
1873
+ }
1864
1874
  $computeIfNeeded$() {
1865
1875
  if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
1866
1876
  return false;
@@ -1868,11 +1878,12 @@
1868
1878
  const computeQrl = this.$computeQrl$;
1869
1879
  throwIfQRLNotResolved(computeQrl);
1870
1880
  const [cleanup] = cleanupFn(this, (err) => this.$container$?.handleError(err, null));
1871
- const untrackedValue = this.$promiseValue$ ??
1872
- computeQrl.getFn()({
1881
+ const untrackedValue = this.$promiseValue$ === NEEDS_COMPUTATION
1882
+ ? computeQrl.getFn()({
1873
1883
  track: trackFn(this, this.$container$),
1874
1884
  cleanup,
1875
- });
1885
+ })
1886
+ : this.$promiseValue$;
1876
1887
  if (isPromise(untrackedValue)) {
1877
1888
  this.untrackedLoading = true;
1878
1889
  this.untrackedError = null;
@@ -1883,11 +1894,12 @@
1883
1894
  this.untrackedError = null;
1884
1895
  })
1885
1896
  .catch((err) => {
1897
+ this.$promiseValue$ = err;
1886
1898
  this.untrackedLoading = false;
1887
1899
  this.untrackedError = err;
1888
1900
  });
1889
1901
  }
1890
- this.$promiseValue$ = null;
1902
+ this.$promiseValue$ = NEEDS_COMPUTATION;
1891
1903
  this.$flags$ &= -2 /* SignalFlags.INVALID */;
1892
1904
  const didChange = untrackedValue !== this.$untrackedValue$;
1893
1905
  if (didChange) {
@@ -1902,13 +1914,15 @@
1902
1914
  return new SignalImpl(null, value);
1903
1915
  };
1904
1916
  /** @internal */
1905
- const createComputedSignal = (qrl) => {
1906
- throwIfQRLNotResolved(qrl);
1907
- return new ComputedSignalImpl(null, qrl);
1917
+ const createComputedSignal = (qrl, options) => {
1918
+ return new ComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'always'));
1919
+ };
1920
+ /** @internal */
1921
+ const createAsyncComputedSignal = (qrl, options) => {
1922
+ return new AsyncComputedSignalImpl(options?.container || null, qrl, getComputedSignalFlags(options?.serializationStrategy || 'never'));
1908
1923
  };
1909
1924
  /** @internal */
1910
1925
  const createSerializerSignal = (arg) => {
1911
- throwIfQRLNotResolved(arg);
1912
1926
  return new SerializerSignalImpl(null, arg);
1913
1927
  };
1914
1928
 
@@ -1927,11 +1941,22 @@
1927
1941
  * The QRL must be a function which returns the value of the signal. The function must not have side
1928
1942
  * effects, and it must be synchronous.
1929
1943
  *
1930
- * If you need the function to be async, use `useSignal` and `useTask$` instead.
1944
+ * If you need the function to be async, use `useAsyncComputed$` instead.
1931
1945
  *
1932
1946
  * @public
1933
1947
  */
1934
1948
  const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedSignal);
1949
+ /**
1950
+ * Create an async computed signal which is calculated from the given QRL. A computed signal is a
1951
+ * signal which is calculated from other signals or async operation. When the signals change, the
1952
+ * computed signal is recalculated.
1953
+ *
1954
+ * The QRL must be a function which returns the value of the signal. The function must not have side
1955
+ * effects, and it can be async.
1956
+ *
1957
+ * @public
1958
+ */
1959
+ const createAsyncComputed$ = /*#__PURE__*/ implicit$FirstArg(createAsyncComputedSignal);
1935
1960
  /**
1936
1961
  * Create a signal that holds a custom serializable value. See {@link useSerializer$} for more
1937
1962
  * details.
@@ -1991,17 +2016,6 @@
1991
2016
  // the object is not reactive, so we can just return the value
1992
2017
  return obj[prop];
1993
2018
  };
1994
- /** @internal */
1995
- const _wrapStore = (obj, prop) => {
1996
- const target = getStoreTarget(obj);
1997
- const value = target[prop];
1998
- if (isSignal(value)) {
1999
- return value;
2000
- }
2001
- else {
2002
- return new WrappedSignalImpl(null, getProp, [obj, prop], null, 1 /* SignalFlags.INVALID */);
2003
- }
2004
- };
2005
2019
  /** @internal @deprecated v1 compat */
2006
2020
  const _wrapSignal = (obj, prop) => {
2007
2021
  const r = _wrapProp(obj, prop);
@@ -2423,7 +2437,6 @@
2423
2437
  if (!isInlineComponent) {
2424
2438
  container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
2425
2439
  container.setHostProp(renderHost, USE_ON_LOCAL_SEQ_IDX, null);
2426
- container.setHostProp(renderHost, ELEMENT_PROPS, props);
2427
2440
  }
2428
2441
  if (vnode_isVNode(renderHost)) {
2429
2442
  clearAllEffects(container, renderHost);
@@ -2437,9 +2450,12 @@
2437
2450
  return jsx;
2438
2451
  }, (err) => {
2439
2452
  if (isPromise(err) && retryCount < MAX_RETRY_ON_PROMISE_COUNT) {
2440
- return err.then(() => executeComponentWithPromiseExceptionRetry(retryCount++));
2453
+ return err.then(() => executeComponentWithPromiseExceptionRetry(++retryCount));
2441
2454
  }
2442
2455
  else {
2456
+ if (retryCount >= MAX_RETRY_ON_PROMISE_COUNT) {
2457
+ throw new Error(`Max retry count of component execution reached`);
2458
+ }
2443
2459
  throw err;
2444
2460
  }
2445
2461
  });
@@ -4542,16 +4558,36 @@
4542
4558
  shouldRender = true;
4543
4559
  }
4544
4560
  if (host) {
4545
- const vNodeProps = vnode_getProp(host, ELEMENT_PROPS, container.$getObjectById$);
4546
- shouldRender = shouldRender || propsDiffer(jsxProps, vNodeProps);
4561
+ let vNodeProps = vnode_getProp(host, ELEMENT_PROPS, container.$getObjectById$);
4562
+ const propsAreDifferent = propsDiffer(jsxProps, vNodeProps);
4563
+ shouldRender = shouldRender || propsAreDifferent;
4547
4564
  if (shouldRender) {
4565
+ if (propsAreDifferent) {
4566
+ if (vNodeProps) {
4567
+ // Reuse the same props instance, qrls can use the current props instance
4568
+ // as a capture ref, so we can't change it.
4569
+ // We need to do this directly, because normally we would subscribe to the signals
4570
+ // if any signal is there.
4571
+ vNodeProps[_CONST_PROPS] = jsxProps[_CONST_PROPS];
4572
+ vNodeProps[_VAR_PROPS] = jsxProps[_VAR_PROPS];
4573
+ }
4574
+ else if (jsxProps) {
4575
+ // If there is no props instance, create a new one.
4576
+ // We can do this because we are not using the props instance for anything else.
4577
+ vnode_setProp(host, ELEMENT_PROPS, jsxProps);
4578
+ vNodeProps = jsxProps;
4579
+ }
4580
+ }
4581
+ // Assign the new QRL instance to the host.
4582
+ // Unfortunately it is created every time, something to fix in the optimizer.
4583
+ vnode_setProp(host, OnRenderProp, componentQRL);
4548
4584
  /**
4549
4585
  * Mark host as not deleted. The host could have been marked as deleted if it there was a
4550
4586
  * cleanup run. Now we found it and want to reuse it, so we need to mark it as not
4551
4587
  * deleted.
4552
4588
  */
4553
4589
  host[0 /* VNodeProps.flags */] &= -33 /* VNodeFlags.Deleted */;
4554
- container.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQRL, jsxProps);
4590
+ container.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQRL, vNodeProps);
4555
4591
  }
4556
4592
  }
4557
4593
  descendContentToProject(jsxNode.children, host);
@@ -4982,10 +5018,12 @@
4982
5018
  return resource.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
4983
5019
  }
4984
5020
  else if (isSignal(resource)) {
4985
- return Promise.resolve(resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
5021
+ const value = retryOnPromise(() => resource.value);
5022
+ const promise = isPromise(value) ? value : Promise.resolve(value);
5023
+ return promise.then(useBindInvokeContext(props.onResolved));
4986
5024
  }
4987
5025
  else {
4988
- return Promise.resolve(resource).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
5026
+ return Promise.resolve(resource).then(useBindInvokeContext(props.onResolved));
4989
5027
  }
4990
5028
  }
4991
5029
  const _createResourceReturn = (opts) => {
@@ -5511,22 +5549,23 @@
5511
5549
  {
5512
5550
  const target = chore.$target$;
5513
5551
  const effects = chore.$payload$;
5552
+ const ctx = newInvokeContext();
5553
+ ctx.$container$ = container;
5514
5554
  if (target instanceof ComputedSignalImpl || target instanceof WrappedSignalImpl) {
5515
5555
  const forceRunEffects = target.$forceRunEffects$;
5516
5556
  target.$forceRunEffects$ = false;
5517
- if (!target.$effects$?.size) {
5557
+ if (!effects?.size && !forceRunEffects) {
5518
5558
  break;
5519
5559
  }
5520
- returnValue = retryOnPromise(() => {
5521
- if (target.$computeIfNeeded$() || forceRunEffects) {
5522
- triggerEffects(container, target, effects);
5560
+ // needed for computed signals and throwing QRLs
5561
+ returnValue = maybeThen(retryOnPromise(() => invoke.call(target, ctx, target.$computeIfNeeded$)), (didChange) => {
5562
+ if (didChange || forceRunEffects) {
5563
+ return retryOnPromise(() => triggerEffects(container, target, effects));
5523
5564
  }
5524
5565
  });
5525
5566
  }
5526
5567
  else {
5527
- returnValue = retryOnPromise(() => {
5528
- triggerEffects(container, target, effects);
5529
- });
5568
+ returnValue = retryOnPromise(() => triggerEffects(container, target, effects));
5530
5569
  }
5531
5570
  }
5532
5571
  break;
@@ -5608,7 +5647,10 @@
5608
5647
  return idxDiff;
5609
5648
  }
5610
5649
  // If the host is the same (or missing), and the type is the same, we need to compare the target.
5611
- if (a.$target$ !== b.$target$ || a.$payload$ !== b.$payload$) {
5650
+ if (a.$target$ !== b.$target$) {
5651
+ if (isQrl(a.$target$) && isQrl(b.$target$) && a.$target$.$hash$ === b.$target$.$hash$) {
5652
+ return 0;
5653
+ }
5612
5654
  // 1 means that we are going to process chores as FIFO
5613
5655
  return 1;
5614
5656
  }
@@ -5656,7 +5698,7 @@
5656
5698
  * multiple times during component execution. For this reason it is necessary for us to update
5657
5699
  * the chore with the latest result of the signal.
5658
5700
  */
5659
- if (existing.$type$ === 4 /* ChoreType.NODE_DIFF */) {
5701
+ if (existing.$payload$ !== value.$payload$) {
5660
5702
  existing.$payload$ = value.$payload$;
5661
5703
  }
5662
5704
  if (existing.$executed$) {
@@ -6456,7 +6498,7 @@
6456
6498
  container.$scheduler$(1 /* ChoreType.QRL_RESOLVE */, null, consumer.$computeQrl$);
6457
6499
  }
6458
6500
  }
6459
- consumer.$invalidate$();
6501
+ consumer.invalidate();
6460
6502
  }
6461
6503
  else if (property === ":" /* EffectProperty.COMPONENT */) {
6462
6504
  const host = consumer;
@@ -6491,7 +6533,23 @@
6491
6533
  };
6492
6534
  /** @internal */
6493
6535
  const isSerializerObj = (obj) => {
6494
- return (typeof obj === 'object' && obj !== null && typeof obj[SerializerSymbol] === 'function');
6536
+ return isObject(obj) && typeof obj[SerializerSymbol] === 'function';
6537
+ };
6538
+ const getComputedSignalFlags = (serializationStrategy) => {
6539
+ let flags = 1 /* SignalFlags.INVALID */;
6540
+ switch (serializationStrategy) {
6541
+ // TODO: implement this in the future
6542
+ // case 'auto':
6543
+ // flags |= ComputedSignalFlags.SERIALIZATION_STRATEGY_AUTO;
6544
+ // break;
6545
+ case 'never':
6546
+ flags |= 8 /* ComputedSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
6547
+ break;
6548
+ case 'always':
6549
+ flags |= 16 /* ComputedSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
6550
+ break;
6551
+ }
6552
+ return flags;
6495
6553
  };
6496
6554
 
6497
6555
  const stringifyPath = [];
@@ -7788,12 +7846,15 @@
7788
7846
  let nextToConsumeIdx = 0;
7789
7847
  let ch = 0;
7790
7848
  let peekCh = 0;
7849
+ const getChar = (idx) => {
7850
+ return idx < vData.length ? vData.charCodeAt(idx) : 0;
7851
+ };
7791
7852
  const peek = () => {
7792
7853
  if (peekCh !== 0) {
7793
7854
  return peekCh;
7794
7855
  }
7795
7856
  else {
7796
- return (peekCh = nextToConsumeIdx < vData.length ? vData.charCodeAt(nextToConsumeIdx) : 0);
7857
+ return (peekCh = getChar(nextToConsumeIdx));
7797
7858
  }
7798
7859
  };
7799
7860
  const consume = () => {
@@ -7814,7 +7875,7 @@
7814
7875
  return vData.substring(start, nextToConsumeIdx);
7815
7876
  };
7816
7877
  while (peek() !== 0) {
7817
- callback(peek, consumeValue, consume, nextToConsumeIdx);
7878
+ callback(peek, consumeValue, consume, getChar, nextToConsumeIdx);
7818
7879
  }
7819
7880
  };
7820
7881
  const vnode_getNextSibling = (vnode) => {
@@ -8028,21 +8089,19 @@
8028
8089
  let textIdx = 0;
8029
8090
  let combinedText = null;
8030
8091
  let container = null;
8031
- processVNodeData(vData, (peek, consumeValue, consume, nextToConsumeIdx) => {
8092
+ processVNodeData(vData, (peek, consumeValue, consume, getChar, nextToConsumeIdx) => {
8032
8093
  if (isNumber(peek())) {
8033
8094
  // Element counts get encoded as numbers.
8034
- while (!isElement(child)) {
8095
+ while (!isElement(child) ||
8096
+ // We pretend that style element's don't exist as they can get moved out.
8097
+ // skip over style elements, as those need to be moved to the head
8098
+ // and are not included in the counts.
8099
+ isQStyleElement(child)) {
8035
8100
  child = fastNextSibling(child);
8036
8101
  if (!child) {
8037
8102
  throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), nextToConsumeIdx]);
8038
8103
  }
8039
8104
  }
8040
- // We pretend that style element's don't exist as they can get moved out.
8041
- while (isQStyleElement(child)) {
8042
- // skip over style elements, as those need to be moved to the head
8043
- // and are not included in the counts.
8044
- child = fastNextSibling(child);
8045
- }
8046
8105
  combinedText = null;
8047
8106
  previousTextNode = null;
8048
8107
  let value = 0;
@@ -8074,7 +8133,17 @@
8074
8133
  vnode_setAttr(null, vParent, ELEMENT_PROPS, consumeValue());
8075
8134
  }
8076
8135
  else if (peek() === VNodeDataChar.KEY) {
8077
- vnode_setAttr(null, vParent, ELEMENT_KEY, consumeValue());
8136
+ const isEscapedValue = getChar(nextToConsumeIdx + 1) === VNodeDataChar.SEPARATOR;
8137
+ let value;
8138
+ if (isEscapedValue) {
8139
+ consume();
8140
+ value = decodeURI(consumeValue());
8141
+ consume();
8142
+ }
8143
+ else {
8144
+ value = consumeValue();
8145
+ }
8146
+ vnode_setAttr(null, vParent, ELEMENT_KEY, value);
8078
8147
  }
8079
8148
  else if (peek() === VNodeDataChar.SEQ) {
8080
8149
  vnode_setAttr(null, vParent, ELEMENT_SEQ, consumeValue());
@@ -8120,6 +8189,10 @@
8120
8189
  vnode_setAttr(null, vParent, QSlot, consumeValue());
8121
8190
  }
8122
8191
  else {
8192
+ // skip over style elements in front of text nodes, where text node is the first child (except the style node)
8193
+ while (isQStyleElement(child)) {
8194
+ child = fastNextSibling(child);
8195
+ }
8123
8196
  const textNode = child && fastNodeType(child) === /* Node.TEXT_NODE */ 3 ? child : null;
8124
8197
  // must be alphanumeric
8125
8198
  if (combinedText === null) {
@@ -8216,7 +8289,7 @@
8216
8289
  /** There's [documentation](./serialization.md) */
8217
8290
  const deserializedProxyMap = new WeakMap();
8218
8291
  const isDeserializerProxy = (value) => {
8219
- return typeof value === 'object' && value !== null && SERIALIZER_PROXY_UNWRAP in value;
8292
+ return isObject(value) && SERIALIZER_PROXY_UNWRAP in value;
8220
8293
  };
8221
8294
  const SERIALIZER_PROXY_UNWRAP = Symbol('UNWRAP');
8222
8295
  /** Call this on the serialized root state */
@@ -8424,9 +8497,7 @@
8424
8497
  if (hasValue) {
8425
8498
  asyncComputed.$untrackedValue$ = d[6];
8426
8499
  }
8427
- else {
8428
- asyncComputed.$flags$ |= 1 /* SignalFlags.INVALID */;
8429
- }
8500
+ asyncComputed.$flags$ |= 1 /* SignalFlags.INVALID */;
8430
8501
  break;
8431
8502
  }
8432
8503
  // Inflating a SerializerSignal is the same as inflating a ComputedSignal
@@ -8526,7 +8597,7 @@
8526
8597
  propsProxy[_VAR_PROPS] = data === 0 ? {} : data[0];
8527
8598
  propsProxy[_CONST_PROPS] = data[1];
8528
8599
  break;
8529
- case 35 /* TypeIds.EffectData */: {
8600
+ case 35 /* TypeIds.SubscriptionData */: {
8530
8601
  const effectData = target;
8531
8602
  effectData.data.$scopedStyleIdPrefix$ = data[0];
8532
8603
  effectData.data.$isConst$ = data[1];
@@ -8547,6 +8618,7 @@
8547
8618
  EMPTY_OBJ,
8548
8619
  NEEDS_COMPUTATION,
8549
8620
  STORE_ALL_PROPS,
8621
+ _UNINITIALIZED,
8550
8622
  Slot,
8551
8623
  Fragment,
8552
8624
  NaN,
@@ -8566,6 +8638,7 @@
8566
8638
  'EMPTY_OBJ',
8567
8639
  'NEEDS_COMPUTATION',
8568
8640
  'STORE_ALL_PROPS',
8641
+ '_UNINITIALIZED',
8569
8642
  'Slot',
8570
8643
  'Fragment',
8571
8644
  'NaN',
@@ -8587,7 +8660,13 @@
8587
8660
  if (!container.$forwardRefs$) {
8588
8661
  throw qError(18 /* QError.serializeErrorCannotAllocate */, ['forward ref']);
8589
8662
  }
8590
- return container.$getObjectById$(container.$forwardRefs$[value]);
8663
+ const rootRef = container.$forwardRefs$[value];
8664
+ if (rootRef === -1) {
8665
+ return _UNINITIALIZED;
8666
+ }
8667
+ else {
8668
+ return container.$getObjectById$(rootRef);
8669
+ }
8591
8670
  case 2 /* TypeIds.ForwardRefs */:
8592
8671
  return value;
8593
8672
  case 3 /* TypeIds.Constant */:
@@ -8682,7 +8761,7 @@
8682
8761
  else {
8683
8762
  throw qError(17 /* QError.serializeErrorExpectedVNode */, [typeof vNode]);
8684
8763
  }
8685
- case 35 /* TypeIds.EffectData */:
8764
+ case 35 /* TypeIds.SubscriptionData */:
8686
8765
  return new SubscriptionData({});
8687
8766
  default:
8688
8767
  throw qError(18 /* QError.serializeErrorCannotAllocate */, [typeId]);
@@ -8744,7 +8823,7 @@
8744
8823
  };
8745
8824
  }
8746
8825
  const seenObjsMap = new Map();
8747
- const rootsPathMap = new Map();
8826
+ const objectPathStringCache = new Map();
8748
8827
  const syncFnMap = new Map();
8749
8828
  const syncFns = [];
8750
8829
  const roots = [];
@@ -8753,7 +8832,7 @@
8753
8832
  return seenObjsMap.set(obj, { $parent$: parent, $index$: index, $rootIndex$: -1 });
8754
8833
  };
8755
8834
  const $addRootPath$ = (obj) => {
8756
- const rootPath = rootsPathMap.get(obj);
8835
+ const rootPath = objectPathStringCache.get(obj);
8757
8836
  if (rootPath) {
8758
8837
  return rootPath;
8759
8838
  }
@@ -8772,7 +8851,7 @@
8772
8851
  current = seenObjsMap.get(current.$parent$);
8773
8852
  }
8774
8853
  const pathStr = path.length > 1 ? path.join(' ') : path.length ? path[0] : seen.$index$;
8775
- rootsPathMap.set(obj, pathStr);
8854
+ objectPathStringCache.set(obj, pathStr);
8776
8855
  return pathStr;
8777
8856
  };
8778
8857
  const $addRoot$ = (obj, parent = null) => {
@@ -8839,7 +8918,7 @@
8839
8918
  $storeProxyMap$: storeProxyMap,
8840
8919
  $getProp$: getProp,
8841
8920
  $setProp$: setProp,
8842
- $pathMap$: rootsPathMap,
8921
+ $objectPathStringCache$: objectPathStringCache,
8843
8922
  };
8844
8923
  };
8845
8924
  function $discoverRoots$(serializationContext, obj, parent, index) {
@@ -8863,7 +8942,8 @@
8863
8942
  for (let i = 1; i < value.length; i += 2) {
8864
8943
  const keyValue = value[i - 1];
8865
8944
  const attrValue = value[i];
8866
- if (typeof attrValue === 'string' ||
8945
+ if (attrValue == null ||
8946
+ typeof attrValue === 'string' ||
8867
8947
  // skip empty props
8868
8948
  (keyValue === ELEMENT_PROPS &&
8869
8949
  Object.keys(attrValue).length === 0)) {
@@ -8888,6 +8968,14 @@
8888
8968
  this.$qrl$ = $qrl$;
8889
8969
  }
8890
8970
  }
8971
+ class SerializationWeakRef {
8972
+ $obj$;
8973
+ constructor($obj$) {
8974
+ this.$obj$ = $obj$;
8975
+ }
8976
+ }
8977
+ /** @internal */
8978
+ const _serializationWeakRef = (obj) => new SerializationWeakRef(obj);
8891
8979
  /**
8892
8980
  * Format:
8893
8981
  *
@@ -8898,12 +8986,14 @@
8898
8986
  * - Therefore root indexes need to be doubled to get the actual index.
8899
8987
  */
8900
8988
  async function serialize(serializationContext) {
8901
- const { $writer$, $isSsrNode$, $isDomRef$, $storeProxyMap$, $addRoot$, $pathMap$, $wasSeen$ } = serializationContext;
8989
+ const { $writer$, $isSsrNode$, $isDomRef$, $storeProxyMap$, $addRoot$, $objectPathStringCache$, $wasSeen$, } = serializationContext;
8902
8990
  let depth = 0;
8991
+ let rootIdx = 0;
8903
8992
  const forwardRefs = [];
8904
8993
  let forwardRefsId = 0;
8905
8994
  const promises = new Set();
8906
8995
  const preloadQrls = new Set();
8996
+ const s11nWeakRefs = new Map();
8907
8997
  let parent = null;
8908
8998
  const isRootObject = () => depth === 0;
8909
8999
  const outputArray = (value, writeFn) => {
@@ -8948,19 +9038,41 @@
8948
9038
  };
8949
9039
  const addPreloadQrl = (qrl) => {
8950
9040
  preloadQrls.add(qrl);
8951
- serializationContext.$addRoot$(qrl, null);
9041
+ serializationContext.$addRoot$(qrl);
8952
9042
  };
8953
- const outputRootRef = (value, rootDepth = 0) => {
9043
+ const outputAsRootRef = (value, rootDepth = 0) => {
8954
9044
  const seen = $wasSeen$(value);
8955
- const rootRefPath = $pathMap$.get(value);
9045
+ const rootRefPath = $objectPathStringCache$.get(value);
9046
+ // Objects are the only way to create circular dependencies.
9047
+ // So the first thing to to is to see if we have a circular dependency.
9048
+ // (NOTE: For root objects we need to serialize them regardless if we have seen
9049
+ // them before, otherwise the root object reference will point to itself.)
9050
+ // Also note that depth will be 1 for objects in root
8956
9051
  if (rootDepth === depth && seen && seen.$parent$ !== null && rootRefPath) {
8957
9052
  output(0 /* TypeIds.RootRef */, rootRefPath);
8958
9053
  return true;
8959
9054
  }
8960
9055
  else if (depth > rootDepth && seen && seen.$rootIndex$ !== -1) {
9056
+ // We have seen this object before, so we can serialize it as a reference.
9057
+ // Otherwise serialize as normal
8961
9058
  output(0 /* TypeIds.RootRef */, seen.$rootIndex$);
8962
9059
  return true;
8963
9060
  }
9061
+ else if (s11nWeakRefs.has(value)) {
9062
+ const forwardRefId = s11nWeakRefs.get(value);
9063
+ // We see the object again, we must now make it a root and update the forward ref
9064
+ if (rootDepth === depth) {
9065
+ // It's already a root
9066
+ forwardRefs[forwardRefId] = rootIdx;
9067
+ }
9068
+ else {
9069
+ // ref
9070
+ const rootRef = $addRoot$(value);
9071
+ output(0 /* TypeIds.RootRef */, rootRef);
9072
+ forwardRefs[forwardRefId] = rootRef;
9073
+ return true;
9074
+ }
9075
+ }
8964
9076
  return false;
8965
9077
  };
8966
9078
  const writeValue = (value) => {
@@ -8975,13 +9087,13 @@
8975
9087
  }
8976
9088
  else if (typeof value === 'function') {
8977
9089
  if (value === Slot) {
8978
- output(3 /* TypeIds.Constant */, 9 /* Constants.Slot */);
9090
+ output(3 /* TypeIds.Constant */, 10 /* Constants.Slot */);
8979
9091
  }
8980
9092
  else if (value === Fragment) {
8981
- output(3 /* TypeIds.Constant */, 10 /* Constants.Fragment */);
9093
+ output(3 /* TypeIds.Constant */, 11 /* Constants.Fragment */);
8982
9094
  }
8983
9095
  else if (isQrl(value)) {
8984
- if (!outputRootRef(value)) {
9096
+ if (!outputAsRootRef(value)) {
8985
9097
  const qrl = qrlToString(serializationContext, value);
8986
9098
  const type = preloadQrls.has(value) ? 21 /* TypeIds.PreloadQRL */ : 20 /* TypeIds.QRL */;
8987
9099
  if (isRootObject()) {
@@ -9004,19 +9116,19 @@
9004
9116
  }
9005
9117
  else if (typeof value === 'number') {
9006
9118
  if (Number.isNaN(value)) {
9007
- output(3 /* TypeIds.Constant */, 11 /* Constants.NaN */);
9119
+ output(3 /* TypeIds.Constant */, 12 /* Constants.NaN */);
9008
9120
  }
9009
9121
  else if (!Number.isFinite(value)) {
9010
- output(3 /* TypeIds.Constant */, value < 0 ? 13 /* Constants.NegativeInfinity */ : 12 /* Constants.PositiveInfinity */);
9122
+ output(3 /* TypeIds.Constant */, value < 0 ? 14 /* Constants.NegativeInfinity */ : 13 /* Constants.PositiveInfinity */);
9011
9123
  }
9012
9124
  else if (value === Number.MAX_SAFE_INTEGER) {
9013
- output(3 /* TypeIds.Constant */, 14 /* Constants.MaxSafeInt */);
9125
+ output(3 /* TypeIds.Constant */, 15 /* Constants.MaxSafeInt */);
9014
9126
  }
9015
9127
  else if (value === Number.MAX_SAFE_INTEGER - 1) {
9016
- output(3 /* TypeIds.Constant */, 15 /* Constants.AlmostMaxSafeInt */);
9128
+ output(3 /* TypeIds.Constant */, 16 /* Constants.AlmostMaxSafeInt */);
9017
9129
  }
9018
9130
  else if (value === Number.MIN_SAFE_INTEGER) {
9019
- output(3 /* TypeIds.Constant */, 16 /* Constants.MinSafeInt */);
9131
+ output(3 /* TypeIds.Constant */, 17 /* Constants.MinSafeInt */);
9020
9132
  }
9021
9133
  else {
9022
9134
  output(4 /* TypeIds.Number */, value);
@@ -9046,7 +9158,7 @@
9046
9158
  output(3 /* TypeIds.Constant */, 4 /* Constants.EmptyString */);
9047
9159
  }
9048
9160
  else {
9049
- if (!outputRootRef(value)) {
9161
+ if (!outputAsRootRef(value)) {
9050
9162
  output(5 /* TypeIds.String */, value);
9051
9163
  }
9052
9164
  }
@@ -9060,6 +9172,9 @@
9060
9172
  else if (value === STORE_ALL_PROPS) {
9061
9173
  output(3 /* TypeIds.Constant */, 8 /* Constants.STORE_ALL_PROPS */);
9062
9174
  }
9175
+ else if (value === _UNINITIALIZED) {
9176
+ output(3 /* TypeIds.Constant */, 9 /* Constants.UNINITIALIZED */);
9177
+ }
9063
9178
  else {
9064
9179
  throw qError(20 /* QError.serializeErrorUnknownType */, [typeof value]);
9065
9180
  }
@@ -9069,14 +9184,11 @@
9069
9184
  * The object writer outputs an array object (without type prefix) and this increases the depth
9070
9185
  * for the objects within (depth 1).
9071
9186
  */
9072
- // Objects are the only way to create circular dependencies.
9073
- // So the first thing to to is to see if we have a circular dependency.
9074
- // (NOTE: For root objects we need to serialize them regardless if we have seen
9075
- // them before, otherwise the root object reference will point to itself.)
9076
- // Also note that depth will be 1 for objects in root
9077
- if (outputRootRef(value, 1)) {
9187
+ if (outputAsRootRef(value, 1)) {
9078
9188
  return;
9079
9189
  }
9190
+ // handle custom serializers
9191
+ // add to the seen map
9080
9192
  if (isPropsProxy(value)) {
9081
9193
  const varProps = value[_VAR_PROPS];
9082
9194
  const constProps = value[_CONST_PROPS];
@@ -9088,7 +9200,7 @@
9088
9200
  output(34 /* TypeIds.PropsProxy */, out);
9089
9201
  }
9090
9202
  else if (value instanceof SubscriptionData) {
9091
- output(35 /* TypeIds.EffectData */, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
9203
+ output(35 /* TypeIds.SubscriptionData */, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
9092
9204
  }
9093
9205
  else if (isStore(value)) {
9094
9206
  if (isResource(value)) {
@@ -9164,14 +9276,6 @@
9164
9276
  output(1 /* TypeIds.ForwardRef */, forwardRefId);
9165
9277
  return;
9166
9278
  }
9167
- /**
9168
- * Special case: when a Signal value is an SSRNode, it always needs to be a DOM ref instead.
9169
- * It can never be meant to become a vNode, because vNodes are internal only.
9170
- */
9171
- const v = value instanceof ComputedSignalImpl &&
9172
- (value.$flags$ & 1 /* SignalFlags.INVALID */ || fastSkipSerialize(value.$untrackedValue$))
9173
- ? NEEDS_COMPUTATION
9174
- : value.$untrackedValue$;
9175
9279
  if (value instanceof WrappedSignalImpl) {
9176
9280
  output(26 /* TypeIds.WrappedSignal */, [
9177
9281
  ...serializeWrappingFn(serializationContext, value),
@@ -9181,35 +9285,34 @@
9181
9285
  ...(value.$effects$ || []),
9182
9286
  ]);
9183
9287
  }
9184
- else if (value instanceof AsyncComputedSignalImpl) {
9185
- addPreloadQrl(value.$computeQrl$);
9186
- const out = [
9187
- value.$computeQrl$,
9188
- value.$effects$,
9189
- value.$loadingEffects$,
9190
- value.$errorEffects$,
9191
- value.$untrackedLoading$,
9192
- value.$untrackedError$,
9193
- ];
9194
- if (v !== NEEDS_COMPUTATION) {
9195
- out.push(v);
9196
- }
9197
- output(28 /* TypeIds.AsyncComputedSignal */, out);
9198
- }
9199
9288
  else if (value instanceof ComputedSignalImpl) {
9289
+ let v = value.$untrackedValue$;
9290
+ const shouldAlwaysSerialize = value.$flags$ & 16 /* ComputedSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
9291
+ const shouldNeverSerialize = value.$flags$ & 8 /* ComputedSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
9292
+ const isInvalid = value.$flags$ & 1 /* SignalFlags.INVALID */;
9293
+ const isSkippable = fastSkipSerialize(value.$untrackedValue$);
9294
+ if (shouldAlwaysSerialize) {
9295
+ v = value.$untrackedValue$;
9296
+ }
9297
+ else if (shouldNeverSerialize) {
9298
+ v = NEEDS_COMPUTATION;
9299
+ }
9300
+ else if (isInvalid || isSkippable) {
9301
+ v = NEEDS_COMPUTATION;
9302
+ }
9200
9303
  addPreloadQrl(value.$computeQrl$);
9201
- const out = [
9202
- value.$computeQrl$,
9203
- // TODO check if we can use domVRef for effects
9204
- value.$effects$,
9205
- ];
9304
+ const out = [value.$computeQrl$, value.$effects$];
9305
+ const isAsync = value instanceof AsyncComputedSignalImpl;
9306
+ if (isAsync) {
9307
+ out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedLoading$, value.$untrackedError$);
9308
+ }
9206
9309
  if (v !== NEEDS_COMPUTATION) {
9207
9310
  out.push(v);
9208
9311
  }
9209
- output(27 /* TypeIds.ComputedSignal */, out);
9312
+ output(isAsync ? 28 /* TypeIds.AsyncComputedSignal */ : 27 /* TypeIds.ComputedSignal */, out);
9210
9313
  }
9211
9314
  else {
9212
- output(25 /* TypeIds.Signal */, [v, ...(value.$effects$ || [])]);
9315
+ output(25 /* TypeIds.Signal */, [value.$untrackedValue$, ...(value.$effects$ || [])]);
9213
9316
  }
9214
9317
  }
9215
9318
  else if (value instanceof URL) {
@@ -9344,6 +9447,12 @@
9344
9447
  const out = btoa(buf).replace(/=+$/, '');
9345
9448
  output(19 /* TypeIds.Uint8Array */, out);
9346
9449
  }
9450
+ else if (value instanceof SerializationWeakRef) {
9451
+ const forwardRefId = forwardRefsId++;
9452
+ s11nWeakRefs.set(value.$obj$, forwardRefId);
9453
+ forwardRefs[forwardRefId] = -1;
9454
+ output(1 /* TypeIds.ForwardRef */, forwardRefId);
9455
+ }
9347
9456
  else if (vnode_isVNode(value)) {
9348
9457
  output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
9349
9458
  }
@@ -9367,21 +9476,20 @@
9367
9476
  }
9368
9477
  const outputRoots = async () => {
9369
9478
  $writer$.write('[');
9370
- let lastRootsLength = 0;
9371
9479
  let rootsLength = serializationContext.$roots$.length;
9372
- while (lastRootsLength < rootsLength || promises.size) {
9373
- if (lastRootsLength !== 0) {
9480
+ while (rootIdx < rootsLength || promises.size) {
9481
+ if (rootIdx !== 0) {
9374
9482
  $writer$.write(',');
9375
9483
  }
9376
9484
  let separator = false;
9377
- for (let i = lastRootsLength; i < rootsLength; i++) {
9485
+ for (; rootIdx < rootsLength; rootIdx++) {
9378
9486
  if (separator) {
9379
9487
  $writer$.write(',');
9380
9488
  }
9381
9489
  else {
9382
9490
  separator = true;
9383
9491
  }
9384
- writeValue(serializationContext.$roots$[i]);
9492
+ writeValue(serializationContext.$roots$[rootIdx]);
9385
9493
  }
9386
9494
  if (promises.size) {
9387
9495
  try {
@@ -9391,7 +9499,6 @@
9391
9499
  // ignore rejections, they will be serialized as rejected promises
9392
9500
  }
9393
9501
  }
9394
- lastRootsLength = rootsLength;
9395
9502
  rootsLength = serializationContext.$roots$.length;
9396
9503
  }
9397
9504
  if (forwardRefs.length) {
@@ -9697,7 +9804,7 @@
9697
9804
  return (
9698
9805
  // THINK: Not sure if we need to keep track of functions (QRLs) Let's skip them for now.
9699
9806
  // and see if we have a test case which requires them.
9700
- (typeof obj === 'object' && obj !== null) ||
9807
+ isObject(obj) ||
9701
9808
  /**
9702
9809
  * We track all strings greater than 1 character, because those take at least 6 bytes to encode
9703
9810
  * and even with 999 root objects it saves one byte per reference. Tracking more objects makes
@@ -9725,9 +9832,7 @@
9725
9832
  return '__brand' in value && value.__brand === 'resource';
9726
9833
  }
9727
9834
  const frameworkType = (obj) => {
9728
- return ((typeof obj === 'object' &&
9729
- obj !== null &&
9730
- (obj instanceof SignalImpl || obj instanceof Task || isJSXNode(obj))) ||
9835
+ return ((isObject(obj) && (obj instanceof SignalImpl || obj instanceof Task || isJSXNode(obj))) ||
9731
9836
  isQrl(obj));
9732
9837
  };
9733
9838
  const canSerialize = (value, seen = new WeakSet()) => {
@@ -9813,6 +9918,9 @@
9813
9918
  return true;
9814
9919
  }
9815
9920
  }
9921
+ else if (value === _UNINITIALIZED) {
9922
+ return true;
9923
+ }
9816
9924
  return false;
9817
9925
  };
9818
9926
  const QRL_RUNTIME_CHUNK = 'mock-chunk';
@@ -9852,12 +9960,12 @@
9852
9960
  'FormData',
9853
9961
  'JSXNode',
9854
9962
  'PropsProxy',
9855
- 'EffectData',
9963
+ 'SubscriptionData',
9856
9964
  ];
9857
9965
  const circularProofJson = (obj, indent) => {
9858
9966
  const seen = new WeakSet();
9859
- return JSON.stringify(obj, (key, value) => {
9860
- if (typeof value === 'object' && value !== null) {
9967
+ return JSON.stringify(obj, (_, value) => {
9968
+ if (isObject(value)) {
9861
9969
  if (seen.has(value)) {
9862
9970
  return `[Circular ${value.constructor.name}]`;
9863
9971
  }
@@ -9894,7 +10002,7 @@
9894
10002
  let value = state[++i];
9895
10003
  if (key === undefined) {
9896
10004
  hasRaw = true;
9897
- out.push(`${RED}[raw${typeof value === 'object' && value ? ` ${value.constructor.name}` : ''}]${RESET} ${printRaw(value, `${prefix} `)}`);
10005
+ out.push(`${RED}[raw${isObject(value) ? ` ${value.constructor.name}` : ''}]${RESET} ${printRaw(value, `${prefix} `)}`);
9898
10006
  }
9899
10007
  else {
9900
10008
  if (key === 3 /* TypeIds.Constant */) {
@@ -10008,7 +10116,6 @@
10008
10116
  return value;
10009
10117
  };
10010
10118
  const noSerializeSet = /*#__PURE__*/ new WeakSet();
10011
- const weakSerializeSet = /*#__PURE__*/ new WeakSet();
10012
10119
  const shouldSerialize = (obj) => {
10013
10120
  if (isObject(obj) || isFunction(obj)) {
10014
10121
  return !noSerializeSet.has(obj);
@@ -10017,7 +10124,7 @@
10017
10124
  };
10018
10125
  const fastSkipSerialize = (obj) => {
10019
10126
  return (obj &&
10020
- (typeof obj === 'object' || typeof obj === 'function') &&
10127
+ (isObject(obj) || typeof obj === 'function') &&
10021
10128
  (NoSerializeSymbol in obj || noSerializeSet.has(obj)));
10022
10129
  };
10023
10130
  // <docs markdown="../../readme.md#noSerialize">
@@ -10042,16 +10149,11 @@
10042
10149
  // </docs>
10043
10150
  const noSerialize = (input) => {
10044
10151
  // only add supported values to the noSerializeSet, prevent console errors
10045
- if ((typeof input === 'object' && input !== null) || typeof input === 'function') {
10152
+ if ((isObject(input) && input !== null) || typeof input === 'function') {
10046
10153
  noSerializeSet.add(input);
10047
10154
  }
10048
10155
  return input;
10049
10156
  };
10050
- /** @internal */
10051
- const _weakSerialize = (input) => {
10052
- weakSerializeSet.add(input);
10053
- return input;
10054
- };
10055
10157
  /**
10056
10158
  * If an object has this property, it will not be serialized. Use this on prototypes to avoid having
10057
10159
  * to call `noSerialize()` on every object.
@@ -10078,6 +10180,7 @@
10078
10180
  const SerializerSymbol = Symbol('serialize');
10079
10181
 
10080
10182
  // keep these imports above the rest to prevent circular dep issues
10183
+ const resolvedSymbol = Symbol('resolved');
10081
10184
  const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10082
10185
  if (qDev && qSerialize) {
10083
10186
  if (captureRef) {
@@ -10130,9 +10233,6 @@
10130
10233
  };
10131
10234
  return bound;
10132
10235
  }
10133
- const resolveLazy = (containerEl) => {
10134
- return symbolRef !== null ? symbolRef : resolve(containerEl);
10135
- };
10136
10236
  // Wrap functions to provide their lexical scope
10137
10237
  const wrapFn = (fn) => {
10138
10238
  if (typeof fn !== 'function' || (!capture?.length && !captureRef?.length)) {
@@ -10161,45 +10261,58 @@
10161
10261
  return invoke.call(this, context, fn, ...args);
10162
10262
  };
10163
10263
  };
10164
- const resolve = async (containerEl) => {
10165
- if (symbolRef !== null) {
10166
- // Resolving (Promise) or already resolved (value)
10264
+ // Retrieve memoized result from symbolFn
10265
+ if (symbolFn && resolvedSymbol in symbolFn) {
10266
+ symbolRef = symbolFn[resolvedSymbol];
10267
+ }
10268
+ const resolve = symbolRef
10269
+ ? async () => symbolRef
10270
+ : async (containerEl) => {
10271
+ if (symbolRef !== null) {
10272
+ // Resolving (Promise) or already resolved (value)
10273
+ return symbolRef;
10274
+ }
10275
+ if (containerEl) {
10276
+ setContainer(containerEl);
10277
+ }
10278
+ if (chunk === '') {
10279
+ // Sync QRL
10280
+ assertDefined(_containerEl, 'Sync QRL must have container element');
10281
+ const hash = _containerEl.getAttribute(QInstanceAttr);
10282
+ const doc = _containerEl.ownerDocument;
10283
+ const qFuncs = getQFuncs(doc, hash);
10284
+ // No need to wrap, syncQRLs can't have captured scope
10285
+ return (qrl.resolved = symbolRef = qFuncs[Number(symbol)]);
10286
+ }
10287
+ if (build.isBrowser && chunk) {
10288
+ /** We run the QRL, so now the probability of the chunk is 100% */
10289
+ preloader.p(chunk, 1);
10290
+ }
10291
+ const start = now();
10292
+ const ctx = tryGetInvokeContext();
10293
+ if (symbolFn !== null) {
10294
+ symbolRef = symbolFn().then((module) => {
10295
+ const resolved = wrapFn((symbolRef = module[symbol]));
10296
+ // We memoize the result on the symbolFn
10297
+ symbolFn[resolvedSymbol] = resolved;
10298
+ qrl.resolved = resolved;
10299
+ return resolved;
10300
+ });
10301
+ }
10302
+ else {
10303
+ // TODO cache the imported symbol but watch out for dev mode
10304
+ const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
10305
+ symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
10306
+ }
10307
+ if (isPromise(symbolRef)) {
10308
+ symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
10309
+ console.error(`qrl ${symbol} failed to load`, err);
10310
+ // We shouldn't cache rejections, we can try again later
10311
+ symbolRef = null;
10312
+ });
10313
+ }
10167
10314
  return symbolRef;
10168
- }
10169
- if (containerEl) {
10170
- setContainer(containerEl);
10171
- }
10172
- if (chunk === '') {
10173
- // Sync QRL
10174
- assertDefined(_containerEl, 'Sync QRL must have container element');
10175
- const hash = _containerEl.getAttribute(QInstanceAttr);
10176
- const doc = _containerEl.ownerDocument;
10177
- const qFuncs = getQFuncs(doc, hash);
10178
- // No need to wrap, syncQRLs can't have captured scope
10179
- return (qrl.resolved = symbolRef = qFuncs[Number(symbol)]);
10180
- }
10181
- if (build.isBrowser && chunk) {
10182
- /** We run the QRL, so now the probability of the chunk is 100% */
10183
- preloader.p(chunk, 1);
10184
- }
10185
- const start = now();
10186
- const ctx = tryGetInvokeContext();
10187
- if (symbolFn !== null) {
10188
- symbolRef = symbolFn().then((module) => (qrl.resolved = wrapFn((symbolRef = module[symbol]))));
10189
- }
10190
- else {
10191
- const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
10192
- symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
10193
- }
10194
- if (typeof symbolRef === 'object' && isPromise(symbolRef)) {
10195
- symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
10196
- console.error(`qrl ${symbol} failed to load`, err);
10197
- // We shouldn't cache rejections, we can try again later
10198
- symbolRef = null;
10199
- });
10200
- }
10201
- return symbolRef;
10202
- };
10315
+ };
10203
10316
  const createOrReuseInvocationContext = (invoke) => {
10204
10317
  if (invoke == null) {
10205
10318
  return newInvokeContext();
@@ -10217,7 +10330,6 @@
10217
10330
  getHash: () => hash,
10218
10331
  getCaptured: () => captureRef,
10219
10332
  resolve,
10220
- $resolveLazy$: resolveLazy,
10221
10333
  $setContainer$: setContainer,
10222
10334
  $chunk$: chunk,
10223
10335
  $symbol$: symbol,
@@ -11058,13 +11170,13 @@
11058
11170
  const styleId = styleKey(styleQrl, i);
11059
11171
  const host = iCtx.$hostElement$;
11060
11172
  set(styleId);
11061
- const value = styleQrl.$resolveLazy$(iCtx.$element$);
11062
- if (isPromise(value)) {
11063
- value.then((val) => iCtx.$container$.$appendStyle$(transform(val, styleId), styleId, host, scoped));
11064
- throw value;
11173
+ if (styleQrl.resolved) {
11174
+ iCtx.$container$.$appendStyle$(transform(styleQrl.resolved, styleId), styleId, host, scoped);
11065
11175
  }
11066
11176
  else {
11067
- iCtx.$container$.$appendStyle$(transform(value, styleId), styleId, host, scoped);
11177
+ throw styleQrl
11178
+ .resolve()
11179
+ .then((val) => iCtx.$container$.$appendStyle$(transform(val, styleId), styleId, host, scoped));
11068
11180
  }
11069
11181
  return styleId;
11070
11182
  };
@@ -11245,13 +11357,13 @@
11245
11357
  return set(value);
11246
11358
  };
11247
11359
 
11248
- const useComputedCommon = (qrl, Class) => {
11360
+ const useComputedCommon = (qrl, createFn, options) => {
11249
11361
  const { val, set } = useSequentialScope();
11250
11362
  if (val) {
11251
11363
  return val;
11252
11364
  }
11253
11365
  assertQrl(qrl);
11254
- const signal = new Class(null, qrl);
11366
+ const signal = createFn(qrl, options);
11255
11367
  set(signal);
11256
11368
  // Note that we first save the signal
11257
11369
  // and then we throw to load the qrl
@@ -11260,8 +11372,8 @@
11260
11372
  return signal;
11261
11373
  };
11262
11374
  /** @internal */
11263
- const useComputedQrl = (qrl) => {
11264
- return useComputedCommon(qrl, ComputedSignalImpl);
11375
+ const useComputedQrl = (qrl, options) => {
11376
+ return useComputedCommon(qrl, createComputedSignal, options);
11265
11377
  };
11266
11378
  /**
11267
11379
  * Creates a computed signal which is calculated from the given function. A computed signal is a
@@ -11276,7 +11388,7 @@
11276
11388
  const useComputed$ = implicit$FirstArg(useComputedQrl);
11277
11389
 
11278
11390
  /** @internal */
11279
- const useSerializerQrl = (qrl) => useComputedCommon(qrl, SerializerSignalImpl);
11391
+ const useSerializerQrl = (qrl) => useComputedCommon(qrl, createSerializerSignal);
11280
11392
  /**
11281
11393
  * Creates a signal which holds a custom serializable value. It requires that the value implements
11282
11394
  * the `CustomSerializable` type, which means having a function under the `[SerializeSymbol]`
@@ -11355,7 +11467,7 @@
11355
11467
  set(task);
11356
11468
  useRunTask(task, eagerness);
11357
11469
  if (!isServerPlatform()) {
11358
- qrl.$resolveLazy$(iCtx.$element$);
11470
+ qrl.resolve(iCtx.$element$);
11359
11471
  iCtx.$container$.$scheduler$(32 /* ChoreType.VISIBLE */, task);
11360
11472
  }
11361
11473
  };
@@ -11531,8 +11643,8 @@
11531
11643
  const useVisibleTask$ = /*#__PURE__*/ implicit$FirstArg(useVisibleTaskQrl);
11532
11644
 
11533
11645
  /** @internal */
11534
- const useAsyncComputedQrl = (qrl) => {
11535
- return useComputedCommon(qrl, AsyncComputedSignalImpl);
11646
+ const useAsyncComputedQrl = (qrl, options) => {
11647
+ return useComputedCommon(qrl, createAsyncComputedSignal, options);
11536
11648
  };
11537
11649
  /**
11538
11650
  * Creates a computed signal which is calculated from the given function. A computed signal is a
@@ -11656,10 +11768,12 @@
11656
11768
  exports._IMMUTABLE = _IMMUTABLE;
11657
11769
  exports._SharedContainer = _SharedContainer;
11658
11770
  exports._SubscriptionData = SubscriptionData;
11771
+ exports._UNINITIALIZED = _UNINITIALIZED;
11659
11772
  exports._VAR_PROPS = _VAR_PROPS;
11660
11773
  exports._deserialize = _deserialize;
11661
11774
  exports._dumpState = dumpState;
11662
11775
  exports._fnSignal = _fnSignal;
11776
+ exports._getContextContainer = _getContextContainer;
11663
11777
  exports._getContextElement = _getContextElement;
11664
11778
  exports._getContextEvent = _getContextEvent;
11665
11779
  exports._getDomContainer = getDomContainer;
@@ -11679,18 +11793,20 @@
11679
11793
  exports._regSymbol = _regSymbol;
11680
11794
  exports._restProps = _restProps;
11681
11795
  exports._run = queueQRL;
11796
+ exports._serializationWeakRef = _serializationWeakRef;
11682
11797
  exports._serialize = _serialize;
11683
11798
  exports._task = scheduleTask;
11799
+ exports._useInvokeContext = useInvokeContext;
11684
11800
  exports._verifySerializable = verifySerializable;
11685
11801
  exports._vnode_toString = vnode_toString;
11686
11802
  exports._waitUntilRendered = _waitUntilRendered;
11687
11803
  exports._walkJSX = _walkJSX;
11688
- exports._weakSerialize = _weakSerialize;
11689
11804
  exports._wrapProp = _wrapProp;
11690
11805
  exports._wrapSignal = _wrapSignal;
11691
- exports._wrapStore = _wrapStore;
11692
11806
  exports.component$ = component$;
11693
11807
  exports.componentQrl = componentQrl;
11808
+ exports.createAsyncComputed$ = createAsyncComputed$;
11809
+ exports.createAsyncComputedQrl = createAsyncComputedSignal;
11694
11810
  exports.createComputed$ = createComputed$;
11695
11811
  exports.createComputedQrl = createComputedSignal;
11696
11812
  exports.createContextId = createContextId;