@qwik.dev/core 2.0.0-beta.31 → 2.0.0-beta.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * @qwik.dev/core 2.0.0-beta.31-dev+906321a
3
+ * @qwik.dev/core 2.0.0-beta.32-dev+0e29f8a
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
@@ -189,9 +189,11 @@ const isPrimitiveOrNullUndefined = (v) => {
189
189
  return (typeof v !== 'object' && typeof v !== 'function') || v === null || v === undefined;
190
190
  };
191
191
 
192
+ const baseUrl = 'https://qwikdev-build-v2.qwik-8nx.pages.dev/docs/errors/#Q';
192
193
  const codeToText = (code, ...parts) => {
193
194
  if (qDev) {
194
195
  // Keep one error, one line to make it easier to search for the error message.
196
+ // Keep in sync with packages/docs/src/routes/docs/errors/index.mdx
195
197
  const MAP = [
196
198
  'Error while serializing class or style attributes', // 0
197
199
  'Scheduler not found', // 1
@@ -228,6 +230,7 @@ const codeToText = (code, ...parts) => {
228
230
  'Attribute value is unsafe for SSR {{0}}', // 32
229
231
  'SerializerSymbol function returned rejected promise', // 33
230
232
  'Serialization Error: Cannot serialize function: {{0}}', // 34
233
+ 'Cannot read .value of a clientOnly async signal during SSR. Use .loading to check state, or provide an initial value.', // 35
231
234
  ];
232
235
  let text = MAP[code] ?? '';
233
236
  if (parts.length) {
@@ -242,9 +245,7 @@ const codeToText = (code, ...parts) => {
242
245
  return `Code(Q${code}): ${text}`;
243
246
  }
244
247
  else {
245
- // cute little hack to give roughly the correct line number. Update the line number if it shifts.
246
- // TODO change the URL after merging into main
247
- return `Code(Q${code}) https://github.com/QwikDev/qwik/blob/build/v2/packages/qwik/src/core/shared/error/error.ts#${parts.join()}L${9 + code}`;
248
+ return `Code(Q${code}) ${baseUrl}${code}`;
248
249
  }
249
250
  };
250
251
  const qError = (code, errorMessageArgs = []) => {
@@ -571,49 +572,52 @@ const addComponentStylePrefix = (styleId) => {
571
572
  * - A `-` (not at the beginning) makes next character uppercase: `dbl-click` => `dblClick`
572
573
  */
573
574
  const EVENT_SUFFIX = '$';
575
+ const DOM_CONTENT_LOADED_EVENT = 'DOMContentLoaded';
574
576
  const isHtmlAttributeAnEventName = (name) => {
575
577
  return (name.charCodeAt(0) === 113 /* q */ &&
576
578
  name.charCodeAt(1) === 45 /* - */ &&
577
- name.charCodeAt(3) === 58 /* : */);
579
+ (name.charCodeAt(3) === 58 /* : */ ||
580
+ (name.charCodeAt(3) === 112 /* p */ && name.charCodeAt(4) === 58)) /* : */);
578
581
  };
579
- function jsxEventToHtmlAttribute(jsxEvent) {
582
+ function jsxEventToHtmlAttribute(jsxEvent, isPassive = false) {
580
583
  if (jsxEvent.endsWith(EVENT_SUFFIX)) {
581
- const [prefix, idx] = getEventScopeDataFromJsxEvent(jsxEvent);
584
+ const [prefix, idx] = getEventScopeDataFromJsxEvent(jsxEvent, isPassive);
582
585
  if (idx !== -1) {
583
- const name = jsxEvent.slice(idx, -1);
584
- return name === 'DOMContentLoaded'
585
- ? // The only DOM event that is not all lowercase
586
- prefix + '-d-o-m-content-loaded'
587
- : createEventName(name.charAt(0) === '-'
588
- ? // marker for case sensitive event name
589
- name.slice(1)
590
- : name.toLowerCase(), prefix);
586
+ return prefix + normalizeJsxEventName(jsxEvent.slice(idx, -1));
591
587
  }
592
588
  }
593
589
  return null; // Return null if not matching expected format
594
590
  }
595
- function createEventName(event, prefix) {
591
+ function createEventName(event, prefix = '') {
596
592
  const eventName = fromCamelToKebabCase(event);
597
593
  return prefix + eventName;
598
594
  }
599
- function getEventScopeDataFromJsxEvent(eventName) {
595
+ function getEventScopeDataFromJsxEvent(eventName, isPassive = false) {
600
596
  let prefix;
601
597
  let idx = -1;
602
598
  // set prefix and idx based on the scope
603
599
  if (eventName.startsWith("on" /* EventNameJSXScope.on */)) {
604
- prefix = "q-e:" /* EventNameHtmlScope.on */;
600
+ prefix = isPassive ? "q-ep:" /* EventNameHtmlScope.onPassive */ : "q-e:" /* EventNameHtmlScope.on */;
605
601
  idx = 2;
606
602
  }
607
603
  else if (eventName.startsWith("window:on" /* EventNameJSXScope.window */)) {
608
- prefix = "q-w:" /* EventNameHtmlScope.window */;
604
+ prefix = isPassive ? "q-wp:" /* EventNameHtmlScope.windowPassive */ : "q-w:" /* EventNameHtmlScope.window */;
609
605
  idx = 9;
610
606
  }
611
607
  else if (eventName.startsWith("document:on" /* EventNameJSXScope.document */)) {
612
- prefix = "q-d:" /* EventNameHtmlScope.document */;
608
+ prefix = isPassive ? "q-dp:" /* EventNameHtmlScope.documentPassive */ : "q-d:" /* EventNameHtmlScope.document */;
613
609
  idx = 11;
614
610
  }
615
611
  return [prefix, idx];
616
612
  }
613
+ const normalizeJsxEventName = (name) => {
614
+ return name === DOM_CONTENT_LOADED_EVENT
615
+ ? '-d-o-m-content-loaded'
616
+ : createEventName(name.charAt(0) === '-'
617
+ ? // marker for case sensitive event name
618
+ name.slice(1)
619
+ : name.toLowerCase());
620
+ };
617
621
  function isPreventDefault(key) {
618
622
  return key.startsWith('preventdefault:');
619
623
  }
@@ -621,11 +625,11 @@ function isPreventDefault(key) {
621
625
  const fromCamelToKebabCase = (text) => {
622
626
  return text.replace(/([A-Z-])/g, (a) => '-' + a.toLowerCase());
623
627
  };
624
- /** E.g. `"q-e:click"` => `['e', 'click']` */
625
- const getEventDataFromHtmlAttribute = (htmlKey) => [
626
- htmlKey.charAt(2),
627
- htmlKey.substring(4),
628
- ];
628
+ /** E.g. `"q-e:click"` => `['e', 'click']`, `"q-ep:click"` => `['ep', 'click']` */
629
+ const getEventDataFromHtmlAttribute = (htmlKey) => {
630
+ const separatorIndex = htmlKey.indexOf(':');
631
+ return [htmlKey.slice(2, separatorIndex), htmlKey.slice(separatorIndex + 1)];
632
+ };
629
633
  /** E.g. `"e:click"`, `"w:load"` */
630
634
  const getScopedEventName = (scope, eventName) => scope + ':' + eventName;
631
635
 
@@ -1215,7 +1219,7 @@ const COMMA = ',';
1215
1219
  *
1216
1220
  * @public
1217
1221
  */
1218
- const version = "2.0.0-beta.31-dev+906321a";
1222
+ const version = "2.0.0-beta.32-dev+0e29f8a";
1219
1223
 
1220
1224
  const isNode = (value) => {
1221
1225
  return value && typeof value.nodeType === 'number';
@@ -2033,19 +2037,16 @@ console.log('ASYNC COMPUTED SIGNAL', ...args.map(qwikDebugToString));
2033
2037
  /** Retains job metadata and also serves as the argument for the compute function */
2034
2038
  class AsyncJob {
2035
2039
  $signal$;
2036
- info;
2037
- $infoVersion$;
2038
2040
  /** First holds the compute promise and then the cleanup promise */
2039
2041
  $promise$ = null;
2040
2042
  $cleanupRequested$ = false;
2041
2043
  $canWrite$ = true;
2042
- $track$;
2043
- $cleanups$;
2044
- $abortController$;
2045
2044
  constructor($signal$, info, $infoVersion$) {
2046
2045
  this.$signal$ = $signal$;
2047
- this.info = info;
2048
- this.$infoVersion$ = $infoVersion$;
2046
+ if (info !== undefined) {
2047
+ this.info = info;
2048
+ this.$infoVersion$ = $infoVersion$;
2049
+ }
2049
2050
  }
2050
2051
  get track() {
2051
2052
  return (this.$track$ ||= trackFn(this.$signal$, this.$signal$.$container$));
@@ -2056,7 +2057,7 @@ class AsyncJob {
2056
2057
  /** Backward compatible cache method for resource */
2057
2058
  cache() {
2058
2059
  isDev &&
2059
- console.error('useResource cache() method does not do anything. Use `useAsync$` instead of `useResource$`, use the `interval` option for polling behavior.');
2060
+ console.error('useResource cache() method does not do anything. Use `useAsync$` instead of `useResource$`, use the `expires` option for polling behavior.');
2060
2061
  }
2061
2062
  get previous() {
2062
2063
  const val = this.$signal$.$untrackedValue$;
@@ -2076,48 +2077,55 @@ class AsyncJob {
2076
2077
  * AsyncSignalImpl
2077
2078
  *
2078
2079
  * # ================================
2080
+ *
2081
+ * @internal
2079
2082
  */
2080
2083
  class AsyncSignalImpl extends ComputedSignalImpl {
2081
2084
  $untrackedLoading$ = false;
2082
2085
  $untrackedError$ = undefined;
2083
- $loadingEffects$ = undefined;
2084
- $errorEffects$ = undefined;
2085
2086
  $current$ = null;
2086
- // TODO only create the array if concurrency > 1
2087
- $jobs$ = [];
2088
- $concurrency$ = 1;
2089
- $interval$ = 0;
2090
- $timeoutMs$;
2091
- $info$ = undefined;
2092
- $infoVersion$ = 0;
2093
2087
  [_EFFECT_BACK_REF] = undefined;
2094
2088
  constructor(container, fn, flags = 1 /* SignalFlags.INVALID */ |
2095
2089
  16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */, options) {
2096
2090
  super(container, fn, flags);
2097
- const interval = options?.interval;
2098
- const concurrency = options?.concurrency ?? 1;
2099
- const initial = options?.initial;
2100
- const timeout = options?.timeout;
2101
- const eagerCleanup = options?.eagerCleanup;
2102
- const clientOnly = options?.clientOnly;
2091
+ if (!options) {
2092
+ return;
2093
+ }
2103
2094
  // Handle initial value - eagerly evaluate if function, set $untrackedValue$ and $promiseValue$
2104
2095
  // Do NOT call setValue() which would clear the INVALID flag and prevent async computation
2096
+ const initial = options.initial;
2105
2097
  if (initial !== undefined) {
2106
2098
  const initialValue = typeof initial === 'function' ? initial() : initial;
2107
2099
  this.$untrackedValue$ = initialValue;
2108
2100
  }
2109
- this.$concurrency$ = concurrency;
2101
+ const concurrency = options.concurrency;
2102
+ if (concurrency !== undefined && concurrency >= 0 && concurrency !== 1) {
2103
+ this.$concurrency$ = concurrency;
2104
+ this.$jobs$ = [];
2105
+ }
2106
+ const timeout = options.timeout;
2110
2107
  if (timeout) {
2111
2108
  this.$timeoutMs$ = timeout;
2112
2109
  }
2113
- if (eagerCleanup) {
2110
+ if (options.eagerCleanup) {
2114
2111
  this.$flags$ |= 32 /* AsyncSignalFlags.EAGER_CLEANUP */;
2115
2112
  }
2116
- if (clientOnly) {
2113
+ if (options.clientOnly) {
2117
2114
  this.$flags$ |= 64 /* AsyncSignalFlags.CLIENT_ONLY */;
2118
2115
  }
2119
- if (interval) {
2120
- this.interval = interval;
2116
+ if (options.allowStale === false) {
2117
+ if (isDev && initial !== undefined) {
2118
+ throw new Error('allowStale: false and initial cannot be used together. ' +
2119
+ 'allowStale: false clears the value on invalidation, which conflicts with providing an initial value.');
2120
+ }
2121
+ this.$flags$ |= 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */;
2122
+ }
2123
+ const expires = options.expires ?? (options.interval ? Math.abs(options.interval) : undefined);
2124
+ if (expires) {
2125
+ this.expires = expires;
2126
+ }
2127
+ if (options.poll === false || (options.interval !== undefined && options.interval < 0)) {
2128
+ this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
2121
2129
  }
2122
2130
  }
2123
2131
  get untrackedValue() {
@@ -2137,9 +2145,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
2137
2145
  if ((import.meta.env.TEST ? isServerPlatform() : isServer) &&
2138
2146
  this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */ &&
2139
2147
  this.$untrackedValue$ === NEEDS_COMPUTATION) {
2140
- throw new Error(isDev
2141
- ? 'During SSR, cannot read .value from clientOnly async signal without an initial value. Use .loading or provide an initial value.'
2142
- : 'Cannot read .value from clientOnly');
2148
+ throw qError(35 /* QError.asyncClientOnlyValueDuringSSR */);
2143
2149
  }
2144
2150
  return this.$untrackedValue$;
2145
2151
  }
@@ -2166,8 +2172,13 @@ class AsyncSignalImpl extends ComputedSignalImpl {
2166
2172
  this.untrackedError = undefined;
2167
2173
  this.$info$ = undefined;
2168
2174
  // Prevent pending computations from overwriting this value
2169
- for (let i = 0; i < this.$jobs$.length; i++) {
2170
- this.$jobs$[i].$canWrite$ = false;
2175
+ if (this.$jobs$) {
2176
+ for (let i = 0; i < this.$jobs$.length; i++) {
2177
+ this.$jobs$[i].$canWrite$ = false;
2178
+ }
2179
+ }
2180
+ else if (this.$current$) {
2181
+ this.$current$.$canWrite$ = false;
2171
2182
  }
2172
2183
  this.$clearNextPoll$();
2173
2184
  super.value = value;
@@ -2235,28 +2246,64 @@ class AsyncSignalImpl extends ComputedSignalImpl {
2235
2246
  get untrackedError() {
2236
2247
  return this.$untrackedError$;
2237
2248
  }
2238
- get interval() {
2239
- return this.$interval$;
2249
+ get expires() {
2250
+ return this.$expires$ || 0;
2240
2251
  }
2241
- set interval(value) {
2252
+ set expires(value) {
2242
2253
  this.$clearNextPoll$();
2243
- this.$interval$ = value;
2244
- if (this.$interval$ !== 0 && this.$hasSubscribers$()) {
2254
+ this.$expires$ = value;
2255
+ if (this.$expires$ && this.$hasSubscribers$()) {
2256
+ this.$scheduleNextPoll$();
2257
+ }
2258
+ }
2259
+ get poll() {
2260
+ return !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
2261
+ }
2262
+ set poll(value) {
2263
+ if (value) {
2264
+ this.$flags$ &= -257 /* AsyncSignalFlags.NO_POLL */;
2265
+ }
2266
+ else {
2267
+ this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
2268
+ }
2269
+ // Reschedule since poll behavior changed
2270
+ if (this.$expires$ && this.$hasSubscribers$()) {
2271
+ this.$clearNextPoll$();
2245
2272
  this.$scheduleNextPoll$();
2246
2273
  }
2247
2274
  }
2275
+ /** @deprecated Use `expires` and `poll` instead. */
2276
+ get interval() {
2277
+ const expires = this.$expires$ || 0;
2278
+ return this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */ ? -expires : expires;
2279
+ }
2280
+ set interval(value) {
2281
+ if (value < 0) {
2282
+ this.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
2283
+ }
2284
+ else {
2285
+ this.$flags$ &= -257 /* AsyncSignalFlags.NO_POLL */;
2286
+ }
2287
+ this.expires = Math.abs(value);
2288
+ }
2248
2289
  /** Invalidates the signal, causing it to re-compute its value. */
2249
2290
  async invalidate(info) {
2250
- this.$flags$ |= 1 /* SignalFlags.INVALID */;
2251
- this.$clearNextPoll$();
2252
2291
  if (arguments.length > 0) {
2253
2292
  this.$info$ = info;
2254
- this.$infoVersion$++;
2293
+ this.$infoVersion$ = this.$infoVersion$ === undefined ? 1 : this.$infoVersion$ + 1;
2255
2294
  }
2256
- if (this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size) {
2295
+ this.$setInvalid$(true, this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */);
2296
+ }
2297
+ $setInvalid$(allowRecalc, mustClear) {
2298
+ this.$flags$ |= 1 /* SignalFlags.INVALID */;
2299
+ this.$clearNextPoll$();
2300
+ if (mustClear) {
2301
+ this.$untrackedValue$ = NEEDS_COMPUTATION;
2302
+ }
2303
+ if (allowRecalc &&
2304
+ (this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size)) {
2257
2305
  // compute in next microtask
2258
- await true;
2259
- this.$computeIfNeeded$();
2306
+ Promise.resolve().then(() => this.$computeIfNeeded$());
2260
2307
  }
2261
2308
  }
2262
2309
  /** Abort the current computation and run cleanups if needed. */
@@ -2301,35 +2348,46 @@ class AsyncSignalImpl extends ComputedSignalImpl {
2301
2348
  return;
2302
2349
  }
2303
2350
  this.$clearNextPoll$();
2304
- if (this.$current$) {
2305
- this.$requestCleanups$(this.$current$);
2351
+ // Clear flag here to make sure the cleanups don't start another compute
2352
+ this.$flags$ &= -2 /* SignalFlags.INVALID */;
2353
+ const current = this.$current$;
2354
+ if (current) {
2355
+ this.$requestCleanups$(current);
2306
2356
  }
2307
- const limit = this.$concurrency$ === 0 ? Number.POSITIVE_INFINITY : this.$concurrency$;
2308
- if (this.$jobs$.length >= limit) {
2357
+ const limit = this.$concurrency$ === 0 ? Number.POSITIVE_INFINITY : (this.$concurrency$ ?? 1);
2358
+ // We only have $jobs$[] when concurrency != 1
2359
+ if (this.$jobs$ ? this.$jobs$.length >= limit : current?.$promise$) {
2309
2360
  // We requested cleanups for all the previous jobs, once one finishes it will be removed from the jobs array and trigger computeIfNeeded
2361
+ // Restore invalid state
2362
+ this.$flags$ |= 1 /* SignalFlags.INVALID */;
2310
2363
  return;
2311
2364
  }
2312
- this.$flags$ &= -2 /* SignalFlags.INVALID */;
2313
2365
  // We put the actual computation in a separate method so we can easily retain the promise
2314
2366
  const infoVersion = this.$infoVersion$;
2315
2367
  const running = new AsyncJob(this, this.$info$, infoVersion);
2316
2368
  this.$current$ = running;
2317
- this.$jobs$.push(running);
2369
+ if (this.$jobs$) {
2370
+ this.$jobs$.push(running);
2371
+ }
2318
2372
  running.$promise$ = this.$runComputation$(running);
2319
2373
  }
2320
2374
  async $runComputation$(running) {
2321
2375
  const isCurrent = () => running === this.$current$;
2322
2376
  this.untrackedLoading = true;
2323
- const fn = this.$computeQrl$.resolved || (await this.$computeQrl$.resolve());
2377
+ let fn = this.$computeQrl$.resolved;
2378
+ if (!fn) {
2379
+ fn = await this.$computeQrl$.resolve();
2380
+ if (running.$abortController$?.signal.aborted) {
2381
+ running.$promise$ = null;
2382
+ return;
2383
+ }
2384
+ }
2324
2385
  try {
2325
2386
  if (this.$timeoutMs$) {
2326
2387
  this.$computationTimeoutId$ = setTimeout(() => {
2327
- running.$abortController$?.abort();
2328
- const error = new Error(`timeout`);
2329
- if (isCurrent()) {
2330
- this.untrackedError = error;
2331
- running.$canWrite$ = false;
2332
- }
2388
+ const error = new Error(`timeout ${this.$timeoutMs$}ms`);
2389
+ this.$setError$(running, error);
2390
+ running.$abortController$?.abort(error);
2333
2391
  }, this.$timeoutMs$);
2334
2392
  }
2335
2393
  // Try to stay sync if possible
@@ -2337,27 +2395,32 @@ class AsyncSignalImpl extends ComputedSignalImpl {
2337
2395
  const value = isPromise(valuePromise) ? await valuePromise : valuePromise;
2338
2396
  running.$promise$ = null;
2339
2397
  if (running.$canWrite$) {
2340
- const index = this.$jobs$.indexOf(running);
2341
- if (index !== -1) {
2342
- for (let i = 0; i < index; i++) {
2343
- this.$jobs$[i].$canWrite$ = false;
2398
+ const jobs = this.$jobs$;
2399
+ if (jobs) {
2400
+ let doDisable = false;
2401
+ for (let i = jobs.length - 1; i >= 0; i--) {
2402
+ if (jobs[i] === running) {
2403
+ doDisable = true;
2404
+ }
2405
+ else if (doDisable) {
2406
+ jobs[i].$canWrite$ = false;
2407
+ }
2344
2408
  }
2345
2409
  }
2346
2410
  DEBUG && log('Promise resolved', value);
2347
2411
  // we leave error as-is until result
2348
2412
  // Note that these assignments run setters
2349
2413
  this.untrackedError = undefined;
2350
- // Use super.value instead of this.value to avoid the AsyncSignalImpl setter
2351
- // which clears INVALID and disables all jobs. INVALID must persist so that
2352
- // line 442 can detect dependency changes during computation and re-run.
2414
+ /**
2415
+ * Use super.value instead of this.value to persist invalid state, so that invalidation
2416
+ * during computation recomputes
2417
+ */
2353
2418
  super.value = value;
2354
2419
  }
2355
2420
  }
2356
2421
  catch (err) {
2357
2422
  running.$promise$ = null;
2358
- if (isCurrent()) {
2359
- this.untrackedError = err;
2360
- }
2423
+ this.$setError$(running, err);
2361
2424
  }
2362
2425
  if (isCurrent()) {
2363
2426
  clearTimeout(this.$computationTimeoutId$);
@@ -2374,14 +2437,37 @@ class AsyncSignalImpl extends ComputedSignalImpl {
2374
2437
  }
2375
2438
  }
2376
2439
  }
2440
+ /**
2441
+ * Sets the error from the given job. We only accept errors from the current job and we ignore
2442
+ * AbortErrors.
2443
+ */
2444
+ $setError$(job, error) {
2445
+ if (job !== this.$current$ || !job.$canWrite$) {
2446
+ return;
2447
+ }
2448
+ job.$canWrite$ = false;
2449
+ if (error instanceof Error && error.name === 'AbortError') {
2450
+ // AbortError from AbortSignal is a cancellation, not an actual error
2451
+ return;
2452
+ }
2453
+ this.untrackedError = error;
2454
+ // Job failures should be rare and require retrying
2455
+ this.untrackedValue = NEEDS_COMPUTATION;
2456
+ }
2377
2457
  /** Called after SSR/unmount */
2378
2458
  async $destroy$() {
2379
2459
  this.$clearNextPoll$();
2380
2460
  clearTimeout(this.$computationTimeoutId$);
2381
- if (this.$current$) {
2382
- await this.$requestCleanups$(this.$current$);
2461
+ const current = this.$current$;
2462
+ if (current) {
2463
+ this.$requestCleanups$(current);
2464
+ }
2465
+ if (this.$jobs$) {
2466
+ await Promise.all(this.$jobs$.map((job) => job.$promise$));
2467
+ }
2468
+ else {
2469
+ await current?.$promise$;
2383
2470
  }
2384
- await Promise.all(this.$jobs$.map((job) => job.$promise$));
2385
2471
  }
2386
2472
  $clearNextPoll$() {
2387
2473
  if (this.$pollTimeoutId$ !== undefined) {
@@ -2390,66 +2476,76 @@ class AsyncSignalImpl extends ComputedSignalImpl {
2390
2476
  }
2391
2477
  }
2392
2478
  $scheduleNextPoll$() {
2393
- if (!(import.meta.env.TEST ? !isServerPlatform() : isBrowser$1) || this.$interval$ === 0) {
2479
+ if ((import.meta.env.TEST ? isServerPlatform() : isServer) || !this.$expires$) {
2394
2480
  return;
2395
2481
  }
2396
2482
  this.$clearNextPoll$();
2397
- if (this.$interval$ < 0) {
2398
- this.$pollTimeoutId$ = setTimeout(() => {
2399
- this.$pollTimeoutId$ = undefined;
2400
- this.$flags$ |= 1 /* SignalFlags.INVALID */;
2401
- }, -this.$interval$);
2402
- }
2403
- else {
2404
- this.$pollTimeoutId$ = setTimeout(this.invalidate.bind(this), this.$interval$);
2405
- }
2483
+ const allowRecalc = !(this.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */);
2484
+ // Even when clear on invalidate, we don't clear if we're merely re-running due to polling
2485
+ // We expect to get the new value soon, so we can avoid showing a loading state
2486
+ const mustClear = this.$flags$ & 128 /* AsyncSignalFlags.CLEAR_ON_INVALIDATE */ && !allowRecalc;
2487
+ this.$pollTimeoutId$ = setTimeout(() => this.$setInvalid$(allowRecalc, mustClear), this.$expires$);
2406
2488
  this.$pollTimeoutId$?.unref?.();
2407
2489
  }
2408
2490
  $hasSubscribers$() {
2409
2491
  return !!(this.$effects$?.size || this.$loadingEffects$?.size || this.$errorEffects$?.size);
2410
2492
  }
2411
- async $requestCleanups$(job, reason) {
2493
+ $requestCleanups$(job, reason) {
2412
2494
  if (job.$cleanupRequested$) {
2413
- return job.$promise$;
2495
+ return;
2414
2496
  }
2415
2497
  job.$cleanupRequested$ = true;
2416
2498
  job.$abortController$?.abort(reason);
2417
- job.$promise$ = Promise.resolve(job.$promise$).then(() => (job.$promise$ = this.$runCleanups$(job)));
2499
+ job.$promise$ = maybeThen(job.$promise$, () => this.$runCleanups$(job));
2418
2500
  }
2419
2501
  /** Clean up and trigger signal compute once complete */
2420
- async $runCleanups$(job) {
2502
+ $runCleanups$(job) {
2421
2503
  const cleanups = job.$cleanups$;
2422
- if (cleanups?.length) {
2423
- const onError = (err) => {
2424
- const handleError = this.$container$?.handleError;
2425
- if (handleError) {
2426
- handleError(err, null);
2427
- }
2428
- else {
2429
- console.error('Error in async signal cleanup', err);
2504
+ const onError = (err) => {
2505
+ const handleError = this.$container$?.handleError;
2506
+ if (handleError) {
2507
+ handleError(err, null);
2508
+ }
2509
+ else {
2510
+ console.error('Error in async signal cleanup', err);
2511
+ }
2512
+ };
2513
+ const onDone = () => {
2514
+ job.$promise$ = null;
2515
+ if (cleanups) {
2516
+ cleanups.length = 0;
2517
+ }
2518
+ // Now trigger compute
2519
+ const jobs = this.$jobs$;
2520
+ if (jobs) {
2521
+ const idx = jobs.indexOf(job);
2522
+ if (idx !== -1) {
2523
+ jobs.splice(idx, 1);
2430
2524
  }
2431
- };
2525
+ }
2526
+ this.$computeIfNeeded$();
2527
+ };
2528
+ let promiseChain = undefined;
2529
+ if (cleanups) {
2432
2530
  // Keep this sync-ish so sync functions run immediately.
2433
- await Promise.all(cleanups.map((fn) => {
2531
+ for (let i = 0; i < cleanups.length; i++) {
2434
2532
  try {
2435
- const result = fn();
2533
+ const result = cleanups[i]();
2436
2534
  if (isPromise(result)) {
2437
- return result.catch(onError);
2535
+ promiseChain = (promiseChain ? promiseChain.then(() => result) : result).catch(onError);
2438
2536
  }
2439
2537
  }
2440
2538
  catch (err) {
2441
2539
  onError(err);
2442
2540
  }
2443
- }));
2444
- cleanups.length = 0;
2541
+ }
2445
2542
  }
2446
- // Now trigger compute
2447
- const jobs = this.$jobs$;
2448
- const idx = jobs.indexOf(job);
2449
- if (idx !== -1) {
2450
- jobs.splice(idx, 1);
2543
+ if (promiseChain) {
2544
+ return promiseChain.then(onDone);
2545
+ }
2546
+ else {
2547
+ onDone();
2451
2548
  }
2452
- this.$computeIfNeeded$();
2453
2549
  }
2454
2550
  }
2455
2551
 
@@ -3108,7 +3204,69 @@ const isJSXNode = (n) => {
3108
3204
 
3109
3205
  const BIND_VALUE = 'bind:value';
3110
3206
  const BIND_CHECKED = 'bind:checked';
3207
+ const PASSIVE = 'passive:';
3208
+ const PREVENT_DEFAULT = 'preventdefault:';
3111
3209
  const _hasOwnProperty$1 = Object.prototype.hasOwnProperty;
3210
+ const removePassiveMarkers = (props, passiveKeys, preventDefaultKeys, passiveEvents, canMutate = false) => {
3211
+ let mutableProps = props;
3212
+ let copied = canMutate;
3213
+ if (passiveKeys.length > 0) {
3214
+ if (!copied) {
3215
+ mutableProps = { ...mutableProps };
3216
+ copied = true;
3217
+ }
3218
+ for (let i = 0; i < passiveKeys.length; i++) {
3219
+ const k = passiveKeys[i];
3220
+ delete mutableProps[k];
3221
+ }
3222
+ }
3223
+ if (preventDefaultKeys.length > 0) {
3224
+ for (let i = 0; i < preventDefaultKeys.length; i++) {
3225
+ const k = preventDefaultKeys[i];
3226
+ if (passiveEvents.has(normalizeJsxEventName(k.slice(PREVENT_DEFAULT.length)))) {
3227
+ if (!copied) {
3228
+ mutableProps = { ...mutableProps };
3229
+ copied = true;
3230
+ }
3231
+ delete mutableProps[k];
3232
+ }
3233
+ }
3234
+ }
3235
+ return mutableProps;
3236
+ };
3237
+ const getPassiveEventKey = (key) => {
3238
+ if (key.startsWith('on') && key.endsWith('$')) {
3239
+ return normalizeJsxEventName(key.slice(2, -1));
3240
+ }
3241
+ if (key.startsWith('window:on') && key.endsWith('$')) {
3242
+ return normalizeJsxEventName(key.slice(9, -1));
3243
+ }
3244
+ if (key.startsWith('document:on') && key.endsWith('$')) {
3245
+ return normalizeJsxEventName(key.slice(11, -1));
3246
+ }
3247
+ return null;
3248
+ };
3249
+ const convertJsxEventProps = (props, eventKeys, keyOrder, passiveEvents, canMutate = false) => {
3250
+ let mutableProps = props;
3251
+ let copied = canMutate;
3252
+ for (let i = 0; i < eventKeys.length; i++) {
3253
+ const k = eventKeys[i];
3254
+ const passiveEventKey = getPassiveEventKey(k);
3255
+ const attr = jsxEventToHtmlAttribute(k, passiveEvents.has(passiveEventKey));
3256
+ if (attr) {
3257
+ if (!copied) {
3258
+ mutableProps = { ...mutableProps };
3259
+ copied = true;
3260
+ }
3261
+ const attrIndex = keyOrder.get(attr);
3262
+ if (attrIndex === undefined || attrIndex < keyOrder.get(k)) {
3263
+ mutableProps[attr] = mutableProps[k];
3264
+ }
3265
+ delete mutableProps[k];
3266
+ }
3267
+ }
3268
+ return mutableProps;
3269
+ };
3112
3270
  /**
3113
3271
  * Create a JSXNode with the properties fully split into variable and constant parts, and children
3114
3272
  * separated out. Furthermore, the varProps must be a sorted object, that is, the keys must be
@@ -3154,20 +3312,28 @@ const _jsxSplit = (type, varProps, constProps, children, flags, key, dev) => {
3154
3312
  let bindCheckedSignal = null;
3155
3313
  // Apply transformations for native HTML elements only
3156
3314
  if (typeof type === 'string') {
3157
- // Transform event names (onClick$ -> q-e:click)
3315
+ const passiveEvents = new Set();
3316
+ const constEventKeys = [];
3317
+ const varEventKeys = [];
3318
+ const constPassiveKeys = [];
3319
+ const varPassiveKeys = [];
3320
+ const constPreventDefaultKeys = [];
3321
+ const varPreventDefaultKeys = [];
3322
+ const constKeyOrder = new Map();
3323
+ const varKeyOrder = new Map();
3158
3324
  if (constProps) {
3159
- const processedKeys = new Set();
3325
+ let index = 0;
3160
3326
  for (const k in constProps) {
3161
- const attr = jsxEventToHtmlAttribute(k);
3162
- if (attr) {
3163
- if (!constPropsCopied) {
3164
- constProps = { ...constProps };
3165
- constPropsCopied = true;
3166
- }
3167
- if (!_hasOwnProperty$1.call(constProps, attr) || processedKeys.has(attr)) {
3168
- constProps[attr] = constProps[k];
3169
- }
3170
- delete constProps[k];
3327
+ constKeyOrder.set(k, index++);
3328
+ if (k.startsWith(PASSIVE)) {
3329
+ constPassiveKeys.push(k);
3330
+ passiveEvents.add(normalizeJsxEventName(k.slice(PASSIVE.length)));
3331
+ }
3332
+ else if (k.startsWith(PREVENT_DEFAULT)) {
3333
+ constPreventDefaultKeys.push(k);
3334
+ }
3335
+ else if (getPassiveEventKey(k) !== null) {
3336
+ constEventKeys.push(k);
3171
3337
  }
3172
3338
  else if (k === BIND_CHECKED) {
3173
3339
  // Set flag, will process after walk
@@ -3177,24 +3343,21 @@ const _jsxSplit = (type, varProps, constProps, children, flags, key, dev) => {
3177
3343
  // Set flag, will process after walk
3178
3344
  bindValueSignal = constProps[k];
3179
3345
  }
3180
- processedKeys.add(k);
3181
3346
  }
3182
3347
  }
3183
3348
  if (varProps) {
3184
- const processedKeys = new Set();
3349
+ let index = 0;
3185
3350
  for (const k in varProps) {
3186
- const attr = jsxEventToHtmlAttribute(k);
3187
- if (attr) {
3188
- if (!varPropsCopied) {
3189
- varProps = { ...varProps };
3190
- varPropsCopied = true;
3191
- }
3192
- // Transform event name in place
3193
- if (!_hasOwnProperty$1.call(varProps, attr) || processedKeys.has(attr)) {
3194
- varProps[attr] = varProps[k];
3195
- }
3196
- delete varProps[k];
3197
- toSort = true;
3351
+ varKeyOrder.set(k, index++);
3352
+ if (k.startsWith(PASSIVE)) {
3353
+ varPassiveKeys.push(k);
3354
+ passiveEvents.add(normalizeJsxEventName(k.slice(PASSIVE.length)));
3355
+ }
3356
+ else if (k.startsWith(PREVENT_DEFAULT)) {
3357
+ varPreventDefaultKeys.push(k);
3358
+ }
3359
+ else if (getPassiveEventKey(k) !== null) {
3360
+ varEventKeys.push(k);
3198
3361
  }
3199
3362
  else if (k === BIND_CHECKED) {
3200
3363
  // Set flag, will process after walk
@@ -3204,9 +3367,23 @@ const _jsxSplit = (type, varProps, constProps, children, flags, key, dev) => {
3204
3367
  // Set flag, will process after walk
3205
3368
  bindValueSignal = varProps[k];
3206
3369
  }
3207
- processedKeys.add(k);
3208
3370
  }
3209
3371
  }
3372
+ if (constProps) {
3373
+ const originalConstProps = constProps;
3374
+ constProps = removePassiveMarkers(constProps, constPassiveKeys, constPreventDefaultKeys, passiveEvents, constPropsCopied);
3375
+ constPropsCopied = constPropsCopied || constProps !== originalConstProps;
3376
+ constProps = convertJsxEventProps(constProps, constEventKeys, constKeyOrder, passiveEvents, constPropsCopied);
3377
+ constPropsCopied = constPropsCopied || constProps !== originalConstProps;
3378
+ }
3379
+ if (varProps) {
3380
+ const originalVarProps = varProps;
3381
+ varProps = removePassiveMarkers(varProps, varPassiveKeys, varPreventDefaultKeys, passiveEvents, varPropsCopied);
3382
+ varPropsCopied = varPropsCopied || varProps !== originalVarProps;
3383
+ varProps = convertJsxEventProps(varProps, varEventKeys, varKeyOrder, passiveEvents, varPropsCopied);
3384
+ varPropsCopied = varPropsCopied || varProps !== originalVarProps;
3385
+ toSort = toSort || varEventKeys.length > 0;
3386
+ }
3210
3387
  // Handle bind:* - only in varProps, bind:* should be moved to varProps
3211
3388
  if (bindCheckedSignal || bindValueSignal) {
3212
3389
  if (!varPropsCopied) {
@@ -3518,11 +3695,13 @@ function addUseOnEvents(jsx, useOnEvents) {
3518
3695
  }
3519
3696
  else {
3520
3697
  if (isDev) {
3698
+ const sourceLocation = getUseOnSourceLocation(useOnEvents[key].qrls);
3521
3699
  logWarn('You are trying to add an event "' +
3522
3700
  key +
3523
3701
  '" using `useOn` hook, ' +
3524
3702
  'but a node to which you can add an event is not found. ' +
3525
- 'Please make sure that the component has a valid element node. ');
3703
+ 'Please make sure that the component outputs a DOM element.' +
3704
+ (sourceLocation ? ` Offending \`useOn\`: ${sourceLocation}.` : ''));
3526
3705
  }
3527
3706
  continue;
3528
3707
  }
@@ -3531,11 +3710,12 @@ function addUseOnEvents(jsx, useOnEvents) {
3531
3710
  if (targetElement.type === 'script' && key === qVisibleEvent) {
3532
3711
  eventKey = 'q-d:qinit';
3533
3712
  if (isDev) {
3534
- logWarn('You are trying to add an event "' +
3535
- key +
3536
- '" using the `useVisibleTask$` hook with the "intersection-observer" strategy, ' +
3537
- 'but a node to which you can add an event is not found. ' +
3538
- 'Using "document-ready" or "document-idle" instead.');
3713
+ const sourceLocation = getUseOnSourceLocation(useOnEvents[key].qrls);
3714
+ logWarn(`You are trying to add the event "${key}" ` +
3715
+ 'using the `useVisibleTask$` hook with the "intersection-observer" strategy, ' +
3716
+ 'but this only works when the component outputs a DOM element. Falling back to ' +
3717
+ '"document-ready" instead.' +
3718
+ (sourceLocation ? ` Offending \`useVisibleTask$\`: ${sourceLocation}.` : ''));
3539
3719
  }
3540
3720
  }
3541
3721
  addUseOnEvent(targetElement, eventKey, useOnEvents[key]);
@@ -3545,6 +3725,21 @@ function addUseOnEvents(jsx, useOnEvents) {
3545
3725
  return jsxResult;
3546
3726
  });
3547
3727
  }
3728
+ function getUseOnSourceLocation(eventQrls) {
3729
+ for (let i = 0; i < eventQrls.length; i++) {
3730
+ const eventQrl = eventQrls[i];
3731
+ const task = eventQrl?.getCaptured()?.[0];
3732
+ if (isTask(task)) {
3733
+ const dev = task.$qrl$.dev;
3734
+ if (dev?.file) {
3735
+ return typeof dev.lo === 'number' && typeof dev.hi === 'number'
3736
+ ? `${dev.file}:${dev.lo}-${dev.hi}`
3737
+ : dev.file;
3738
+ }
3739
+ }
3740
+ }
3741
+ return null;
3742
+ }
3548
3743
  /**
3549
3744
  * Adds an event to the JSX element.
3550
3745
  *
@@ -3556,14 +3751,15 @@ function addUseOnEvent(jsxElement, key, value) {
3556
3751
  // These handlers are always there, so they go in constProps
3557
3752
  const props = (jsxElement.constProps ||= {});
3558
3753
  const propValue = props[key];
3754
+ const qrls = value.qrls;
3559
3755
  if (propValue == null) {
3560
- props[key] = value;
3756
+ props[key] = qrls;
3561
3757
  }
3562
3758
  else if (Array.isArray(propValue)) {
3563
- propValue.push(...value);
3759
+ propValue.push(...qrls);
3564
3760
  }
3565
3761
  else {
3566
- props[key] = [propValue, ...value];
3762
+ props[key] = [propValue, ...qrls];
3567
3763
  }
3568
3764
  const varProp = jsxElement.varProps[key];
3569
3765
  if (varProp) {
@@ -3572,10 +3768,28 @@ function addUseOnEvent(jsxElement, key, value) {
3572
3768
  propValue.push(...props[key]);
3573
3769
  }
3574
3770
  else {
3575
- jsxElement.varProps[key] = [propValue, ...value];
3771
+ jsxElement.varProps[key] = [propValue, ...qrls];
3576
3772
  }
3577
3773
  props[key] = undefined;
3578
3774
  }
3775
+ const capture = value.capture;
3776
+ const preventdefault = value.preventdefault;
3777
+ const stoppropagation = value.stoppropagation;
3778
+ if (!capture && !preventdefault && !stoppropagation) {
3779
+ return;
3780
+ }
3781
+ const [, eventName] = getEventDataFromHtmlAttribute(key);
3782
+ capture && addUseOnModifier(jsxElement, eventName, 'capture');
3783
+ preventdefault && addUseOnModifier(jsxElement, eventName, 'preventdefault');
3784
+ stoppropagation && addUseOnModifier(jsxElement, eventName, 'stoppropagation');
3785
+ }
3786
+ function addUseOnModifier(jsxElement, eventName, modifier) {
3787
+ const key = `${modifier}:${eventName}`;
3788
+ const varProps = jsxElement.varProps;
3789
+ if (varProps === EMPTY_OBJ) {
3790
+ jsxElement.varProps = {};
3791
+ }
3792
+ jsxElement.varProps[key] = true;
3579
3793
  }
3580
3794
  /**
3581
3795
  * Finds the first element node in the JSX output.
@@ -9115,6 +9329,95 @@ function getEffects(target, prop, storeEffects) {
9115
9329
  return effectsToTrigger;
9116
9330
  }
9117
9331
 
9332
+ /** Used to represent an undefined value that must be serialized */
9333
+ const explicitUndefined = Symbol('undefined');
9334
+ // Used for allocate, make sure they are in sync with Constants
9335
+ const _constants = [
9336
+ undefined,
9337
+ null,
9338
+ true,
9339
+ false,
9340
+ '',
9341
+ EMPTY_ARRAY,
9342
+ EMPTY_OBJ,
9343
+ NEEDS_COMPUTATION,
9344
+ STORE_ALL_PROPS,
9345
+ _UNINITIALIZED,
9346
+ Slot,
9347
+ Fragment,
9348
+ NaN,
9349
+ Infinity,
9350
+ -Infinity,
9351
+ Number.MAX_SAFE_INTEGER,
9352
+ Number.MAX_SAFE_INTEGER - 1,
9353
+ Number.MIN_SAFE_INTEGER,
9354
+ ];
9355
+ // Used for dumpState, make sure they are in sync with Constants
9356
+ const _constantNames = [
9357
+ 'undefined',
9358
+ 'null',
9359
+ 'true',
9360
+ 'false',
9361
+ "''",
9362
+ 'EMPTY_ARRAY',
9363
+ 'EMPTY_OBJ',
9364
+ 'NEEDS_COMPUTATION',
9365
+ 'STORE_ALL_PROPS',
9366
+ '_UNINITIALIZED',
9367
+ 'Slot',
9368
+ 'Fragment',
9369
+ 'NaN',
9370
+ 'Infinity',
9371
+ '-Infinity',
9372
+ 'MAX_SAFE_INTEGER',
9373
+ 'MAX_SAFE_INTEGER-1',
9374
+ 'MIN_SAFE_INTEGER',
9375
+ ];
9376
+ // Used for dumpState, make sure they are in sync with TypeIds
9377
+ const _typeIdNames = [
9378
+ 'Plain',
9379
+ 'RootRef',
9380
+ 'ForwardRef',
9381
+ 'Constant',
9382
+ 'Array',
9383
+ 'Object',
9384
+ 'URL',
9385
+ 'Date',
9386
+ 'Regex',
9387
+ 'QRL',
9388
+ 'VNode',
9389
+ 'RefVNode',
9390
+ 'BigInt',
9391
+ 'URLSearchParams',
9392
+ 'ForwardRefs',
9393
+ 'TemporalDuration',
9394
+ 'TemporalInstant',
9395
+ 'TemporalPlainDate',
9396
+ 'TemporalPlainDateTime',
9397
+ 'TemporalPlainMonthDay',
9398
+ 'TemporalPlainTime',
9399
+ 'TemporalPlainYearMonth',
9400
+ 'TemporalZonedDateTime',
9401
+ 'Error',
9402
+ 'Promise',
9403
+ 'Set',
9404
+ 'Map',
9405
+ 'Uint8Array',
9406
+ 'Task',
9407
+ 'Component',
9408
+ 'Signal',
9409
+ 'WrappedSignal',
9410
+ 'ComputedSignal',
9411
+ 'AsyncSignal',
9412
+ 'SerializerSignal',
9413
+ 'Store',
9414
+ 'FormData',
9415
+ 'JSXNode',
9416
+ 'PropsProxy',
9417
+ 'SubscriptionData',
9418
+ 'EffectSubscription',
9419
+ ];
9420
+
9118
9421
  function qrlToString(serializationContext, qrl, raw) {
9119
9422
  let symbol = qrl.$symbol$;
9120
9423
  let chunk = qrl.$chunk$;
@@ -9211,6 +9514,8 @@ class Serializer {
9211
9514
  $parent$;
9212
9515
  $qrlMap$ = new Map();
9213
9516
  $writer$;
9517
+ /** We need to determine this at runtime because polyfills may not be loaded a module load time */
9518
+ $hasTemporal$ = typeof Temporal !== 'undefined';
9214
9519
  constructor($serializationContext$) {
9215
9520
  this.$serializationContext$ = $serializationContext$;
9216
9521
  this.$writer$ = $serializationContext$.$writer$;
@@ -9254,6 +9559,29 @@ class Serializer {
9254
9559
  }
9255
9560
  return false;
9256
9561
  }
9562
+ maybeNumericObjectKey$(key) {
9563
+ if (key.length === 0 || key.length >= 8) {
9564
+ return key;
9565
+ }
9566
+ let i = 0;
9567
+ if (key.charCodeAt(0) === 45) {
9568
+ if (key.length === 1) {
9569
+ return key;
9570
+ }
9571
+ i = 1;
9572
+ }
9573
+ const first = key.charCodeAt(i);
9574
+ if (first < 49 || first > 57) {
9575
+ return key;
9576
+ }
9577
+ for (i++; i < key.length; i++) {
9578
+ const c = key.charCodeAt(i);
9579
+ if (c < 48 || c > 57) {
9580
+ return key;
9581
+ }
9582
+ }
9583
+ return Number(key);
9584
+ }
9257
9585
  /** Output a type,value pair. If the value is an array, it calls writeValue on each item. */
9258
9586
  output(type, value, keepUndefined) {
9259
9587
  if (typeof value === 'number') {
@@ -9381,6 +9709,9 @@ class Serializer {
9381
9709
  else if (value === _UNINITIALIZED) {
9382
9710
  this.output(3 /* TypeIds.Constant */, 9 /* Constants.UNINITIALIZED */);
9383
9711
  }
9712
+ else if (value === explicitUndefined) {
9713
+ this.output(3 /* TypeIds.Constant */, 0 /* Constants.Undefined */);
9714
+ }
9384
9715
  break;
9385
9716
  case 'function':
9386
9717
  if (value === Slot) {
@@ -9418,7 +9749,7 @@ class Serializer {
9418
9749
  else if (isQwikComponent(value)) {
9419
9750
  const [qrl] = value[SERIALIZABLE_STATE];
9420
9751
  this.$serializationContext$.$renderSymbols$.add(qrl.$symbol$);
9421
- this.output(21 /* TypeIds.Component */, [qrl]);
9752
+ this.output(29 /* TypeIds.Component */, [qrl]);
9422
9753
  }
9423
9754
  else {
9424
9755
  throw qError(34 /* QError.serializeErrorCannotSerializeFunction */, [value.toString()]);
@@ -9456,7 +9787,7 @@ class Serializer {
9456
9787
  writeObjectValue(value) {
9457
9788
  if (isPropsProxy(value)) {
9458
9789
  const owner = value[_OWNER];
9459
- this.output(30 /* TypeIds.PropsProxy */, [
9790
+ this.output(38 /* TypeIds.PropsProxy */, [
9460
9791
  _serializationWeakRef(owner),
9461
9792
  owner.varProps,
9462
9793
  owner.constProps,
@@ -9464,13 +9795,15 @@ class Serializer {
9464
9795
  ]);
9465
9796
  }
9466
9797
  else if (value instanceof SubscriptionData) {
9467
- this.output(31 /* TypeIds.SubscriptionData */, [
9798
+ // TODO make everything optional or use two types
9799
+ this.output(39 /* TypeIds.SubscriptionData */, [
9468
9800
  value.data.$scopedStyleIdPrefix$,
9469
9801
  value.data.$isConst$,
9470
9802
  ]);
9471
9803
  }
9472
9804
  else if (value instanceof EffectSubscription) {
9473
- this.output(32 /* TypeIds.EffectSubscription */, [value.consumer, value.property, value.data]);
9805
+ // TODO no data if [null, true]
9806
+ this.output(40 /* TypeIds.EffectSubscription */, [value.consumer, value.property, value.data]);
9474
9807
  }
9475
9808
  else if (isStore(value)) {
9476
9809
  const storeHandler = getStoreHandler(value);
@@ -9490,13 +9823,13 @@ class Serializer {
9490
9823
  while (out[out.length - 1] === undefined) {
9491
9824
  out.pop();
9492
9825
  }
9493
- this.output(27 /* TypeIds.Store */, out);
9826
+ this.output(35 /* TypeIds.Store */, out);
9494
9827
  }
9495
9828
  else if (isSerializerObj(value)) {
9496
9829
  const result = value[SerializerSymbol](value);
9497
9830
  if (isPromise(result)) {
9498
9831
  const forwardRef = this.resolvePromise(result, (resolved, resolvedValue) => {
9499
- return new PromiseResult(26 /* TypeIds.SerializerSignal */, resolved, resolvedValue, undefined, undefined);
9832
+ return new PromiseResult(34 /* TypeIds.SerializerSignal */, resolved, resolvedValue, undefined, undefined);
9500
9833
  });
9501
9834
  this.output(2 /* TypeIds.ForwardRef */, forwardRef);
9502
9835
  }
@@ -9517,7 +9850,7 @@ class Serializer {
9517
9850
  if (Object.prototype.hasOwnProperty.call(value, key)) {
9518
9851
  const subVal = value[key];
9519
9852
  if (!fastSkipSerialize(subVal)) {
9520
- out.push(key, subVal);
9853
+ out.push(this.maybeNumericObjectKey$(key), subVal);
9521
9854
  }
9522
9855
  }
9523
9856
  }
@@ -9533,17 +9866,17 @@ class Serializer {
9533
9866
  const maybeValue = getCustomSerializerPromise(value, value.$untrackedValue$);
9534
9867
  if (isPromise(maybeValue)) {
9535
9868
  const forwardRefId = this.resolvePromise(maybeValue, (resolved, resolvedValue) => {
9536
- return new PromiseResult(26 /* TypeIds.SerializerSignal */, resolved, resolvedValue, value.$effects$, value.$computeQrl$);
9869
+ return new PromiseResult(34 /* TypeIds.SerializerSignal */, resolved, resolvedValue, value.$effects$, value.$computeQrl$);
9537
9870
  });
9538
9871
  this.output(2 /* TypeIds.ForwardRef */, forwardRefId);
9539
9872
  }
9540
9873
  else {
9541
- this.output(26 /* TypeIds.SerializerSignal */, [value.$computeQrl$, value.$effects$, maybeValue]);
9874
+ this.output(34 /* TypeIds.SerializerSignal */, [value.$computeQrl$, value.$effects$, maybeValue]);
9542
9875
  }
9543
9876
  return;
9544
9877
  }
9545
9878
  if (value instanceof WrappedSignalImpl) {
9546
- this.output(23 /* TypeIds.WrappedSignal */, [
9879
+ this.output(31 /* TypeIds.WrappedSignal */, [
9547
9880
  ...serializeWrappingFn(this.$serializationContext$, value),
9548
9881
  value.$flags$,
9549
9882
  value.$hostElement$,
@@ -9557,7 +9890,7 @@ class Serializer {
9557
9890
  const isInvalid = value.$flags$ & 1 /* SignalFlags.INVALID */;
9558
9891
  const isSkippable = fastSkipSerialize(value.$untrackedValue$);
9559
9892
  const isAsync = value instanceof AsyncSignalImpl;
9560
- const interval = isAsync && value.$interval$ !== 0 ? value.$interval$ : undefined;
9893
+ const expires = isAsync && value.$expires$ !== 0 ? value.$expires$ : undefined;
9561
9894
  const concurrency = isAsync && value.$concurrency$ !== 1 ? value.$concurrency$ : undefined;
9562
9895
  const timeout = isAsync && value.$timeoutMs$ !== 0 ? value.$timeoutMs$ : undefined;
9563
9896
  // Send the flags but remove the serialization bits and default to 0 when undefined
@@ -9578,36 +9911,31 @@ class Serializer {
9578
9911
  out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedError$);
9579
9912
  out.push(asyncFlags || undefined);
9580
9913
  }
9581
- let keepUndefined = false;
9582
9914
  if (v !== NEEDS_COMPUTATION ||
9583
- interval !== undefined ||
9915
+ expires !== undefined ||
9584
9916
  concurrency !== undefined ||
9585
9917
  timeout !== undefined) {
9586
- out.push(v);
9587
- if (v === undefined) {
9588
- /**
9589
- * If value is undefined, we need to keep it in the output. If we don't do that, later
9590
- * during resuming, the value will be set to symbol(invalid) with flag invalid, and
9591
- * thats is incorrect.
9592
- */
9593
- keepUndefined = true;
9594
- }
9918
+ /**
9919
+ * If value is undefined, we need to keep it in the output. If we don't do that, later
9920
+ * during resuming, the value will be set to symbol(invalid) with flag invalid, and thats
9921
+ * is incorrect.
9922
+ */
9923
+ out.push(v === undefined ? explicitUndefined : v);
9595
9924
  }
9596
9925
  if (isAsync) {
9597
- out.push(interval);
9926
+ out.push(expires);
9598
9927
  out.push(concurrency);
9599
9928
  out.push(timeout);
9600
9929
  }
9601
- this.output(isAsync ? 25 /* TypeIds.AsyncSignal */ : 24 /* TypeIds.ComputedSignal */, out, keepUndefined);
9930
+ this.output(isAsync ? 33 /* TypeIds.AsyncSignal */ : 32 /* TypeIds.ComputedSignal */, out);
9602
9931
  }
9603
9932
  else {
9604
9933
  const v = value.$untrackedValue$;
9605
- const keepUndefined = v === undefined;
9606
- const out = [v];
9934
+ const out = [v === undefined ? explicitUndefined : v];
9607
9935
  if (value.$effects$) {
9608
9936
  out.push(...value.$effects$);
9609
9937
  }
9610
- this.output(22 /* TypeIds.Signal */, out, keepUndefined);
9938
+ this.output(30 /* TypeIds.Signal */, out);
9611
9939
  }
9612
9940
  }
9613
9941
  else if (value instanceof URL) {
@@ -9616,6 +9944,30 @@ class Serializer {
9616
9944
  else if (value instanceof Date) {
9617
9945
  this.output(7 /* TypeIds.Date */, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
9618
9946
  }
9947
+ else if (this.$hasTemporal$ && value instanceof Temporal.Duration) {
9948
+ this.output(15 /* TypeIds.TemporalDuration */, value.toJSON());
9949
+ }
9950
+ else if (this.$hasTemporal$ && value instanceof Temporal.Instant) {
9951
+ this.output(16 /* TypeIds.TemporalInstant */, value.toJSON());
9952
+ }
9953
+ else if (this.$hasTemporal$ && value instanceof Temporal.PlainDate) {
9954
+ this.output(17 /* TypeIds.TemporalPlainDate */, value.toJSON());
9955
+ }
9956
+ else if (this.$hasTemporal$ && value instanceof Temporal.PlainDateTime) {
9957
+ this.output(18 /* TypeIds.TemporalPlainDateTime */, value.toJSON());
9958
+ }
9959
+ else if (this.$hasTemporal$ && value instanceof Temporal.PlainMonthDay) {
9960
+ this.output(19 /* TypeIds.TemporalPlainMonthDay */, value.toJSON());
9961
+ }
9962
+ else if (this.$hasTemporal$ && value instanceof Temporal.PlainTime) {
9963
+ this.output(20 /* TypeIds.TemporalPlainTime */, value.toJSON());
9964
+ }
9965
+ else if (this.$hasTemporal$ && value instanceof Temporal.PlainYearMonth) {
9966
+ this.output(21 /* TypeIds.TemporalPlainYearMonth */, value.toJSON());
9967
+ }
9968
+ else if (this.$hasTemporal$ && value instanceof Temporal.ZonedDateTime) {
9969
+ this.output(22 /* TypeIds.TemporalZonedDateTime */, value.toJSON());
9970
+ }
9619
9971
  else if (value instanceof RegExp) {
9620
9972
  this.output(8 /* TypeIds.Regex */, value.toString());
9621
9973
  }
@@ -9627,7 +9979,7 @@ class Serializer {
9627
9979
  if (isDev) {
9628
9980
  out.push('stack', value.stack);
9629
9981
  }
9630
- this.output(15 /* TypeIds.Error */, out);
9982
+ this.output(23 /* TypeIds.Error */, out);
9631
9983
  }
9632
9984
  else if (this.$serializationContext$.$isSsrNode$(value)) {
9633
9985
  const rootIndex = this.$serializationContext$.$addRoot$(value);
@@ -9659,20 +10011,20 @@ class Serializer {
9659
10011
  array.push(k, v);
9660
10012
  }
9661
10013
  }
9662
- this.output(28 /* TypeIds.FormData */, array);
10014
+ this.output(36 /* TypeIds.FormData */, array);
9663
10015
  }
9664
10016
  else if (value instanceof URLSearchParams) {
9665
10017
  this.output(13 /* TypeIds.URLSearchParams */, value.toString());
9666
10018
  }
9667
10019
  else if (value instanceof Set) {
9668
- this.output(17 /* TypeIds.Set */, [...value.values()]);
10020
+ this.output(25 /* TypeIds.Set */, [...value.values()]);
9669
10021
  }
9670
10022
  else if (value instanceof Map) {
9671
10023
  const combined = [];
9672
10024
  for (const [k, v] of value.entries()) {
9673
10025
  combined.push(k, v);
9674
10026
  }
9675
- this.output(18 /* TypeIds.Map */, combined);
10027
+ this.output(26 /* TypeIds.Map */, combined);
9676
10028
  }
9677
10029
  else if (isJSXNode(value)) {
9678
10030
  const out = [
@@ -9686,25 +10038,25 @@ class Serializer {
9686
10038
  while (out[out.length - 1] === undefined) {
9687
10039
  out.pop();
9688
10040
  }
9689
- this.output(29 /* TypeIds.JSXNode */, out);
10041
+ this.output(37 /* TypeIds.JSXNode */, out);
9690
10042
  }
9691
10043
  else if (value instanceof Task) {
9692
10044
  const out = [value.$qrl$, value.$flags$, value.$index$, value.$el$, value.$state$];
9693
10045
  while (out[out.length - 1] === undefined) {
9694
10046
  out.pop();
9695
10047
  }
9696
- this.output(20 /* TypeIds.Task */, out);
10048
+ this.output(28 /* TypeIds.Task */, out);
9697
10049
  }
9698
10050
  else if (isPromise(value)) {
9699
10051
  const forwardRefId = this.resolvePromise(value, (resolved, resolvedValue) => {
9700
- return new PromiseResult(16 /* TypeIds.Promise */, resolved, resolvedValue);
10052
+ return new PromiseResult(24 /* TypeIds.Promise */, resolved, resolvedValue);
9701
10053
  });
9702
10054
  this.output(2 /* TypeIds.ForwardRef */, forwardRefId);
9703
10055
  }
9704
10056
  else if (value instanceof PromiseResult) {
9705
- if (value.$type$ === 26 /* TypeIds.SerializerSignal */) {
10057
+ if (value.$type$ === 34 /* TypeIds.SerializerSignal */) {
9706
10058
  if (value.$qrl$) {
9707
- this.output(26 /* TypeIds.SerializerSignal */, [value.$qrl$, value.$effects$, value.$value$]);
10059
+ this.output(34 /* TypeIds.SerializerSignal */, [value.$qrl$, value.$effects$, value.$value$]);
9708
10060
  }
9709
10061
  else if (value.$resolved$) {
9710
10062
  // We replace ourselves with this value
@@ -9718,7 +10070,7 @@ class Serializer {
9718
10070
  }
9719
10071
  }
9720
10072
  else {
9721
- this.output(16 /* TypeIds.Promise */, [value.$resolved$, value.$value$]);
10073
+ this.output(24 /* TypeIds.Promise */, [value.$resolved$, value.$value$]);
9722
10074
  }
9723
10075
  }
9724
10076
  else if (value instanceof Uint8Array) {
@@ -9728,7 +10080,7 @@ class Serializer {
9728
10080
  buf += String.fromCharCode(value[i]);
9729
10081
  }
9730
10082
  const out = btoa(buf).replace(/=+$/, '');
9731
- this.output(19 /* TypeIds.Uint8Array */, out);
10083
+ this.output(27 /* TypeIds.Uint8Array */, out);
9732
10084
  }
9733
10085
  else if (value instanceof SerializationWeakRef) {
9734
10086
  const obj = value.$obj$;
@@ -10056,6 +10408,7 @@ DomRefConstructor, symbolToChunkResolver, setProp, storeProxyMap, writer) => {
10056
10408
 
10057
10409
  const getKeyVal = (value, key) => value[key];
10058
10410
  const canSerialize = (value, seen = new WeakSet()) => {
10411
+ const hasTemporal = typeof Temporal !== 'undefined';
10059
10412
  if (value == null ||
10060
10413
  typeof value === 'string' ||
10061
10414
  typeof value === 'number' ||
@@ -10118,6 +10471,30 @@ const canSerialize = (value, seen = new WeakSet()) => {
10118
10471
  else if (value instanceof Date) {
10119
10472
  return true;
10120
10473
  }
10474
+ else if (hasTemporal && value instanceof Temporal.Duration) {
10475
+ return true;
10476
+ }
10477
+ else if (hasTemporal && value instanceof Temporal.Instant) {
10478
+ return true;
10479
+ }
10480
+ else if (hasTemporal && value instanceof Temporal.PlainDate) {
10481
+ return true;
10482
+ }
10483
+ else if (hasTemporal && value instanceof Temporal.PlainDateTime) {
10484
+ return true;
10485
+ }
10486
+ else if (hasTemporal && value instanceof Temporal.PlainMonthDay) {
10487
+ return true;
10488
+ }
10489
+ else if (hasTemporal && value instanceof Temporal.PlainTime) {
10490
+ return true;
10491
+ }
10492
+ else if (hasTemporal && value instanceof Temporal.PlainYearMonth) {
10493
+ return true;
10494
+ }
10495
+ else if (hasTemporal && value instanceof Temporal.ZonedDateTime) {
10496
+ return true;
10497
+ }
10121
10498
  else if (value instanceof RegExp) {
10122
10499
  return true;
10123
10500
  }
@@ -10154,85 +10531,6 @@ const canSerialize = (value, seen = new WeakSet()) => {
10154
10531
  return false;
10155
10532
  };
10156
10533
 
10157
- // Used for allocate, make sure they are in sync with Constants
10158
- const _constants = [
10159
- undefined,
10160
- null,
10161
- true,
10162
- false,
10163
- '',
10164
- EMPTY_ARRAY,
10165
- EMPTY_OBJ,
10166
- NEEDS_COMPUTATION,
10167
- STORE_ALL_PROPS,
10168
- _UNINITIALIZED,
10169
- Slot,
10170
- Fragment,
10171
- NaN,
10172
- Infinity,
10173
- -Infinity,
10174
- Number.MAX_SAFE_INTEGER,
10175
- Number.MAX_SAFE_INTEGER - 1,
10176
- Number.MIN_SAFE_INTEGER,
10177
- ];
10178
- // Used for dumpState, make sure they are in sync with Constants
10179
- const _constantNames = [
10180
- 'undefined',
10181
- 'null',
10182
- 'true',
10183
- 'false',
10184
- "''",
10185
- 'EMPTY_ARRAY',
10186
- 'EMPTY_OBJ',
10187
- 'NEEDS_COMPUTATION',
10188
- 'STORE_ALL_PROPS',
10189
- '_UNINITIALIZED',
10190
- 'Slot',
10191
- 'Fragment',
10192
- 'NaN',
10193
- 'Infinity',
10194
- '-Infinity',
10195
- 'MAX_SAFE_INTEGER',
10196
- 'MAX_SAFE_INTEGER-1',
10197
- 'MIN_SAFE_INTEGER',
10198
- ];
10199
- // Used for dumpState, make sure they are in sync with TypeIds
10200
- const _typeIdNames = [
10201
- 'Plain',
10202
- 'RootRef',
10203
- 'ForwardRef',
10204
- 'Constant',
10205
- 'Array',
10206
- 'Object',
10207
- 'URL',
10208
- 'Date',
10209
- 'Regex',
10210
- 'QRL',
10211
- 'VNode',
10212
- 'RefVNode',
10213
- 'BigInt',
10214
- 'URLSearchParams',
10215
- 'ForwardRefs',
10216
- 'Error',
10217
- 'Promise',
10218
- 'Set',
10219
- 'Map',
10220
- 'Uint8Array',
10221
- 'Task',
10222
- 'Component',
10223
- 'Signal',
10224
- 'WrappedSignal',
10225
- 'ComputedSignal',
10226
- 'AsyncSignal',
10227
- 'SerializerSignal',
10228
- 'Store',
10229
- 'FormData',
10230
- 'JSXNode',
10231
- 'PropsProxy',
10232
- 'SubscriptionData',
10233
- 'EffectSubscription',
10234
- ];
10235
-
10236
10534
  const circularProofJson = (obj, indent) => {
10237
10535
  const seen = new WeakSet();
10238
10536
  return JSON.stringify(obj, (_, value) => {
@@ -10445,30 +10743,46 @@ const allocate = (container, typeId, value) => {
10445
10743
  }
10446
10744
  return qrl;
10447
10745
  }
10448
- case 20 /* TypeIds.Task */:
10746
+ case 28 /* TypeIds.Task */:
10449
10747
  return new Task(-1, -1, null, null, null, null);
10450
10748
  case 6 /* TypeIds.URL */:
10451
10749
  return new URL(value);
10452
10750
  case 7 /* TypeIds.Date */:
10453
10751
  return new Date(value);
10752
+ case 15 /* TypeIds.TemporalDuration */:
10753
+ return Temporal.Duration.from(value);
10754
+ case 16 /* TypeIds.TemporalInstant */:
10755
+ return Temporal.Instant.from(value);
10756
+ case 17 /* TypeIds.TemporalPlainDate */:
10757
+ return Temporal.PlainDate.from(value);
10758
+ case 18 /* TypeIds.TemporalPlainDateTime */:
10759
+ return Temporal.PlainDateTime.from(value);
10760
+ case 19 /* TypeIds.TemporalPlainMonthDay */:
10761
+ return Temporal.PlainMonthDay.from(value);
10762
+ case 20 /* TypeIds.TemporalPlainTime */:
10763
+ return Temporal.PlainTime.from(value);
10764
+ case 21 /* TypeIds.TemporalPlainYearMonth */:
10765
+ return Temporal.PlainYearMonth.from(value);
10766
+ case 22 /* TypeIds.TemporalZonedDateTime */:
10767
+ return Temporal.ZonedDateTime.from(value);
10454
10768
  case 8 /* TypeIds.Regex */:
10455
10769
  const idx = value.lastIndexOf('/');
10456
10770
  return new RegExp(value.slice(1, idx), value.slice(idx + 1));
10457
- case 15 /* TypeIds.Error */:
10771
+ case 23 /* TypeIds.Error */:
10458
10772
  return new Error();
10459
- case 21 /* TypeIds.Component */:
10773
+ case 29 /* TypeIds.Component */:
10460
10774
  return componentQrl(null);
10461
- case 22 /* TypeIds.Signal */:
10775
+ case 30 /* TypeIds.Signal */:
10462
10776
  return new SignalImpl(container, 0);
10463
- case 23 /* TypeIds.WrappedSignal */:
10777
+ case 31 /* TypeIds.WrappedSignal */:
10464
10778
  return new WrappedSignalImpl(container, null, null, null);
10465
- case 24 /* TypeIds.ComputedSignal */:
10779
+ case 32 /* TypeIds.ComputedSignal */:
10466
10780
  return new ComputedSignalImpl(container, null);
10467
- case 25 /* TypeIds.AsyncSignal */:
10468
- return new AsyncSignalImpl(container, null, undefined, { interval: 0 });
10469
- case 26 /* TypeIds.SerializerSignal */:
10781
+ case 33 /* TypeIds.AsyncSignal */:
10782
+ return new AsyncSignalImpl(container, null, undefined, {});
10783
+ case 34 /* TypeIds.SerializerSignal */:
10470
10784
  return new SerializerSignalImpl(container, null);
10471
- case 27 /* TypeIds.Store */: {
10785
+ case 35 /* TypeIds.Store */: {
10472
10786
  const data = value;
10473
10787
  // We need to allocate the store first, before we inflate its data, because the data can
10474
10788
  // reference the store itself (circular)
@@ -10487,17 +10801,17 @@ const allocate = (container, typeId, value) => {
10487
10801
  }
10488
10802
  case 13 /* TypeIds.URLSearchParams */:
10489
10803
  return new URLSearchParams(value);
10490
- case 28 /* TypeIds.FormData */:
10804
+ case 36 /* TypeIds.FormData */:
10491
10805
  return new FormData();
10492
- case 29 /* TypeIds.JSXNode */:
10806
+ case 37 /* TypeIds.JSXNode */:
10493
10807
  return new JSXNodeImpl(null, null, null, null, 0, null);
10494
10808
  case 12 /* TypeIds.BigInt */:
10495
10809
  return BigInt(value);
10496
- case 17 /* TypeIds.Set */:
10810
+ case 25 /* TypeIds.Set */:
10497
10811
  return new Set();
10498
- case 18 /* TypeIds.Map */:
10812
+ case 26 /* TypeIds.Map */:
10499
10813
  return new Map();
10500
- case 16 /* TypeIds.Promise */:
10814
+ case 24 /* TypeIds.Promise */:
10501
10815
  let resolve;
10502
10816
  let reject;
10503
10817
  const promise = new Promise((res, rej) => {
@@ -10508,13 +10822,13 @@ const allocate = (container, typeId, value) => {
10508
10822
  // Don't leave unhandled promise rejections
10509
10823
  promise.catch(() => { });
10510
10824
  return promise;
10511
- case 19 /* TypeIds.Uint8Array */:
10825
+ case 27 /* TypeIds.Uint8Array */:
10512
10826
  const encodedLength = value.length;
10513
10827
  const blocks = encodedLength >>> 2;
10514
10828
  const rest = encodedLength & 3;
10515
10829
  const decodedLength = blocks * 3 + (rest ? rest - 1 : 0);
10516
10830
  return new Uint8Array(decodedLength);
10517
- case 30 /* TypeIds.PropsProxy */:
10831
+ case 38 /* TypeIds.PropsProxy */:
10518
10832
  return createPropsProxy(null);
10519
10833
  case 10 /* TypeIds.VNode */:
10520
10834
  return retrieveVNodeOrDocument(container, value);
@@ -10552,9 +10866,9 @@ const allocate = (container, typeId, value) => {
10552
10866
  else {
10553
10867
  throw qError(17 /* QError.serializeErrorExpectedVNode */, [typeof vNode]);
10554
10868
  }
10555
- case 31 /* TypeIds.SubscriptionData */:
10869
+ case 39 /* TypeIds.SubscriptionData */:
10556
10870
  return new SubscriptionData({});
10557
- case 32 /* TypeIds.EffectSubscription */:
10871
+ case 40 /* TypeIds.EffectSubscription */:
10558
10872
  return new EffectSubscription(null, null, null, null);
10559
10873
  default:
10560
10874
  throw qError(18 /* QError.serializeErrorCannotAllocate */, [typeId]);
@@ -10964,10 +11278,11 @@ function maybeAddPollingAsyncSignalToEagerResume(serializationCtx, signal) {
10964
11278
  // Unwrap if it's a WrappedSignalImpl
10965
11279
  const unwrappedSignal = signal instanceof WrappedSignalImpl ? signal.$unwrapIfSignal$() : signal;
10966
11280
  if (unwrappedSignal instanceof AsyncSignalImpl) {
10967
- const interval = unwrappedSignal.$interval$;
11281
+ const expires = unwrappedSignal.$expires$;
10968
11282
  // Don't check for $effects$ here - effects are added later during tracking.
10969
11283
  // The AsyncSignal's polling mechanism will check for effects before scheduling.
10970
- if (interval > 0) {
11284
+ // Only eager-resume for polling signals, not stale-only ones.
11285
+ if (expires && !(unwrappedSignal.$flags$ & 256 /* AsyncSignalFlags.NO_POLL */)) {
10971
11286
  serializationCtx.$addRoot$(unwrappedSignal);
10972
11287
  serializationCtx.$eagerResume$.add(unwrappedSignal);
10973
11288
  }
@@ -11195,8 +11510,8 @@ function addQwikEventToSerializationContext(serializationCtx, key, qrl) {
11195
11510
  * @see `useOn`, `useOnWindow`, `useOnDocument`.
11196
11511
  */
11197
11512
  // </docs>
11198
- const useOn = (event, eventQrl) => {
11199
- _useOn("q-e:" /* EventNameHtmlScope.on */, event, eventQrl);
11513
+ const useOn = (event, eventQrl, options) => {
11514
+ _useOn(options?.passive ? "q-ep:" /* EventNameHtmlScope.onPassive */ : "q-e:" /* EventNameHtmlScope.on */, event, eventQrl, options);
11200
11515
  };
11201
11516
  // <docs markdown="../readme.md#useOnDocument">
11202
11517
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
@@ -11229,8 +11544,8 @@ const useOn = (event, eventQrl) => {
11229
11544
  * ```
11230
11545
  */
11231
11546
  // </docs>
11232
- const useOnDocument = (event, eventQrl) => {
11233
- _useOn("q-d:" /* EventNameHtmlScope.document */, event, eventQrl);
11547
+ const useOnDocument = (event, eventQrl, options) => {
11548
+ _useOn(options?.passive ? "q-dp:" /* EventNameHtmlScope.documentPassive */ : "q-d:" /* EventNameHtmlScope.document */, event, eventQrl, options);
11234
11549
  };
11235
11550
  // <docs markdown="../readme.md#useOnWindow">
11236
11551
  // !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
@@ -11264,10 +11579,10 @@ const useOnDocument = (event, eventQrl) => {
11264
11579
  * ```
11265
11580
  */
11266
11581
  // </docs>
11267
- const useOnWindow = (event, eventQrl) => {
11268
- _useOn("q-w:" /* EventNameHtmlScope.window */, event, eventQrl);
11582
+ const useOnWindow = (event, eventQrl, options) => {
11583
+ _useOn(options?.passive ? "q-wp:" /* EventNameHtmlScope.windowPassive */ : "q-w:" /* EventNameHtmlScope.window */, event, eventQrl, options);
11269
11584
  };
11270
- const _useOn = (prefix, eventName, eventQrl) => {
11585
+ const _useOn = (prefix, eventName, eventQrl, options) => {
11271
11586
  const { isAdded, addEvent } = useOnEventsSequentialScope();
11272
11587
  if (isAdded) {
11273
11588
  return;
@@ -11276,11 +11591,11 @@ const _useOn = (prefix, eventName, eventQrl) => {
11276
11591
  if (Array.isArray(eventName)) {
11277
11592
  for (let i = 0; i < eventName.length; i++) {
11278
11593
  const event = eventName[i];
11279
- addEvent(prefix + fromCamelToKebabCase(event), eventQrl);
11594
+ addEvent(prefix + fromCamelToKebabCase(event), eventQrl, options);
11280
11595
  }
11281
11596
  }
11282
11597
  else {
11283
- addEvent(prefix + fromCamelToKebabCase(eventName), eventQrl);
11598
+ addEvent(prefix + fromCamelToKebabCase(eventName), eventQrl, options);
11284
11599
  }
11285
11600
  }
11286
11601
  };
@@ -11317,13 +11632,27 @@ const useOnEventsSequentialScope = () => {
11317
11632
  while (addedFlags.length <= seqIdx) {
11318
11633
  addedFlags.push(false);
11319
11634
  }
11320
- const addEvent = (eventName, eventQrl) => {
11635
+ const addEvent = (eventName, eventQrl, options) => {
11321
11636
  addedFlags[seqIdx] = true;
11322
- let events = onMap[eventName];
11323
- if (!events) {
11324
- onMap[eventName] = events = [];
11637
+ let event = onMap[eventName];
11638
+ if (!event) {
11639
+ onMap[eventName] = event = {
11640
+ qrls: [],
11641
+ capture: false,
11642
+ preventdefault: false,
11643
+ stoppropagation: false,
11644
+ };
11645
+ }
11646
+ event.qrls.push(eventQrl);
11647
+ if (options?.capture) {
11648
+ event.capture = true;
11649
+ }
11650
+ if (options?.preventdefault) {
11651
+ event.preventdefault = true;
11652
+ }
11653
+ if (options?.stoppropagation) {
11654
+ event.stoppropagation = true;
11325
11655
  }
11326
- events.push(eventQrl);
11327
11656
  };
11328
11657
  return {
11329
11658
  isAdded: addedFlags[seqIdx],
@@ -11451,6 +11780,9 @@ const dangerousObjectKeys = new Set([
11451
11780
  'then',
11452
11781
  ]);
11453
11782
  const isSafeObjectKV = (key, value) => {
11783
+ if (typeof key === 'number') {
11784
+ return true;
11785
+ }
11454
11786
  return (typeof key === 'string' &&
11455
11787
  key !== '__proto__' &&
11456
11788
  (typeof value !== 'function' || !dangerousObjectKeys.has(key)));
@@ -11483,7 +11815,7 @@ const inflate = (container, target, typeId, data) => {
11483
11815
  target[key] = value;
11484
11816
  }
11485
11817
  break;
11486
- case 20 /* TypeIds.Task */:
11818
+ case 28 /* TypeIds.Task */:
11487
11819
  const task = target;
11488
11820
  const v = data;
11489
11821
  task.$qrl$ = v[0];
@@ -11492,10 +11824,10 @@ const inflate = (container, target, typeId, data) => {
11492
11824
  task.$el$ = v[3];
11493
11825
  task.$state$ = v[4];
11494
11826
  break;
11495
- case 21 /* TypeIds.Component */:
11827
+ case 29 /* TypeIds.Component */:
11496
11828
  target[SERIALIZABLE_STATE][0] = data[0];
11497
11829
  break;
11498
- case 27 /* TypeIds.Store */: {
11830
+ case 35 /* TypeIds.Store */: {
11499
11831
  // Inflate the store target
11500
11832
  const store = unwrapStore(target);
11501
11833
  const storeTarget = pendingStoreTargets.get(store);
@@ -11514,7 +11846,7 @@ const inflate = (container, target, typeId, data) => {
11514
11846
  restoreEffectBackRefForEffectsMap(storeHandler.$effects$, store);
11515
11847
  break;
11516
11848
  }
11517
- case 22 /* TypeIds.Signal */: {
11849
+ case 30 /* TypeIds.Signal */: {
11518
11850
  const signal = target;
11519
11851
  const d = data;
11520
11852
  signal.$untrackedValue$ = d[0];
@@ -11522,7 +11854,7 @@ const inflate = (container, target, typeId, data) => {
11522
11854
  restoreEffectBackRefForEffects(signal.$effects$, signal);
11523
11855
  break;
11524
11856
  }
11525
- case 23 /* TypeIds.WrappedSignal */: {
11857
+ case 31 /* TypeIds.WrappedSignal */: {
11526
11858
  const signal = target;
11527
11859
  const d = data;
11528
11860
  signal.$func$ = container.getSyncFn(d[0]);
@@ -11536,14 +11868,22 @@ const inflate = (container, target, typeId, data) => {
11536
11868
  restoreEffectBackRefForEffects(signal.$effects$, signal);
11537
11869
  break;
11538
11870
  }
11539
- case 25 /* TypeIds.AsyncSignal */: {
11871
+ case 33 /* TypeIds.AsyncSignal */: {
11540
11872
  const asyncSignal = target;
11541
11873
  const d = data;
11542
11874
  asyncSignal.$computeQrl$ = d[0];
11543
- asyncSignal.$effects$ = new Set(d[1]);
11544
- asyncSignal.$loadingEffects$ = new Set(d[2]);
11545
- asyncSignal.$errorEffects$ = new Set(d[3]);
11546
- asyncSignal.$untrackedError$ = d[4];
11875
+ if (d[1]) {
11876
+ asyncSignal.$effects$ = new Set(d[1]);
11877
+ }
11878
+ if (d[2]) {
11879
+ asyncSignal.$loadingEffects$ = new Set(d[2]);
11880
+ }
11881
+ if (d[3]) {
11882
+ asyncSignal.$errorEffects$ = new Set(d[3]);
11883
+ }
11884
+ if (d[4]) {
11885
+ asyncSignal.$untrackedError$ = d[4];
11886
+ }
11547
11887
  asyncSignal.$flags$ = d[5] ?? 0;
11548
11888
  if (asyncSignal.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
11549
11889
  // If it's client only, it was serialized because it pretended to be loading
@@ -11557,9 +11897,16 @@ const inflate = (container, target, typeId, data) => {
11557
11897
  if (asyncSignal.$untrackedValue$ === NEEDS_COMPUTATION) {
11558
11898
  asyncSignal.$flags$ |= 1 /* SignalFlags.INVALID */;
11559
11899
  }
11560
- // Note, we use the setter so that it schedules polling if needed
11561
- asyncSignal.interval = (d[7] ?? 0);
11562
- asyncSignal.$concurrency$ = (d[8] ?? 1);
11900
+ // Handle old format (negative = no poll) and new format (always positive, flag in d[5])
11901
+ const rawExpires = (d[7] ?? 0);
11902
+ asyncSignal.expires = Math.abs(rawExpires);
11903
+ if (rawExpires < 0) {
11904
+ asyncSignal.$flags$ |= 256 /* AsyncSignalFlags.NO_POLL */;
11905
+ }
11906
+ if (d[8] !== undefined && d[8] !== 1) {
11907
+ asyncSignal.$concurrency$ = (d[8] ?? 1);
11908
+ asyncSignal.$jobs$ = [];
11909
+ }
11563
11910
  asyncSignal.$timeoutMs$ = (d[9] ?? 0);
11564
11911
  restoreEffectBackRefForEffects(asyncSignal.$effects$, asyncSignal);
11565
11912
  restoreEffectBackRefForEffects(asyncSignal.$loadingEffects$, asyncSignal);
@@ -11567,8 +11914,8 @@ const inflate = (container, target, typeId, data) => {
11567
11914
  break;
11568
11915
  }
11569
11916
  // Inflating a SerializerSignal is the same as inflating a ComputedSignal
11570
- case 26 /* TypeIds.SerializerSignal */:
11571
- case 24 /* TypeIds.ComputedSignal */: {
11917
+ case 34 /* TypeIds.SerializerSignal */:
11918
+ case 32 /* TypeIds.ComputedSignal */: {
11572
11919
  const computed = target;
11573
11920
  const d = data;
11574
11921
  computed.$computeQrl$ = d[0];
@@ -11588,7 +11935,7 @@ const inflate = (container, target, typeId, data) => {
11588
11935
  if (hasValue) {
11589
11936
  computed.$untrackedValue$ = d[2];
11590
11937
  }
11591
- if (typeId !== 26 /* TypeIds.SerializerSignal */ && computed.$untrackedValue$ !== NEEDS_COMPUTATION) {
11938
+ if (typeId !== 34 /* TypeIds.SerializerSignal */ && computed.$untrackedValue$ !== NEEDS_COMPUTATION) {
11592
11939
  // If we have a value after SSR, it will always be mean the signal was not invalid
11593
11940
  // The serialized signal is always left invalid so it can recreate the custom object
11594
11941
  computed.$flags$ &= -2 /* SignalFlags.INVALID */;
@@ -11596,7 +11943,7 @@ const inflate = (container, target, typeId, data) => {
11596
11943
  restoreEffectBackRefForEffects(computed.$effects$, computed);
11597
11944
  break;
11598
11945
  }
11599
- case 15 /* TypeIds.Error */: {
11946
+ case 23 /* TypeIds.Error */: {
11600
11947
  const d = data;
11601
11948
  target.message = d[0];
11602
11949
  for (let i = 1; i < d.length; i += 2) {
@@ -11604,7 +11951,7 @@ const inflate = (container, target, typeId, data) => {
11604
11951
  }
11605
11952
  break;
11606
11953
  }
11607
- case 28 /* TypeIds.FormData */: {
11954
+ case 36 /* TypeIds.FormData */: {
11608
11955
  const formData = target;
11609
11956
  const d = data;
11610
11957
  for (let i = 0; i < d.length; i++) {
@@ -11612,7 +11959,7 @@ const inflate = (container, target, typeId, data) => {
11612
11959
  }
11613
11960
  break;
11614
11961
  }
11615
- case 29 /* TypeIds.JSXNode */: {
11962
+ case 37 /* TypeIds.JSXNode */: {
11616
11963
  const jsx = target;
11617
11964
  const [type, key, varProps, constProps, children, toSort] = data;
11618
11965
  jsx.type = type;
@@ -11623,7 +11970,7 @@ const inflate = (container, target, typeId, data) => {
11623
11970
  jsx.toSort = !!toSort;
11624
11971
  break;
11625
11972
  }
11626
- case 17 /* TypeIds.Set */: {
11973
+ case 25 /* TypeIds.Set */: {
11627
11974
  const set = target;
11628
11975
  const d = data;
11629
11976
  for (let i = 0; i < d.length; i++) {
@@ -11631,7 +11978,7 @@ const inflate = (container, target, typeId, data) => {
11631
11978
  }
11632
11979
  break;
11633
11980
  }
11634
- case 18 /* TypeIds.Map */: {
11981
+ case 26 /* TypeIds.Map */: {
11635
11982
  const map = target;
11636
11983
  const d = data;
11637
11984
  for (let i = 0; i < d.length; i++) {
@@ -11639,7 +11986,7 @@ const inflate = (container, target, typeId, data) => {
11639
11986
  }
11640
11987
  break;
11641
11988
  }
11642
- case 16 /* TypeIds.Promise */: {
11989
+ case 24 /* TypeIds.Promise */: {
11643
11990
  const promise = target;
11644
11991
  const [resolved, result] = data;
11645
11992
  const [resolve, reject] = resolvers.get(promise);
@@ -11651,7 +11998,7 @@ const inflate = (container, target, typeId, data) => {
11651
11998
  }
11652
11999
  break;
11653
12000
  }
11654
- case 19 /* TypeIds.Uint8Array */:
12001
+ case 27 /* TypeIds.Uint8Array */:
11655
12002
  const bytes = target;
11656
12003
  const buf = atob(data);
11657
12004
  let i = 0;
@@ -11660,7 +12007,7 @@ const inflate = (container, target, typeId, data) => {
11660
12007
  bytes[i++] = s.charCodeAt(0);
11661
12008
  }
11662
12009
  break;
11663
- case 30 /* TypeIds.PropsProxy */:
12010
+ case 38 /* TypeIds.PropsProxy */:
11664
12011
  const propsProxy = target;
11665
12012
  const d = data;
11666
12013
  let owner = d[0];
@@ -11673,13 +12020,13 @@ const inflate = (container, target, typeId, data) => {
11673
12020
  propsHandler.$effects$ = d[3];
11674
12021
  restoreEffectBackRefForEffectsMap(propsHandler.$effects$, propsProxy);
11675
12022
  break;
11676
- case 31 /* TypeIds.SubscriptionData */: {
12023
+ case 39 /* TypeIds.SubscriptionData */: {
11677
12024
  const effectData = target;
11678
12025
  effectData.data.$scopedStyleIdPrefix$ = data[0];
11679
12026
  effectData.data.$isConst$ = data[1];
11680
12027
  break;
11681
12028
  }
11682
- case 32 /* TypeIds.EffectSubscription */: {
12029
+ case 40 /* TypeIds.EffectSubscription */: {
11683
12030
  const effectSub = target;
11684
12031
  const d = data;
11685
12032
  effectSub.consumer = d[0];
@@ -11770,7 +12117,7 @@ function restoreEffectBackRefForEffectsMap(effectsMap, consumer) {
11770
12117
  }
11771
12118
 
11772
12119
  /** Arrays/Objects are special-cased so their identifiers is a single digit. */
11773
- const needsInflation = (typeId) => typeId >= 15 /* TypeIds.Error */ || typeId === 4 /* TypeIds.Array */ || typeId === 5 /* TypeIds.Object */;
12120
+ const needsInflation = (typeId) => typeId >= 23 /* TypeIds.Error */ || typeId === 4 /* TypeIds.Array */ || typeId === 5 /* TypeIds.Object */;
11774
12121
  const deserializedProxyMap = new WeakMap();
11775
12122
  const isDeserializerProxy = (value) => {
11776
12123
  return isObject(value) && SERIALIZER_PROXY_UNWRAP in value;
@@ -13308,13 +13655,15 @@ class QRLClass {
13308
13655
  $container$;
13309
13656
  constructor($lazy$, $captures$, container) {
13310
13657
  this.$lazy$ = $lazy$;
13658
+ if (qDev) {
13659
+ initQrlClassDev($lazy$, $captures$, this);
13660
+ }
13311
13661
  if ($captures$) {
13312
13662
  this.$captures$ = $captures$;
13313
13663
  if (typeof $captures$ === 'string') {
13314
13664
  // We cannot rely on the container of the lazy ref, it may be missing or different
13315
13665
  this.$container$ = container;
13316
13666
  }
13317
- qDev && initQrlClassDev($lazy$, $captures$, this);
13318
13667
  }
13319
13668
  // If it is plain value with deserialized or missing captures, resolve it immediately
13320
13669
  // Otherwise we keep using the async path so we can wait for qrls to load