@qwik.dev/core 2.0.0-alpha.6 → 2.0.0-alpha.7

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 (52) 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/build/package.json +1 -1
  7. package/dist/cli.cjs +65 -42
  8. package/dist/core-internal.d.ts +77 -76
  9. package/dist/core.cjs +1498 -1323
  10. package/dist/core.cjs.map +1 -1
  11. package/dist/core.min.mjs +1 -1
  12. package/dist/core.mjs +1496 -1323
  13. package/dist/core.mjs.map +1 -1
  14. package/dist/core.prod.cjs +884 -782
  15. package/dist/core.prod.mjs +1006 -867
  16. package/dist/insights/index.qwik.cjs +3652 -154
  17. package/dist/insights/index.qwik.mjs +3652 -154
  18. package/dist/loader/index.cjs +2 -2
  19. package/dist/loader/index.mjs +2 -2
  20. package/dist/loader/package.json +1 -1
  21. package/dist/optimizer.cjs +210 -5714
  22. package/dist/optimizer.mjs +191 -6037
  23. package/dist/prefetch/package.json +1 -1
  24. package/dist/qwikloader.debug.js +12 -15
  25. package/dist/qwikloader.js +2 -2
  26. package/dist/server.cjs +762 -7127
  27. package/dist/server.mjs +778 -7121
  28. package/dist/starters/adapters/fastify/src/plugins/fastify-qwik.ts +2 -0
  29. package/dist/starters/features/cypress/package.json +1 -1
  30. package/dist/starters/features/drizzle/drizzle/schema.ts +6 -18
  31. package/dist/starters/features/drizzle/drizzle.config.ts +5 -4
  32. package/dist/starters/features/drizzle/package.json +14 -11
  33. package/dist/starters/features/pandacss/package.json +1 -1
  34. package/dist/starters/features/partytown/package.json +1 -1
  35. package/dist/starters/features/postcss/package.json +1 -1
  36. package/dist/starters/features/prisma/package.json +1 -1
  37. package/dist/starters/features/react/package.json +1 -1
  38. package/dist/starters/features/storybook/package.json +1 -1
  39. package/dist/starters/features/styled-vanilla-extract/package.json +2 -1
  40. package/dist/starters/features/tailwind/package.json +15 -9
  41. package/dist/starters/features/tailwind/src/global.css +1 -7
  42. package/dist/starters/features/turso/package.json +1 -1
  43. package/dist/starters/features/vitest/package.json +1 -1
  44. package/dist/testing/index.cjs +1265 -1124
  45. package/dist/testing/index.mjs +1271 -1124
  46. package/dist/testing/package.json +1 -1
  47. package/handlers.mjs +9 -0
  48. package/package.json +6 -4
  49. package/public.d.ts +2 -0
  50. package/dist/starters/features/tailwind/.vscode/settings.json +0 -3
  51. package/dist/starters/features/tailwind/postcss.config.cjs +0 -6
  52. package/dist/starters/features/tailwind/tailwind.config.js +0 -8
package/dist/core.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * @qwik.dev/core 2.0.0-alpha.6-dev+d848ba5
3
+ * @qwik.dev/core 2.0.0-alpha.7-dev+a26598a
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
@@ -121,8 +121,8 @@
121
121
  // Keep one error, one line to make it easier to search for the error message.
122
122
  const MAP = [
123
123
  'Error while serializing class or style attributes', // 0
124
- '', // 1 unused
125
- '', // 2 unused
124
+ 'Scheduler not found', // 1
125
+ 'track() received object, without prop to track', // 2
126
126
  'Only primitive and object literals can be serialized. {{0}}', // 3
127
127
  '', // 4 unused
128
128
  'You can render over a existing q:container. Skipping render().', // 5
@@ -165,12 +165,11 @@
165
165
  "Element must have 'q:container' attribute.", // 42
166
166
  'Unknown vnode type {{0}}.', // 43
167
167
  'Materialize error: missing element: {{0}} {{1}} {{2}}', // 44
168
- 'Cannot coerce a Signal, use `.value` instead', // 46
169
- 'useComputedSignal$ QRL {{0}} {{1}} returned a Promise', // 47
170
- 'ComputedSignal is read-only', // 48
171
- 'WrappedSignal is read-only', // 49
172
- 'SsrError: Promises not expected here.', // 50
173
- 'Attribute value is unsafe for SSR', // 51
168
+ 'Cannot coerce a Signal, use `.value` instead', // 45
169
+ 'useComputedSignal$ QRL {{0}} {{1}} returned a Promise', // 46
170
+ 'ComputedSignal is read-only', // 47
171
+ 'WrappedSignal is read-only', // 48
172
+ 'Attribute value is unsafe for SSR', // 49
174
173
  ];
175
174
  let text = MAP[code] ?? '';
176
175
  if (parts.length) {
@@ -192,8 +191,8 @@
192
191
  var QError;
193
192
  (function (QError) {
194
193
  QError[QError["stringifyClassOrStyle"] = 0] = "stringifyClassOrStyle";
195
- QError[QError["UNUSED_1"] = 1] = "UNUSED_1";
196
- QError[QError["UNUSED_2"] = 2] = "UNUSED_2";
194
+ QError[QError["schedulerNotFound"] = 1] = "schedulerNotFound";
195
+ QError[QError["trackObjectWithoutProp"] = 2] = "trackObjectWithoutProp";
197
196
  QError[QError["verifySerializable"] = 3] = "verifySerializable";
198
197
  QError[QError["UNUSED_4"] = 4] = "UNUSED_4";
199
198
  QError[QError["cannotRenderOverExistingContainer"] = 5] = "cannotRenderOverExistingContainer";
@@ -240,14 +239,37 @@
240
239
  QError[QError["computedNotSync"] = 46] = "computedNotSync";
241
240
  QError[QError["computedReadOnly"] = 47] = "computedReadOnly";
242
241
  QError[QError["wrappedReadOnly"] = 48] = "wrappedReadOnly";
243
- QError[QError["promisesNotExpected"] = 49] = "promisesNotExpected";
244
- QError[QError["unsafeAttr"] = 50] = "unsafeAttr";
242
+ QError[QError["unsafeAttr"] = 49] = "unsafeAttr";
245
243
  })(QError || (QError = {}));
246
244
  const qError = (code, errorMessageArgs = []) => {
247
245
  const text = codeToText(code, ...errorMessageArgs);
248
246
  return logErrorAndStop(text, ...errorMessageArgs);
249
247
  };
250
248
 
249
+ /** QRL related utilities that you can import without importing all of Qwik. */
250
+ const SYNC_QRL = '<sync>';
251
+ /** Sync QRL is a function which is serialized into `<script q:func="qwik/json">` tag. */
252
+ const isSyncQrl = (value) => {
253
+ return isQrl$1(value) && value.$symbol$ == SYNC_QRL;
254
+ };
255
+ const isQrl$1 = (value) => {
256
+ return typeof value === 'function' && typeof value.getSymbol === 'function';
257
+ };
258
+ function assertQrl(qrl) {
259
+ if (build.isDev) {
260
+ if (!isQrl$1(qrl)) {
261
+ throw new Error('Not a QRL');
262
+ }
263
+ }
264
+ }
265
+ const getSymbolHash = (symbolName) => {
266
+ const index = symbolName.lastIndexOf('_');
267
+ if (index > -1) {
268
+ return symbolName.slice(index + 1);
269
+ }
270
+ return symbolName;
271
+ };
272
+
251
273
  /**
252
274
  * A friendly name tag for a VirtualVNode.
253
275
  *
@@ -291,7 +313,7 @@
291
313
  /** State factory of the component. */
292
314
  const OnRenderProp = 'q:renderFn';
293
315
  /** Component style content prefix */
294
- const ComponentStylesPrefixContent = '⭐️';
316
+ const ComponentStylesPrefixContent = '⚡️';
295
317
  /** `<some-element q:slot="...">` */
296
318
  const QSlot = 'q:slot';
297
319
  const QSlotParent = ':';
@@ -303,7 +325,7 @@
303
325
  const QStylesAllSelector = QStyleSelector + ',' + QStyleSSelector;
304
326
  const QScopedStyle = 'q:sstyle';
305
327
  const QCtxAttr = 'q:ctx';
306
- const QSubscribers = 'q:subs';
328
+ const QBackRefs = 'q:brefs';
307
329
  const QFuncsPrefix = 'qFuncs_';
308
330
  const getQFuncs = (document, hash) => {
309
331
  return document[QFuncsPrefix + hash] || [];
@@ -499,11 +521,6 @@
499
521
  ? valueOrPromise.then(thenFn, shouldNotError)
500
522
  : thenFn(valueOrPromise);
501
523
  };
502
- const maybeThenPassError = (valueOrPromise, thenFn) => {
503
- return isPromise(valueOrPromise)
504
- ? valueOrPromise.then(thenFn)
505
- : thenFn(valueOrPromise);
506
- };
507
524
  const shouldNotError = (reason) => {
508
525
  throwErrorAndStop(reason);
509
526
  };
@@ -621,7 +638,7 @@
621
638
  _locale = locale;
622
639
  }
623
640
 
624
- const isQrl$1 = (value) => {
641
+ const isQrl = (value) => {
625
642
  return typeof value === 'function' && typeof value.getSymbol === 'function';
626
643
  };
627
644
 
@@ -693,21 +710,21 @@
693
710
  // Emit event
694
711
  announcedQRL.add(symbol);
695
712
  emitEvent('qprefetch', {
696
- symbols: [getSymbolHash(symbol)],
713
+ symbols: [symbol],
697
714
  bundles: chunk && [chunk],
698
715
  });
699
716
  }
700
717
  // Unwrap subscribers
701
- return createQRL(chunk, symbol, null, symbolFn, null, lexicalScopeCapture, null);
718
+ return createQRL(chunk, symbol, null, symbolFn, null, lexicalScopeCapture);
702
719
  };
703
720
  /** @internal */
704
721
  const inlinedQrl = (symbol, symbolName, lexicalScopeCapture = EMPTY_ARRAY) => {
705
722
  // Unwrap subscribers
706
- return createQRL(null, symbolName, symbol, null, null, lexicalScopeCapture, null);
723
+ return createQRL(null, symbolName, symbol, null, null, lexicalScopeCapture);
707
724
  };
708
725
  /** @internal */
709
726
  const _noopQrl = (symbolName, lexicalScopeCapture = EMPTY_ARRAY) => {
710
- return createQRL(null, symbolName, null, null, null, lexicalScopeCapture, null);
727
+ return createQRL(null, symbolName, null, null, null, lexicalScopeCapture);
711
728
  };
712
729
  /** @internal */
713
730
  const _noopQrlDEV = (symbolName, opts, lexicalScopeCapture = EMPTY_ARRAY) => {
@@ -736,6 +753,80 @@
736
753
  return symbol;
737
754
  };
738
755
 
756
+ var ChoreType;
757
+ (function (ChoreType) {
758
+ /// MASKS defining three levels of sorting
759
+ ChoreType[ChoreType["MACRO"] = 240] = "MACRO";
760
+ /* order of elements (not encoded here) */
761
+ ChoreType[ChoreType["MICRO"] = 15] = "MICRO";
762
+ /** Ensure that the QRL promise is resolved before processing next chores in the queue */
763
+ ChoreType[ChoreType["QRL_RESOLVE"] = 1] = "QRL_RESOLVE";
764
+ ChoreType[ChoreType["RUN_QRL"] = 2] = "RUN_QRL";
765
+ ChoreType[ChoreType["TASK"] = 3] = "TASK";
766
+ ChoreType[ChoreType["NODE_DIFF"] = 4] = "NODE_DIFF";
767
+ ChoreType[ChoreType["NODE_PROP"] = 5] = "NODE_PROP";
768
+ ChoreType[ChoreType["COMPONENT"] = 6] = "COMPONENT";
769
+ ChoreType[ChoreType["RECOMPUTE_AND_SCHEDULE_EFFECTS"] = 7] = "RECOMPUTE_AND_SCHEDULE_EFFECTS";
770
+ // Next macro level
771
+ ChoreType[ChoreType["JOURNAL_FLUSH"] = 16] = "JOURNAL_FLUSH";
772
+ // Next macro level
773
+ ChoreType[ChoreType["VISIBLE"] = 32] = "VISIBLE";
774
+ // Next macro level
775
+ ChoreType[ChoreType["CLEANUP_VISIBLE"] = 48] = "CLEANUP_VISIBLE";
776
+ // Next macro level
777
+ ChoreType[ChoreType["WAIT_FOR_ALL"] = 255] = "WAIT_FOR_ALL";
778
+ })(ChoreType || (ChoreType = {}));
779
+
780
+ // <docs markdown="../readme.md#useLexicalScope">
781
+ // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
782
+ // (edit ../readme.md#useLexicalScope instead and run `pnpm docs.sync`)
783
+ /**
784
+ * Used by the Qwik Optimizer to restore the lexically scoped variables.
785
+ *
786
+ * This method should not be present in the application source code.
787
+ *
788
+ * NOTE: `useLexicalScope` method can only be used in the synchronous portion of the callback
789
+ * (before any `await` statements.)
790
+ *
791
+ * @internal
792
+ */
793
+ // </docs>
794
+ const useLexicalScope = () => {
795
+ const context = getInvokeContext();
796
+ let qrl = context.$qrl$;
797
+ if (!qrl) {
798
+ const el = context.$element$;
799
+ assertDefined(el, 'invoke: element must be defined inside useLexicalScope()', context);
800
+ const containerElement = _getQContainerElement(el);
801
+ assertDefined(containerElement, `invoke: cant find parent q:container of`, el);
802
+ const container = getDomContainer(containerElement);
803
+ qrl = container.parseQRL(decodeURIComponent(String(context.$url$)));
804
+ }
805
+ else {
806
+ assertQrl(qrl);
807
+ assertDefined(qrl.$captureRef$, 'invoke: qrl $captureRef$ must be defined inside useLexicalScope()', qrl);
808
+ }
809
+ return qrl.$captureRef$;
810
+ };
811
+
812
+ /**
813
+ * This is called by qwik-loader to schedule a QRL. It has to be synchronous.
814
+ *
815
+ * @internal
816
+ */
817
+ const queueQRL = (...args) => {
818
+ // This will already check container
819
+ const [runQrl] = useLexicalScope();
820
+ const context = getInvokeContext();
821
+ const hostElement = context.$hostElement$;
822
+ const container = getDomContainer(hostElement);
823
+ const scheduler = container.$scheduler$;
824
+ if (!scheduler) {
825
+ throw qError(QError.schedulerNotFound);
826
+ }
827
+ return scheduler(ChoreType.RUN_QRL, hostElement, runQrl, args);
828
+ };
829
+
739
830
  /**
740
831
  * Allows to project the children of the current component. <Slot/> can only be used within the
741
832
  * context of a component defined with `component$`.
@@ -860,6 +951,47 @@
860
951
  return key.startsWith('preventdefault:');
861
952
  }
862
953
 
954
+ function getFileLocationFromJsx(jsxDev) {
955
+ if (!jsxDev) {
956
+ return null;
957
+ }
958
+ const sanitizedFileName = jsxDev.fileName?.replace(/\\/g, '/');
959
+ if (sanitizedFileName) {
960
+ return `${sanitizedFileName}:${jsxDev.lineNumber}:${jsxDev.columnNumber}`;
961
+ }
962
+ return null;
963
+ }
964
+
965
+ const styleContent = (styleId) => {
966
+ return ComponentStylesPrefixContent + styleId;
967
+ };
968
+ function hasClassAttr(props) {
969
+ for (const key in props) {
970
+ if (Object.prototype.hasOwnProperty.call(props, key) && isClassAttr(key)) {
971
+ return true;
972
+ }
973
+ }
974
+ return false;
975
+ }
976
+ function isClassAttr(key) {
977
+ return key === 'class' || key === 'className';
978
+ }
979
+ function convertScopedStyleIdsToArray(scopedStyleIds) {
980
+ return scopedStyleIds?.split(' ') ?? null;
981
+ }
982
+ function convertStyleIdsToString(scopedStyleIds) {
983
+ return Array.from(scopedStyleIds).join(' ');
984
+ }
985
+ const addComponentStylePrefix = (styleId) => {
986
+ if (styleId) {
987
+ let idx = 0;
988
+ do {
989
+ styleId = styleId.substring(0, idx) + styleContent(styleId.substring(idx));
990
+ } while ((idx = styleId.indexOf(' ', idx) + 1) !== 0);
991
+ }
992
+ return styleId || null;
993
+ };
994
+
863
995
  /** CSS properties which accept numbers but are not in units of "px". */
864
996
  const unitlessNumbers = new Set([
865
997
  'animationIterationCount',
@@ -1018,36 +1150,6 @@
1018
1150
  assertQrl(qStyles);
1019
1151
  return `${hashCode(qStyles.$hash$)}-${index}`;
1020
1152
  };
1021
- const styleContent = (styleId) => {
1022
- return ComponentStylesPrefixContent + styleId;
1023
- };
1024
-
1025
- function hasClassAttr(props) {
1026
- for (const key in props) {
1027
- if (Object.prototype.hasOwnProperty.call(props, key) && isClassAttr(key)) {
1028
- return true;
1029
- }
1030
- }
1031
- return false;
1032
- }
1033
- function isClassAttr(key) {
1034
- return key === 'class' || key === 'className';
1035
- }
1036
- function convertScopedStyleIdsToArray(scopedStyleIds) {
1037
- return scopedStyleIds?.split(' ') ?? null;
1038
- }
1039
- function convertStyleIdsToString(scopedStyleIds) {
1040
- return Array.from(scopedStyleIds).join(' ');
1041
- }
1042
- const addComponentStylePrefix = (styleId) => {
1043
- if (styleId) {
1044
- let idx = 0;
1045
- do {
1046
- styleId = styleId.substring(0, idx) + styleContent(styleId.substring(idx));
1047
- } while ((idx = styleId.indexOf(' ', idx) + 1) !== 0);
1048
- }
1049
- return styleId || null;
1050
- };
1051
1153
 
1052
1154
  const STORE_TARGET = Symbol('store.target');
1053
1155
  const STORE_HANDLER = Symbol('store.handler');
@@ -1192,8 +1294,12 @@
1192
1294
  return Reflect.ownKeys(target);
1193
1295
  }
1194
1296
  getOwnPropertyDescriptor(target, prop) {
1297
+ const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
1195
1298
  if (Array.isArray(target) || typeof prop === 'symbol') {
1196
- return Object.getOwnPropertyDescriptor(target, prop);
1299
+ return descriptor;
1300
+ }
1301
+ if (descriptor && !descriptor.configurable) {
1302
+ return descriptor;
1197
1303
  }
1198
1304
  return {
1199
1305
  enumerable: true,
@@ -1201,355 +1307,280 @@
1201
1307
  };
1202
1308
  }
1203
1309
  }
1204
- function addEffect(target, prop, store, effectSubscriber) {
1205
- const effectsMap = (store.$effects$ ||= {});
1206
- const effects = (Object.prototype.hasOwnProperty.call(effectsMap, prop) && effectsMap[prop]) ||
1207
- (effectsMap[prop] = []);
1310
+ function addEffect(target, prop, store, effectSubscription) {
1311
+ const effectsMap = (store.$effects$ ||= new Map());
1312
+ let effects = effectsMap.get(prop);
1313
+ if (!effects) {
1314
+ effects = new Set();
1315
+ effectsMap.set(prop, effects);
1316
+ }
1208
1317
  // Let's make sure that we have a reference to this effect.
1209
1318
  // Adding reference is essentially adding a subscription, so if the signal
1210
1319
  // changes we know who to notify.
1211
- ensureContainsEffect(effects, effectSubscriber);
1320
+ ensureContainsSubscription(effects, effectSubscription);
1212
1321
  // But when effect is scheduled in needs to be able to know which signals
1213
1322
  // to unsubscribe from. So we need to store the reference from the effect back
1214
1323
  // to this signal.
1215
- ensureContains(effectSubscriber, target);
1216
- // We need to add the subscriber to the effect so that we can clean it up later
1217
- ensureEffectContainsSubscriber(effectSubscriber[EffectSubscriptionsProp.EFFECT], target, store.$container$);
1324
+ ensureContainsBackRef(effectSubscription, target);
1325
+ addQrlToSerializationCtx(effectSubscription, store.$container$);
1218
1326
  }
1219
1327
  function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
1220
1328
  target[prop] = value;
1221
1329
  triggerEffects(currentStore.$container$, currentStore, getEffects(target, prop, currentStore.$effects$));
1222
1330
  }
1223
1331
  function getEffects(target, prop, storeEffects) {
1224
- let effectsToTrigger = storeEffects
1225
- ? Array.isArray(target)
1226
- ? Object.values(storeEffects).flatMap((effects) => effects)
1227
- : storeEffects[prop]
1228
- : null;
1229
- const storeArrayValue = storeEffects?.[STORE_ARRAY_PROP];
1332
+ let effectsToTrigger;
1333
+ if (storeEffects) {
1334
+ if (Array.isArray(target)) {
1335
+ for (const effects of storeEffects.values()) {
1336
+ effectsToTrigger ||= new Set();
1337
+ for (const effect of effects) {
1338
+ effectsToTrigger.add(effect);
1339
+ }
1340
+ }
1341
+ }
1342
+ else {
1343
+ effectsToTrigger = storeEffects.get(prop);
1344
+ }
1345
+ }
1346
+ const storeArrayValue = storeEffects?.get(STORE_ARRAY_PROP);
1230
1347
  if (storeArrayValue) {
1231
- effectsToTrigger ||= [];
1232
- effectsToTrigger.push(...storeArrayValue);
1348
+ effectsToTrigger ||= new Set();
1349
+ for (const effect of storeArrayValue) {
1350
+ effectsToTrigger.add(effect);
1351
+ }
1233
1352
  }
1234
- return effectsToTrigger;
1353
+ return effectsToTrigger || null;
1235
1354
  }
1236
1355
 
1237
1356
  /**
1238
- * @internal
1239
- * The storage provider for hooks. Each invocation increases index i. Data is stored in an array.
1357
+ * Special value used to mark that a given signal needs to be computed. This is essentially a
1358
+ * "marked as dirty" flag.
1240
1359
  */
1241
- const useSequentialScope = () => {
1242
- const iCtx = useInvokeContext();
1243
- const hostElement = iCtx.$hostElement$;
1244
- const host = hostElement;
1245
- let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
1246
- if (seq === null) {
1247
- seq = [];
1248
- iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
1249
- }
1250
- let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
1251
- if (seqIdx === null) {
1252
- seqIdx = 0;
1253
- }
1254
- iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
1255
- while (seq.length <= seqIdx) {
1256
- seq.push(undefined);
1257
- }
1258
- const set = (value) => {
1259
- if (qDev && qSerialize) {
1260
- verifySerializable(value);
1261
- }
1262
- return (seq[seqIdx] = value);
1263
- };
1264
- return {
1265
- val: seq[seqIdx],
1266
- set,
1267
- i: seqIdx,
1268
- iCtx,
1269
- };
1270
- };
1360
+ const NEEDS_COMPUTATION = Symbol('invalid');
1361
+ /** @internal */
1362
+ const _EFFECT_BACK_REF = Symbol('backRef');
1271
1363
 
1272
- class Subscriber {
1273
- $effectDependencies$ = null;
1364
+ /** Class for back reference to the EffectSubscription */
1365
+ class BackRef {
1366
+ [_EFFECT_BACK_REF] = null;
1274
1367
  }
1275
- function isSubscriber(value) {
1276
- return value instanceof Subscriber || value instanceof WrappedSignal;
1277
- }
1278
- function clearVNodeEffectDependencies(container, value) {
1279
- if (vnode_isElementVNode(value)) {
1280
- ensureMaterialized(value);
1368
+ function clearAllEffects(container, consumer) {
1369
+ if (vnode_isVNode(consumer) && vnode_isElementVNode(consumer)) {
1370
+ ensureMaterialized(consumer);
1281
1371
  }
1282
- const effects = vnode_getProp(value, QSubscribers, container.$getObjectById$);
1372
+ const effects = consumer[_EFFECT_BACK_REF];
1283
1373
  if (!effects) {
1284
1374
  return;
1285
1375
  }
1286
- for (let i = effects.length - 1; i >= 0; i--) {
1287
- const subscriber = effects[i];
1288
- clearEffects(subscriber, value, effects, i, container);
1289
- }
1290
- if (effects.length === 0) {
1291
- vnode_setProp(value, QSubscribers, null);
1292
- }
1293
- }
1294
- function clearSubscriberEffectDependencies(container, value) {
1295
- if (value.$effectDependencies$) {
1296
- for (let i = value.$effectDependencies$.length - 1; i >= 0; i--) {
1297
- const subscriber = value.$effectDependencies$[i];
1298
- clearEffects(subscriber, value, value.$effectDependencies$, i, container);
1299
- }
1300
- if (value.$effectDependencies$.length === 0) {
1301
- value.$effectDependencies$ = null;
1376
+ for (const [, effect] of effects) {
1377
+ const backRefs = effect[EffectSubscriptionProp.BACK_REF];
1378
+ if (!backRefs) {
1379
+ return;
1302
1380
  }
1303
- }
1304
- }
1305
- function clearEffects(subscriber, value, effectArray, indexToRemove, container) {
1306
- let subscriptionRemoved = false;
1307
- const seenSet = new Set();
1308
- if (subscriber instanceof WrappedSignal) {
1309
- subscriptionRemoved = clearSignalEffects(subscriber, value, seenSet);
1310
- }
1311
- else if (container.$storeProxyMap$.has(subscriber)) {
1312
- const store = container.$storeProxyMap$.get(subscriber);
1313
- const handler = getStoreHandler(store);
1314
- subscriptionRemoved = clearStoreEffects(handler, value);
1315
- }
1316
- if (subscriptionRemoved) {
1317
- effectArray.splice(indexToRemove, 1);
1318
- }
1319
- }
1320
- function clearSignalEffects(subscriber, value, seenSet) {
1321
- const effectSubscriptions = subscriber.$effects$;
1322
- let subscriptionRemoved = false;
1323
- if (effectSubscriptions) {
1324
- for (let i = effectSubscriptions.length - 1; i >= 0; i--) {
1325
- const effect = effectSubscriptions[i];
1326
- if (effect[EffectSubscriptionsProp.EFFECT] === value) {
1327
- effectSubscriptions.splice(i, 1);
1328
- subscriptionRemoved = true;
1381
+ for (const producer of backRefs) {
1382
+ if (producer instanceof Signal) {
1383
+ clearSignal(container, producer, effect);
1329
1384
  }
1330
- }
1331
- }
1332
- if (subscriber instanceof WrappedSignal) {
1333
- const hostElement = subscriber.$hostElement$;
1334
- if (hostElement && hostElement === value) {
1335
- subscriber.$hostElement$ = null;
1336
- }
1337
- // clear the effects of the arguments
1338
- const args = subscriber.$args$;
1339
- if (args) {
1340
- clearArgsEffects(args, subscriber, seenSet);
1341
- }
1342
- }
1343
- return subscriptionRemoved;
1344
- }
1345
- function clearStoreEffects(storeHandler, value) {
1346
- const effectSubscriptions = storeHandler.$effects$;
1347
- if (!effectSubscriptions) {
1348
- return false;
1349
- }
1350
- let subscriptionRemoved = false;
1351
- for (const key in effectSubscriptions) {
1352
- const effects = effectSubscriptions[key];
1353
- for (let i = effects.length - 1; i >= 0; i--) {
1354
- const effect = effects[i];
1355
- if (effect[EffectSubscriptionsProp.EFFECT] === value) {
1356
- effects.splice(i, 1);
1357
- subscriptionRemoved = true;
1385
+ else if (container.$storeProxyMap$.has(producer)) {
1386
+ const target = container.$storeProxyMap$.get(producer);
1387
+ const storeHandler = getStoreHandler(target);
1388
+ clearStore(storeHandler, effect);
1358
1389
  }
1359
1390
  }
1360
- if (effects.length === 0) {
1361
- delete effectSubscriptions[key];
1362
- }
1363
- }
1364
- return subscriptionRemoved;
1365
- }
1366
- function clearArgsEffects(args, subscriber, seenSet) {
1367
- for (let i = args.length - 1; i >= 0; i--) {
1368
- const arg = args[i];
1369
- clearArgEffect(arg, subscriber, seenSet);
1370
1391
  }
1371
1392
  }
1372
- function clearArgEffect(arg, subscriber, seenSet) {
1373
- if (seenSet.has(arg)) {
1374
- return;
1393
+ function clearSignal(container, producer, effect) {
1394
+ const effects = producer.$effects$;
1395
+ if (effects) {
1396
+ effects.delete(effect);
1375
1397
  }
1376
- seenSet.add(arg);
1377
- if (isSignal(arg)) {
1378
- clearSignalEffects(arg, subscriber, seenSet);
1398
+ if (producer instanceof WrappedSignal) {
1399
+ producer.$hostElement$ = null;
1400
+ clearAllEffects(container, producer);
1379
1401
  }
1380
- else if (typeof arg === 'object' && arg !== null) {
1381
- if (isStore(arg)) {
1382
- clearStoreEffects(getStoreHandler(arg), subscriber);
1383
- }
1384
- else if (isPropsProxy(arg)) {
1385
- // Separate check for props proxy, because props proxy getter could call signal getter.
1386
- // To avoid that we need to get the constProps and varProps directly
1387
- // from the props proxy object and loop over them.
1388
- const constProps = arg[_CONST_PROPS];
1389
- const varProps = arg[_VAR_PROPS];
1390
- if (constProps) {
1391
- for (const key in constProps) {
1392
- clearArgEffect(constProps[key], subscriber, seenSet);
1393
- }
1394
- }
1395
- for (const key in varProps) {
1396
- clearArgEffect(varProps[key], subscriber, seenSet);
1397
- }
1398
- }
1399
- else {
1400
- for (const key in arg) {
1401
- clearArgEffect(arg[key], subscriber, seenSet);
1402
- }
1402
+ }
1403
+ function clearStore(producer, effect) {
1404
+ const effects = producer?.$effects$;
1405
+ if (effects) {
1406
+ for (const propEffects of effects.values()) {
1407
+ propEffects.delete(effect);
1403
1408
  }
1404
1409
  }
1405
- else if (Array.isArray(arg)) {
1406
- clearArgsEffects(arg, subscriber, seenSet);
1407
- }
1408
- else ;
1409
1410
  }
1410
1411
 
1411
- /** @internal */
1412
- const useResourceQrl = (qrl, opts) => {
1413
- const { val, set, i, iCtx } = useSequentialScope();
1414
- if (val != null) {
1415
- return val;
1416
- }
1417
- assertQrl(qrl);
1418
- const container = iCtx.$container$;
1419
- const resource = createResourceReturn(container, opts);
1420
- const el = iCtx.$hostElement$;
1421
- const task = new Task(TaskFlags.DIRTY | TaskFlags.RESOURCE, i, el, qrl, resource, null);
1422
- runResource(task, container, iCtx.$hostElement$);
1423
- set(resource);
1424
- return resource;
1425
- };
1426
- // <docs markdown="../readme.md#useResource">
1412
+ // <docs markdown="../../readme.md#implicit$FirstArg">
1427
1413
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
1428
- // (edit ../readme.md#useResource instead and run `pnpm docs.sync`)
1414
+ // (edit ../../readme.md#implicit$FirstArg instead and run `pnpm docs.sync`)
1429
1415
  /**
1430
- * This method works like an async memoized function that runs whenever some tracked value changes
1431
- * and returns some data.
1416
+ * Create a `____$(...)` convenience method from `___(...)`.
1432
1417
  *
1433
- * `useResource` however returns immediate a `ResourceReturn` object that contains the data and a
1434
- * state that indicates if the data is available or not.
1418
+ * It is very common for functions to take a lazy-loadable resource as a first argument. For this
1419
+ * reason, the Qwik Optimizer automatically extracts the first argument from any function which ends
1420
+ * in `$`.
1435
1421
  *
1436
- * The status can be one of the following:
1422
+ * This means that `foo$(arg0)` and `foo($(arg0))` are equivalent with respect to Qwik Optimizer.
1423
+ * The former is just a shorthand for the latter.
1437
1424
  *
1438
- * - `pending` - the data is not yet available.
1439
- * - `resolved` - the data is available.
1440
- * - `rejected` - the data is not available due to an error or timeout.
1425
+ * For example, these function calls are equivalent:
1441
1426
  *
1442
- * Be careful when using a `try/catch` statement in `useResource$`. If you catch the error and don't
1443
- * re-throw it (or a new Error), the resource status will never be `rejected`.
1427
+ * - `component$(() => {...})` is same as `component($(() => {...}))`
1444
1428
  *
1445
- * ### Example
1429
+ * ```tsx
1430
+ * export function myApi(callback: QRL<() => void>): void {
1431
+ * // ...
1432
+ * }
1446
1433
  *
1447
- * Example showing how `useResource` to perform a fetch to request the weather, whenever the input
1448
- * city name changes.
1434
+ * export const myApi$ = implicit$FirstArg(myApi);
1435
+ * // type of myApi$: (callback: () => void): void
1449
1436
  *
1450
- * ```tsx
1451
- * const Cmp = component$(() => {
1452
- * const cityS = useSignal('');
1437
+ * // can be used as:
1438
+ * myApi$(() => console.log('callback'));
1453
1439
  *
1454
- * const weatherResource = useResource$(async ({ track, cleanup }) => {
1455
- * const cityName = track(cityS);
1456
- * const abortController = new AbortController();
1457
- * cleanup(() => abortController.abort('cleanup'));
1458
- * const res = await fetch(`http://weatherdata.com?city=${cityName}`, {
1459
- * signal: abortController.signal,
1460
- * });
1461
- * const data = await res.json();
1462
- * return data as { temp: number };
1463
- * });
1440
+ * // will be transpiled to:
1441
+ * // FILE: <current file>
1442
+ * myApi(qrl('./chunk-abc.js', 'callback'));
1464
1443
  *
1465
- * return (
1466
- * <div>
1467
- * <input name="city" bind:value={cityS} />
1468
- * <Resource
1469
- * value={weatherResource}
1470
- * onResolved={(weather) => {
1471
- * return <div>Temperature: {weather.temp}</div>;
1472
- * }}
1473
- * />
1474
- * </div>
1475
- * );
1476
- * });
1444
+ * // FILE: chunk-abc.js
1445
+ * export const callback = () => console.log('callback');
1477
1446
  * ```
1478
1447
  *
1448
+ * @param fn - A function that should have its first argument automatically `$`.
1479
1449
  * @public
1480
- * @see Resource
1481
- * @see ResourceReturn
1482
1450
  */
1483
1451
  // </docs>
1484
- const Resource = (props) => {
1485
- // Resource path
1486
- return _jsxSorted(Fragment, null, null, getResourceValueAsPromise(props), 0, null);
1452
+ const implicit$FirstArg = (fn) => {
1453
+ return function (first, ...rest) {
1454
+ return fn.call(null, dollar(first), ...rest);
1455
+ };
1487
1456
  };
1488
- function getResourceValueAsPromise(props) {
1489
- const resource = props.value;
1490
- if (isResourceReturn(resource)) {
1491
- const isBrowser = !isServerPlatform();
1492
- if (isBrowser) {
1493
- // create a subscription for the resource._state changes
1494
- const state = resource._state;
1495
- if (state === 'pending' && props.onPending) {
1496
- return Promise.resolve().then(useBindInvokeContext(props.onPending));
1497
- }
1498
- else if (state === 'rejected' && props.onRejected) {
1499
- return Promise.resolve(resource._error).then(useBindInvokeContext(props.onRejected));
1500
- }
1501
- else {
1502
- const resolvedValue = untrack(() => resource._resolved);
1503
- if (resolvedValue !== undefined) {
1504
- // resolved, pending without onPending prop or rejected without onRejected prop
1505
- return Promise.resolve(resolvedValue).then(useBindInvokeContext(props.onResolved));
1506
- }
1507
- }
1508
- }
1509
- return resource.value.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
1510
- }
1511
- else if (isPromise(resource)) {
1512
- return resource.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
1457
+
1458
+ const createSignal$1 = (value) => {
1459
+ return new Signal(null, value);
1460
+ };
1461
+ const createComputedSignal = (qrl) => {
1462
+ throwIfQRLNotResolved(qrl);
1463
+ return new ComputedSignal(null, qrl);
1464
+ };
1465
+
1466
+ /**
1467
+ * Creates a Signal with the given value. If no value is given, the signal is created with
1468
+ * `undefined`.
1469
+ *
1470
+ * @public
1471
+ */
1472
+ const createSignal = createSignal$1;
1473
+ /** @internal */
1474
+ const createComputedQrl = createComputedSignal;
1475
+ /**
1476
+ * Create a computed signal which is calculated from the given QRL. A computed signal is a signal
1477
+ * which is calculated from other signals. When the signals change, the computed signal is
1478
+ * recalculated.
1479
+ *
1480
+ * The QRL must be a function which returns the value of the signal. The function must not have side
1481
+ * effects, and it mus be synchronous.
1482
+ *
1483
+ * If you need the function to be async, use `useSignal` and `useTask$` instead.
1484
+ *
1485
+ * @public
1486
+ */
1487
+ const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedQrl);
1488
+
1489
+ /**
1490
+ * @internal
1491
+ * The storage provider for hooks. Each invocation increases index i. Data is stored in an array.
1492
+ */
1493
+ const useSequentialScope = () => {
1494
+ const iCtx = useInvokeContext();
1495
+ const hostElement = iCtx.$hostElement$;
1496
+ const host = hostElement;
1497
+ let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
1498
+ if (seq === null) {
1499
+ seq = [];
1500
+ iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
1513
1501
  }
1514
- else if (isSignal(resource)) {
1515
- return Promise.resolve(resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
1502
+ let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
1503
+ if (seqIdx === null) {
1504
+ seqIdx = 0;
1516
1505
  }
1517
- else {
1518
- return Promise.resolve(resource).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
1506
+ iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
1507
+ while (seq.length <= seqIdx) {
1508
+ seq.push(undefined);
1519
1509
  }
1520
- }
1521
- const _createResourceReturn = (opts) => {
1522
- const resource = {
1523
- __brand: 'resource',
1524
- value: undefined,
1525
- loading: isServerPlatform() ? false : true,
1526
- _resolved: undefined,
1527
- _error: undefined,
1528
- _state: 'pending',
1529
- _timeout: opts?.timeout ?? -1,
1530
- _cache: 0,
1510
+ const set = (value) => {
1511
+ if (qDev && qSerialize) {
1512
+ verifySerializable(value);
1513
+ }
1514
+ return (seq[seqIdx] = value);
1515
+ };
1516
+ return {
1517
+ val: seq[seqIdx],
1518
+ set,
1519
+ i: seqIdx,
1520
+ iCtx,
1531
1521
  };
1532
- return resource;
1533
- };
1534
- const createResourceReturn = (container, opts, initialPromise) => {
1535
- const result = _createResourceReturn(opts);
1536
- result.value = initialPromise;
1537
- return createStore(container, result, StoreFlags.RECURSIVE);
1538
1522
  };
1539
- const isResourceReturn = (obj) => {
1540
- return isObject(obj) && (getStoreTarget(obj) || obj).__brand === 'resource';
1523
+
1524
+ function getSubscriber(effect, prop, data) {
1525
+ if (!effect[_EFFECT_BACK_REF]) {
1526
+ if (build.isServer && isSsrNode(effect)) {
1527
+ effect.setProp(QBackRefs, new Map());
1528
+ }
1529
+ else {
1530
+ effect[_EFFECT_BACK_REF] = new Map();
1531
+ }
1532
+ }
1533
+ const subMap = effect[_EFFECT_BACK_REF];
1534
+ let sub = subMap.get(prop);
1535
+ if (!sub) {
1536
+ sub = [effect, prop];
1537
+ subMap.set(prop, sub);
1538
+ }
1539
+ if (data) {
1540
+ sub[EffectSubscriptionProp.DATA] = data;
1541
+ }
1542
+ return sub;
1543
+ }
1544
+ function isSsrNode(value) {
1545
+ return '__brand__' in value && 'currentComponentNode' in value;
1546
+ }
1547
+
1548
+ var TaskFlags;
1549
+ (function (TaskFlags) {
1550
+ TaskFlags[TaskFlags["VISIBLE_TASK"] = 1] = "VISIBLE_TASK";
1551
+ TaskFlags[TaskFlags["TASK"] = 2] = "TASK";
1552
+ TaskFlags[TaskFlags["RESOURCE"] = 4] = "RESOURCE";
1553
+ TaskFlags[TaskFlags["DIRTY"] = 8] = "DIRTY";
1554
+ })(TaskFlags || (TaskFlags = {}));
1555
+ /** @internal */
1556
+ const useTaskQrl = (qrl) => {
1557
+ const { val, set, iCtx, i } = useSequentialScope();
1558
+ if (val) {
1559
+ return;
1560
+ }
1561
+ assertQrl(qrl);
1562
+ set(1);
1563
+ const task = new Task(TaskFlags.DIRTY | TaskFlags.TASK, i, iCtx.$hostElement$, qrl, undefined, null);
1564
+ // In V2 we add the task to the sequential scope. We need to do this
1565
+ // in order to be able to retrieve it later when the parent element is
1566
+ // deleted and we need to be able to release the task subscriptions.
1567
+ set(task);
1568
+ const container = iCtx.$container$;
1569
+ const promise = container.$scheduler$(ChoreType.TASK, task);
1570
+ if (isPromise(promise)) {
1571
+ // TODO: should we handle this differently?
1572
+ promise.catch(() => { });
1573
+ }
1541
1574
  };
1542
- const runResource = (task, container, host) => {
1575
+ const runTask = (task, container, host) => {
1543
1576
  task.$flags$ &= ~TaskFlags.DIRTY;
1544
1577
  cleanupTask(task);
1545
- const iCtx = newInvokeContext(container.$locale$, host, undefined, ResourceEvent);
1578
+ const iCtx = newInvokeContext(container.$locale$, host, undefined, TaskEvent);
1546
1579
  iCtx.$container$ = container;
1547
- const taskFn = task.$qrl$.getFn(iCtx, () => clearSubscriberEffectDependencies(container, task));
1548
- const resource = task.$state$;
1549
- assertDefined(resource, 'useResource: when running a resource, "task.resource" must be a defined.', task);
1580
+ const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
1550
1581
  const track = (obj, prop) => {
1551
1582
  const ctx = newInvokeContext();
1552
- ctx.$effectSubscriber$ = [task, EffectProperty.COMPONENT];
1583
+ ctx.$effectSubscriber$ = getSubscriber(task, EffectProperty.COMPONENT);
1553
1584
  ctx.$container$ = container;
1554
1585
  return invoke(ctx, () => {
1555
1586
  if (isFunction(obj)) {
@@ -1562,115 +1593,85 @@
1562
1593
  return obj.value;
1563
1594
  }
1564
1595
  else {
1565
- return obj;
1596
+ throw qError(QError.trackObjectWithoutProp);
1566
1597
  }
1567
1598
  });
1568
1599
  };
1569
1600
  const handleError = (reason) => container.handleError(reason, host);
1570
- const cleanups = [];
1571
- task.$destroy$ = noSerialize(() => {
1572
- cleanups.forEach((fn) => {
1573
- try {
1574
- fn();
1575
- }
1576
- catch (err) {
1577
- handleError(err);
1601
+ let cleanupFns = null;
1602
+ const cleanup = (fn) => {
1603
+ if (typeof fn == 'function') {
1604
+ if (!cleanupFns) {
1605
+ cleanupFns = [];
1606
+ task.$destroy$ = noSerialize(() => {
1607
+ task.$destroy$ = null;
1608
+ cleanupFns.forEach((fn) => {
1609
+ try {
1610
+ fn();
1611
+ }
1612
+ catch (err) {
1613
+ handleError(err);
1614
+ }
1615
+ });
1616
+ });
1578
1617
  }
1579
- });
1580
- done = true;
1618
+ cleanupFns.push(fn);
1619
+ }
1620
+ };
1621
+ const taskApi = { track, cleanup };
1622
+ const result = safeCall(() => taskFn(taskApi), cleanup, (err) => {
1623
+ // If a Promise is thrown, that means we need to re-run the task.
1624
+ if (isPromise(err)) {
1625
+ return err.then(() => runTask(task, container, host));
1626
+ }
1627
+ else {
1628
+ throw err;
1629
+ }
1581
1630
  });
1582
- const resourceTarget = unwrapStore(resource);
1583
- const opts = {
1584
- track,
1585
- cleanup(fn) {
1586
- if (typeof fn === 'function') {
1587
- cleanups.push(fn);
1588
- }
1589
- },
1590
- cache(policy) {
1591
- let milliseconds = 0;
1592
- if (policy === 'immutable') {
1593
- milliseconds = Infinity;
1594
- }
1595
- else {
1596
- milliseconds = policy;
1597
- }
1598
- resource._cache = milliseconds;
1599
- },
1600
- previous: resourceTarget._resolved,
1601
- };
1602
- let resolve;
1603
- let reject;
1604
- let done = false;
1605
- const setState = (resolved, value) => {
1606
- if (!done) {
1607
- done = true;
1608
- if (resolved) {
1609
- done = true;
1610
- resource.loading = false;
1611
- resource._state = 'resolved';
1612
- resource._resolved = value;
1613
- resource._error = undefined;
1614
- resolve(value);
1615
- }
1616
- else {
1617
- done = true;
1618
- resource.loading = false;
1619
- resource._state = 'rejected';
1620
- resource._error = value;
1621
- reject(value);
1622
- }
1623
- return true;
1624
- }
1625
- return false;
1626
- };
1627
- /**
1628
- * Add cleanup to resolve the resource if we are trying to run the same resource again while the
1629
- * previous one is not resolved yet. The next `runResource` run will call this cleanup
1630
- */
1631
- cleanups.push(() => {
1632
- if (untrack(() => resource.loading) === true) {
1633
- const value = untrack(() => resource._resolved);
1634
- setState(true, value);
1635
- }
1636
- });
1637
- // Execute mutation inside empty invocation
1638
- invoke(iCtx, () => {
1639
- // console.log('RESOURCE.pending: ');
1640
- resource._state = 'pending';
1641
- resource.loading = !isServerPlatform();
1642
- const promise = (resource.value = new Promise((r, re) => {
1643
- resolve = r;
1644
- reject = re;
1645
- }));
1646
- promise.catch(ignoreErrorToPreventNodeFromCrashing);
1647
- });
1648
- const promise = safeCall(() => Promise.resolve(taskFn(opts)), (value) => {
1649
- setState(true, value);
1650
- }, (err) => {
1651
- if (isPromise(err)) {
1652
- return err.then(() => runResource(task, container, host));
1631
+ return result;
1632
+ };
1633
+ const cleanupTask = (task) => {
1634
+ const destroy = task.$destroy$;
1635
+ if (destroy) {
1636
+ task.$destroy$ = null;
1637
+ try {
1638
+ destroy();
1653
1639
  }
1654
- else {
1655
- setState(false, err);
1640
+ catch (err) {
1641
+ logError(err);
1656
1642
  }
1657
- });
1658
- const timeout = resourceTarget._timeout;
1659
- if (timeout > 0) {
1660
- return Promise.race([
1661
- promise,
1662
- delay(timeout).then(() => {
1663
- if (setState(false, new Error('timeout'))) {
1664
- cleanupTask(task);
1665
- }
1666
- }),
1667
- ]);
1668
1643
  }
1669
- return promise;
1670
1644
  };
1671
- const ignoreErrorToPreventNodeFromCrashing = (err) => {
1672
- // ignore error to prevent node from crashing
1673
- // node will crash in promise is rejected and no one is listening to the rejection.
1645
+ class Task extends BackRef {
1646
+ $flags$;
1647
+ $index$;
1648
+ $el$;
1649
+ $qrl$;
1650
+ $state$;
1651
+ $destroy$;
1652
+ constructor($flags$, $index$, $el$, $qrl$, $state$, $destroy$) {
1653
+ super();
1654
+ this.$flags$ = $flags$;
1655
+ this.$index$ = $index$;
1656
+ this.$el$ = $el$;
1657
+ this.$qrl$ = $qrl$;
1658
+ this.$state$ = $state$;
1659
+ this.$destroy$ = $destroy$;
1660
+ }
1661
+ }
1662
+ const isTask = (value) => {
1663
+ return value instanceof Task;
1664
+ };
1665
+ /**
1666
+ * Used internally as a qrl event handler to schedule a task.
1667
+ *
1668
+ * @internal
1669
+ */
1670
+ const scheduleTask = (_event, element) => {
1671
+ const [task] = useLexicalScope();
1672
+ const type = task.$flags$ & TaskFlags.VISIBLE_TASK ? ChoreType.VISIBLE : ChoreType.TASK;
1673
+ const container = getDomContainer(element);
1674
+ container.$scheduler$(type, task);
1674
1675
  };
1675
1676
 
1676
1677
  /** @file Public types for the client deserialization */
@@ -1748,22 +1749,67 @@
1748
1749
  VirtualVNodeProps[VirtualVNodeProps["PROPS_OFFSET"] = 6] = "PROPS_OFFSET";
1749
1750
  })(VirtualVNodeProps || (VirtualVNodeProps = {}));
1750
1751
 
1751
- const isForeignObjectElement = (elementName) => elementName.toLowerCase() === 'foreignobject';
1752
+ const mapApp_findIndx = (elementVNode, key, start) => {
1753
+ assertTrue(start % 2 === 0, 'Expecting even number.');
1754
+ let bottom = start >> 1;
1755
+ let top = (elementVNode.length - 2) >> 1;
1756
+ while (bottom <= top) {
1757
+ const mid = bottom + ((top - bottom) >> 1);
1758
+ const midKey = elementVNode[mid << 1];
1759
+ if (midKey === key) {
1760
+ return mid << 1;
1761
+ }
1762
+ if (midKey < key) {
1763
+ bottom = mid + 1;
1764
+ }
1765
+ else {
1766
+ top = mid - 1;
1767
+ }
1768
+ }
1769
+ return (bottom << 1) ^ -1;
1770
+ };
1771
+ const mapArray_set = (elementVNode, key, value, start) => {
1772
+ const indx = mapApp_findIndx(elementVNode, key, start);
1773
+ if (indx >= 0) {
1774
+ if (value == null) {
1775
+ elementVNode.splice(indx, 2);
1776
+ }
1777
+ else {
1778
+ elementVNode[indx + 1] = value;
1779
+ }
1780
+ }
1781
+ else if (value != null) {
1782
+ elementVNode.splice(indx ^ -1, 0, key, value);
1783
+ }
1784
+ };
1785
+ const mapArray_get = (elementVNode, key, start) => {
1786
+ const indx = mapApp_findIndx(elementVNode, key, start);
1787
+ if (indx >= 0) {
1788
+ return elementVNode[indx + 1];
1789
+ }
1790
+ else {
1791
+ return null;
1792
+ }
1793
+ };
1794
+
1795
+ const isForeignObjectElement = (elementName) => {
1796
+ return build.isDev ? elementName.toLowerCase() === 'foreignobject' : elementName === 'foreignObject';
1797
+ };
1752
1798
  const isSvgElement = (elementName) => elementName === 'svg' || isForeignObjectElement(elementName);
1753
1799
  const isMathElement = (elementName) => elementName === 'math';
1754
1800
  const vnode_isDefaultNamespace = (vnode) => {
1755
1801
  const flags = vnode[VNodeProps.flags];
1756
1802
  return (flags & VNodeFlags.NAMESPACE_MASK) === 0;
1757
1803
  };
1758
- const vnode_getElementNamespaceFlags = (elementName) => {
1759
- if (isSvgElement(elementName)) {
1760
- return VNodeFlags.NS_svg;
1761
- }
1762
- else if (isMathElement(elementName)) {
1763
- return VNodeFlags.NS_math;
1764
- }
1765
- else {
1766
- return VNodeFlags.NS_html;
1804
+ const vnode_getElementNamespaceFlags = (element) => {
1805
+ const namespace = fastNamespaceURI(element);
1806
+ switch (namespace) {
1807
+ case SVG_NS:
1808
+ return VNodeFlags.NS_svg;
1809
+ case MATH_NS:
1810
+ return VNodeFlags.NS_math;
1811
+ default:
1812
+ return VNodeFlags.NS_html;
1767
1813
  }
1768
1814
  };
1769
1815
  function vnode_getDomChildrenWithCorrectNamespacesToInsert(journal, domParentVNode, newChild) {
@@ -2117,19 +2163,21 @@
2117
2163
  * @returns
2118
2164
  */
2119
2165
  const executeComponent = (container, renderHost, subscriptionHost, componentQRL, props) => {
2120
- const iCtx = newInvokeContext(container.$locale$, subscriptionHost, undefined, RenderEvent);
2121
- iCtx.$effectSubscriber$ = [subscriptionHost, EffectProperty.COMPONENT];
2122
- iCtx.$container$ = container;
2166
+ const iCtx = newInvokeContext(container.$locale$, subscriptionHost || undefined, undefined, RenderEvent);
2167
+ if (subscriptionHost) {
2168
+ iCtx.$effectSubscriber$ = getSubscriber(subscriptionHost, EffectProperty.COMPONENT);
2169
+ iCtx.$container$ = container;
2170
+ }
2123
2171
  let componentFn;
2124
2172
  container.ensureProjectionResolved(renderHost);
2125
2173
  let isInlineComponent = false;
2126
2174
  if (componentQRL === null) {
2127
- componentQRL = componentQRL || container.getHostProp(renderHost, OnRenderProp);
2175
+ componentQRL = container.getHostProp(renderHost, OnRenderProp);
2128
2176
  assertDefined(componentQRL, 'No Component found at this location');
2129
2177
  }
2130
- if (isQrl(componentQRL)) {
2178
+ if (isQrl$1(componentQRL)) {
2131
2179
  props = props || container.getHostProp(renderHost, ELEMENT_PROPS) || EMPTY_OBJ;
2132
- if (props && props.children) {
2180
+ if (props.children) {
2133
2181
  delete props.children;
2134
2182
  }
2135
2183
  componentFn = componentQRL.getFn(iCtx);
@@ -2147,18 +2195,16 @@
2147
2195
  if (!isInlineComponent) {
2148
2196
  container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
2149
2197
  container.setHostProp(renderHost, USE_ON_LOCAL_SEQ_IDX, null);
2150
- if (container.getHostProp(renderHost, ELEMENT_PROPS) !== props) {
2151
- container.setHostProp(renderHost, ELEMENT_PROPS, props);
2152
- }
2198
+ container.setHostProp(renderHost, ELEMENT_PROPS, props);
2153
2199
  }
2154
2200
  if (vnode_isVNode(renderHost)) {
2155
- clearVNodeEffectDependencies(container, renderHost);
2201
+ clearAllEffects(container, renderHost);
2156
2202
  }
2157
2203
  return componentFn(props);
2158
2204
  }, (jsx) => {
2159
2205
  const useOnEvents = container.getHostProp(renderHost, USE_ON_LOCAL);
2160
2206
  if (useOnEvents) {
2161
- return maybeThen(addUseOnEvents(jsx, useOnEvents), () => jsx);
2207
+ return addUseOnEvents(jsx, useOnEvents);
2162
2208
  }
2163
2209
  return jsx;
2164
2210
  }, (err) => {
@@ -2184,6 +2230,7 @@
2184
2230
  */
2185
2231
  function addUseOnEvents(jsx, useOnEvents) {
2186
2232
  const jsxElement = findFirstStringJSX(jsx);
2233
+ let jsxResult = jsx;
2187
2234
  return maybeThen(jsxElement, (jsxElement) => {
2188
2235
  let isInvisibleComponent = false;
2189
2236
  if (!jsxElement) {
@@ -2202,13 +2249,15 @@
2202
2249
  if (Object.prototype.hasOwnProperty.call(useOnEvents, key)) {
2203
2250
  if (isInvisibleComponent) {
2204
2251
  if (key === 'onQvisible$') {
2205
- jsxElement = addScriptNodeForInvisibleComponents(jsx);
2252
+ const [jsxElement, jsx] = addScriptNodeForInvisibleComponents(jsxResult);
2253
+ jsxResult = jsx;
2206
2254
  if (jsxElement) {
2207
2255
  addUseOnEvent(jsxElement, 'document:onQinit$', useOnEvents[key]);
2208
2256
  }
2209
2257
  }
2210
2258
  else if (key.startsWith('document:') || key.startsWith('window:')) {
2211
- jsxElement = addScriptNodeForInvisibleComponents(jsx);
2259
+ const [jsxElement, jsx] = addScriptNodeForInvisibleComponents(jsxResult);
2260
+ jsxResult = jsx;
2212
2261
  if (jsxElement) {
2213
2262
  addUseOnEvent(jsxElement, key, useOnEvents[key]);
2214
2263
  }
@@ -2226,7 +2275,7 @@
2226
2275
  }
2227
2276
  }
2228
2277
  }
2229
- return jsxElement;
2278
+ return jsxResult;
2230
2279
  });
2231
2280
  }
2232
2281
  function addUseOnEvent(jsxElement, key, value) {
@@ -2272,6 +2321,9 @@
2272
2321
  type: 'placeholder',
2273
2322
  hidden: '',
2274
2323
  }, null, 3);
2324
+ if (jsx.type === Slot) {
2325
+ return [jsxElement, _jsxSorted(Fragment, null, null, [jsx, jsxElement], 0, null)];
2326
+ }
2275
2327
  if (jsx.children == null) {
2276
2328
  jsx.children = jsxElement;
2277
2329
  }
@@ -2281,15 +2333,23 @@
2281
2333
  else {
2282
2334
  jsx.children = [jsx.children, jsxElement];
2283
2335
  }
2284
- return jsxElement;
2336
+ return [jsxElement, jsx];
2285
2337
  }
2286
2338
  else if (Array.isArray(jsx) && jsx.length) {
2287
2339
  // get first element
2288
- return addScriptNodeForInvisibleComponents(jsx[0]);
2340
+ const [jsxElement, _] = addScriptNodeForInvisibleComponents(jsx[0]);
2341
+ return [jsxElement, jsx];
2289
2342
  }
2290
- return null;
2343
+ return [null, null];
2291
2344
  }
2292
2345
 
2346
+ /** @internal */
2347
+ const _CONST_PROPS = Symbol('CONST');
2348
+ /** @internal */
2349
+ const _VAR_PROPS = Symbol('VAR');
2350
+ /** @internal @deprecated v1 compat */
2351
+ const _IMMUTABLE = Symbol('IMMUTABLE');
2352
+
2293
2353
  function isSlotProp(prop) {
2294
2354
  return !prop.startsWith('q:') && !prop.startsWith(NON_SERIALIZABLE_MARKER_PREFIX);
2295
2355
  }
@@ -2298,12 +2358,24 @@
2298
2358
  }
2299
2359
  /** @internal */
2300
2360
  const _restProps = (props, omit, target = {}) => {
2301
- for (const key in props) {
2361
+ let constPropsTarget = null;
2362
+ const constProps = props[_CONST_PROPS];
2363
+ if (constProps) {
2364
+ for (const key in constProps) {
2365
+ if (!omit.includes(key)) {
2366
+ constPropsTarget ||= {};
2367
+ constPropsTarget[key] = constProps[key];
2368
+ }
2369
+ }
2370
+ }
2371
+ const varPropsTarget = target;
2372
+ const varProps = props[_VAR_PROPS];
2373
+ for (const key in varProps) {
2302
2374
  if (!omit.includes(key)) {
2303
- target[key] = props[key];
2375
+ varPropsTarget[key] = varProps[key];
2304
2376
  }
2305
2377
  }
2306
- return target;
2378
+ return createPropsProxy(varPropsTarget, constPropsTarget);
2307
2379
  };
2308
2380
 
2309
2381
  function escapeHTML(html) {
@@ -2345,17 +2417,6 @@
2345
2417
  }
2346
2418
  }
2347
2419
 
2348
- function getFileLocationFromJsx(jsxDev) {
2349
- if (!jsxDev) {
2350
- return null;
2351
- }
2352
- const sanitizedFileName = jsxDev.fileName?.replace(/\\/g, '/');
2353
- if (sanitizedFileName) {
2354
- return `${sanitizedFileName}:${jsxDev.lineNumber}:${jsxDev.columnNumber}`;
2355
- }
2356
- return null;
2357
- }
2358
-
2359
2420
  const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
2360
2421
  let journal = container.$journal$;
2361
2422
  /**
@@ -2374,9 +2435,9 @@
2374
2435
  /// (Node can be null, if we are at the end of the list.)
2375
2436
  let vCurrent = null;
2376
2437
  /// When we insert new node we start it here so that we can descend into it.
2377
- /// NOTE: it can't be stored in `vCurrent` because `vNewCurrent` is in journal
2438
+ /// NOTE: it can't be stored in `vCurrent` because `vNewNode` is in journal
2378
2439
  /// and is not connected to the tree.
2379
- let vNewNode = null; // TODO: delete, because journal is on vNode, the above comment no longer applies
2440
+ let vNewNode = null;
2380
2441
  /// When elements have keys they can be consumed out of order and therefore we can't use nextSibling.
2381
2442
  /// In such a case this array will contain the elements after the current location.
2382
2443
  /// The array even indices will contains keys and odd indices the vNode.
@@ -2429,7 +2490,7 @@
2429
2490
  }
2430
2491
  else if (isSignal(jsxValue)) {
2431
2492
  if (vCurrent) {
2432
- clearVNodeEffectDependencies(container, vCurrent);
2493
+ clearAllEffects(container, vCurrent);
2433
2494
  }
2434
2495
  expectVirtual(VirtualType.WrappedSignal, null);
2435
2496
  descend(trackSignalAndAssignHost(jsxValue, (vNewNode || vCurrent), EffectProperty.VNODE, container), true);
@@ -2644,9 +2705,10 @@
2644
2705
  };
2645
2706
  const projections = [];
2646
2707
  if (host) {
2708
+ const props = vnode_getProps(host);
2647
2709
  // we need to create empty projections for all the slots to remove unused slots content
2648
- for (let i = vnode_getPropStartIndex(host); i < host.length; i = i + 2) {
2649
- const prop = host[i];
2710
+ for (let i = 0; i < props.length; i = i + 2) {
2711
+ const prop = props[i];
2650
2712
  if (isSlotProp(prop)) {
2651
2713
  const slotName = prop;
2652
2714
  projections.push(slotName);
@@ -2814,10 +2876,19 @@
2814
2876
  // But we need to mark them so that they don't get pulled into the diff.
2815
2877
  const eventName = getEventNameFromJsxProp(key);
2816
2878
  const scope = getEventNameScopeFromJsxProp(key);
2817
- vnode_setProp(vNewNode, HANDLER_PREFIX + ':' + scope + ':' + eventName, value);
2818
2879
  if (eventName) {
2880
+ vnode_setProp(vNewNode, HANDLER_PREFIX + ':' + scope + ':' + eventName, value);
2819
2881
  registerQwikLoaderEvent(eventName);
2820
2882
  }
2883
+ if (scope) {
2884
+ // add an event attr with empty value for qwikloader element selector.
2885
+ // We don't need value here. For ssr this value is a QRL,
2886
+ // but for CSR value should be just empty
2887
+ const htmlEvent = convertEventNameFromJsxPropToHtmlAttr(key);
2888
+ if (htmlEvent) {
2889
+ vnode_setAttr(journal, vNewNode, htmlEvent, '');
2890
+ }
2891
+ }
2821
2892
  needsQDispatchEventPatch = true;
2822
2893
  continue;
2823
2894
  }
@@ -2830,12 +2901,15 @@
2830
2901
  value(element);
2831
2902
  continue;
2832
2903
  }
2904
+ else if (value == null) {
2905
+ continue;
2906
+ }
2833
2907
  else {
2834
2908
  throw qError(QError.invalidRefValue, [currentFile]);
2835
2909
  }
2836
2910
  }
2837
2911
  if (isSignal(value)) {
2838
- const signalData = new EffectPropData({
2912
+ const signalData = new SubscriptionData({
2839
2913
  $scopedStyleIdPrefix$: scopedStyleIdPrefix,
2840
2914
  $isConst$: true,
2841
2915
  });
@@ -2939,7 +3013,7 @@
2939
3013
  let returnValue = false;
2940
3014
  qrls.flat(2).forEach((qrl) => {
2941
3015
  if (qrl) {
2942
- const value = qrl(event, element);
3016
+ const value = container.$scheduler$(ChoreType.RUN_QRL, vNode, qrl, [event, element]);
2943
3017
  returnValue = returnValue || value === true;
2944
3018
  }
2945
3019
  });
@@ -2951,10 +3025,10 @@
2951
3025
  /** @param tag Returns true if `qDispatchEvent` needs patching */
2952
3026
  function setBulkProps(vnode, srcAttrs, currentFile) {
2953
3027
  vnode_ensureElementInflated(vnode);
2954
- const dstAttrs = vnode;
3028
+ const dstAttrs = vnode_getProps(vnode);
2955
3029
  let srcIdx = 0;
2956
3030
  const srcLength = srcAttrs.length;
2957
- let dstIdx = ElementVNodeProps.PROPS_OFFSET;
3031
+ let dstIdx = 0;
2958
3032
  let dstLength = dstAttrs.length;
2959
3033
  let srcKey = srcIdx < srcLength ? srcAttrs[srcIdx++] : null;
2960
3034
  let dstKey = dstIdx < dstLength ? dstAttrs[dstIdx++] : null;
@@ -2974,12 +3048,15 @@
2974
3048
  value(element);
2975
3049
  return;
2976
3050
  }
3051
+ else if (value == null) {
3052
+ return;
3053
+ }
2977
3054
  else {
2978
3055
  throw qError(QError.invalidRefValue, [currentFile]);
2979
3056
  }
2980
3057
  }
2981
3058
  if (isSignal(value)) {
2982
- const signalData = new EffectPropData({
3059
+ const signalData = new SubscriptionData({
2983
3060
  $scopedStyleIdPrefix$: scopedStyleIdPrefix,
2984
3061
  $isConst$: false,
2985
3062
  });
@@ -2993,21 +3070,21 @@
2993
3070
  };
2994
3071
  const recordJsxEvent = (key, value) => {
2995
3072
  const eventName = getEventNameFromJsxProp(key);
3073
+ const scope = getEventNameScopeFromJsxProp(key);
2996
3074
  if (eventName) {
2997
- const scope = getEventNameScopeFromJsxProp(key);
2998
3075
  record(':' + scope + ':' + eventName, value);
2999
- }
3000
- // add an event attr with empty value for qwikloader element selector.
3001
- // We don't need value here. For ssr this value is a QRL,
3002
- // but for CSR value should be just empty
3003
- const htmlEvent = convertEventNameFromJsxPropToHtmlAttr(key);
3004
- if (htmlEvent) {
3005
- record(htmlEvent, '');
3006
- }
3007
- // register an event for qwik loader
3008
- if (eventName) {
3076
+ // register an event for qwik loader
3009
3077
  registerQwikLoaderEvent(eventName);
3010
3078
  }
3079
+ if (scope) {
3080
+ // add an event attr with empty value for qwikloader element selector.
3081
+ // We don't need value here. For ssr this value is a QRL,
3082
+ // but for CSR value should be just empty
3083
+ const htmlEvent = convertEventNameFromJsxPropToHtmlAttr(key);
3084
+ if (htmlEvent) {
3085
+ record(htmlEvent, '');
3086
+ }
3087
+ }
3011
3088
  };
3012
3089
  while (srcKey !== null || dstKey !== null) {
3013
3090
  if (dstKey?.startsWith(HANDLER_PREFIX) || dstKey?.startsWith(Q_PREFIX)) {
@@ -3203,10 +3280,6 @@
3203
3280
  else if (!hashesAreEqual) {
3204
3281
  insertNewComponent(host, componentQRL, jsxProps);
3205
3282
  if (vNewNode) {
3206
- if (host) {
3207
- // TODO(varixo): not sure why we need to copy flags here.
3208
- vNewNode[VNodeProps.flags] = host[VNodeProps.flags];
3209
- }
3210
3283
  host = vNewNode;
3211
3284
  shouldRender = true;
3212
3285
  }
@@ -3259,7 +3332,7 @@
3259
3332
  }
3260
3333
  function insertNewComponent(host, componentQRL, jsxProps) {
3261
3334
  if (host) {
3262
- clearVNodeEffectDependencies(container, host);
3335
+ clearAllEffects(container, host);
3263
3336
  }
3264
3337
  vnode_insertBefore(journal, vParent, (vNewNode = vnode_newVirtual()), vCurrent && getInsertBefore());
3265
3338
  const jsxNode = jsxValue;
@@ -3347,8 +3420,8 @@
3347
3420
  if (!src || !dst) {
3348
3421
  return true;
3349
3422
  }
3350
- let srcKeys = removePropsKeys(Object.keys(src), ['children', QSubscribers]);
3351
- let dstKeys = removePropsKeys(Object.keys(dst), ['children', QSubscribers]);
3423
+ let srcKeys = removePropsKeys(Object.keys(src), ['children', QBackRefs]);
3424
+ let dstKeys = removePropsKeys(Object.keys(dst), ['children', QBackRefs]);
3352
3425
  if (srcKeys.length !== dstKeys.length) {
3353
3426
  return true;
3354
3427
  }
@@ -3394,7 +3467,7 @@
3394
3467
  do {
3395
3468
  const type = vCursor[VNodeProps.flags];
3396
3469
  if (type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) {
3397
- clearVNodeEffectDependencies(container, vCursor);
3470
+ clearAllEffects(container, vCursor);
3398
3471
  markVNodeAsDeleted(vCursor);
3399
3472
  // Only elements and virtual nodes need to be traversed for children
3400
3473
  if (type & VNodeFlags.Virtual) {
@@ -3404,7 +3477,7 @@
3404
3477
  const obj = seq[i];
3405
3478
  if (isTask(obj)) {
3406
3479
  const task = obj;
3407
- clearSubscriberEffectDependencies(container, task);
3480
+ clearAllEffects(container, task);
3408
3481
  if (task.$flags$ & TaskFlags.VISIBLE_TASK) {
3409
3482
  container.$scheduler$(ChoreType.CLEANUP_VISIBLE, task);
3410
3483
  }
@@ -3419,8 +3492,8 @@
3419
3492
  vnode_getProp(vCursor, OnRenderProp, null) !== null;
3420
3493
  if (isComponent) {
3421
3494
  // SPECIAL CASE: If we are a component, we need to descend into the projected content and release the content.
3422
- const attrs = vCursor;
3423
- for (let i = VirtualVNodeProps.PROPS_OFFSET; i < attrs.length; i = i + 2) {
3495
+ const attrs = vnode_getProps(vCursor);
3496
+ for (let i = 0; i < attrs.length; i = i + 2) {
3424
3497
  const key = attrs[i];
3425
3498
  if (!isParentSlotProp(key) && isSlotProp(key)) {
3426
3499
  const value = attrs[i + 1];
@@ -3528,82 +3601,270 @@
3528
3601
  SiblingsArray[SiblingsArray["NextVNode"] = 5] = "NextVNode";
3529
3602
  })(SiblingsArray || (SiblingsArray = {}));
3530
3603
 
3531
- // <docs markdown="../../readme.md#implicit$FirstArg">
3604
+ /** @internal */
3605
+ const useResourceQrl = (qrl, opts) => {
3606
+ const { val, set, i, iCtx } = useSequentialScope();
3607
+ if (val != null) {
3608
+ return val;
3609
+ }
3610
+ assertQrl(qrl);
3611
+ const container = iCtx.$container$;
3612
+ const resource = createResourceReturn(container, opts);
3613
+ const el = iCtx.$hostElement$;
3614
+ const task = new Task(TaskFlags.DIRTY | TaskFlags.RESOURCE, i, el, qrl, resource, null);
3615
+ container.$scheduler$(ChoreType.TASK, task);
3616
+ set(resource);
3617
+ return resource;
3618
+ };
3619
+ // <docs markdown="../readme.md#useResource">
3532
3620
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
3533
- // (edit ../../readme.md#implicit$FirstArg instead and run `pnpm docs.sync`)
3621
+ // (edit ../readme.md#useResource instead and run `pnpm docs.sync`)
3534
3622
  /**
3535
- * Create a `____$(...)` convenience method from `___(...)`.
3623
+ * This method works like an async memoized function that runs whenever some tracked value changes
3624
+ * and returns some data.
3536
3625
  *
3537
- * It is very common for functions to take a lazy-loadable resource as a first argument. For this
3538
- * reason, the Qwik Optimizer automatically extracts the first argument from any function which ends
3539
- * in `$`.
3626
+ * `useResource` however returns immediate a `ResourceReturn` object that contains the data and a
3627
+ * state that indicates if the data is available or not.
3540
3628
  *
3541
- * This means that `foo$(arg0)` and `foo($(arg0))` are equivalent with respect to Qwik Optimizer.
3542
- * The former is just a shorthand for the latter.
3629
+ * The status can be one of the following:
3543
3630
  *
3544
- * For example, these function calls are equivalent:
3631
+ * - `pending` - the data is not yet available.
3632
+ * - `resolved` - the data is available.
3633
+ * - `rejected` - the data is not available due to an error or timeout.
3545
3634
  *
3546
- * - `component$(() => {...})` is same as `component($(() => {...}))`
3635
+ * Be careful when using a `try/catch` statement in `useResource$`. If you catch the error and don't
3636
+ * re-throw it (or a new Error), the resource status will never be `rejected`.
3547
3637
  *
3548
- * ```tsx
3549
- * export function myApi(callback: QRL<() => void>): void {
3550
- * // ...
3551
- * }
3638
+ * ### Example
3552
3639
  *
3553
- * export const myApi$ = implicit$FirstArg(myApi);
3554
- * // type of myApi$: (callback: () => void): void
3640
+ * Example showing how `useResource` to perform a fetch to request the weather, whenever the input
3641
+ * city name changes.
3555
3642
  *
3556
- * // can be used as:
3557
- * myApi$(() => console.log('callback'));
3643
+ * ```tsx
3644
+ * const Cmp = component$(() => {
3645
+ * const cityS = useSignal('');
3558
3646
  *
3559
- * // will be transpiled to:
3560
- * // FILE: <current file>
3561
- * myApi(qrl('./chunk-abc.js', 'callback'));
3647
+ * const weatherResource = useResource$(async ({ track, cleanup }) => {
3648
+ * const cityName = track(cityS);
3649
+ * const abortController = new AbortController();
3650
+ * cleanup(() => abortController.abort('cleanup'));
3651
+ * const res = await fetch(`http://weatherdata.com?city=${cityName}`, {
3652
+ * signal: abortController.signal,
3653
+ * });
3654
+ * const data = await res.json();
3655
+ * return data as { temp: number };
3656
+ * });
3562
3657
  *
3563
- * // FILE: chunk-abc.js
3564
- * export const callback = () => console.log('callback');
3658
+ * return (
3659
+ * <div>
3660
+ * <input name="city" bind:value={cityS} />
3661
+ * <Resource
3662
+ * value={weatherResource}
3663
+ * onResolved={(weather) => {
3664
+ * return <div>Temperature: {weather.temp}</div>;
3665
+ * }}
3666
+ * />
3667
+ * </div>
3668
+ * );
3669
+ * });
3565
3670
  * ```
3566
3671
  *
3567
- * @param fn - A function that should have its first argument automatically `$`.
3568
3672
  * @public
3673
+ * @see Resource
3674
+ * @see ResourceReturn
3569
3675
  */
3570
3676
  // </docs>
3571
- const implicit$FirstArg = (fn) => {
3572
- return function (first, ...rest) {
3573
- return fn.call(null, dollar(first), ...rest);
3677
+ const Resource = (props) => {
3678
+ // Resource path
3679
+ return _jsxSorted(Fragment, null, null, getResourceValueAsPromise(props), 0, null);
3680
+ };
3681
+ function getResourceValueAsPromise(props) {
3682
+ const resource = props.value;
3683
+ if (isResourceReturn(resource) && resource.value) {
3684
+ const isBrowser = !isServerPlatform();
3685
+ if (isBrowser) {
3686
+ // create a subscription for the resource._state changes
3687
+ const state = resource._state;
3688
+ if (state === 'pending' && props.onPending) {
3689
+ return Promise.resolve().then(useBindInvokeContext(props.onPending));
3690
+ }
3691
+ else if (state === 'rejected' && props.onRejected) {
3692
+ return Promise.resolve(resource._error).then(useBindInvokeContext(props.onRejected));
3693
+ }
3694
+ else {
3695
+ const resolvedValue = untrack(() => resource._resolved);
3696
+ if (resolvedValue !== undefined) {
3697
+ // resolved, pending without onPending prop or rejected without onRejected prop
3698
+ return Promise.resolve(resolvedValue).then(useBindInvokeContext(props.onResolved));
3699
+ }
3700
+ }
3701
+ }
3702
+ return resource.value.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
3703
+ }
3704
+ else if (isPromise(resource)) {
3705
+ return resource.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
3706
+ }
3707
+ else if (isSignal(resource)) {
3708
+ return Promise.resolve(resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
3709
+ }
3710
+ else {
3711
+ return Promise.resolve(resource).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
3712
+ }
3713
+ }
3714
+ const _createResourceReturn = (opts) => {
3715
+ const resource = {
3716
+ __brand: 'resource',
3717
+ value: undefined,
3718
+ loading: isServerPlatform() ? false : true,
3719
+ _resolved: undefined,
3720
+ _error: undefined,
3721
+ _state: 'pending',
3722
+ _timeout: opts?.timeout ?? -1,
3723
+ _cache: 0,
3574
3724
  };
3725
+ return resource;
3575
3726
  };
3576
-
3577
- const createSignal$1 = (value) => {
3578
- return new Signal(null, value);
3727
+ const createResourceReturn = (container, opts, initialPromise) => {
3728
+ const result = _createResourceReturn(opts);
3729
+ result.value = initialPromise;
3730
+ return createStore(container, result, StoreFlags.RECURSIVE);
3579
3731
  };
3580
- const createComputedSignal = (qrl) => {
3581
- throwIfQRLNotResolved(qrl);
3582
- return new ComputedSignal(null, qrl);
3732
+ const isResourceReturn = (obj) => {
3733
+ return isObject(obj) && (getStoreTarget(obj) || obj).__brand === 'resource';
3734
+ };
3735
+ const runResource = (task, container, host) => {
3736
+ task.$flags$ &= ~TaskFlags.DIRTY;
3737
+ cleanupTask(task);
3738
+ const iCtx = newInvokeContext(container.$locale$, host, undefined, ResourceEvent);
3739
+ iCtx.$container$ = container;
3740
+ const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
3741
+ const resource = task.$state$;
3742
+ assertDefined(resource, 'useResource: when running a resource, "task.resource" must be a defined.', task);
3743
+ const track = (obj, prop) => {
3744
+ const ctx = newInvokeContext();
3745
+ ctx.$effectSubscriber$ = getSubscriber(task, EffectProperty.COMPONENT);
3746
+ ctx.$container$ = container;
3747
+ return invoke(ctx, () => {
3748
+ if (isFunction(obj)) {
3749
+ return obj();
3750
+ }
3751
+ if (prop) {
3752
+ return obj[prop];
3753
+ }
3754
+ else if (isSignal(obj)) {
3755
+ return obj.value;
3756
+ }
3757
+ else {
3758
+ return obj;
3759
+ }
3760
+ });
3761
+ };
3762
+ const handleError = (reason) => container.handleError(reason, host);
3763
+ const cleanups = [];
3764
+ task.$destroy$ = noSerialize(() => {
3765
+ cleanups.forEach((fn) => {
3766
+ try {
3767
+ fn();
3768
+ }
3769
+ catch (err) {
3770
+ handleError(err);
3771
+ }
3772
+ });
3773
+ done = true;
3774
+ });
3775
+ const resourceTarget = unwrapStore(resource);
3776
+ const opts = {
3777
+ track,
3778
+ cleanup(fn) {
3779
+ if (typeof fn === 'function') {
3780
+ cleanups.push(fn);
3781
+ }
3782
+ },
3783
+ cache(policy) {
3784
+ let milliseconds = 0;
3785
+ if (policy === 'immutable') {
3786
+ milliseconds = Infinity;
3787
+ }
3788
+ else {
3789
+ milliseconds = policy;
3790
+ }
3791
+ resource._cache = milliseconds;
3792
+ },
3793
+ previous: resourceTarget._resolved,
3794
+ };
3795
+ let resolve;
3796
+ let reject;
3797
+ let done = false;
3798
+ const setState = (resolved, value) => {
3799
+ if (!done) {
3800
+ done = true;
3801
+ if (resolved) {
3802
+ done = true;
3803
+ resource.loading = false;
3804
+ resource._state = 'resolved';
3805
+ resource._resolved = value;
3806
+ resource._error = undefined;
3807
+ resolve(value);
3808
+ }
3809
+ else {
3810
+ done = true;
3811
+ resource.loading = false;
3812
+ resource._state = 'rejected';
3813
+ resource._error = value;
3814
+ reject(value);
3815
+ }
3816
+ return true;
3817
+ }
3818
+ return false;
3819
+ };
3820
+ /**
3821
+ * Add cleanup to resolve the resource if we are trying to run the same resource again while the
3822
+ * previous one is not resolved yet. The next `runResource` run will call this cleanup
3823
+ */
3824
+ cleanups.push(() => {
3825
+ if (untrack(() => resource.loading) === true) {
3826
+ const value = untrack(() => resource._resolved);
3827
+ setState(true, value);
3828
+ }
3829
+ });
3830
+ // Execute mutation inside empty invocation
3831
+ invoke(iCtx, () => {
3832
+ // console.log('RESOURCE.pending: ');
3833
+ resource._state = 'pending';
3834
+ resource.loading = !isServerPlatform();
3835
+ const promise = (resource.value = new Promise((r, re) => {
3836
+ resolve = r;
3837
+ reject = re;
3838
+ }));
3839
+ promise.catch(ignoreErrorToPreventNodeFromCrashing);
3840
+ });
3841
+ const promise = safeCall(() => Promise.resolve(taskFn(opts)), (value) => {
3842
+ setState(true, value);
3843
+ }, (err) => {
3844
+ if (isPromise(err)) {
3845
+ return err.then(() => runResource(task, container, host));
3846
+ }
3847
+ else {
3848
+ setState(false, err);
3849
+ }
3850
+ });
3851
+ const timeout = resourceTarget._timeout;
3852
+ if (timeout > 0) {
3853
+ return Promise.race([
3854
+ promise,
3855
+ delay(timeout).then(() => {
3856
+ if (setState(false, new Error('timeout'))) {
3857
+ cleanupTask(task);
3858
+ }
3859
+ }),
3860
+ ]);
3861
+ }
3862
+ return promise;
3863
+ };
3864
+ const ignoreErrorToPreventNodeFromCrashing = (err) => {
3865
+ // ignore error to prevent node from crashing
3866
+ // node will crash in promise is rejected and no one is listening to the rejection.
3583
3867
  };
3584
-
3585
- /**
3586
- * Creates a Signal with the given value. If no value is given, the signal is created with
3587
- * `undefined`.
3588
- *
3589
- * @public
3590
- */
3591
- const createSignal = createSignal$1;
3592
- /** @internal */
3593
- const createComputedQrl = createComputedSignal;
3594
- /**
3595
- * Create a computed signal which is calculated from the given QRL. A computed signal is a signal
3596
- * which is calculated from other signals. When the signals change, the computed signal is
3597
- * recalculated.
3598
- *
3599
- * The QRL must be a function which returns the value of the signal. The function must not have side
3600
- * effects, and it mus be synchronous.
3601
- *
3602
- * If you need the function to be async, use `useSignal` and `useTask$` instead.
3603
- *
3604
- * @public
3605
- */
3606
- const createComputed$ = /*#__PURE__*/ implicit$FirstArg(createComputedQrl);
3607
3868
 
3608
3869
  /// These global variables are used to avoid creating new arrays for each call to `vnode_documentPosition`.
3609
3870
  const aVNodePath = [];
@@ -3788,38 +4049,29 @@
3788
4049
  * - Visible Tasks are sorted afterJournalFlush, than depth first on component and finally in
3789
4050
  * declaration order within component.
3790
4051
  */
3791
- var ChoreType;
3792
- (function (ChoreType) {
3793
- /// MASKS defining three levels of sorting
3794
- ChoreType[ChoreType["MACRO"] = 240] = "MACRO";
3795
- /* order of elements (not encoded here) */
3796
- ChoreType[ChoreType["MICRO"] = 15] = "MICRO";
3797
- /** Ensure tha the QRL promise is resolved before processing next chores in the queue */
3798
- ChoreType[ChoreType["QRL_RESOLVE"] = 1] = "QRL_RESOLVE";
3799
- ChoreType[ChoreType["RESOURCE"] = 2] = "RESOURCE";
3800
- ChoreType[ChoreType["TASK"] = 3] = "TASK";
3801
- ChoreType[ChoreType["NODE_DIFF"] = 4] = "NODE_DIFF";
3802
- ChoreType[ChoreType["NODE_PROP"] = 5] = "NODE_PROP";
3803
- ChoreType[ChoreType["COMPONENT_SSR"] = 6] = "COMPONENT_SSR";
3804
- ChoreType[ChoreType["COMPONENT"] = 7] = "COMPONENT";
3805
- ChoreType[ChoreType["RECOMPUTE_AND_SCHEDULE_EFFECTS"] = 8] = "RECOMPUTE_AND_SCHEDULE_EFFECTS";
3806
- ChoreType[ChoreType["JOURNAL_FLUSH"] = 16] = "JOURNAL_FLUSH";
3807
- ChoreType[ChoreType["VISIBLE"] = 32] = "VISIBLE";
3808
- ChoreType[ChoreType["CLEANUP_VISIBLE"] = 48] = "CLEANUP_VISIBLE";
3809
- ChoreType[ChoreType["WAIT_FOR_ALL"] = 255] = "WAIT_FOR_ALL";
3810
- })(ChoreType || (ChoreType = {}));
4052
+ // Turn this on to get debug output of what the scheduler is doing.
4053
+ const DEBUG$1 = false;
4054
+ const getPromise = (chore) => (chore.$promise$ ||= new Promise((resolve) => {
4055
+ chore.$resolve$ = resolve;
4056
+ }));
3811
4057
  const createScheduler = (container, scheduleDrain, journalFlush) => {
3812
4058
  const choreQueue = [];
4059
+ const qrlRuns = [];
3813
4060
  let currentChore = null;
3814
- let journalFlushScheduled = false;
4061
+ let drainScheduled = false;
3815
4062
  return schedule;
3816
4063
  ///// IMPLEMENTATION /////
3817
4064
  function schedule(type, hostOrTask = null, targetOrQrl = null, payload = null) {
3818
- const runLater = type !== ChoreType.WAIT_FOR_ALL && type !== ChoreType.COMPONENT_SSR;
3819
- const isTask = type === ChoreType.TASK ||
3820
- type === ChoreType.VISIBLE ||
3821
- type === ChoreType.RESOURCE ||
3822
- type === ChoreType.CLEANUP_VISIBLE;
4065
+ const isServer = !isDomContainer(container);
4066
+ const isComponentSsr = isServer && type === ChoreType.COMPONENT;
4067
+ const runLater = type !== ChoreType.WAIT_FOR_ALL && !isComponentSsr && type !== ChoreType.RUN_QRL;
4068
+ const isTask = type === ChoreType.TASK || type === ChoreType.VISIBLE || type === ChoreType.CLEANUP_VISIBLE;
4069
+ const isClientOnly = type === ChoreType.JOURNAL_FLUSH ||
4070
+ type === ChoreType.NODE_DIFF ||
4071
+ type === ChoreType.NODE_PROP;
4072
+ if (isServer && isClientOnly) {
4073
+ return;
4074
+ }
3823
4075
  if (isTask) {
3824
4076
  hostOrTask.$flags$ |= TaskFlags.DIRTY;
3825
4077
  }
@@ -3838,192 +4090,234 @@
3838
4090
  $returnValue$: null,
3839
4091
  $executed$: false,
3840
4092
  };
3841
- chore.$promise$ = new Promise((resolve) => (chore.$resolve$ = resolve));
3842
4093
  chore = sortedInsert(choreQueue, chore, container.rootVNode || null);
3843
- if (!journalFlushScheduled && runLater) {
4094
+ if (!drainScheduled && runLater) {
3844
4095
  // If we are not currently draining, we need to schedule a drain.
3845
- journalFlushScheduled = true;
4096
+ drainScheduled = true;
3846
4097
  schedule(ChoreType.JOURNAL_FLUSH);
3847
- scheduleDrain();
4098
+ // Catch here to avoid unhandled promise rejection
4099
+ scheduleDrain()?.catch?.(() => { });
3848
4100
  }
4101
+ // TODO figure out what to do with chore errors
3849
4102
  if (runLater) {
3850
- return chore.$promise$;
4103
+ return getPromise(chore);
3851
4104
  }
3852
4105
  else {
3853
- return drainUpTo(chore, container.rootVNode || null);
4106
+ return drainUpTo(chore, isServer);
3854
4107
  }
3855
4108
  }
3856
- /**
3857
- * Execute all of the chores up to and including the given chore.
3858
- *
3859
- * @param runUptoChore
3860
- */
3861
- function drainUpTo(runUptoChore, rootVNode) {
3862
- // If it already ran, it's not in the queue
3863
- if (runUptoChore.$executed$) {
3864
- return runUptoChore.$returnValue$;
3865
- }
3866
- if (currentChore) {
3867
- // Already running chore, which means we're waiting for async completion
3868
- return runUptoChore.$promise$;
3869
- }
4109
+ /** Execute all of the chores up to and including the given chore. */
4110
+ function drainUpTo(runUptoChore, isServer) {
4111
+ let maxRetries = 5000;
3870
4112
  while (choreQueue.length) {
3871
- const nextChore = choreQueue.shift();
3872
- const order = choreComparator(nextChore, runUptoChore, rootVNode);
3873
- if (order === null) {
3874
- continue;
4113
+ if (maxRetries-- < 0) {
4114
+ throw new Error('drainUpTo: max retries reached');
3875
4115
  }
3876
- if (order > 0) {
3877
- // we have processed all of the chores up to and including the given chore.
3878
- break;
4116
+ if (currentChore) {
4117
+ // Already running chore, which means we're waiting for async completion
4118
+ return getPromise(currentChore)
4119
+ .then(() => drainUpTo(runUptoChore, isServer))
4120
+ .catch((e) => {
4121
+ container.handleError(e, currentChore?.$host$);
4122
+ });
4123
+ }
4124
+ const nextChore = choreQueue[0];
4125
+ if (nextChore.$executed$) {
4126
+ choreQueue.shift();
4127
+ if (nextChore === runUptoChore) {
4128
+ break;
4129
+ }
4130
+ continue;
3879
4131
  }
3880
- const isDeletedVNode = vNodeAlreadyDeleted(nextChore);
3881
- if (isDeletedVNode &&
4132
+ if (vNodeAlreadyDeleted(nextChore) &&
3882
4133
  // we need to process cleanup tasks for deleted nodes
3883
4134
  nextChore.$type$ !== ChoreType.CLEANUP_VISIBLE) {
4135
+ choreQueue.shift();
3884
4136
  continue;
3885
4137
  }
3886
- const returnValue = executeChore(nextChore);
3887
- if (isPromise(returnValue)) {
3888
- const promise = returnValue.then(() => drainUpTo(runUptoChore, rootVNode));
3889
- return promise;
3890
- }
4138
+ executeChore(nextChore, isServer);
3891
4139
  }
3892
4140
  return runUptoChore.$returnValue$;
3893
4141
  }
3894
- function executeChore(chore) {
4142
+ function executeChore(chore, isServer) {
3895
4143
  const host = chore.$host$;
3896
4144
  assertEqual(currentChore, null, 'Chore already running.');
3897
4145
  currentChore = chore;
3898
4146
  let returnValue = null;
3899
- switch (chore.$type$) {
3900
- case ChoreType.JOURNAL_FLUSH:
3901
- returnValue = journalFlush();
3902
- journalFlushScheduled = false;
3903
- break;
3904
- case ChoreType.COMPONENT:
3905
- case ChoreType.COMPONENT_SSR:
3906
- returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
3907
- if (chore.$type$ === ChoreType.COMPONENT) {
3908
- const styleScopedId = container.getHostProp(host, QScopedStyle);
3909
- return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
4147
+ try {
4148
+ switch (chore.$type$) {
4149
+ case ChoreType.WAIT_FOR_ALL:
4150
+ {
4151
+ if (isServer) {
4152
+ drainScheduled = false;
4153
+ }
3910
4154
  }
3911
- else {
3912
- return jsx;
4155
+ break;
4156
+ case ChoreType.JOURNAL_FLUSH:
4157
+ {
4158
+ returnValue = journalFlush();
4159
+ drainScheduled = false;
4160
+ }
4161
+ break;
4162
+ case ChoreType.COMPONENT:
4163
+ {
4164
+ returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
4165
+ if (isServer) {
4166
+ return jsx;
4167
+ }
4168
+ else {
4169
+ const styleScopedId = container.getHostProp(host, QScopedStyle);
4170
+ return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
4171
+ }
4172
+ }, (err) => container.handleError(err, host));
4173
+ }
4174
+ break;
4175
+ case ChoreType.RUN_QRL:
4176
+ {
4177
+ const fn = chore.$target$.getFn();
4178
+ const result = retryOnPromise(() => fn(...chore.$payload$));
4179
+ if (isPromise(result)) {
4180
+ const handled = result
4181
+ .finally(() => {
4182
+ qrlRuns.splice(qrlRuns.indexOf(handled), 1);
4183
+ })
4184
+ .catch((error) => {
4185
+ container.handleError(error, chore.$host$);
4186
+ });
4187
+ // Don't wait for the promise to resolve
4188
+ // TODO come up with a better solution, we also want concurrent signal handling with tasks but serial tasks
4189
+ qrlRuns.push(handled);
4190
+ DEBUG$1 &&
4191
+ debugTrace('execute.DONE (but still running)', chore, currentChore, choreQueue);
4192
+ chore.$returnValue$ = handled;
4193
+ chore.$resolve$?.(handled);
4194
+ currentChore = null;
4195
+ chore.$executed$ = true;
4196
+ // early out so we don't call after()
4197
+ return;
4198
+ }
4199
+ returnValue = null;
4200
+ }
4201
+ break;
4202
+ case ChoreType.TASK:
4203
+ case ChoreType.VISIBLE:
4204
+ {
4205
+ const payload = chore.$payload$;
4206
+ if (payload.$flags$ & TaskFlags.RESOURCE) {
4207
+ const result = runResource(payload, container, host);
4208
+ // Don't await the return value of the resource, because async resources should not be awaited.
4209
+ // The reason for this is that we should be able to update for example a node with loading
4210
+ // text. If we await the resource, the loading text will not be displayed until the resource
4211
+ // is loaded.
4212
+ // Awaiting on the client also causes a deadlock.
4213
+ // In any case, the resource will never throw.
4214
+ returnValue = isServer ? result : null;
4215
+ }
4216
+ else {
4217
+ returnValue = runTask(payload, container, host);
4218
+ }
4219
+ }
4220
+ break;
4221
+ case ChoreType.CLEANUP_VISIBLE:
4222
+ {
4223
+ const task = chore.$payload$;
4224
+ cleanupTask(task);
4225
+ }
4226
+ break;
4227
+ case ChoreType.NODE_DIFF:
4228
+ {
4229
+ const parentVirtualNode = chore.$target$;
4230
+ let jsx = chore.$payload$;
4231
+ if (isSignal(jsx)) {
4232
+ jsx = jsx.value;
4233
+ }
4234
+ returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
4235
+ }
4236
+ break;
4237
+ case ChoreType.NODE_PROP:
4238
+ {
4239
+ const virtualNode = chore.$host$;
4240
+ const payload = chore.$payload$;
4241
+ let value = payload.$value$;
4242
+ if (isSignal(value)) {
4243
+ value = value.value;
4244
+ }
4245
+ const isConst = payload.$isConst$;
4246
+ const journal = container.$journal$;
4247
+ const property = chore.$idx$;
4248
+ const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
4249
+ if (isConst) {
4250
+ const element = virtualNode[ElementVNodeProps.element];
4251
+ journal.push(VNodeJournalOpCode.SetAttribute, element, property, serializedValue);
4252
+ }
4253
+ else {
4254
+ vnode_setAttr(journal, virtualNode, property, serializedValue);
4255
+ }
4256
+ }
4257
+ break;
4258
+ case ChoreType.QRL_RESOLVE: {
4259
+ {
4260
+ const target = chore.$target$;
4261
+ returnValue = !target.resolved ? target.resolve() : null;
3913
4262
  }
3914
- }, (err) => container.handleError(err, host));
3915
- break;
3916
- case ChoreType.RESOURCE:
3917
- // Don't await the return value of the resource, because async resources should not be awaited.
3918
- // The reason for this is that we should be able to update for example a node with loading
3919
- // text. If we await the resource, the loading text will not be displayed until the resource
3920
- // is loaded.
3921
- const result = runResource(chore.$payload$, container, host);
3922
- returnValue = isDomContainer(container) ? null : result;
3923
- break;
3924
- case ChoreType.TASK:
3925
- returnValue = runTask(chore.$payload$, container, host);
3926
- break;
3927
- case ChoreType.VISIBLE:
3928
- returnValue = runTask(chore.$payload$, container, host);
3929
- break;
3930
- case ChoreType.CLEANUP_VISIBLE:
3931
- const task = chore.$payload$;
3932
- cleanupTask(task);
3933
- break;
3934
- case ChoreType.NODE_DIFF:
3935
- const parentVirtualNode = chore.$target$;
3936
- let jsx = chore.$payload$;
3937
- if (isSignal(jsx)) {
3938
- jsx = jsx.value;
3939
- }
3940
- returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
3941
- break;
3942
- case ChoreType.NODE_PROP:
3943
- const virtualNode = chore.$host$;
3944
- const payload = chore.$payload$;
3945
- let value = payload.$value$;
3946
- if (isSignal(value)) {
3947
- value = value.value;
3948
- }
3949
- const isConst = payload.$isConst$;
3950
- const journal = container.$journal$;
3951
- const property = chore.$idx$;
3952
- const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
3953
- if (isConst) {
3954
- const element = virtualNode[ElementVNodeProps.element];
3955
- journal.push(VNodeJournalOpCode.SetAttribute, element, property, serializedValue);
3956
- }
3957
- else {
3958
- vnode_setAttr(journal, virtualNode, property, serializedValue);
3959
- }
3960
- break;
3961
- case ChoreType.QRL_RESOLVE: {
3962
- const target = chore.$target$;
3963
- returnValue = !target.resolved ? target.resolve() : null;
3964
- break;
3965
- }
3966
- case ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS: {
3967
- const target = chore.$target$;
3968
- const forceRunEffects = target.$forceRunEffects$;
3969
- target.$forceRunEffects$ = false;
3970
- if (!target.$effects$?.length) {
3971
4263
  break;
3972
4264
  }
3973
- returnValue = retryOnPromise(() => {
3974
- if (target.$computeIfNeeded$() || forceRunEffects) {
3975
- triggerEffects(container, target, target.$effects$);
4265
+ case ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS: {
4266
+ {
4267
+ const target = chore.$target$;
4268
+ const forceRunEffects = target.$forceRunEffects$;
4269
+ target.$forceRunEffects$ = false;
4270
+ if (!target.$effects$?.size) {
4271
+ break;
4272
+ }
4273
+ returnValue = retryOnPromise(() => {
4274
+ if (target.$computeIfNeeded$() || forceRunEffects) {
4275
+ triggerEffects(container, target, target.$effects$);
4276
+ }
4277
+ });
3976
4278
  }
3977
- });
3978
- break;
4279
+ break;
4280
+ }
3979
4281
  }
3980
4282
  }
3981
- return maybeThenPassError(returnValue, (value) => {
3982
- if (currentChore) {
3983
- currentChore.$executed$ = true;
3984
- currentChore.$resolve$?.(value);
3985
- }
4283
+ catch (e) {
4284
+ returnValue = Promise.reject(e);
4285
+ }
4286
+ const after = (value, error) => {
3986
4287
  currentChore = null;
3987
- return (chore.$returnValue$ = value);
3988
- });
3989
- }
3990
- };
3991
- const toNumber = (value) => {
3992
- return typeof value === 'number' ? value : -1;
3993
- };
3994
- /**
3995
- * When a derived signal is update we need to run vnode_diff. However the signal can update multiple
3996
- * times during component execution. For this reason it is necessary for us to update the schedule
3997
- * work with the latest result of the signal.
3998
- */
3999
- const choreUpdate = (existing, newChore) => {
4000
- if (existing.$type$ === ChoreType.NODE_DIFF) {
4001
- existing.$payload$ = newChore.$payload$;
4002
- }
4003
- };
4004
- function vNodeAlreadyDeleted(chore) {
4005
- return !!(chore.$host$ &&
4006
- vnode_isVNode(chore.$host$) &&
4007
- chore.$host$[VNodeProps.flags] & VNodeFlags.Deleted);
4008
- }
4009
- /**
4010
- * Compares two chores to determine their execution order in the scheduler's queue.
4011
- *
4012
- * @param a - The first chore to compare
4013
- * @param b - The second chore to compare
4014
- * @returns A number indicating the relative order of the chores. A negative number means `a` runs
4015
- * before `b`.
4016
- */
4017
- function choreComparator(a, b, rootVNode) {
4018
- const macroTypeDiff = (a.$type$ & ChoreType.MACRO) - (b.$type$ & ChoreType.MACRO);
4019
- if (macroTypeDiff !== 0) {
4020
- return macroTypeDiff;
4288
+ chore.$executed$ = true;
4289
+ if (error) {
4290
+ container.handleError(error, host);
4291
+ }
4292
+ else {
4293
+ chore.$returnValue$ = value;
4294
+ chore.$resolve$?.(value);
4295
+ }
4296
+ };
4297
+ if (isPromise(returnValue)) {
4298
+ chore.$promise$ = returnValue.then(after, (error) => after(undefined, error));
4299
+ chore.$resolve$?.(chore.$promise$);
4300
+ chore.$resolve$ = undefined;
4301
+ }
4302
+ else {
4303
+ after(returnValue);
4304
+ }
4021
4305
  }
4022
- // JOURNAL_FLUSH does not have a host or $idx$, so we can't compare it.
4023
- if (a.$type$ !== ChoreType.JOURNAL_FLUSH) {
4306
+ /**
4307
+ * Compares two chores to determine their execution order in the scheduler's queue.
4308
+ *
4309
+ * @param a - The first chore to compare
4310
+ * @param b - The second chore to compare
4311
+ * @returns A number indicating the relative order of the chores. A negative number means `a` runs
4312
+ * before `b`.
4313
+ */
4314
+ function choreComparator(a, b, rootVNode) {
4315
+ const macroTypeDiff = (a.$type$ & ChoreType.MACRO) - (b.$type$ & ChoreType.MACRO);
4316
+ if (macroTypeDiff !== 0) {
4317
+ return macroTypeDiff;
4318
+ }
4024
4319
  const aHost = a.$host$;
4025
4320
  const bHost = b.$host$;
4026
- // QRL_RESOLVE does not have a host.
4027
4321
  if (aHost !== bHost && aHost !== null && bHost !== null) {
4028
4322
  if (vnode_isVNode(aHost) && vnode_isVNode(bHost)) {
4029
4323
  // we are running on the client.
@@ -4033,6 +4327,8 @@
4033
4327
  }
4034
4328
  }
4035
4329
  else {
4330
+ assertFalse(vnode_isVNode(aHost), 'expected aHost to be SSRNode but it is a VNode');
4331
+ assertFalse(vnode_isVNode(bHost), 'expected bHost to be SSRNode but it is a VNode');
4036
4332
  // we are running on the server.
4037
4333
  // On server we can't schedule task for a different host!
4038
4334
  // Server is SSR, and therefore scheduling for anything but the current host
@@ -4052,247 +4348,114 @@
4052
4348
  if (microTypeDiff !== 0) {
4053
4349
  return microTypeDiff;
4054
4350
  }
4351
+ // types are the same
4055
4352
  const idxDiff = toNumber(a.$idx$) - toNumber(b.$idx$);
4056
- if (idxDiff !== 0) {
4057
- return idxDiff;
4058
- }
4059
- // If the host is the same, we need to compare the target.
4060
- if (a.$target$ !== b.$target$ &&
4061
- ((a.$type$ === ChoreType.QRL_RESOLVE && b.$type$ === ChoreType.QRL_RESOLVE) ||
4062
- (a.$type$ === ChoreType.NODE_PROP && b.$type$ === ChoreType.NODE_PROP) ||
4063
- (a.$type$ === ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS &&
4064
- b.$type$ === ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS))) {
4065
- // 1 means that we are going to process chores as FIFO
4066
- return 1;
4067
- }
4068
- }
4069
- return 0;
4070
- }
4071
- function sortedFindIndex(sortedArray, value, rootVNode) {
4072
- /// We need to ensure that the `queue` is sorted by priority.
4073
- /// 1. Find a place where to insert into.
4074
- let bottom = 0;
4075
- let top = sortedArray.length;
4076
- while (bottom < top) {
4077
- const middle = bottom + ((top - bottom) >> 1);
4078
- const midChore = sortedArray[middle];
4079
- const comp = choreComparator(value, midChore, rootVNode);
4080
- if (comp < 0) {
4081
- top = middle;
4082
- }
4083
- else if (comp > 0) {
4084
- bottom = middle + 1;
4085
- }
4086
- else {
4087
- // We already have the host in the queue.
4088
- return middle;
4089
- }
4090
- }
4091
- return ~bottom;
4092
- }
4093
- function sortedInsert(sortedArray, value, rootVNode) {
4094
- /// We need to ensure that the `queue` is sorted by priority.
4095
- /// 1. Find a place where to insert into.
4096
- const idx = sortedFindIndex(sortedArray, value, rootVNode);
4097
- if (idx < 0) {
4098
- /// 2. Insert the chore into the queue.
4099
- sortedArray.splice(~idx, 0, value);
4100
- return value;
4101
- }
4102
- const existing = sortedArray[idx];
4103
- choreUpdate(existing, value);
4104
- return existing;
4105
- }
4106
-
4107
- // <docs markdown="../readme.md#useLexicalScope">
4108
- // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
4109
- // (edit ../readme.md#useLexicalScope instead and run `pnpm docs.sync`)
4110
- /**
4111
- * Used by the Qwik Optimizer to restore the lexically scoped variables.
4112
- *
4113
- * This method should not be present in the application source code.
4114
- *
4115
- * NOTE: `useLexicalScope` method can only be used in the synchronous portion of the callback
4116
- * (before any `await` statements.)
4117
- *
4118
- * @internal
4119
- */
4120
- // </docs>
4121
- const useLexicalScope = () => {
4122
- const context = getInvokeContext();
4123
- let qrl = context.$qrl$;
4124
- if (!qrl) {
4125
- const el = context.$element$;
4126
- assertDefined(el, 'invoke: element must be defined inside useLexicalScope()', context);
4127
- const containerElement = _getQContainerElement(el);
4128
- assertDefined(containerElement, `invoke: cant find parent q:container of`, el);
4129
- const container = getDomContainer(containerElement);
4130
- qrl = container.parseQRL(decodeURIComponent(String(context.$url$)));
4131
- }
4132
- else {
4133
- assertQrl(qrl);
4134
- assertDefined(qrl.$captureRef$, 'invoke: qrl $captureRef$ must be defined inside useLexicalScope()', qrl);
4135
- }
4136
- return qrl.$captureRef$;
4137
- };
4138
-
4139
- var TaskFlags;
4140
- (function (TaskFlags) {
4141
- TaskFlags[TaskFlags["VISIBLE_TASK"] = 1] = "VISIBLE_TASK";
4142
- TaskFlags[TaskFlags["TASK"] = 2] = "TASK";
4143
- TaskFlags[TaskFlags["RESOURCE"] = 4] = "RESOURCE";
4144
- TaskFlags[TaskFlags["DIRTY"] = 8] = "DIRTY";
4145
- })(TaskFlags || (TaskFlags = {}));
4146
- /** @internal */
4147
- const useTaskQrl = (qrl, opts) => {
4148
- const { val, set, iCtx, i } = useSequentialScope();
4149
- if (val) {
4150
- return;
4151
- }
4152
- assertQrl(qrl);
4153
- set(1);
4154
- const host = iCtx.$hostElement$;
4155
- const task = new Task(TaskFlags.DIRTY | TaskFlags.TASK, i, iCtx.$hostElement$, qrl, undefined, null);
4156
- // In V2 we add the task to the sequential scope. We need to do this
4157
- // in order to be able to retrieve it later when the parent element is
4158
- // deleted and we need to be able to release the task subscriptions.
4159
- set(task);
4160
- const result = runTask(task, iCtx.$container$, host);
4161
- if (isPromise(result)) {
4162
- throw result;
4163
- }
4164
- qrl.$resolveLazy$(iCtx.$element$);
4165
- if (isServerPlatform()) {
4166
- useRunTask(task, opts?.eagerness);
4167
- }
4168
- };
4169
- const runTask = (task, container, host) => {
4170
- task.$flags$ &= ~TaskFlags.DIRTY;
4171
- cleanupTask(task);
4172
- const iCtx = newInvokeContext(container.$locale$, host, undefined, TaskEvent);
4173
- iCtx.$container$ = container;
4174
- const taskFn = task.$qrl$.getFn(iCtx, () => clearSubscriberEffectDependencies(container, task));
4175
- const track = (obj, prop) => {
4176
- const ctx = newInvokeContext();
4177
- ctx.$effectSubscriber$ = [task, EffectProperty.COMPONENT];
4178
- ctx.$container$ = container;
4179
- return invoke(ctx, () => {
4180
- if (isFunction(obj)) {
4181
- return obj();
4182
- }
4183
- if (prop) {
4184
- return obj[prop];
4185
- }
4186
- else if (isSignal(obj)) {
4187
- return obj.value;
4188
- }
4189
- else {
4190
- return obj;
4191
- }
4192
- });
4193
- };
4194
- const handleError = (reason) => container.handleError(reason, host);
4195
- let cleanupFns = null;
4196
- const cleanup = (fn) => {
4197
- if (typeof fn == 'function') {
4198
- if (!cleanupFns) {
4199
- cleanupFns = [];
4200
- task.$destroy$ = noSerialize(() => {
4201
- task.$destroy$ = null;
4202
- cleanupFns.forEach((fn) => {
4203
- try {
4204
- fn();
4205
- }
4206
- catch (err) {
4207
- handleError(err);
4208
- }
4209
- });
4210
- });
4211
- }
4212
- cleanupFns.push(fn);
4213
- }
4214
- };
4215
- const taskApi = { track, cleanup };
4216
- const result = safeCall(() => taskFn(taskApi), cleanup, (err) => {
4217
- if (isPromise(err)) {
4218
- return err.then(() => runTask(task, container, host));
4219
- }
4220
- else {
4221
- return handleError(err);
4353
+ if (idxDiff !== 0) {
4354
+ return idxDiff;
4222
4355
  }
4223
- });
4224
- return result;
4225
- };
4226
- const cleanupTask = (task) => {
4227
- const destroy = task.$destroy$;
4228
- if (destroy) {
4229
- task.$destroy$ = null;
4230
- try {
4231
- destroy();
4356
+ // If the host is the same (or missing), and the type is the same, we need to compare the target.
4357
+ if (a.$target$ !== b.$target$ || a.$payload$ !== b.$payload$) {
4358
+ // 1 means that we are going to process chores as FIFO
4359
+ return 1;
4232
4360
  }
4233
- catch (err) {
4234
- logError(err);
4361
+ // If the chore is the same as the current chore, we will run it again
4362
+ if (b === currentChore) {
4363
+ return 1;
4235
4364
  }
4365
+ // The chores are the same and will run only once
4366
+ return 0;
4236
4367
  }
4237
- };
4238
- const useRunTask = (task, eagerness) => {
4239
- if (eagerness === 'visible' || eagerness === 'intersection-observer') {
4240
- useOn('qvisible', getTaskHandlerQrl(task));
4241
- }
4242
- else if (eagerness === 'load' || eagerness === 'document-ready') {
4243
- useOnDocument('qinit', getTaskHandlerQrl(task));
4368
+ function sortedFindIndex(sortedArray, value, rootVNode) {
4369
+ /// We need to ensure that the `queue` is sorted by priority.
4370
+ /// 1. Find a place where to insert into.
4371
+ let bottom = 0;
4372
+ let top = sortedArray.length;
4373
+ while (bottom < top) {
4374
+ const middle = bottom + ((top - bottom) >> 1);
4375
+ const midChore = sortedArray[middle];
4376
+ const comp = choreComparator(value, midChore, rootVNode);
4377
+ if (comp < 0) {
4378
+ top = middle;
4379
+ }
4380
+ else if (comp > 0) {
4381
+ bottom = middle + 1;
4382
+ }
4383
+ else {
4384
+ // We already have the host in the queue.
4385
+ return middle;
4386
+ }
4387
+ }
4388
+ return ~bottom;
4244
4389
  }
4245
- else if (eagerness === 'idle' || eagerness === 'document-idle') {
4246
- useOnDocument('qidle', getTaskHandlerQrl(task));
4390
+ function sortedInsert(sortedArray, value, rootVNode) {
4391
+ /// We need to ensure that the `queue` is sorted by priority.
4392
+ /// 1. Find a place where to insert into.
4393
+ const idx = sortedFindIndex(sortedArray, value, rootVNode);
4394
+ if (idx < 0) {
4395
+ /// 2. Insert the chore into the queue.
4396
+ sortedArray.splice(~idx, 0, value);
4397
+ return value;
4398
+ }
4399
+ const existing = sortedArray[idx];
4400
+ /**
4401
+ * When a derived signal is updated we need to run vnode_diff. However the signal can update
4402
+ * multiple times during component execution. For this reason it is necessary for us to update
4403
+ * the chore with the latest result of the signal.
4404
+ */
4405
+ if (existing.$type$ === ChoreType.NODE_DIFF) {
4406
+ existing.$payload$ = value.$payload$;
4407
+ }
4408
+ if (existing.$executed$) {
4409
+ existing.$executed$ = false;
4410
+ }
4411
+ return existing;
4247
4412
  }
4248
4413
  };
4249
- const getTaskHandlerQrl = (task) => {
4250
- const taskQrl = task.$qrl$;
4251
- const taskHandler = createQRL(taskQrl.$chunk$, '_hW', _hW, null, null, [task], taskQrl.$symbol$);
4252
- // Needed for chunk lookup in dev mode
4253
- if (taskQrl.dev) {
4254
- taskHandler.dev = taskQrl.dev;
4255
- }
4256
- return taskHandler;
4414
+ const toNumber = (value) => {
4415
+ return typeof value === 'number' ? value : -1;
4257
4416
  };
4258
- class Task extends Subscriber {
4259
- $flags$;
4260
- $index$;
4261
- $el$;
4262
- $qrl$;
4263
- $state$;
4264
- $destroy$;
4265
- constructor($flags$, $index$, $el$, $qrl$, $state$, $destroy$) {
4266
- super();
4267
- this.$flags$ = $flags$;
4268
- this.$index$ = $index$;
4269
- this.$el$ = $el$;
4270
- this.$qrl$ = $qrl$;
4271
- this.$state$ = $state$;
4272
- this.$destroy$ = $destroy$;
4417
+ function vNodeAlreadyDeleted(chore) {
4418
+ return !!(chore.$host$ &&
4419
+ vnode_isVNode(chore.$host$) &&
4420
+ chore.$host$[VNodeProps.flags] & VNodeFlags.Deleted);
4421
+ }
4422
+ function debugChoreTypeToString(type) {
4423
+ return ({
4424
+ [ChoreType.QRL_RESOLVE]: 'QRL_RESOLVE',
4425
+ [ChoreType.RUN_QRL]: 'RUN_QRL',
4426
+ [ChoreType.TASK]: 'TASK',
4427
+ [ChoreType.NODE_DIFF]: 'NODE_DIFF',
4428
+ [ChoreType.NODE_PROP]: 'NODE_PROP',
4429
+ [ChoreType.COMPONENT]: 'COMPONENT',
4430
+ [ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS]: 'RECOMPUTE_SIGNAL',
4431
+ [ChoreType.JOURNAL_FLUSH]: 'JOURNAL_FLUSH',
4432
+ [ChoreType.VISIBLE]: 'VISIBLE',
4433
+ [ChoreType.CLEANUP_VISIBLE]: 'CLEANUP_VISIBLE',
4434
+ [ChoreType.WAIT_FOR_ALL]: 'WAIT_FOR_ALL',
4435
+ }[type] || 'UNKNOWN: ' + type);
4436
+ }
4437
+ function debugChoreToString(chore) {
4438
+ const type = debugChoreTypeToString(chore.$type$);
4439
+ const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
4440
+ const qrlTarget = chore.$target$?.$symbol$;
4441
+ return `Chore(${type} ${chore.$type$ === ChoreType.QRL_RESOLVE || chore.$type$ === ChoreType.RUN_QRL ? qrlTarget : host} ${chore.$idx$})`;
4442
+ }
4443
+ function debugTrace(action, arg, currentChore, queue) {
4444
+ const lines = ['===========================\nScheduler: ' + action];
4445
+ if (arg && !('$type$' in arg)) {
4446
+ lines.push(' arg: ' + String(arg).replaceAll(/\n.*/gim, ''));
4447
+ }
4448
+ if (queue) {
4449
+ queue.forEach((chore) => {
4450
+ const active = chore === arg ? '>>>' : ' ';
4451
+ lines.push(` ${active} > ` +
4452
+ (chore === currentChore ? '[running] ' : '') +
4453
+ debugChoreToString(chore));
4454
+ });
4273
4455
  }
4456
+ // eslint-disable-next-line no-console
4457
+ console.log(lines.join('\n') + '\n');
4274
4458
  }
4275
- const isTask = (value) => {
4276
- return value instanceof Task;
4277
- };
4278
- /**
4279
- * Low-level API used by the Optimizer to process `useTask$()` API. This method is not intended to
4280
- * be used by developers.
4281
- *
4282
- * @internal
4283
- */
4284
- const _hW = () => {
4285
- const [task] = useLexicalScope();
4286
- const container = getDomContainer(task.$el$);
4287
- const type = task.$flags$ & TaskFlags.VISIBLE_TASK ? ChoreType.VISIBLE : ChoreType.TASK;
4288
- container.$scheduler$(type, task);
4289
- };
4290
-
4291
- /**
4292
- * Special value used to mark that a given signal needs to be computed. This is essentially a
4293
- * "marked as dirty" flag.
4294
- */
4295
- const NEEDS_COMPUTATION = Symbol('invalid');
4296
4459
 
4297
4460
  /**
4298
4461
  * @file
@@ -4326,18 +4489,19 @@
4326
4489
  return value instanceof Signal;
4327
4490
  };
4328
4491
  /** @internal */
4329
- class EffectPropData {
4492
+ class SubscriptionData {
4330
4493
  data;
4331
4494
  constructor(data) {
4332
4495
  this.data = data;
4333
4496
  }
4334
4497
  }
4335
- var EffectSubscriptionsProp;
4336
- (function (EffectSubscriptionsProp) {
4337
- EffectSubscriptionsProp[EffectSubscriptionsProp["EFFECT"] = 0] = "EFFECT";
4338
- EffectSubscriptionsProp[EffectSubscriptionsProp["PROPERTY"] = 1] = "PROPERTY";
4339
- EffectSubscriptionsProp[EffectSubscriptionsProp["FIRST_BACK_REF_OR_DATA"] = 2] = "FIRST_BACK_REF_OR_DATA";
4340
- })(EffectSubscriptionsProp || (EffectSubscriptionsProp = {}));
4498
+ var EffectSubscriptionProp;
4499
+ (function (EffectSubscriptionProp) {
4500
+ EffectSubscriptionProp[EffectSubscriptionProp["CONSUMER"] = 0] = "CONSUMER";
4501
+ EffectSubscriptionProp[EffectSubscriptionProp["PROPERTY"] = 1] = "PROPERTY";
4502
+ EffectSubscriptionProp[EffectSubscriptionProp["BACK_REF"] = 2] = "BACK_REF";
4503
+ EffectSubscriptionProp[EffectSubscriptionProp["DATA"] = 3] = "DATA";
4504
+ })(EffectSubscriptionProp || (EffectSubscriptionProp = {}));
4341
4505
  var EffectProperty;
4342
4506
  (function (EffectProperty) {
4343
4507
  EffectProperty["COMPONENT"] = ":";
@@ -4374,19 +4538,16 @@
4374
4538
  }
4375
4539
  const effectSubscriber = ctx.$effectSubscriber$;
4376
4540
  if (effectSubscriber) {
4377
- const effects = (this.$effects$ ||= []);
4541
+ const effects = (this.$effects$ ||= new Set());
4378
4542
  // Let's make sure that we have a reference to this effect.
4379
4543
  // Adding reference is essentially adding a subscription, so if the signal
4380
4544
  // changes we know who to notify.
4381
- ensureContainsEffect(effects, effectSubscriber);
4545
+ ensureContainsSubscription(effects, effectSubscriber);
4382
4546
  // But when effect is scheduled in needs to be able to know which signals
4383
4547
  // to unsubscribe from. So we need to store the reference from the effect back
4384
4548
  // to this signal.
4385
- ensureContains(effectSubscriber, this);
4386
- if (isSubscriber(this)) {
4387
- // We need to add the subscriber to the effect so that we can clean it up later
4388
- ensureEffectContainsSubscriber(effectSubscriber[EffectSubscriptionsProp.EFFECT], this, this.$container$);
4389
- }
4549
+ ensureContainsBackRef(effectSubscriber, this);
4550
+ addQrlToSerializationCtx(effectSubscriber, this.$container$);
4390
4551
  }
4391
4552
  }
4392
4553
  return this.untrackedValue;
@@ -4405,122 +4566,97 @@
4405
4566
  }
4406
4567
  toString() {
4407
4568
  return (`[${this.constructor.name}${this.$invalid$ ? ' INVALID' : ''} ${String(this.$untrackedValue$)}]` +
4408
- (this.$effects$?.map((e) => '\n -> ' + pad(qwikDebugToString(e[0]), ' ')).join('\n') || ''));
4569
+ (Array.from(this.$effects$ || [])
4570
+ .map((e) => '\n -> ' + pad(qwikDebugToString(e[0]), ' '))
4571
+ .join('\n') || ''));
4409
4572
  }
4410
4573
  toJSON() {
4411
4574
  return { value: this.$untrackedValue$ };
4412
4575
  }
4413
4576
  }
4414
- /** Ensure the item is in array (do nothing if already there) */
4415
- const ensureContains = (array, value) => {
4416
- const isMissing = array.indexOf(value) === -1;
4417
- if (isMissing) {
4418
- array.push(value);
4419
- }
4420
- };
4421
- const ensureContainsEffect = (array, effectSubscriptions) => {
4422
- for (let i = 0; i < array.length; i++) {
4423
- const existingEffect = array[i];
4424
- if (existingEffect[0] === effectSubscriptions[0] &&
4425
- existingEffect[1] === effectSubscriptions[1]) {
4426
- return;
4427
- }
4428
- }
4429
- array.push(effectSubscriptions);
4577
+ const ensureContainsSubscription = (array, effectSubscription) => {
4578
+ array.add(effectSubscription);
4430
4579
  };
4431
- const ensureEffectContainsSubscriber = (effect, subscriber, container) => {
4432
- if (isSubscriber(effect)) {
4433
- effect.$effectDependencies$ ||= [];
4434
- if (subscriberExistInSubscribers(effect.$effectDependencies$, subscriber)) {
4435
- return;
4580
+ /** Ensure the item is in back refs set */
4581
+ const ensureContainsBackRef = (array, value) => {
4582
+ array[EffectSubscriptionProp.BACK_REF] ||= new Set();
4583
+ array[EffectSubscriptionProp.BACK_REF].add(value);
4584
+ };
4585
+ const addQrlToSerializationCtx = (effectSubscriber, container) => {
4586
+ if (!!container && !isDomContainer(container)) {
4587
+ const effect = effectSubscriber[EffectSubscriptionProp.CONSUMER];
4588
+ const property = effectSubscriber[EffectSubscriptionProp.PROPERTY];
4589
+ let qrl = null;
4590
+ if (isTask(effect)) {
4591
+ qrl = effect.$qrl$;
4436
4592
  }
4437
- effect.$effectDependencies$.push(subscriber);
4438
- }
4439
- else if (vnode_isVNode(effect) && !vnode_isTextVNode(effect)) {
4440
- let subscribers = vnode_getProp(effect, QSubscribers, container ? container.$getObjectById$ : null);
4441
- subscribers ||= [];
4442
- if (subscriberExistInSubscribers(subscribers, subscriber)) {
4443
- return;
4593
+ else if (effect instanceof ComputedSignal) {
4594
+ qrl = effect.$computeQrl$;
4444
4595
  }
4445
- subscribers.push(subscriber);
4446
- vnode_setProp(effect, QSubscribers, subscribers);
4447
- }
4448
- else if (isSSRNode(effect)) {
4449
- let subscribers = effect.getProp(QSubscribers);
4450
- subscribers ||= [];
4451
- if (subscriberExistInSubscribers(subscribers, subscriber)) {
4452
- return;
4596
+ else if (property === EffectProperty.COMPONENT) {
4597
+ qrl = container.getHostProp(effect, OnRenderProp);
4453
4598
  }
4454
- subscribers.push(subscriber);
4455
- effect.setProp(QSubscribers, subscribers);
4456
- }
4457
- };
4458
- const isSSRNode = (effect) => {
4459
- return 'setProp' in effect && 'getProp' in effect && 'removeProp' in effect && 'id' in effect;
4460
- };
4461
- const subscriberExistInSubscribers = (subscribers, subscriber) => {
4462
- for (let i = 0; i < subscribers.length; i++) {
4463
- if (subscribers[i] === subscriber) {
4464
- return true;
4599
+ if (qrl) {
4600
+ container.serializationCtx.$eventQrls$.add(qrl);
4465
4601
  }
4466
4602
  }
4467
- return false;
4468
4603
  };
4469
4604
  const triggerEffects = (container, signal, effects) => {
4605
+ const isBrowser = isDomContainer(container);
4470
4606
  if (effects) {
4471
- const scheduleEffect = (effectSubscriptions) => {
4472
- const effect = effectSubscriptions[EffectSubscriptionsProp.EFFECT];
4473
- const property = effectSubscriptions[EffectSubscriptionsProp.PROPERTY];
4607
+ const scheduleEffect = (effectSubscription) => {
4608
+ const consumer = effectSubscription[EffectSubscriptionProp.CONSUMER];
4609
+ const property = effectSubscription[EffectSubscriptionProp.PROPERTY];
4474
4610
  assertDefined(container, 'Container must be defined.');
4475
- if (isTask(effect)) {
4476
- effect.$flags$ |= TaskFlags.DIRTY;
4611
+ if (isTask(consumer)) {
4612
+ consumer.$flags$ |= TaskFlags.DIRTY;
4477
4613
  let choreType = ChoreType.TASK;
4478
- if (effect.$flags$ & TaskFlags.VISIBLE_TASK) {
4614
+ if (consumer.$flags$ & TaskFlags.VISIBLE_TASK) {
4479
4615
  choreType = ChoreType.VISIBLE;
4480
4616
  }
4481
- else if (effect.$flags$ & TaskFlags.RESOURCE) {
4482
- choreType = ChoreType.RESOURCE;
4483
- }
4484
- container.$scheduler$(choreType, effect);
4617
+ container.$scheduler$(choreType, consumer);
4485
4618
  }
4486
- else if (effect instanceof Signal) {
4619
+ else if (consumer instanceof Signal) {
4487
4620
  // we don't schedule ComputedSignal/DerivedSignal directly, instead we invalidate it and
4488
4621
  // and schedule the signals effects (recursively)
4489
- if (effect instanceof ComputedSignal) {
4622
+ if (consumer instanceof ComputedSignal) {
4490
4623
  // Ensure that the computed signal's QRL is resolved.
4491
4624
  // If not resolved schedule it to be resolved.
4492
- if (!effect.$computeQrl$.resolved) {
4493
- container.$scheduler$(ChoreType.QRL_RESOLVE, null, effect.$computeQrl$);
4625
+ if (!consumer.$computeQrl$.resolved) {
4626
+ container.$scheduler$(ChoreType.QRL_RESOLVE, null, consumer.$computeQrl$);
4494
4627
  }
4495
4628
  }
4496
- effect.$invalidate$();
4629
+ consumer.$invalidate$();
4497
4630
  }
4498
4631
  else if (property === EffectProperty.COMPONENT) {
4499
- const host = effect;
4632
+ const host = consumer;
4500
4633
  const qrl = container.getHostProp(host, OnRenderProp);
4501
4634
  assertDefined(qrl, 'Component must have QRL');
4502
4635
  const props = container.getHostProp(host, ELEMENT_PROPS);
4503
4636
  container.$scheduler$(ChoreType.COMPONENT, host, qrl, props);
4504
4637
  }
4505
- else if (property === EffectProperty.VNODE) {
4506
- const host = effect;
4507
- const target = host;
4508
- container.$scheduler$(ChoreType.NODE_DIFF, host, target, signal);
4509
- }
4510
- else {
4511
- const host = effect;
4512
- const effectData = effectSubscriptions[EffectSubscriptionsProp.FIRST_BACK_REF_OR_DATA];
4513
- if (effectData instanceof EffectPropData) {
4514
- const data = effectData.data;
4515
- const payload = {
4516
- ...data,
4517
- $value$: signal,
4518
- };
4519
- container.$scheduler$(ChoreType.NODE_PROP, host, property, payload);
4638
+ else if (isBrowser) {
4639
+ if (property === EffectProperty.VNODE) {
4640
+ const host = consumer;
4641
+ container.$scheduler$(ChoreType.NODE_DIFF, host, host, signal);
4642
+ }
4643
+ else {
4644
+ const host = consumer;
4645
+ const effectData = effectSubscription[EffectSubscriptionProp.DATA];
4646
+ if (effectData instanceof SubscriptionData) {
4647
+ const data = effectData.data;
4648
+ const payload = {
4649
+ ...data,
4650
+ $value$: signal,
4651
+ };
4652
+ container.$scheduler$(ChoreType.NODE_PROP, host, property, payload);
4653
+ }
4520
4654
  }
4521
4655
  }
4522
4656
  };
4523
- effects.forEach(scheduleEffect);
4657
+ for (const effect of effects) {
4658
+ scheduleEffect(effect);
4659
+ }
4524
4660
  }
4525
4661
  };
4526
4662
  /**
@@ -4578,7 +4714,7 @@
4578
4714
  throwIfQRLNotResolved(computeQrl);
4579
4715
  const ctx = tryGetInvokeContext();
4580
4716
  const previousEffectSubscription = ctx?.$effectSubscriber$;
4581
- ctx && (ctx.$effectSubscriber$ = [this, EffectProperty.VNODE]);
4717
+ ctx && (ctx.$effectSubscriber$ = getSubscriber(this, EffectProperty.VNODE));
4582
4718
  try {
4583
4719
  const untrackedValue = computeQrl.getFn(ctx)();
4584
4720
  if (isPromise(untrackedValue)) {
@@ -4616,9 +4752,9 @@
4616
4752
  // We need a separate flag to know when the computation needs running because
4617
4753
  // we need the old value to know if effects need running after computation
4618
4754
  $invalid$ = true;
4619
- $effectDependencies$ = null;
4620
4755
  $hostElement$ = null;
4621
4756
  $forceRunEffects$ = false;
4757
+ [_EFFECT_BACK_REF] = null;
4622
4758
  constructor(container, fn, args, fnStr) {
4623
4759
  super(container, NEEDS_COMPUTATION);
4624
4760
  this.$args$ = args;
@@ -4686,7 +4822,7 @@
4686
4822
  if (jsx.key !== null) {
4687
4823
  host.setProp(ELEMENT_KEY, jsx.key);
4688
4824
  }
4689
- return scheduler(ChoreType.COMPONENT_SSR, host, componentQrl, srcProps);
4825
+ return scheduler(ChoreType.COMPONENT, host, componentQrl, srcProps);
4690
4826
  };
4691
4827
 
4692
4828
  class ParentComponentData {
@@ -4698,21 +4834,10 @@
4698
4834
  }
4699
4835
  }
4700
4836
  /** @internal */
4701
- function _walkJSX(ssr, value, options) {
4837
+ async function _walkJSX(ssr, value, options) {
4702
4838
  const stack = [value];
4703
- let resolveDrain;
4704
- let rejectDrain;
4705
- const drained = options.allowPromises &&
4706
- new Promise((res, rej) => {
4707
- resolveDrain = res;
4708
- rejectDrain = rej;
4709
- });
4710
4839
  const enqueue = (value) => stack.push(value);
4711
- const resolveValue = (value) => {
4712
- stack.push(value);
4713
- drain();
4714
- };
4715
- const drain = () => {
4840
+ const drain = async () => {
4716
4841
  while (stack.length) {
4717
4842
  const value = stack.pop();
4718
4843
  if (value instanceof ParentComponentData) {
@@ -4722,20 +4847,10 @@
4722
4847
  }
4723
4848
  else if (typeof value === 'function') {
4724
4849
  if (value === Promise) {
4725
- if (!options.allowPromises) {
4726
- throw qError(QError.promisesNotExpected);
4727
- }
4728
- stack.pop().then(resolveValue, rejectDrain);
4729
- return;
4730
- }
4731
- const waitOn = value.apply(ssr);
4732
- if (waitOn) {
4733
- if (!options.allowPromises) {
4734
- throw qError(QError.promisesNotExpected);
4735
- }
4736
- waitOn.then(drain, rejectDrain);
4737
- return;
4850
+ stack.push(await stack.pop());
4851
+ continue;
4738
4852
  }
4853
+ await value.apply(ssr);
4739
4854
  continue;
4740
4855
  }
4741
4856
  processJSXNode(ssr, enqueue, value, {
@@ -4743,12 +4858,8 @@
4743
4858
  parentComponentFrame: options.parentComponentFrame,
4744
4859
  });
4745
4860
  }
4746
- if (stack.length === 0 && options.allowPromises) {
4747
- resolveDrain();
4748
- }
4749
4861
  };
4750
- drain();
4751
- return drained;
4862
+ await drain();
4752
4863
  }
4753
4864
  function processJSXNode(ssr, enqueue, value, options) {
4754
4865
  // console.log('processJSXNode', value);
@@ -4787,7 +4898,6 @@
4787
4898
  enqueue(async () => {
4788
4899
  for await (const chunk of value) {
4789
4900
  await _walkJSX(ssr, chunk, {
4790
- allowPromises: true,
4791
4901
  currentStyleScoped: options.styleScoped,
4792
4902
  parentComponentFrame: options.parentComponentFrame,
4793
4903
  });
@@ -4874,7 +4984,6 @@
4874
4984
  value = generator({
4875
4985
  async write(chunk) {
4876
4986
  await _walkJSX(ssr, chunk, {
4877
- allowPromises: true,
4878
4987
  currentStyleScoped: options.styleScoped,
4879
4988
  parentComponentFrame: options.parentComponentFrame,
4880
4989
  });
@@ -5031,11 +5140,23 @@
5031
5140
  const appendToValue = (valueToAppend) => {
5032
5141
  value = (value == null ? '' : value + '\n') + valueToAppend;
5033
5142
  };
5143
+ const getQrlString = (qrl) => {
5144
+ /**
5145
+ * If there are captures we need to schedule so everything is executed in the right order + qrls
5146
+ * are resolved.
5147
+ *
5148
+ * For internal qrls (starting with `_`) we assume that they do the right thing.
5149
+ */
5150
+ if (!qrl.$symbol$.startsWith('_') && (qrl.$captureRef$ || qrl.$capture$)) {
5151
+ qrl = createQRL(null, '_run', queueQRL, null, null, [qrl]);
5152
+ }
5153
+ return qrlToString(serializationCtx, qrl);
5154
+ };
5034
5155
  if (Array.isArray(qrls)) {
5035
5156
  for (let i = 0; i <= qrls.length; i++) {
5036
5157
  const qrl = qrls[i];
5037
- if (isQrl(qrl)) {
5038
- appendToValue(qrlToString(serializationCtx, qrl));
5158
+ if (isQrl$1(qrl)) {
5159
+ appendToValue(getQrlString(qrl));
5039
5160
  addQwikEventToSerializationContext(serializationCtx, key, qrl);
5040
5161
  }
5041
5162
  else if (qrl != null) {
@@ -5047,8 +5168,8 @@
5047
5168
  }
5048
5169
  }
5049
5170
  }
5050
- else if (isQrl(qrls)) {
5051
- value = qrlToString(serializationCtx, qrls);
5171
+ else if (isQrl$1(qrls)) {
5172
+ value = getQrlString(qrls);
5052
5173
  addQwikEventToSerializationContext(serializationCtx, key, qrls);
5053
5174
  }
5054
5175
  return value;
@@ -5098,7 +5219,7 @@
5098
5219
  *
5099
5220
  * @public
5100
5221
  */
5101
- const version = "2.0.0-alpha.6-dev+d848ba5";
5222
+ const version = "2.0.0-alpha.7-dev+a26598a";
5102
5223
 
5103
5224
  /** @internal */
5104
5225
  class _SharedContainer {
@@ -5130,13 +5251,6 @@
5130
5251
  }
5131
5252
  }
5132
5253
 
5133
- /** @internal */
5134
- const _CONST_PROPS = Symbol('CONST');
5135
- /** @internal */
5136
- const _VAR_PROPS = Symbol('VAR');
5137
- /** @internal @deprecated v1 compat */
5138
- const _IMMUTABLE = Symbol('IMMUTABLE');
5139
-
5140
5254
  // Keep these properties named like this so they're the same as from wrapSignal
5141
5255
  const getValueProp = (p0) => p0.value;
5142
5256
  const getProp = (p0, p1) => p0[p1];
@@ -5548,7 +5662,7 @@
5548
5662
  else if (isTask(value)) {
5549
5663
  return `Task(${qwikDebugToString(value.$qrl$)})`;
5550
5664
  }
5551
- else if (isQrl$1(value)) {
5665
+ else if (isQrl(value)) {
5552
5666
  return `Qrl(${value.$symbol$})`;
5553
5667
  }
5554
5668
  else if (typeof value === 'object' || typeof value === 'function') {
@@ -5702,14 +5816,21 @@
5702
5816
  CONTEXT_CHAR: /* **** */ ']',
5703
5817
  SEQ_IDX: /* ************ */ 94, // `^` - `q:seqIdx' - Sequential scope id
5704
5818
  SEQ_IDX_CHAR: /* **** */ '^',
5705
- SUBS: /* *************** */ 96, // '`' - `q:subs' - Effect dependencies/subscriptions
5706
- SUBS_CHAR: /* ******* */ '`',
5819
+ BACK_REFS: /* ********** */ 96, // '`' - `q:brefs' - Effect dependencies/subscriptions
5820
+ BACK_REFS_CHAR: /* ** */ '`',
5707
5821
  SEPARATOR: /* ********* */ 124, // `|` - Separator char to encode any key/value pairs.
5708
5822
  SEPARATOR_CHAR: /* ** */ '|',
5709
5823
  SLOT: /* ************** */ 126, // `~` - `q:slot' - Slot name
5710
5824
  SLOT_CHAR: /* ******* */ '~',
5711
5825
  };
5712
5826
 
5827
+ const mergeMaps = (map1, map2) => {
5828
+ for (const [k, v] of map2) {
5829
+ map1.set(k, v);
5830
+ }
5831
+ return map1;
5832
+ };
5833
+
5713
5834
  /**
5714
5835
  * @file
5715
5836
  *
@@ -5965,6 +6086,7 @@
5965
6086
  elementVNode[VNodeProps.flags] ^= VNodeFlags.Inflated;
5966
6087
  const element = elementVNode[ElementVNodeProps.element];
5967
6088
  const attributes = element.attributes;
6089
+ const props = vnode_getProps(elementVNode);
5968
6090
  for (let idx = 0; idx < attributes.length; idx++) {
5969
6091
  const attr = attributes[idx];
5970
6092
  const key = attr.name;
@@ -5975,15 +6097,15 @@
5975
6097
  }
5976
6098
  else if (key.startsWith(QContainerAttr)) {
5977
6099
  if (attr.value === QContainerValue.HTML) {
5978
- mapArray_set(elementVNode, dangerouslySetInnerHTML, element.innerHTML, ElementVNodeProps.PROPS_OFFSET);
6100
+ mapArray_set(props, dangerouslySetInnerHTML, element.innerHTML, 0);
5979
6101
  }
5980
6102
  else if (attr.value === QContainerValue.TEXT && 'value' in element) {
5981
- mapArray_set(elementVNode, 'value', element.value, ElementVNodeProps.PROPS_OFFSET);
6103
+ mapArray_set(props, 'value', element.value, 0);
5982
6104
  }
5983
6105
  }
5984
6106
  else if (!key.startsWith('on:')) {
5985
6107
  const value = attr.value;
5986
- mapArray_set(elementVNode, key, value, ElementVNodeProps.PROPS_OFFSET);
6108
+ mapArray_set(props, key, value, 0);
5987
6109
  }
5988
6110
  }
5989
6111
  }
@@ -6419,54 +6541,16 @@
6419
6541
  journal.length = 0;
6420
6542
  };
6421
6543
  //////////////////////////////////////////////////////////////////////////////////////////////////////
6422
- const mapApp_findIndx = (elementVNode, key, start) => {
6423
- assertTrue(start % 2 === 0, 'Expecting even number.');
6424
- let bottom = start >> 1;
6425
- let top = (elementVNode.length - 2) >> 1;
6426
- while (bottom <= top) {
6427
- const mid = bottom + ((top - bottom) >> 1);
6428
- const midKey = elementVNode[mid << 1];
6429
- if (midKey === key) {
6430
- return mid << 1;
6431
- }
6432
- if (midKey < key) {
6433
- bottom = mid + 1;
6434
- }
6435
- else {
6436
- top = mid - 1;
6437
- }
6438
- }
6439
- return (bottom << 1) ^ -1;
6440
- };
6441
- const mapArray_set = (elementVNode, key, value, start) => {
6442
- const indx = mapApp_findIndx(elementVNode, key, start);
6443
- if (indx >= 0) {
6444
- if (value == null) {
6445
- elementVNode.splice(indx, 2);
6446
- }
6447
- else {
6448
- elementVNode[indx + 1] = value;
6449
- }
6450
- }
6451
- else if (value != null) {
6452
- elementVNode.splice(indx ^ -1, 0, key, value);
6453
- }
6454
- };
6455
- const mapArray_get = (elementVNode, key, start) => {
6456
- const indx = mapApp_findIndx(elementVNode, key, start);
6457
- if (indx >= 0) {
6458
- return elementVNode[indx + 1];
6459
- }
6460
- else {
6461
- return null;
6462
- }
6463
- };
6464
- //////////////////////////////////////////////////////////////////////////////////////////////////////
6465
6544
  const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
6466
6545
  ensureElementOrVirtualVNode(parent);
6467
6546
  if (vnode_isElementVNode(parent)) {
6468
6547
  ensureMaterialized(parent);
6469
6548
  }
6549
+ if (newChild === insertBefore) {
6550
+ // invalid insertBefore. We can't insert before self reference
6551
+ // prevent infinity loop and putting self reference to next sibling
6552
+ insertBefore = null;
6553
+ }
6470
6554
  let adjustedInsertBefore = null;
6471
6555
  if (insertBefore == null) {
6472
6556
  if (vnode_isVirtualVNode(parent)) {
@@ -6590,9 +6674,10 @@
6590
6674
  const elementVNode = ensureElementVNode(vnode);
6591
6675
  let elementName = elementVNode[ElementVNodeProps.elementName];
6592
6676
  if (elementName === undefined) {
6593
- elementName = elementVNode[ElementVNodeProps.elementName] =
6594
- elementVNode[ElementVNodeProps.element].nodeName.toLowerCase();
6595
- elementVNode[VNodeProps.flags] |= vnode_getElementNamespaceFlags(elementName);
6677
+ const element = elementVNode[ElementVNodeProps.element];
6678
+ const nodeName = build.isDev ? fastNodeName(element).toLowerCase() : fastNodeName(element);
6679
+ elementName = elementVNode[ElementVNodeProps.elementName] = nodeName;
6680
+ elementVNode[VNodeProps.flags] |= vnode_getElementNamespaceFlags(element);
6596
6681
  }
6597
6682
  return elementName;
6598
6683
  };
@@ -6774,6 +6859,20 @@
6774
6859
  }
6775
6860
  return node;
6776
6861
  };
6862
+ let _fastNamespaceURI = null;
6863
+ const fastNamespaceURI = (element) => {
6864
+ if (!_fastNamespaceURI) {
6865
+ _fastNamespaceURI = fastGetter(element, 'namespaceURI');
6866
+ }
6867
+ return _fastNamespaceURI.call(element);
6868
+ };
6869
+ let _fastNodeName = null;
6870
+ const fastNodeName = (element) => {
6871
+ if (!_fastNodeName) {
6872
+ _fastNodeName = fastGetter(element, 'nodeName');
6873
+ }
6874
+ return _fastNodeName.call(element);
6875
+ };
6777
6876
  const fastGetter = (prototype, name) => {
6778
6877
  let getter;
6779
6878
  while (prototype && !(getter = Object.getOwnPropertyDescriptor(prototype, name)?.get)) {
@@ -6840,8 +6939,11 @@
6840
6939
  container.$setRawState$(parseInt(id), vParent);
6841
6940
  build.isDev && vnode_setAttr(null, vParent, ELEMENT_ID, id);
6842
6941
  }
6843
- else if (peek() === VNodeDataChar.SUBS) {
6844
- vnode_setProp(vParent, QSubscribers, consumeValue());
6942
+ else if (peek() === VNodeDataChar.BACK_REFS) {
6943
+ if (!container) {
6944
+ container = getDomContainer(vParent[ElementVNodeProps.element]);
6945
+ }
6946
+ setEffectBackRefFromVNodeData(vParent, consumeValue(), container);
6845
6947
  }
6846
6948
  else {
6847
6949
  // prevent infinity loop if there are some characters outside the range
@@ -6851,6 +6953,18 @@
6851
6953
  }
6852
6954
  return vFirstChild;
6853
6955
  };
6956
+ function setEffectBackRefFromVNodeData(vParent, value, container) {
6957
+ const deserializedSubMap = container.$getObjectById$(value);
6958
+ if (!vParent[_EFFECT_BACK_REF]) {
6959
+ Object.defineProperty(vParent, _EFFECT_BACK_REF, {
6960
+ value: deserializedSubMap,
6961
+ });
6962
+ }
6963
+ else {
6964
+ const subMap = vParent[_EFFECT_BACK_REF];
6965
+ mergeMaps(subMap, deserializedSubMap);
6966
+ }
6967
+ }
6854
6968
  const processVNodeData$1 = (vData, callback) => {
6855
6969
  let nextToConsumeIdx = 0;
6856
6970
  let ch = 0;
@@ -6895,8 +7009,9 @@
6895
7009
  if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
6896
7010
  vnode_ensureElementInflated(vnode);
6897
7011
  const keys = [];
6898
- for (let i = vnode_getPropStartIndex(vnode); i < vnode.length; i = i + 2) {
6899
- const key = vnode[i];
7012
+ const props = vnode_getProps(vnode);
7013
+ for (let i = 0; i < props.length; i = i + 2) {
7014
+ const key = props[i];
6900
7015
  if (!key.startsWith(Q_PROPS_SEPARATOR)) {
6901
7016
  keys.push(key);
6902
7017
  }
@@ -6909,22 +7024,23 @@
6909
7024
  const type = vnode[VNodeProps.flags];
6910
7025
  if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
6911
7026
  vnode_ensureElementInflated(vnode);
6912
- const idx = mapApp_findIndx(vnode, key, vnode_getPropStartIndex(vnode));
7027
+ const props = vnode_getProps(vnode);
7028
+ const idx = mapApp_findIndx(props, key, 0);
6913
7029
  if (idx >= 0) {
6914
- if (vnode[idx + 1] != value && (type & VNodeFlags.Element) !== 0) {
7030
+ if (props[idx + 1] != value && (type & VNodeFlags.Element) !== 0) {
6915
7031
  // Values are different, update DOM
6916
7032
  const element = vnode[ElementVNodeProps.element];
6917
7033
  journal && journal.push(VNodeJournalOpCode.SetAttribute, element, key, value);
6918
7034
  }
6919
7035
  if (value == null) {
6920
- vnode.splice(idx, 2);
7036
+ props.splice(idx, 2);
6921
7037
  }
6922
7038
  else {
6923
- vnode[idx + 1] = value;
7039
+ props[idx + 1] = value;
6924
7040
  }
6925
7041
  }
6926
7042
  else if (value != null) {
6927
- vnode.splice(idx ^ -1, 0, key, value);
7043
+ props.splice(idx ^ -1, 0, key, value);
6928
7044
  if ((type & VNodeFlags.Element) !== 0) {
6929
7045
  // New value, update DOM
6930
7046
  const element = vnode[ElementVNodeProps.element];
@@ -6937,7 +7053,8 @@
6937
7053
  const type = vnode[VNodeProps.flags];
6938
7054
  if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
6939
7055
  vnode_ensureElementInflated(vnode);
6940
- return mapArray_get(vnode, key, vnode_getPropStartIndex(vnode));
7056
+ const props = vnode_getProps(vnode);
7057
+ return mapArray_get(props, key, 0);
6941
7058
  }
6942
7059
  return null;
6943
7060
  };
@@ -6945,11 +7062,12 @@
6945
7062
  const type = vnode[VNodeProps.flags];
6946
7063
  if ((type & VNodeFlags.ELEMENT_OR_VIRTUAL_MASK) !== 0) {
6947
7064
  type & VNodeFlags.Element && vnode_ensureElementInflated(vnode);
6948
- const idx = mapApp_findIndx(vnode, key, vnode_getPropStartIndex(vnode));
7065
+ const props = vnode_getProps(vnode);
7066
+ const idx = mapApp_findIndx(props, key, 0);
6949
7067
  if (idx >= 0) {
6950
- let value = vnode[idx + 1];
7068
+ let value = props[idx + 1];
6951
7069
  if (typeof value === 'string' && getObject) {
6952
- vnode[idx + 1] = value = getObject(value);
7070
+ props[idx + 1] = value = getObject(value);
6953
7071
  }
6954
7072
  return value;
6955
7073
  }
@@ -6958,12 +7076,13 @@
6958
7076
  };
6959
7077
  const vnode_setProp = (vnode, key, value) => {
6960
7078
  ensureElementOrVirtualVNode(vnode);
6961
- const idx = mapApp_findIndx(vnode, key, vnode_getPropStartIndex(vnode));
7079
+ const props = vnode_getProps(vnode);
7080
+ const idx = mapApp_findIndx(props, key, 0);
6962
7081
  if (idx >= 0) {
6963
- vnode[idx + 1] = value;
7082
+ props[idx + 1] = value;
6964
7083
  }
6965
7084
  else if (value != null) {
6966
- vnode.splice(idx ^ -1, 0, key, value);
7085
+ props.splice(idx ^ -1, 0, key, value);
6967
7086
  }
6968
7087
  };
6969
7088
  const vnode_getPropStartIndex = (vnode) => {
@@ -6976,6 +7095,9 @@
6976
7095
  }
6977
7096
  throw qError(QError.invalidVNodeType, [type]);
6978
7097
  };
7098
+ const vnode_getProps = (vnode) => {
7099
+ return vnode[vnode_getPropStartIndex(vnode)];
7100
+ };
6979
7101
  const vnode_getParent = (vnode) => {
6980
7102
  return vnode[VNodeProps.parent] || null;
6981
7103
  };
@@ -7139,8 +7261,11 @@
7139
7261
  else if (peek() === VNodeDataChar.SEQ_IDX) {
7140
7262
  vnode_setAttr(null, vParent, ELEMENT_SEQ_IDX, consumeValue());
7141
7263
  }
7142
- else if (peek() === VNodeDataChar.SUBS) {
7143
- vnode_setProp(vParent, QSubscribers, consumeValue());
7264
+ else if (peek() === VNodeDataChar.BACK_REFS) {
7265
+ if (!container) {
7266
+ container = getDomContainer(element);
7267
+ }
7268
+ setEffectBackRefFromVNodeData(vParent, consumeValue(), container);
7144
7269
  }
7145
7270
  else if (peek() === VNodeDataChar.CONTEXT) {
7146
7271
  vnode_setAttr(null, vParent, QCtxAttr, consumeValue());
@@ -7248,23 +7373,20 @@
7248
7373
  };
7249
7374
  const VNodeArray = class VNode extends Array {
7250
7375
  static createElement(flags, parent, previousSibling, nextSibling, firstChild, lastChild, element, elementName) {
7251
- const vnode = new VNode(flags, parent, previousSibling, nextSibling);
7252
- vnode.push(firstChild, lastChild, element, elementName);
7376
+ const vnode = new VNode(flags, parent, previousSibling, nextSibling, firstChild, lastChild, element, elementName, []);
7253
7377
  return vnode;
7254
7378
  }
7255
7379
  static createText(flags, parent, previousSibling, nextSibling, textNode, text) {
7256
- const vnode = new VNode(flags, parent, previousSibling, nextSibling);
7257
- vnode.push(textNode, text);
7380
+ const vnode = new VNode(flags, parent, previousSibling, nextSibling, textNode, text);
7258
7381
  return vnode;
7259
7382
  }
7260
7383
  static createVirtual(flags, parent, previousSibling, nextSibling, firstChild, lastChild) {
7261
- const vnode = new VNode(flags, parent, previousSibling, nextSibling);
7262
- vnode.push(firstChild, lastChild);
7384
+ const vnode = new VNode(flags, parent, previousSibling, nextSibling, firstChild, lastChild, []);
7263
7385
  return vnode;
7264
7386
  }
7265
- constructor(flags, parent, previousSibling, nextSibling) {
7266
- super();
7267
- this.push(flags, parent, previousSibling, nextSibling);
7387
+ constructor(flags, parent, previousSibling, nextSibling, ...rest) {
7388
+ // @ts-expect-error
7389
+ super(flags, parent, previousSibling, nextSibling, ...rest);
7268
7390
  if (build.isDev) {
7269
7391
  this.toString = vnode_toString;
7270
7392
  }
@@ -7329,10 +7451,12 @@
7329
7451
  return returnValue;
7330
7452
  }
7331
7453
  const newInvokeContextFromTuple = ([element, event, url]) => {
7332
- const container = element.closest(QContainerSelector);
7454
+ const domContainer = getDomContainer(element);
7455
+ const container = domContainer.element;
7456
+ const vNode = container ? vnode_locate(domContainer.rootVNode, element) : undefined;
7333
7457
  const locale = container?.getAttribute(QLocaleAttr) || undefined;
7334
7458
  locale && setLocale(locale);
7335
- return newInvokeContext(locale, undefined, element, event, url);
7459
+ return newInvokeContext(locale, vNode, element, event, url);
7336
7460
  };
7337
7461
  // TODO how about putting url and locale (and event/custom?) in to a "static" object
7338
7462
  const newInvokeContext = (locale, hostElement, element, event, url) => {
@@ -7367,16 +7491,14 @@
7367
7491
  * @param property `true` - subscriber is component `false` - subscriber is VNode `string` -
7368
7492
  * subscriber is property
7369
7493
  * @param container
7494
+ * @param data - Additional subscription data
7370
7495
  * @returns
7371
7496
  */
7372
7497
  const trackSignal = (fn, subscriber, property, container, data) => {
7373
7498
  const previousSubscriber = trackInvocation.$effectSubscriber$;
7374
7499
  const previousContainer = trackInvocation.$container$;
7375
7500
  try {
7376
- trackInvocation.$effectSubscriber$ = [subscriber, property];
7377
- if (data) {
7378
- trackInvocation.$effectSubscriber$.push(data);
7379
- }
7501
+ trackInvocation.$effectSubscriber$ = getSubscriber(subscriber, property, data);
7380
7502
  trackInvocation.$container$ = container;
7381
7503
  return invoke(trackInvocation, fn);
7382
7504
  }
@@ -7397,8 +7519,16 @@
7397
7519
  if (iCtx) {
7398
7520
  const hostElement = iCtx.$hostElement$;
7399
7521
  let element = null;
7400
- if (vnode_isVNode(hostElement) && vnode_isElementVNode(hostElement)) {
7401
- element = vnode_getNode(hostElement);
7522
+ if (hostElement != null) {
7523
+ if (vnode_isVNode(hostElement)) {
7524
+ if (vnode_isElementVNode(hostElement)) {
7525
+ element = vnode_getNode(hostElement);
7526
+ }
7527
+ }
7528
+ else {
7529
+ // isSSRnode
7530
+ element = hostElement;
7531
+ }
7402
7532
  }
7403
7533
  return element ?? iCtx.$qrl$?.$setContainer$(undefined);
7404
7534
  }
@@ -8034,9 +8164,9 @@
8034
8164
  $storeProxyMap$ = new WeakMap();
8035
8165
  $qFuncs$;
8036
8166
  $instanceHash$;
8037
- stateData;
8167
+ vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
8168
+ $stateData$;
8038
8169
  $styleIds$ = null;
8039
- $vnodeLocate$ = (id) => vnode_locate(this.rootVNode, id);
8040
8170
  $renderCount$ = 0;
8041
8171
  constructor(element) {
8042
8172
  super(() => this.scheduleRender(), () => vnode_applyJournal(this.$journal$), {}, element.getAttribute('q:locale'));
@@ -8062,29 +8192,29 @@
8062
8192
  this.rootVNode = vnode_newUnMaterializedElement(this.element);
8063
8193
  // These are here to initialize all properties at once for single class transition
8064
8194
  this.$rawStateData$ = null;
8065
- this.stateData = null;
8195
+ this.$stateData$ = null;
8066
8196
  const document = this.element.ownerDocument;
8067
8197
  if (!document.qVNodeData) {
8068
8198
  processVNodeData(document);
8069
8199
  }
8070
8200
  this.$rawStateData$ = [];
8071
- this.stateData = [];
8201
+ this.$stateData$ = [];
8072
8202
  const qwikStates = element.querySelectorAll('script[type="qwik/state"]');
8073
8203
  if (qwikStates.length !== 0) {
8074
8204
  const lastState = qwikStates[qwikStates.length - 1];
8075
8205
  this.$rawStateData$ = JSON.parse(lastState.textContent);
8076
- this.stateData = wrapDeserializerProxy(this, this.$rawStateData$);
8206
+ this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
8077
8207
  }
8078
8208
  this.$qFuncs$ = getQFuncs(document, this.$instanceHash$) || EMPTY_ARRAY;
8079
8209
  }
8080
8210
  $setRawState$(id, vParent) {
8081
- this.stateData[id] = vParent;
8211
+ this.$stateData$[id] = vParent;
8082
8212
  }
8083
8213
  parseQRL(qrl) {
8084
8214
  return inflateQRL(this, parseQRL(qrl));
8085
8215
  }
8086
8216
  handleError(err, host) {
8087
- if (qDev) {
8217
+ if (qDev && host) {
8088
8218
  // Clean vdom
8089
8219
  if (typeof document !== 'undefined') {
8090
8220
  const vHost = host;
@@ -8108,7 +8238,7 @@
8108
8238
  throw err;
8109
8239
  }
8110
8240
  }
8111
- const errorStore = this.resolveContext(host, ERROR_CONTEXT);
8241
+ const errorStore = host && this.resolveContext(host, ERROR_CONTEXT);
8112
8242
  if (!errorStore) {
8113
8243
  throw err;
8114
8244
  }
@@ -8144,7 +8274,7 @@
8144
8274
  vNode =
8145
8275
  vnode_getParent(vNode) ||
8146
8276
  // If virtual node, than it could be a slot so we need to read its parent.
8147
- vnode_getProp(vNode, QSlotParent, this.$vnodeLocate$);
8277
+ vnode_getProp(vNode, QSlotParent, this.vNodeLocate);
8148
8278
  }
8149
8279
  else {
8150
8280
  vNode = vnode_getParent(vNode);
@@ -8164,7 +8294,7 @@
8164
8294
  case ELEMENT_PROPS:
8165
8295
  case OnRenderProp:
8166
8296
  case QCtxAttr:
8167
- case QSubscribers:
8297
+ case QBackRefs:
8168
8298
  getObjectById = this.$getObjectById$;
8169
8299
  break;
8170
8300
  case ELEMENT_SEQ_IDX:
@@ -8177,7 +8307,7 @@
8177
8307
  scheduleRender() {
8178
8308
  this.$renderCount$++;
8179
8309
  this.renderDone ||= getPlatform().nextTick(() => this.processChores());
8180
- return this.renderDone;
8310
+ return this.renderDone.finally(() => emitEvent('qrender', { instanceHash: this.$instanceHash$, renderCount: this.$renderCount$ }));
8181
8311
  }
8182
8312
  processChores() {
8183
8313
  let renderCount = this.$renderCount$;
@@ -8200,12 +8330,13 @@
8200
8330
  ensureProjectionResolved(vNode) {
8201
8331
  if ((vNode[VNodeProps.flags] & VNodeFlags.Resolved) === 0) {
8202
8332
  vNode[VNodeProps.flags] |= VNodeFlags.Resolved;
8203
- for (let i = vnode_getPropStartIndex(vNode); i < vNode.length; i = i + 2) {
8204
- const prop = vNode[i];
8333
+ const props = vnode_getProps(vNode);
8334
+ for (let i = 0; i < props.length; i = i + 2) {
8335
+ const prop = props[i];
8205
8336
  if (isSlotProp(prop)) {
8206
- const value = vNode[i + 1];
8337
+ const value = props[i + 1];
8207
8338
  if (typeof value == 'string') {
8208
- vNode[i + 1] = this.$vnodeLocate$(value);
8339
+ props[i + 1] = this.vNodeLocate(value);
8209
8340
  }
8210
8341
  }
8211
8342
  }
@@ -8216,7 +8347,7 @@
8216
8347
  id = parseFloat(id);
8217
8348
  }
8218
8349
  assertTrue(id < this.$rawStateData$.length / 2, `Invalid reference: ${id} >= ${this.$rawStateData$.length / 2}`);
8219
- return this.stateData[id];
8350
+ return this.$stateData$[id];
8220
8351
  };
8221
8352
  getSyncFn(id) {
8222
8353
  const fn = this.$qFuncs$[id];
@@ -8288,8 +8419,7 @@
8288
8419
  ? parseInt(property, 10)
8289
8420
  : NaN;
8290
8421
  if (Number.isNaN(i) || i < 0 || i >= this.$length$) {
8291
- const out = Reflect.get(target, property, receiver);
8292
- return out;
8422
+ return Reflect.get(target, property, receiver);
8293
8423
  }
8294
8424
  // The serialized data is an array with 2 values for each item
8295
8425
  const idx = i * 2;
@@ -8355,6 +8485,7 @@
8355
8485
  switch (typeId) {
8356
8486
  case TypeIds.Object:
8357
8487
  // We use getters for making complex values lazy
8488
+ // TODO scan the data for computeQRLs and schedule resolve chores
8358
8489
  for (let i = 0; i < data.length; i += 4) {
8359
8490
  const key = deserializeData(container, data[i], data[i + 1]);
8360
8491
  const valType = data[i + 2];
@@ -8394,7 +8525,7 @@
8394
8525
  task.$flags$ = v[1];
8395
8526
  task.$index$ = v[2];
8396
8527
  task.$el$ = v[3];
8397
- task.$effectDependencies$ = v[4];
8528
+ task[_EFFECT_BACK_REF] = v[4];
8398
8529
  task.$state$ = v[5];
8399
8530
  break;
8400
8531
  case TypeIds.Resource:
@@ -8417,12 +8548,9 @@
8417
8548
  break;
8418
8549
  case TypeIds.Store:
8419
8550
  case TypeIds.StoreArray: {
8420
- const [value, flags, effects, storeEffect] = data;
8551
+ const [value, flags, effects] = data;
8421
8552
  const store = getOrCreateStore(value, flags, container);
8422
8553
  const storeHandler = getStoreHandler(store);
8423
- if (storeEffect) {
8424
- effects[STORE_ARRAY_PROP] = storeEffect;
8425
- }
8426
8554
  storeHandler.$effects$ = effects;
8427
8555
  target = store;
8428
8556
  break;
@@ -8431,7 +8559,7 @@
8431
8559
  const signal = target;
8432
8560
  const d = data;
8433
8561
  signal.$untrackedValue$ = d[0];
8434
- signal.$effects$ = d.slice(1);
8562
+ signal.$effects$ = new Set(d.slice(1));
8435
8563
  break;
8436
8564
  }
8437
8565
  case TypeIds.WrappedSignal: {
@@ -8439,10 +8567,10 @@
8439
8567
  const d = data;
8440
8568
  signal.$func$ = container.getSyncFn(d[0]);
8441
8569
  signal.$args$ = d[1];
8442
- signal.$effectDependencies$ = d[2];
8570
+ signal[_EFFECT_BACK_REF] = d[2];
8443
8571
  signal.$untrackedValue$ = d[3];
8444
8572
  signal.$hostElement$ = d[4];
8445
- signal.$effects$ = d.slice(5);
8573
+ signal.$effects$ = new Set(d.slice(5));
8446
8574
  break;
8447
8575
  }
8448
8576
  case TypeIds.ComputedSignal: {
@@ -8562,6 +8690,7 @@
8562
8690
  EMPTY_ARRAY,
8563
8691
  EMPTY_OBJ,
8564
8692
  NEEDS_COMPUTATION,
8693
+ STORE_ARRAY_PROP,
8565
8694
  Slot,
8566
8695
  Fragment,
8567
8696
  NaN,
@@ -8642,6 +8771,8 @@
8642
8771
  reject = rej;
8643
8772
  });
8644
8773
  resolvers.set(promise, [resolve, reject]);
8774
+ // Don't leave unhandled promise rejections
8775
+ promise.catch(() => { });
8645
8776
  return promise;
8646
8777
  case TypeIds.Uint8Array:
8647
8778
  const encodedLength = value.length;
@@ -8651,12 +8782,9 @@
8651
8782
  return new Uint8Array(decodedLength);
8652
8783
  case TypeIds.PropsProxy:
8653
8784
  return createPropsProxy(null, null);
8654
- case TypeIds.RefVNode:
8655
8785
  case TypeIds.VNode:
8656
- const vnodeOrDocument = retrieveVNodeOrDocument(container, value);
8657
- if (typeId === TypeIds.VNode) {
8658
- return vnodeOrDocument;
8659
- }
8786
+ return retrieveVNodeOrDocument(container, value);
8787
+ case TypeIds.RefVNode:
8660
8788
  const vNode = retrieveVNodeOrDocument(container, value);
8661
8789
  if (vnode_isVNode(vNode)) {
8662
8790
  return vnode_getNode(vNode);
@@ -8665,7 +8793,7 @@
8665
8793
  throw qError(QError.serializeErrorExpectedVNode, [typeof vNode]);
8666
8794
  }
8667
8795
  case TypeIds.EffectData:
8668
- return new EffectPropData({});
8796
+ return new SubscriptionData({});
8669
8797
  default:
8670
8798
  throw qError(QError.serializeErrorCannotAllocate, [typeId]);
8671
8799
  }
@@ -8697,7 +8825,7 @@
8697
8825
  assertDefined(backChannel, 'Missing QRL_RUNTIME_CHUNK');
8698
8826
  qrlRef = backChannel.get(symbol);
8699
8827
  }
8700
- return createQRL(chunk, symbol, qrlRef, null, captureIds, null, null);
8828
+ return createQRL(chunk, symbol, qrlRef, null, captureIds, null);
8701
8829
  }
8702
8830
  function inflateQRL(container, qrl) {
8703
8831
  const captureIds = qrl.$capture$;
@@ -8815,7 +8943,7 @@
8815
8943
  /** Visit an object, adding anything that will be serialized as to scan */
8816
8944
  const visit = (obj) => {
8817
8945
  if (typeof obj === 'function') {
8818
- if (isQrl(obj)) {
8946
+ if (isQrl$1(obj)) {
8819
8947
  if (obj.$captureRef$) {
8820
8948
  discoveredValues.push(...obj.$captureRef$);
8821
8949
  }
@@ -8834,6 +8962,7 @@
8834
8962
  obj instanceof RegExp ||
8835
8963
  obj instanceof Uint8Array ||
8836
8964
  obj instanceof URLSearchParams ||
8965
+ vnode_isVNode(obj) ||
8837
8966
  (typeof FormData !== 'undefined' && obj instanceof FormData) ||
8838
8967
  // Ignore the no serialize objects
8839
8968
  fastSkipSerialize(obj)) ;
@@ -8843,8 +8972,7 @@
8843
8972
  else if (isStore(obj)) {
8844
8973
  const target = getStoreTarget(obj);
8845
8974
  const effects = getStoreHandler(obj).$effects$;
8846
- const storeEffect = effects?.[STORE_ARRAY_PROP] ?? null;
8847
- discoveredValues.push(target, effects, storeEffect);
8975
+ discoveredValues.push(target, effects);
8848
8976
  for (const prop in target) {
8849
8977
  const propValue = target[prop];
8850
8978
  if (storeProxyMap.has(propValue)) {
@@ -8878,9 +9006,7 @@
8878
9006
  }
8879
9007
  // WrappedSignal uses syncQrl which has no captured refs
8880
9008
  if (obj instanceof WrappedSignal) {
8881
- if (obj.$effectDependencies$) {
8882
- discoveredValues.push(...obj.$effectDependencies$);
8883
- }
9009
+ discoverEffectBackRefs(obj[_EFFECT_BACK_REF], discoveredValues);
8884
9010
  if (obj.$args$) {
8885
9011
  discoveredValues.push(...obj.$args$);
8886
9012
  }
@@ -8893,7 +9019,8 @@
8893
9019
  }
8894
9020
  }
8895
9021
  else if (obj instanceof Task) {
8896
- discoveredValues.push(obj.$el$, obj.$qrl$, obj.$state$, obj.$effectDependencies$);
9022
+ discoveredValues.push(obj.$el$, obj.$qrl$, obj.$state$);
9023
+ discoverEffectBackRefs(obj[_EFFECT_BACK_REF], discoveredValues);
8897
9024
  }
8898
9025
  else if (isSsrNode(obj)) {
8899
9026
  discoverValuesForVNodeData(obj.vnodeData, discoveredValues);
@@ -8912,7 +9039,7 @@
8912
9039
  else if (Array.isArray(obj)) {
8913
9040
  discoveredValues.push(...obj);
8914
9041
  }
8915
- else if (isQrl(obj)) {
9042
+ else if (isQrl$1(obj)) {
8916
9043
  obj.$captureRef$ && obj.$captureRef$.length && discoveredValues.push(...obj.$captureRef$);
8917
9044
  }
8918
9045
  else if (isPropsProxy(obj)) {
@@ -8928,7 +9055,7 @@
8928
9055
  });
8929
9056
  promises.push(obj);
8930
9057
  }
8931
- else if (obj instanceof EffectPropData) {
9058
+ else if (obj instanceof SubscriptionData) {
8932
9059
  discoveredValues.push(obj.data);
8933
9060
  }
8934
9061
  else if (isObjectLiteral(obj)) {
@@ -8973,15 +9100,31 @@
8973
9100
  for (const value of vnodeData) {
8974
9101
  if (isSsrAttrs(value)) {
8975
9102
  for (let i = 1; i < value.length; i += 2) {
8976
- if (value[i - 1] === ELEMENT_KEY) {
9103
+ const attrValue = value[i];
9104
+ if (typeof attrValue === 'string') {
8977
9105
  continue;
8978
9106
  }
8979
- const attrValue = value[i];
8980
9107
  discoveredValues.push(attrValue);
8981
9108
  }
8982
9109
  }
8983
9110
  }
8984
9111
  };
9112
+ const discoverEffectBackRefs = (effectsBackRefs, discoveredValues) => {
9113
+ if (effectsBackRefs) {
9114
+ // We need serialize effect subscriptions with back refs
9115
+ let hasBackRefs = false;
9116
+ for (const [, effect] of effectsBackRefs) {
9117
+ const backRefs = effect[EffectSubscriptionProp.BACK_REF];
9118
+ if (backRefs) {
9119
+ hasBackRefs = true;
9120
+ break;
9121
+ }
9122
+ }
9123
+ if (hasBackRefs) {
9124
+ discoveredValues.push(effectsBackRefs);
9125
+ }
9126
+ }
9127
+ };
8985
9128
  const promiseResults = new WeakMap();
8986
9129
  /**
8987
9130
  * Format:
@@ -9053,7 +9196,7 @@
9053
9196
  else if (value === Fragment) {
9054
9197
  output(TypeIds.Constant, Constants.Fragment);
9055
9198
  }
9056
- else if (isQrl(value)) {
9199
+ else if (isQrl$1(value)) {
9057
9200
  const qrl = qrlToString(serializationContext, value);
9058
9201
  const id = serializationContext.$addRoot$(qrl);
9059
9202
  output(TypeIds.QRL, id);
@@ -9128,6 +9271,9 @@
9128
9271
  else if (value === NEEDS_COMPUTATION) {
9129
9272
  output(TypeIds.Constant, Constants.NEEDS_COMPUTATION);
9130
9273
  }
9274
+ else if (value === STORE_ARRAY_PROP) {
9275
+ output(TypeIds.Constant, Constants.STORE_ARRAY_PROP);
9276
+ }
9131
9277
  else {
9132
9278
  throw qError(QError.serializeErrorUnknownType, [typeof value]);
9133
9279
  }
@@ -9164,7 +9310,7 @@
9164
9310
  : 0;
9165
9311
  output(TypeIds.PropsProxy, out);
9166
9312
  }
9167
- else if (value instanceof EffectPropData) {
9313
+ else if (value instanceof SubscriptionData) {
9168
9314
  output(TypeIds.EffectData, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
9169
9315
  }
9170
9316
  else if (isStore(value)) {
@@ -9175,6 +9321,7 @@
9175
9321
  if (!res) {
9176
9322
  throw qError(QError.serializeErrorUnvisited, ['resource']);
9177
9323
  }
9324
+ // TODO the effects include the resourcereturn which has duplicate data
9178
9325
  output(TypeIds.Resource, [...res, getStoreHandler(value).$effects$]);
9179
9326
  }
9180
9327
  else {
@@ -9182,7 +9329,6 @@
9182
9329
  const storeTarget = getStoreTarget(value);
9183
9330
  const flags = storeHandler.$flags$;
9184
9331
  const effects = storeHandler.$effects$;
9185
- const storeEffect = effects?.[STORE_ARRAY_PROP] ?? null;
9186
9332
  const innerStores = [];
9187
9333
  for (const prop in storeTarget) {
9188
9334
  const propValue = storeTarget[prop];
@@ -9192,7 +9338,7 @@
9192
9338
  serializationContext.$addRoot$(innerStore);
9193
9339
  }
9194
9340
  }
9195
- const out = [storeTarget, flags, effects, storeEffect, ...innerStores];
9341
+ const out = [storeTarget, flags, effects, ...innerStores];
9196
9342
  while (out[out.length - 1] == null) {
9197
9343
  out.pop();
9198
9344
  }
@@ -9231,7 +9377,7 @@
9231
9377
  if (value instanceof WrappedSignal) {
9232
9378
  output(TypeIds.WrappedSignal, [
9233
9379
  ...serializeWrappingFn(serializationContext, value),
9234
- value.$effectDependencies$,
9380
+ filterEffectBackRefs(value[_EFFECT_BACK_REF]),
9235
9381
  v,
9236
9382
  value.$hostElement$,
9237
9383
  ...(value.$effects$ || []),
@@ -9338,7 +9484,7 @@
9338
9484
  value.$flags$,
9339
9485
  value.$index$,
9340
9486
  value.$el$,
9341
- value.$effectDependencies$,
9487
+ value[_EFFECT_BACK_REF],
9342
9488
  value.$state$,
9343
9489
  ];
9344
9490
  while (out[out.length - 1] == null) {
@@ -9361,12 +9507,27 @@
9361
9507
  const out = btoa(buf).replace(/=+$/, '');
9362
9508
  output(TypeIds.Uint8Array, out);
9363
9509
  }
9510
+ else if (vnode_isVNode(value)) {
9511
+ output(TypeIds.Constant, Constants.Undefined);
9512
+ }
9364
9513
  else {
9365
9514
  throw qError(QError.serializeErrorUnknownType, [typeof value]);
9366
9515
  }
9367
9516
  };
9368
9517
  writeValue(serializationContext.$roots$, -1);
9369
9518
  }
9519
+ function filterEffectBackRefs(effectBackRef) {
9520
+ let effectBackRefToSerialize = null;
9521
+ if (effectBackRef) {
9522
+ for (const [effectProp, effect] of effectBackRef) {
9523
+ if (effect[EffectSubscriptionProp.BACK_REF]) {
9524
+ effectBackRefToSerialize ||= new Map();
9525
+ effectBackRefToSerialize.set(effectProp, effect);
9526
+ }
9527
+ }
9528
+ }
9529
+ return effectBackRefToSerialize;
9530
+ }
9370
9531
  function serializeWrappingFn(serializationContext, value) {
9371
9532
  // if value is an object then we need to wrap this in ()
9372
9533
  if (value.$funcStr$ && value.$funcStr$[0] === '{') {
@@ -9379,15 +9540,12 @@
9379
9540
  function qrlToString(serializationContext, value) {
9380
9541
  let symbol = value.$symbol$;
9381
9542
  let chunk = value.$chunk$;
9382
- const refSymbol = value.$refSymbol$ ?? symbol;
9383
9543
  const platform = getPlatform();
9384
9544
  if (platform) {
9385
- const result = platform.chunkForSymbol(refSymbol, chunk, value.dev?.file);
9545
+ const result = platform.chunkForSymbol(symbol, chunk, value.dev?.file);
9386
9546
  if (result) {
9387
9547
  chunk = result[1];
9388
- if (!value.$refSymbol$) {
9389
- symbol = result[0];
9390
- }
9548
+ symbol = result[0];
9391
9549
  }
9392
9550
  }
9393
9551
  const isSync = isSyncQrl(value);
@@ -9564,9 +9722,9 @@
9564
9722
  return ((typeof obj === 'object' &&
9565
9723
  obj !== null &&
9566
9724
  (obj instanceof Signal || obj instanceof Task || isJSXNode(obj))) ||
9567
- isQrl(obj));
9725
+ isQrl$1(obj));
9568
9726
  };
9569
- const canSerialize = (value) => {
9727
+ const canSerialize = (value, seen = new WeakSet()) => {
9570
9728
  if (value == null ||
9571
9729
  typeof value === 'string' ||
9572
9730
  typeof value === 'number' ||
@@ -9575,6 +9733,10 @@
9575
9733
  return true;
9576
9734
  }
9577
9735
  else if (typeof value === 'object') {
9736
+ if (seen.has(value)) {
9737
+ return true;
9738
+ }
9739
+ seen.add(value);
9578
9740
  const proto = Object.getPrototypeOf(value);
9579
9741
  if (isStore(value)) {
9580
9742
  value = getStoreTarget(value);
@@ -9583,7 +9745,7 @@
9583
9745
  for (const key in value) {
9584
9746
  // if the value is a props proxy, then sometimes we could create a component-level subscription,
9585
9747
  // so we should call untrack here to avoid tracking the value
9586
- if (!canSerialize(untrack(() => value[key]))) {
9748
+ if (!canSerialize(untrack(() => value[key]), seen)) {
9587
9749
  return false;
9588
9750
  }
9589
9751
  }
@@ -9591,7 +9753,7 @@
9591
9753
  }
9592
9754
  else if (proto == Array.prototype) {
9593
9755
  for (let i = 0; i < value.length; i++) {
9594
- if (!canSerialize(value[i])) {
9756
+ if (!canSerialize(value[i], seen)) {
9595
9757
  return false;
9596
9758
  }
9597
9759
  }
@@ -9641,7 +9803,7 @@
9641
9803
  }
9642
9804
  }
9643
9805
  else if (typeof value === 'function') {
9644
- if (isQrl(value) || isQwikComponent(value)) {
9806
+ if (isQrl$1(value) || isQwikComponent(value)) {
9645
9807
  return true;
9646
9808
  }
9647
9809
  }
@@ -9694,20 +9856,21 @@
9694
9856
  Constants[Constants["EMPTY_ARRAY"] = 5] = "EMPTY_ARRAY";
9695
9857
  Constants[Constants["EMPTY_OBJ"] = 6] = "EMPTY_OBJ";
9696
9858
  Constants[Constants["NEEDS_COMPUTATION"] = 7] = "NEEDS_COMPUTATION";
9697
- Constants[Constants["Slot"] = 8] = "Slot";
9698
- Constants[Constants["Fragment"] = 9] = "Fragment";
9699
- Constants[Constants["NaN"] = 10] = "NaN";
9700
- Constants[Constants["PositiveInfinity"] = 11] = "PositiveInfinity";
9701
- Constants[Constants["NegativeInfinity"] = 12] = "NegativeInfinity";
9702
- Constants[Constants["MaxSafeInt"] = 13] = "MaxSafeInt";
9859
+ Constants[Constants["STORE_ARRAY_PROP"] = 8] = "STORE_ARRAY_PROP";
9860
+ Constants[Constants["Slot"] = 9] = "Slot";
9861
+ Constants[Constants["Fragment"] = 10] = "Fragment";
9862
+ Constants[Constants["NaN"] = 11] = "NaN";
9863
+ Constants[Constants["PositiveInfinity"] = 12] = "PositiveInfinity";
9864
+ Constants[Constants["NegativeInfinity"] = 13] = "NegativeInfinity";
9865
+ Constants[Constants["MaxSafeInt"] = 14] = "MaxSafeInt";
9703
9866
  // used for close fragment
9704
- Constants[Constants["AlmostMaxSafeInt"] = 14] = "AlmostMaxSafeInt";
9705
- Constants[Constants["MinSafeInt"] = 15] = "MinSafeInt";
9867
+ Constants[Constants["AlmostMaxSafeInt"] = 15] = "AlmostMaxSafeInt";
9868
+ Constants[Constants["MinSafeInt"] = 16] = "MinSafeInt";
9706
9869
  })(Constants || (Constants = {}));
9707
9870
 
9708
9871
  /** @internal */
9709
9872
  const verifySerializable = (value, preMessage) => {
9710
- const seen = new Set();
9873
+ const seen = new WeakSet();
9711
9874
  return _verifySerializable(value, seen, '_', preMessage);
9712
9875
  };
9713
9876
  const _verifySerializable = (value, seen, ctx, preMessage) => {
@@ -9716,10 +9879,12 @@
9716
9879
  return value;
9717
9880
  }
9718
9881
  if (shouldSerialize(unwrapped)) {
9719
- if (seen.has(unwrapped)) {
9720
- return value;
9882
+ if (typeof unwrapped === 'object') {
9883
+ if (seen.has(unwrapped)) {
9884
+ return value;
9885
+ }
9886
+ seen.add(unwrapped);
9721
9887
  }
9722
- seen.add(unwrapped);
9723
9888
  if (isSignal(unwrapped)) {
9724
9889
  return value;
9725
9890
  }
@@ -9823,16 +9988,7 @@
9823
9988
  return input;
9824
9989
  };
9825
9990
 
9826
- const isQrl = (value) => {
9827
- return typeof value === 'function' && typeof value.getSymbol === 'function';
9828
- };
9829
- // Make sure this value is same as value in `platform.ts`
9830
- const SYNC_QRL = '<sync>';
9831
- /** Sync QRL is a function which is serialized into `<script q:func="qwik/json">` tag. */
9832
- const isSyncQrl = (value) => {
9833
- return isQrl(value) && value.$symbol$ == SYNC_QRL;
9834
- };
9835
- const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef, refSymbol) => {
9991
+ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
9836
9992
  if (qDev && qSerialize) {
9837
9993
  if (captureRef) {
9838
9994
  for (const item of captureRef) {
@@ -9854,9 +10010,14 @@
9854
10010
  };
9855
10011
  function bindFnToContext(currentCtx, beforeFn) {
9856
10012
  // Note that we bind the current `this`
9857
- return (...args) => maybeThen(resolveLazy(), (fn) => {
9858
- if (!isFunction(fn)) {
9859
- throw qError(QError.qrlIsNotFunction);
10013
+ const bound = (...args) => {
10014
+ if (!qrl.resolved) {
10015
+ return qrl.resolve().then((fn) => {
10016
+ if (!isFunction(fn)) {
10017
+ throw qError(QError.qrlIsNotFunction);
10018
+ }
10019
+ return bound(...args);
10020
+ });
9860
10021
  }
9861
10022
  if (beforeFn && beforeFn() === false) {
9862
10023
  return;
@@ -9869,13 +10030,14 @@
9869
10030
  context.$qrl$ = qrl;
9870
10031
  context.$event$ ||= this;
9871
10032
  try {
9872
- return invoke.call(this, context, fn, ...args);
10033
+ return invoke.call(this, context, symbolRef, ...args);
9873
10034
  }
9874
10035
  finally {
9875
10036
  context.$qrl$ = prevQrl;
9876
10037
  context.$event$ = prevEvent;
9877
10038
  }
9878
- });
10039
+ };
10040
+ return bound;
9879
10041
  }
9880
10042
  const resolveLazy = (containerEl) => {
9881
10043
  return symbolRef !== null ? symbolRef : resolve(containerEl);
@@ -9887,8 +10049,20 @@
9887
10049
  }
9888
10050
  return function (...args) {
9889
10051
  let context = tryGetInvokeContext();
10052
+ // use the given qrl if it is the right one
9890
10053
  if (context) {
9891
- return fn.apply(this, args);
10054
+ // TODO check if this is necessary in production
10055
+ if (context.$qrl$?.$symbol$ === qrl.$symbol$) {
10056
+ return fn.apply(this, args);
10057
+ }
10058
+ const prevQrl = context.$qrl$;
10059
+ context.$qrl$ = qrl;
10060
+ try {
10061
+ return fn.apply(this, args);
10062
+ }
10063
+ finally {
10064
+ context.$qrl$ = prevQrl;
10065
+ }
9892
10066
  }
9893
10067
  context = newInvokeContext();
9894
10068
  context.$qrl$ = qrl;
@@ -9916,11 +10090,11 @@
9916
10090
  const start = now();
9917
10091
  const ctx = tryGetInvokeContext();
9918
10092
  if (symbolFn !== null) {
9919
- symbolRef = symbolFn().then((module) => (qrl.resolved = symbolRef = wrapFn(module[symbol])));
10093
+ symbolRef = symbolFn().then((module) => (qrl.resolved = wrapFn((symbolRef = module[symbol]))));
9920
10094
  }
9921
10095
  else {
9922
10096
  const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
9923
- symbolRef = maybeThen(imported, (ref) => (qrl.resolved = symbolRef = wrapFn(ref)));
10097
+ symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
9924
10098
  }
9925
10099
  if (typeof symbolRef === 'object' && isPromise(symbolRef)) {
9926
10100
  symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
@@ -9943,10 +10117,9 @@
9943
10117
  return invoke;
9944
10118
  }
9945
10119
  };
9946
- const resolvedSymbol = refSymbol ?? symbol;
9947
- const hash = getSymbolHash(resolvedSymbol);
10120
+ const hash = getSymbolHash(symbol);
9948
10121
  Object.assign(qrl, {
9949
- getSymbol: () => resolvedSymbol,
10122
+ getSymbol: () => symbol,
9950
10123
  getHash: () => hash,
9951
10124
  getCaptured: () => captureRef,
9952
10125
  resolve,
@@ -9954,7 +10127,6 @@
9954
10127
  $setContainer$: setContainer,
9955
10128
  $chunk$: chunk,
9956
10129
  $symbol$: symbol,
9957
- $refSymbol$: refSymbol,
9958
10130
  $hash$: hash,
9959
10131
  getFn: bindFnToContext,
9960
10132
  $capture$: capture,
@@ -9963,8 +10135,8 @@
9963
10135
  resolved: undefined,
9964
10136
  });
9965
10137
  if (symbolRef) {
9966
- // Replace symbolRef with (a promise for) the value or wrapped function
9967
- symbolRef = maybeThen(symbolRef, (resolved) => (qrl.resolved = symbolRef = wrapFn(resolved)));
10138
+ // Unwrap any promises
10139
+ symbolRef = maybeThen(symbolRef, (resolved) => (qrl.resolved = wrapFn((symbolRef = resolved))));
9968
10140
  }
9969
10141
  if (build.isDev) {
9970
10142
  Object.defineProperty(qrl, '_devOnlySymbolRef', {
@@ -9978,20 +10150,6 @@
9978
10150
  }
9979
10151
  return qrl;
9980
10152
  };
9981
- const getSymbolHash = (symbolName) => {
9982
- const index = symbolName.lastIndexOf('_');
9983
- if (index > -1) {
9984
- return symbolName.slice(index + 1);
9985
- }
9986
- return symbolName;
9987
- };
9988
- function assertQrl(qrl) {
9989
- if (qDev) {
9990
- if (!isQrl(qrl)) {
9991
- throw new Error('Not a QRL');
9992
- }
9993
- }
9994
- }
9995
10153
  const EMITTED = /*#__PURE__*/ new Set();
9996
10154
  const emitUsedSymbol = (symbol, element, reqTime) => {
9997
10155
  if (!EMITTED.has(symbol)) {
@@ -10104,7 +10262,7 @@
10104
10262
  if (!qRuntimeQrl && qDev) {
10105
10263
  throw new Error('Optimizer should replace all usages of $() with some special syntax. If you need to create a QRL manually, use inlinedQrl() instead.');
10106
10264
  }
10107
- return createQRL(null, 's' + runtimeSymbolId++, expression, null, null, null, null);
10265
+ return createQRL(null, 's' + runtimeSymbolId++, expression, null, null, null);
10108
10266
  };
10109
10267
  /** @private Use To avoid optimizer replacement */
10110
10268
  const dollar = $;
@@ -10130,7 +10288,7 @@
10130
10288
  // eslint-disable-next-line no-new-func
10131
10289
  fn = new Function('return ' + fn.toString())();
10132
10290
  }
10133
- return createQRL('', SYNC_QRL, fn, null, null, null, null);
10291
+ return createQRL('', SYNC_QRL, fn, null, null, null);
10134
10292
  };
10135
10293
  /**
10136
10294
  * Extract function into a synchronously loadable QRL.
@@ -10147,7 +10305,7 @@
10147
10305
  serializedFn = fn.toString();
10148
10306
  }
10149
10307
  fn.serialized = serializedFn;
10150
- return createQRL('', SYNC_QRL, fn, null, null, null, null);
10308
+ return createQRL('', SYNC_QRL, fn, null, null, null);
10151
10309
  };
10152
10310
 
10153
10311
  /** @internal */
@@ -10866,6 +11024,21 @@
10866
11024
  iCtx.$container$.$scheduler$(ChoreType.VISIBLE, task);
10867
11025
  }
10868
11026
  };
11027
+ const useRunTask = (task, eagerness) => {
11028
+ if (eagerness === 'intersection-observer') {
11029
+ useOn('qvisible', getTaskHandlerQrl(task));
11030
+ }
11031
+ else if (eagerness === 'document-ready') {
11032
+ useOnDocument('qinit', getTaskHandlerQrl(task));
11033
+ }
11034
+ else if (eagerness === 'document-idle') {
11035
+ useOnDocument('qidle', getTaskHandlerQrl(task));
11036
+ }
11037
+ };
11038
+ const getTaskHandlerQrl = (task) => {
11039
+ const taskHandler = createQRL(null, '_task', scheduleTask, null, null, [task]);
11040
+ return taskHandler;
11041
+ };
10869
11042
 
10870
11043
  // <docs markdown="../readme.md#useResource">
10871
11044
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
@@ -11202,8 +11375,9 @@
11202
11375
  exports.Slot = Slot;
11203
11376
  exports._CONST_PROPS = _CONST_PROPS;
11204
11377
  exports._DomContainer = DomContainer;
11378
+ exports._EFFECT_BACK_REF = _EFFECT_BACK_REF;
11205
11379
  exports._EMPTY_ARRAY = EMPTY_ARRAY;
11206
- exports._EffectData = EffectPropData;
11380
+ exports._EffectData = SubscriptionData;
11207
11381
  exports._IMMUTABLE = _IMMUTABLE;
11208
11382
  exports._SharedContainer = _SharedContainer;
11209
11383
  exports._VAR_PROPS = _VAR_PROPS;
@@ -11213,7 +11387,6 @@
11213
11387
  exports._getContextEvent = _getContextEvent;
11214
11388
  exports._getDomContainer = getDomContainer;
11215
11389
  exports._getQContainerElement = _getQContainerElement;
11216
- exports._hW = _hW;
11217
11390
  exports._isJSXNode = isJSXNode;
11218
11391
  exports._isStringifiable = isStringifiable;
11219
11392
  exports._jsxBranch = _jsxBranch;
@@ -11227,7 +11400,9 @@
11227
11400
  exports._qrlSync = _qrlSync;
11228
11401
  exports._regSymbol = _regSymbol;
11229
11402
  exports._restProps = _restProps;
11403
+ exports._run = queueQRL;
11230
11404
  exports._serialize = _serialize;
11405
+ exports._task = scheduleTask;
11231
11406
  exports._verifySerializable = verifySerializable;
11232
11407
  exports._waitUntilRendered = _waitUntilRendered;
11233
11408
  exports._walkJSX = _walkJSX;