sibujs 4.13.0 → 4.14.0

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 (107) hide show
  1. package/README.md +1 -1
  2. package/dist/browser.cjs +15 -2
  3. package/dist/browser.js +9 -7
  4. package/dist/build.cjs +880 -281
  5. package/dist/build.d.cts +68 -3
  6. package/dist/build.d.ts +68 -3
  7. package/dist/build.js +88 -30
  8. package/dist/cdn.dev.global.js +12 -12
  9. package/dist/cdn.full.dev.global.js +13 -13
  10. package/dist/cdn.full.global.js +12 -12
  11. package/dist/cdn.global.js +12 -12
  12. package/dist/{chunk-7K7W4AA5.js → chunk-2TTRW2TE.js} +6 -6
  13. package/dist/{chunk-J6FW5TV6.js → chunk-3HEX6QJQ.js} +5 -3
  14. package/dist/chunk-3HZOSMPX.js +90 -0
  15. package/dist/{chunk-GNSRXK34.js → chunk-4FJSAUKB.js} +11 -3
  16. package/dist/{chunk-IV74C2YX.js → chunk-4TQDTWWN.js} +6 -5
  17. package/dist/{chunk-L3QHS4O4.js → chunk-7ILEHTVX.js} +1 -1
  18. package/dist/{chunk-CK5F2IR5.js → chunk-A454RAEK.js} +4 -4
  19. package/dist/{chunk-BRRRVLHQ.js → chunk-AE32RGWX.js} +10 -6
  20. package/dist/{chunk-EXXSN3BW.js → chunk-B3HOT4TK.js} +1 -1
  21. package/dist/{chunk-F4W7WYXY.js → chunk-BKZ5N6NK.js} +8 -6
  22. package/dist/{chunk-MNEITZ27.js → chunk-BNXRWZZV.js} +49 -8
  23. package/dist/chunk-BOYKGGVD.js +2015 -0
  24. package/dist/{chunk-G6366I2A.js → chunk-CCKUNHVU.js} +2 -2
  25. package/dist/{chunk-346BYZL2.js → chunk-CJ7KS3DF.js} +16 -10
  26. package/dist/chunk-CNPT6NKV.js +1859 -0
  27. package/dist/{chunk-ENFRHCMK.js → chunk-F67F77IA.js} +2 -2
  28. package/dist/{chunk-TUCPL2HB.js → chunk-GIJ33UJZ.js} +1 -1
  29. package/dist/chunk-GVAMIU6K.js +195 -0
  30. package/dist/{chunk-HDKDBC6V.js → chunk-HQIAL7F2.js} +8 -6
  31. package/dist/{chunk-ZE5LF44R.js → chunk-JTFQ7IL4.js} +8 -8
  32. package/dist/{chunk-AM6DZLBM.js → chunk-LJMX4SQ7.js} +2 -2
  33. package/dist/{chunk-HVVRXRGO.js → chunk-MIRKTVH4.js} +7 -14
  34. package/dist/{chunk-YJ57VR6Y.js → chunk-N7A6FKWW.js} +5 -3
  35. package/dist/chunk-NT3ZYB5S.js +167 -0
  36. package/dist/{chunk-Z3EZX6DZ.js → chunk-QS6GMWDD.js} +151 -86
  37. package/dist/chunk-R5U7XKVJ.js +16 -0
  38. package/dist/{chunk-3C56VNCK.js → chunk-RVR5NPFL.js} +3 -3
  39. package/dist/{chunk-F2UWOZ6J.js → chunk-RVWJGWCL.js} +2 -2
  40. package/dist/{chunk-NYNYSPK7.js → chunk-S37PZD6I.js} +30 -45
  41. package/dist/{chunk-QV5WEOFD.js → chunk-SVULV7O4.js} +119 -26
  42. package/dist/{chunk-C2FAO6VQ.js → chunk-TLS4NVIB.js} +5 -5
  43. package/dist/{chunk-M25RIH6Y.js → chunk-UUIKJJIK.js} +10 -8
  44. package/dist/chunk-UYTYNCMZ.js +199 -0
  45. package/dist/chunk-VM2U5LEL.js +2596 -0
  46. package/dist/{chunk-24L5RDPS.js → chunk-Y4LUM2XS.js} +8 -6
  47. package/dist/data.cjs +265 -35
  48. package/dist/data.d.cts +31 -1
  49. package/dist/data.d.ts +31 -1
  50. package/dist/data.js +16 -10
  51. package/dist/devtools.cjs +15 -2
  52. package/dist/devtools.js +9 -7
  53. package/dist/{dispose-GEIG2KOF.js → dispose-EIHHHDC7.js} +3 -1
  54. package/dist/ecosystem.cjs +62 -23
  55. package/dist/ecosystem.js +14 -12
  56. package/dist/extras.cjs +3520 -270
  57. package/dist/extras.d.cts +3 -3
  58. package/dist/extras.d.ts +3 -3
  59. package/dist/extras.js +39 -29
  60. package/dist/index.cjs +442 -253
  61. package/dist/index.d.cts +93 -283
  62. package/dist/index.d.ts +93 -283
  63. package/dist/index.js +26 -16
  64. package/dist/motion.cjs +12 -1
  65. package/dist/motion.js +6 -4
  66. package/dist/patterns.cjs +15 -2
  67. package/dist/patterns.js +10 -8
  68. package/dist/performance.cjs +36 -2
  69. package/dist/performance.d.cts +2 -2
  70. package/dist/performance.d.ts +2 -2
  71. package/dist/performance.js +14 -10
  72. package/dist/plugins.cjs +5225 -1807
  73. package/dist/plugins.d.cts +8 -834
  74. package/dist/plugins.d.ts +8 -834
  75. package/dist/plugins.js +64 -2329
  76. package/dist/prerenderServer-MXJEVWA3.js +350 -0
  77. package/dist/renderRoute-DP20XwMS.d.cts +86 -0
  78. package/dist/renderRoute-fxgsm2Ir.d.ts +86 -0
  79. package/dist/routeHead-CE9SV-cH.d.cts +995 -0
  80. package/dist/routeHead-DzVxPviY.d.ts +995 -0
  81. package/dist/{routeMiddleware-B1sp4P7a.d.ts → routeMiddleware-BySbueoE.d.ts} +0 -25
  82. package/dist/{routeMiddleware-CedQTsLK.d.cts → routeMiddleware-CijZD5eW.d.cts} +0 -25
  83. package/dist/ssr-JpGpHnpC.d.cts +841 -0
  84. package/dist/ssr-JpGpHnpC.d.ts +841 -0
  85. package/dist/{ssr-VBM6J5SJ.js → ssr-NECEU4X4.js} +15 -6
  86. package/dist/ssr-dom.cjs +1862 -0
  87. package/dist/ssr-dom.d.cts +341 -0
  88. package/dist/ssr-dom.d.ts +341 -0
  89. package/dist/ssr-dom.js +19 -0
  90. package/dist/ssr.cjs +7630 -2064
  91. package/dist/ssr.d.cts +63 -5
  92. package/dist/ssr.d.ts +63 -5
  93. package/dist/ssr.js +136 -14
  94. package/dist/testing.cjs +6543 -87
  95. package/dist/testing.d.cts +80 -1
  96. package/dist/testing.d.ts +80 -1
  97. package/dist/testing.js +117 -4
  98. package/dist/ui.cjs +36 -2
  99. package/dist/ui.js +17 -14
  100. package/dist/widgets.cjs +14 -1
  101. package/dist/widgets.js +11 -9
  102. package/package.json +9 -2
  103. package/dist/chunk-2F4PSJ5Z.js +0 -765
  104. package/dist/chunk-7XHATCIH.js +0 -121
  105. package/dist/chunk-B36ADEIR.js +0 -21
  106. package/dist/ssr-Db0Sgdu3.d.cts +0 -245
  107. package/dist/ssr-Db0Sgdu3.d.ts +0 -245
@@ -3,22 +3,24 @@ import {
3
3
  } from "./chunk-7ZHH77QA.js";
4
4
  import {
5
5
  effect
6
- } from "./chunk-BRRRVLHQ.js";
6
+ } from "./chunk-AE32RGWX.js";
7
7
  import {
8
8
  stripHtml
9
- } from "./chunk-EXXSN3BW.js";
9
+ } from "./chunk-B3HOT4TK.js";
10
10
  import {
11
11
  signal
12
- } from "./chunk-GNSRXK34.js";
12
+ } from "./chunk-4FJSAUKB.js";
13
13
  import {
14
14
  forEachSubscriber,
15
15
  getSubscriberCount,
16
16
  getSubscriberDeps
17
- } from "./chunk-HVVRXRGO.js";
17
+ } from "./chunk-MIRKTVH4.js";
18
+ import {
19
+ dispose
20
+ } from "./chunk-S37PZD6I.js";
18
21
  import {
19
- dispose,
20
22
  isDev
21
- } from "./chunk-NYNYSPK7.js";
23
+ } from "./chunk-NT3ZYB5S.js";
22
24
 
23
25
  // src/devtools/debug.ts
24
26
  var debugEnabled = false;
package/dist/data.cjs CHANGED
@@ -42,7 +42,8 @@ __export(data_exports, {
42
42
  syncAdapter: () => syncAdapter,
43
43
  throttle: () => throttle,
44
44
  withLoader: () => withLoader,
45
- withRetry: () => withRetry
45
+ withRetry: () => withRetry,
46
+ withholdTransfer: () => withholdTransfer
46
47
  });
47
48
  module.exports = __toCommonJS(data_exports);
48
49
 
@@ -112,12 +113,12 @@ function claimedByBoundary(error, context) {
112
113
  }
113
114
  function resolveEventTarget(node) {
114
115
  const ELEMENT_NODE = 1;
115
- let current = node;
116
- while (current) {
117
- if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
118
- return current;
116
+ let current2 = node;
117
+ while (current2) {
118
+ if (current2.nodeType === ELEMENT_NODE && typeof current2.dispatchEvent === "function") {
119
+ return current2;
119
120
  }
120
- current = current.parentNode;
121
+ current2 = current2.parentNode;
121
122
  }
122
123
  const self = node;
123
124
  return typeof self.dispatchEvent === "function" ? self : null;
@@ -126,10 +127,21 @@ function defaultReport(error, context) {
126
127
  if (typeof console === "undefined") return;
127
128
  console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
128
129
  }
130
+ function requestErrorSink() {
131
+ const shared = globalThis[/* @__PURE__ */ Symbol.for("sibujs.ssr.v1")];
132
+ if (!shared) return void 0;
133
+ const store = shared.als ? shared.als.getStore() : shared.fallbackDepth > 0 ? shared.fallbackStore : void 0;
134
+ return store?.errors;
135
+ }
129
136
  function reportError(error, context) {
130
137
  const err = normalizeError(error);
131
138
  untrackedRun(() => {
132
139
  if (claimedByBoundary(err, context)) return;
140
+ const sink = requestErrorSink();
141
+ if (sink) {
142
+ sink.push({ error: err, context });
143
+ return;
144
+ }
133
145
  const s = state();
134
146
  const handler = s.handler;
135
147
  if (handler && s.handlerDepth === 0) {
@@ -150,6 +162,32 @@ function reportError(error, context) {
150
162
  });
151
163
  }
152
164
 
165
+ // src/core/rendering/adoptScope.ts
166
+ var current = null;
167
+ function currentSink() {
168
+ return current?.s.on ? current.s : null;
169
+ }
170
+
171
+ // src/core/rendering/hydrationHooks.ts
172
+ var _a;
173
+ var slot = globalThis[_a = /* @__PURE__ */ Symbol.for("sibujs.hydration.v2")] ?? (globalThis[_a] = { a: /* @__PURE__ */ new Set(), c: null });
174
+ function ownSession() {
175
+ return currentSink()?.h ?? slot.c;
176
+ }
177
+ function hydrationOwners() {
178
+ const own = ownSession();
179
+ return own ? own.open ? [own] : [] : Array.from(slot.a);
180
+ }
181
+ function notify(session) {
182
+ for (const wake of Array.from(session.wake)) wake();
183
+ }
184
+ function holdHydration(sessions, entry) {
185
+ for (const s of sessions) s.pending.add(entry);
186
+ return () => {
187
+ for (const s of sessions) if (s.pending.delete(entry)) notify(s);
188
+ };
189
+ }
190
+
153
191
  // src/core/rendering/dispose.ts
154
192
  function resolveCapture(capture) {
155
193
  let frame = capture;
@@ -737,7 +775,7 @@ function forEachSubscriber(signal2, visit) {
737
775
  }
738
776
 
739
777
  // src/reactivity/track.ts
740
- var _runtimeVersion = true ? "4.13.0" : "dev";
778
+ var _runtimeVersion = true ? "4.14.0" : "dev";
741
779
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
742
780
  function resolveReactiveApi() {
743
781
  const g = globalThis;
@@ -919,6 +957,13 @@ function derived(getter, options) {
919
957
  return computedGetter;
920
958
  }
921
959
 
960
+ // src/core/rendering/streamBoundary.ts
961
+ var _a2;
962
+ var slot2 = globalThis[_a2 = /* @__PURE__ */ Symbol.for("sibujs.streamBoundary.v1")] ?? (globalThis[_a2] = { hook: null, current: null });
963
+ function currentBoundary() {
964
+ return slot2.current;
965
+ }
966
+
922
967
  // src/core/ssr-context.ts
923
968
  var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
924
969
  function detectSSRShared() {
@@ -934,6 +979,8 @@ function detectSSRShared() {
934
979
  }
935
980
  if (mod) detected = new mod.AsyncLocalStorage();
936
981
  }
982
+ const globalAls = globalThis.AsyncLocalStorage;
983
+ if (!detected && typeof globalAls === "function") detected = new globalAls();
937
984
  } catch {
938
985
  detected = null;
939
986
  }
@@ -954,6 +1001,10 @@ function getSSRStore() {
954
1001
  }
955
1002
  return fallbackStore;
956
1003
  }
1004
+ function getRequestStore() {
1005
+ if (als) return als.getStore() ?? null;
1006
+ return _shared.fallbackDepth > 0 ? fallbackStore : null;
1007
+ }
957
1008
  function isSSR() {
958
1009
  return getSSRStore().ssr;
959
1010
  }
@@ -968,6 +1019,33 @@ function getRequestScopedCache(name) {
968
1019
  }
969
1020
  return c;
970
1021
  }
1022
+ function requestSlot(name, create) {
1023
+ const store = getRequestStore();
1024
+ if (!store) return void 0;
1025
+ const slots = store.slots ?? (store.slots = /* @__PURE__ */ new Map());
1026
+ if (!slots.has(name) && create) slots.set(name, create());
1027
+ return slots.get(name);
1028
+ }
1029
+ function trackPending(promise, label, hydration = true) {
1030
+ const store = getRequestStore();
1031
+ const pending = store?.pending;
1032
+ const sessions = pending || !hydration ? [] : hydrationOwners();
1033
+ if (!pending && sessions.length === 0) return promise;
1034
+ const entry = { label, since: Date.now(), boundary: currentBoundary() ?? void 0 };
1035
+ pending?.add(entry);
1036
+ const release = holdHydration(sessions, entry);
1037
+ const done = () => {
1038
+ pending?.delete(entry);
1039
+ store?.wake?.();
1040
+ release();
1041
+ };
1042
+ try {
1043
+ Promise.resolve(promise).then(done, done);
1044
+ } catch {
1045
+ done();
1046
+ }
1047
+ return promise;
1048
+ }
971
1049
 
972
1050
  // src/core/signals/effect.ts
973
1051
  var _g = globalThis;
@@ -1033,7 +1111,7 @@ function disposeEffect(ctx) {
1033
1111
  }
1034
1112
  function effect(effectFn, options) {
1035
1113
  devAssert(typeof effectFn === "function", "effect: argument must be a function.");
1036
- if (isSSR()) return () => {
1114
+ if (isSSR() && !options?.server) return () => {
1037
1115
  };
1038
1116
  const ctx = {
1039
1117
  fn: effectFn,
@@ -1230,6 +1308,73 @@ function globalSingleton(key, create) {
1230
1308
  return g[key] ?? (g[key] = create());
1231
1309
  }
1232
1310
 
1311
+ // src/utils/guards.ts
1312
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1313
+ function isUnsafeKey(key) {
1314
+ return UNSAFE_KEYS.has(key);
1315
+ }
1316
+ function readOwnGlobal(key) {
1317
+ if (typeof window === "undefined") return void 0;
1318
+ if (!Object.hasOwn(window, key)) return void 0;
1319
+ const value = window[key];
1320
+ if (typeof Node !== "undefined" && value instanceof Node) return void 0;
1321
+ return value;
1322
+ }
1323
+
1324
+ // src/utils/transfer.ts
1325
+ var TRANSFER_GLOBAL = "__SIBU_TRANSFER__";
1326
+ var TRANSFER_VERSION = 1;
1327
+ var REGISTRY_KEY2 = /* @__PURE__ */ Symbol.for("sibujs.transfer.v1");
1328
+ function registry() {
1329
+ const g = globalThis;
1330
+ let r = g[REGISTRY_KEY2];
1331
+ if (!r) {
1332
+ r = { collectors: /* @__PURE__ */ new Map(), payload: void 0 };
1333
+ g[REGISTRY_KEY2] = r;
1334
+ }
1335
+ return r;
1336
+ }
1337
+ function registerTransferCollector(section, collect) {
1338
+ registry().collectors.set(section, collect);
1339
+ }
1340
+ function isPlainRecord(value) {
1341
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
1342
+ const proto = Object.getPrototypeOf(value);
1343
+ return proto === Object.prototype || proto === null;
1344
+ }
1345
+ function readPayload() {
1346
+ const r = registry();
1347
+ if (r.payload !== void 0) return r.payload;
1348
+ r.payload = null;
1349
+ if (typeof window === "undefined" || getRequestStore()) return null;
1350
+ const raw = readOwnGlobal(TRANSFER_GLOBAL);
1351
+ if (!isPlainRecord(raw) || raw.v !== TRANSFER_VERSION) return null;
1352
+ const sections = /* @__PURE__ */ Object.create(null);
1353
+ for (const key of Object.keys(raw)) {
1354
+ const section = raw[key];
1355
+ if (key === "v" || isUnsafeKey(key) || !isPlainRecord(section)) continue;
1356
+ const entries = /* @__PURE__ */ Object.create(null);
1357
+ for (const k of Object.keys(section)) if (!isUnsafeKey(k)) entries[k] = section[k];
1358
+ sections[key] = entries;
1359
+ }
1360
+ r.payload = sections;
1361
+ return sections;
1362
+ }
1363
+ function takeTransferred(section, key) {
1364
+ const entries = readPayload()?.[section];
1365
+ if (!entries || !Object.hasOwn(entries, key)) return void 0;
1366
+ const value = entries[key];
1367
+ delete entries[key];
1368
+ return value;
1369
+ }
1370
+ function takeTransferredSection(section) {
1371
+ const payload = readPayload();
1372
+ const entries = payload?.[section];
1373
+ if (!payload || !entries) return {};
1374
+ delete payload[section];
1375
+ return entries;
1376
+ }
1377
+
1233
1378
  // src/data/abort.ts
1234
1379
  function isAbortError(error) {
1235
1380
  return typeof error === "object" && error !== null && error.name === "AbortError";
@@ -1424,8 +1569,34 @@ function sharedView(entry) {
1424
1569
  }
1425
1570
  var globalQueryCache = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.query.cache.v1"), () => /* @__PURE__ */ new Map());
1426
1571
  function getActiveQueryCache() {
1427
- return getRequestScopedCache("query") ?? globalQueryCache;
1428
- }
1572
+ const requestCache = getRequestScopedCache("query");
1573
+ if (requestCache) return requestCache;
1574
+ primeFromTransfer();
1575
+ return globalQueryCache;
1576
+ }
1577
+ var SERVER_EFFECT = { server: true };
1578
+ function primeFromTransfer() {
1579
+ const entries = takeTransferredSection("q");
1580
+ const now = Date.now();
1581
+ for (const key of Object.keys(entries)) {
1582
+ const record = entries[key];
1583
+ if (!record || typeof record !== "object" || record.d === void 0) continue;
1584
+ if (globalQueryCache.has(key)) continue;
1585
+ const entry = getOrCreateEntry(globalQueryCache, key, record.d);
1586
+ const t = typeof record.t === "number" && Number.isFinite(record.t) ? record.t : now;
1587
+ entry.dataUpdatedAt = Math.min(t, now);
1588
+ }
1589
+ }
1590
+ registerTransferCollector("q", () => {
1591
+ const cache = getRequestScopedCache("query");
1592
+ if (!cache) return void 0;
1593
+ const out = {};
1594
+ for (const [key, entry] of cache) {
1595
+ if (entry.noTransfer || entry.data === void 0 || entry.error) continue;
1596
+ out[key] = { d: entry.data, t: entry.dataUpdatedAt };
1597
+ }
1598
+ return out;
1599
+ });
1429
1600
  function abandonEntry(entry) {
1430
1601
  if (entry.gcTimer) clearTimeout(entry.gcTimer);
1431
1602
  entry.gcTimer = null;
@@ -1471,11 +1642,13 @@ function query(key, fetcher, options = {}) {
1471
1642
  onError,
1472
1643
  onSettled,
1473
1644
  select,
1474
- structuralSharing = true
1645
+ structuralSharing = true,
1646
+ ssr = true
1475
1647
  } = options;
1648
+ const onServer = isSSR();
1476
1649
  const resolveKey = typeof key === "function" ? key : () => key;
1477
1650
  const enabledGate = typeof enabled === "function" ? derived(() => Boolean(enabled())) : null;
1478
- const isEnabled = enabledGate ?? (() => Boolean(enabled));
1651
+ const isEnabled = onServer && !ssr ? () => false : enabledGate ?? (() => Boolean(enabled));
1479
1652
  const cache = getActiveQueryCache();
1480
1653
  const [data, setData] = signal(initialData);
1481
1654
  const [isFetching, setIsFetching] = signal(false);
@@ -1549,7 +1722,7 @@ function query(key, fetcher, options = {}) {
1549
1722
  selectedEntry = entry;
1550
1723
  selectedValue = value;
1551
1724
  setData(value);
1552
- }) : null;
1725
+ }, SERVER_EFFECT) : null;
1553
1726
  function detachFromEntry() {
1554
1727
  const entry = attachedEntry;
1555
1728
  const key2 = attachedKey;
@@ -1563,9 +1736,9 @@ function query(key, fetcher, options = {}) {
1563
1736
  if (cache.get(key2) !== entry) return;
1564
1737
  if (entry.gcTimer !== null) clearTimeout(entry.gcTimer);
1565
1738
  entry.gcTimer = setTimeout(() => {
1566
- const current = cache.get(key2);
1567
- if (current === entry && current.subscribers <= 0) {
1568
- abandonEntry(current);
1739
+ const current2 = cache.get(key2);
1740
+ if (current2 === entry && current2.subscribers <= 0) {
1741
+ abandonEntry(current2);
1569
1742
  cache.delete(key2);
1570
1743
  }
1571
1744
  }, cacheTime);
@@ -1632,7 +1805,7 @@ function query(key, fetcher, options = {}) {
1632
1805
  runCallback("query onSettled", () => onSettled?.());
1633
1806
  return;
1634
1807
  }
1635
- entry.promise = promise;
1808
+ entry.promise = trackPending(promise, `query:${key2}`, false);
1636
1809
  try {
1637
1810
  const result = await promise;
1638
1811
  if (entry.generation !== generation) return;
@@ -1704,6 +1877,7 @@ function query(key, fetcher, options = {}) {
1704
1877
  return;
1705
1878
  }
1706
1879
  const entry = getOrCreateEntry(cache, key2, initialData);
1880
+ if (!ssr) entry.noTransfer = true;
1707
1881
  const reattached = attachedEntry !== entry;
1708
1882
  attachToEntry(entry, key2);
1709
1883
  if (keyChanged) setIsFetching(entry.promise !== null);
@@ -1725,15 +1899,15 @@ function query(key, fetcher, options = {}) {
1725
1899
  if (on && (entry.data === void 0 || isDataStale)) {
1726
1900
  doFetch();
1727
1901
  }
1728
- });
1729
- if (refetchInterval && refetchInterval > 0) {
1902
+ }, SERVER_EFFECT);
1903
+ if (!onServer && refetchInterval && refetchInterval > 0) {
1730
1904
  intervalTimer = setInterval(() => {
1731
1905
  if (!disposed && currentKey) doFetch();
1732
1906
  }, refetchInterval);
1733
1907
  }
1734
1908
  let focusHandler = null;
1735
1909
  let onlineHandler = null;
1736
- if (typeof globalThis !== "undefined" && typeof globalThis.addEventListener === "function") {
1910
+ if (!onServer && typeof globalThis !== "undefined" && typeof globalThis.addEventListener === "function") {
1737
1911
  if (refetchOnWindowFocus) {
1738
1912
  focusHandler = () => {
1739
1913
  if (!disposed && currentKey) doFetch();
@@ -2077,12 +2251,12 @@ function infiniteQuery(key, fetcher, options) {
2077
2251
  // src/data/previous.ts
2078
2252
  function previous(getter) {
2079
2253
  const [previous2, setPrevious] = signal(void 0);
2080
- let current = getter();
2254
+ let current2 = getter();
2081
2255
  const stop = effect(() => {
2082
2256
  const next = getter();
2083
- if (!Object.is(next, current)) {
2084
- setPrevious(current);
2085
- current = next;
2257
+ if (!Object.is(next, current2)) {
2258
+ setPrevious(current2);
2259
+ current2 = next;
2086
2260
  }
2087
2261
  });
2088
2262
  Object.defineProperty(previous2, "dispose", {
@@ -2162,6 +2336,28 @@ function throttle(getter, interval) {
2162
2336
  }
2163
2337
 
2164
2338
  // src/data/resource.ts
2339
+ function transferSlot() {
2340
+ return requestSlot("resource:transfer", () => /* @__PURE__ */ new Map());
2341
+ }
2342
+ function withheldSlot() {
2343
+ return requestSlot("resource:transfer:withheld", () => /* @__PURE__ */ new Set());
2344
+ }
2345
+ registerTransferCollector("r", () => {
2346
+ const slot3 = transferSlot();
2347
+ if (!slot3 || slot3.size === 0) return void 0;
2348
+ const withheld = withheldSlot();
2349
+ const out = {};
2350
+ let any = false;
2351
+ for (const [key, value] of slot3) {
2352
+ if (withheld?.has(key)) continue;
2353
+ out[key] = value;
2354
+ any = true;
2355
+ }
2356
+ return any ? out : void 0;
2357
+ });
2358
+ function withholdTransfer(key) {
2359
+ withheldSlot()?.add(key);
2360
+ }
2165
2361
  function resource(sourceOrFetcher, fetcherOrOptions, maybeOptions) {
2166
2362
  let source = null;
2167
2363
  let fetcher;
@@ -2175,10 +2371,14 @@ function resource(sourceOrFetcher, fetcherOrOptions, maybeOptions) {
2175
2371
  fetcher = (_source, info) => rawFetcher(info);
2176
2372
  options = fetcherOrOptions ?? {};
2177
2373
  }
2178
- const [data, setData] = signal(options.initialValue);
2374
+ const transferred = options.key !== void 0 ? takeTransferred("r", options.key) : void 0;
2375
+ const hydrated = transferred !== void 0;
2376
+ const initialValue = hydrated ? transferred : options.initialValue;
2377
+ const onServer = isSSR();
2378
+ const [data, setData] = signal(initialValue);
2179
2379
  const [loading, setLoading] = signal(false);
2180
2380
  const [error, setError] = signal(void 0);
2181
- let currentData = options.initialValue;
2381
+ let currentData = initialValue;
2182
2382
  function commitData(next, explicit) {
2183
2383
  const sharing = options.structuralSharing ?? true;
2184
2384
  const shared = untracked2(
@@ -2186,6 +2386,7 @@ function resource(sourceOrFetcher, fetcherOrOptions, maybeOptions) {
2186
2386
  );
2187
2387
  currentData = shared.ok ? shared.value : next;
2188
2388
  setData(currentData);
2389
+ if (onServer && options.key !== void 0) transferSlot()?.set(options.key, currentData);
2189
2390
  return currentData;
2190
2391
  }
2191
2392
  let abortController = null;
@@ -2231,19 +2432,28 @@ function resource(sourceOrFetcher, fetcherOrOptions, maybeOptions) {
2231
2432
  }
2232
2433
  }
2233
2434
  }
2435
+ const run = (sourceValue) => trackPending(doFetch(sourceValue), "resource", false);
2234
2436
  if (source) {
2235
- effectCleanup = effect(() => {
2236
- const sourceValue = source();
2237
- doFetch(sourceValue);
2238
- });
2239
- } else if (options.immediate !== false) {
2240
- doFetch(void 0);
2437
+ let skipFirst = hydrated;
2438
+ effectCleanup = effect(
2439
+ () => {
2440
+ const sourceValue = source();
2441
+ if (skipFirst) {
2442
+ skipFirst = false;
2443
+ return;
2444
+ }
2445
+ run(sourceValue);
2446
+ },
2447
+ { server: true }
2448
+ );
2449
+ } else if (options.immediate !== false && !hydrated) {
2450
+ run(void 0);
2241
2451
  }
2242
2452
  return {
2243
2453
  data,
2244
2454
  loading,
2245
2455
  error,
2246
- refetch: () => doFetch(source ? source() : void 0),
2456
+ refetch: () => run(source ? source() : void 0),
2247
2457
  mutate: (value) => {
2248
2458
  const newValue = typeof value === "function" ? value(currentData) : value;
2249
2459
  commitData(newValue, true);
@@ -2544,8 +2754,27 @@ function currentScope() {
2544
2754
  }
2545
2755
  return scope;
2546
2756
  }
2757
+ function automaticKey(loader, context) {
2758
+ const key = `loader:${context.path}${loader.name ? `:${loader.name}` : ""}`;
2759
+ const cache = getRequestScopedCache("routeLoader");
2760
+ if (!cache) return key;
2761
+ let owners = cache.get("owners");
2762
+ if (!owners) {
2763
+ owners = /* @__PURE__ */ new Map();
2764
+ cache.set("owners", owners);
2765
+ }
2766
+ const owner = owners.get(key);
2767
+ if (owner === void 0) {
2768
+ owners.set(key, loader);
2769
+ return key;
2770
+ }
2771
+ if (owner === loader) return key;
2772
+ withholdTransfer(key);
2773
+ return void 0;
2774
+ }
2547
2775
  function executeLoader(loader, context, options) {
2548
- const res = resource(({ signal: signal2 }) => loader(context, { signal: signal2 }), options);
2776
+ const key = options?.key ?? automaticKey(loader, context);
2777
+ const res = resource(({ signal: signal2 }) => loader(context, { signal: signal2 }), { ...options, key });
2549
2778
  const disposeResource = res.dispose;
2550
2779
  res.dispose = () => {
2551
2780
  _disposed.add(res);
@@ -2912,5 +3141,6 @@ function stream(url, options) {
2912
3141
  syncAdapter,
2913
3142
  throttle,
2914
3143
  withLoader,
2915
- withRetry
3144
+ withRetry,
3145
+ withholdTransfer
2916
3146
  });
package/dist/data.d.cts CHANGED
@@ -222,6 +222,14 @@ interface QueryOptions<T> {
222
222
  * Also applied to this observer's `select` output.
223
223
  */
224
224
  structuralSharing?: StructuralSharingOption<T>;
225
+ /**
226
+ * Fetch during a server render (default `true`). The server render waits for
227
+ * the fetch and transfers the result to the browser, which then does not
228
+ * fetch it again while it is fresh (`staleTime`). `false` leaves the query
229
+ * idle on the server — it renders its loading state — and keeps its data out
230
+ * of the transferred state; the browser fetches it after takeover.
231
+ */
232
+ ssr?: boolean;
225
233
  }
226
234
  interface QueryResult<T> {
227
235
  /** Reactive getter for the cached data */
@@ -452,6 +460,14 @@ declare function debounce<T>(getter: () => T, delay: number): DisposableAccessor
452
460
  */
453
461
  declare function throttle<T>(getter: () => T, interval: number): DisposableAccessor<T>;
454
462
 
463
+ /**
464
+ * Keep `key` out of this request's transferred state, whatever is or will be
465
+ * stored under it: the browser then fetches it itself. For a key whose owner
466
+ * is ambiguous (two loaders resolved to it). Server only; a no-op outside a
467
+ * request.
468
+ * @internal
469
+ */
470
+ declare function withholdTransfer(key: string): void;
455
471
  /**
456
472
  * Lifecycle callbacks follow the shared data-layer contract: an exception
457
473
  * thrown by `onStart`, `onSuccess`, `onError`, or `onSettled` never changes the
@@ -497,6 +513,13 @@ interface ResourceOptions<T> {
497
513
  * unshared.
498
514
  */
499
515
  structuralSharing?: StructuralSharingOption<T>;
516
+ /**
517
+ * Transfer key. With a key, the value a server render fetched is embedded in
518
+ * the document, and the browser starts from it instead of fetching again
519
+ * (its initial fetch is skipped; `refetch()` and source changes still
520
+ * fetch). Must be unique per page; the data must be JSON-serializable.
521
+ */
522
+ key?: string;
500
523
  }
501
524
  interface Resource<T> {
502
525
  /** Reactive getter for the fetched data */
@@ -676,6 +699,13 @@ interface LoaderRoute {
676
699
  /**
677
700
  * Execute a route loader and wrap its result in a reactive Resource.
678
701
  *
702
+ * The result is transferred from a server render to the browser under the key
703
+ * `loader:<path>:<loader name>` (or `options.key`), so the browser does not run
704
+ * the loader again on takeover. Two different loader functions with the same
705
+ * name for the same path (two `loader: async () => …` properties, two
706
+ * anonymous loaders) cannot be told apart: neither transfers, and both fetch in
707
+ * the browser, unless they have explicit keys.
708
+ *
679
709
  * Executing a loader does not make its data visible to `loaderData()`; render
680
710
  * the route's component inside {@link renderWithLoader} (or use
681
711
  * {@link withLoader}) so the component reads its own route's data.
@@ -777,4 +807,4 @@ declare function stream(url: string, options?: {
777
807
  dispose: () => void;
778
808
  };
779
809
 
780
- export { type ConflictStrategy, type InfiniteQueryOptions, type InfiniteQueryResult, type LoaderRoute, type MutationOptions, type MutationResult, type OfflineStore, type OfflineStoreOptions, type QueryOptions, type QueryResult, type Resource, type ResourceOptions, type RetryOptions, type RouteLoaderFn, type SyncAdapter, type SyncChange, type SyncConflict, type SyncResult, __resetQueryCache, calculateDelay, clearQueryCache, debounce, executeLoader, getQueryData, infiniteQuery, invalidateQueries, loaderData, mutation, offlineStore, preloadRoute, previous, query, renderWithLoader, resource, setQueryData, socket, stream, syncAdapter, throttle, withLoader, withRetry };
810
+ export { type ConflictStrategy, type InfiniteQueryOptions, type InfiniteQueryResult, type LoaderRoute, type MutationOptions, type MutationResult, type OfflineStore, type OfflineStoreOptions, type QueryOptions, type QueryResult, type Resource, type ResourceOptions, type RetryOptions, type RouteLoaderFn, type SyncAdapter, type SyncChange, type SyncConflict, type SyncResult, __resetQueryCache, calculateDelay, clearQueryCache, debounce, executeLoader, getQueryData, infiniteQuery, invalidateQueries, loaderData, mutation, offlineStore, preloadRoute, previous, query, renderWithLoader, resource, setQueryData, socket, stream, syncAdapter, throttle, withLoader, withRetry, withholdTransfer };
package/dist/data.d.ts CHANGED
@@ -222,6 +222,14 @@ interface QueryOptions<T> {
222
222
  * Also applied to this observer's `select` output.
223
223
  */
224
224
  structuralSharing?: StructuralSharingOption<T>;
225
+ /**
226
+ * Fetch during a server render (default `true`). The server render waits for
227
+ * the fetch and transfers the result to the browser, which then does not
228
+ * fetch it again while it is fresh (`staleTime`). `false` leaves the query
229
+ * idle on the server — it renders its loading state — and keeps its data out
230
+ * of the transferred state; the browser fetches it after takeover.
231
+ */
232
+ ssr?: boolean;
225
233
  }
226
234
  interface QueryResult<T> {
227
235
  /** Reactive getter for the cached data */
@@ -452,6 +460,14 @@ declare function debounce<T>(getter: () => T, delay: number): DisposableAccessor
452
460
  */
453
461
  declare function throttle<T>(getter: () => T, interval: number): DisposableAccessor<T>;
454
462
 
463
+ /**
464
+ * Keep `key` out of this request's transferred state, whatever is or will be
465
+ * stored under it: the browser then fetches it itself. For a key whose owner
466
+ * is ambiguous (two loaders resolved to it). Server only; a no-op outside a
467
+ * request.
468
+ * @internal
469
+ */
470
+ declare function withholdTransfer(key: string): void;
455
471
  /**
456
472
  * Lifecycle callbacks follow the shared data-layer contract: an exception
457
473
  * thrown by `onStart`, `onSuccess`, `onError`, or `onSettled` never changes the
@@ -497,6 +513,13 @@ interface ResourceOptions<T> {
497
513
  * unshared.
498
514
  */
499
515
  structuralSharing?: StructuralSharingOption<T>;
516
+ /**
517
+ * Transfer key. With a key, the value a server render fetched is embedded in
518
+ * the document, and the browser starts from it instead of fetching again
519
+ * (its initial fetch is skipped; `refetch()` and source changes still
520
+ * fetch). Must be unique per page; the data must be JSON-serializable.
521
+ */
522
+ key?: string;
500
523
  }
501
524
  interface Resource<T> {
502
525
  /** Reactive getter for the fetched data */
@@ -676,6 +699,13 @@ interface LoaderRoute {
676
699
  /**
677
700
  * Execute a route loader and wrap its result in a reactive Resource.
678
701
  *
702
+ * The result is transferred from a server render to the browser under the key
703
+ * `loader:<path>:<loader name>` (or `options.key`), so the browser does not run
704
+ * the loader again on takeover. Two different loader functions with the same
705
+ * name for the same path (two `loader: async () => …` properties, two
706
+ * anonymous loaders) cannot be told apart: neither transfers, and both fetch in
707
+ * the browser, unless they have explicit keys.
708
+ *
679
709
  * Executing a loader does not make its data visible to `loaderData()`; render
680
710
  * the route's component inside {@link renderWithLoader} (or use
681
711
  * {@link withLoader}) so the component reads its own route's data.
@@ -777,4 +807,4 @@ declare function stream(url: string, options?: {
777
807
  dispose: () => void;
778
808
  };
779
809
 
780
- export { type ConflictStrategy, type InfiniteQueryOptions, type InfiniteQueryResult, type LoaderRoute, type MutationOptions, type MutationResult, type OfflineStore, type OfflineStoreOptions, type QueryOptions, type QueryResult, type Resource, type ResourceOptions, type RetryOptions, type RouteLoaderFn, type SyncAdapter, type SyncChange, type SyncConflict, type SyncResult, __resetQueryCache, calculateDelay, clearQueryCache, debounce, executeLoader, getQueryData, infiniteQuery, invalidateQueries, loaderData, mutation, offlineStore, preloadRoute, previous, query, renderWithLoader, resource, setQueryData, socket, stream, syncAdapter, throttle, withLoader, withRetry };
810
+ export { type ConflictStrategy, type InfiniteQueryOptions, type InfiniteQueryResult, type LoaderRoute, type MutationOptions, type MutationResult, type OfflineStore, type OfflineStoreOptions, type QueryOptions, type QueryResult, type Resource, type ResourceOptions, type RetryOptions, type RouteLoaderFn, type SyncAdapter, type SyncChange, type SyncConflict, type SyncResult, __resetQueryCache, calculateDelay, clearQueryCache, debounce, executeLoader, getQueryData, infiniteQuery, invalidateQueries, loaderData, mutation, offlineStore, preloadRoute, previous, query, renderWithLoader, resource, setQueryData, socket, stream, syncAdapter, throttle, withLoader, withRetry, withholdTransfer };
package/dist/data.js CHANGED
@@ -21,16 +21,21 @@ import {
21
21
  syncAdapter,
22
22
  throttle,
23
23
  withLoader,
24
- withRetry
25
- } from "./chunk-QV5WEOFD.js";
26
- import "./chunk-YJ57VR6Y.js";
24
+ withRetry,
25
+ withholdTransfer
26
+ } from "./chunk-SVULV7O4.js";
27
+ import "./chunk-3HZOSMPX.js";
28
+ import "./chunk-62BDYGAG.js";
29
+ import "./chunk-N7A6FKWW.js";
27
30
  import "./chunk-7ZHH77QA.js";
28
- import "./chunk-BRRRVLHQ.js";
29
- import "./chunk-EXXSN3BW.js";
30
- import "./chunk-7XHATCIH.js";
31
- import "./chunk-GNSRXK34.js";
32
- import "./chunk-HVVRXRGO.js";
33
- import "./chunk-NYNYSPK7.js";
31
+ import "./chunk-AE32RGWX.js";
32
+ import "./chunk-B3HOT4TK.js";
33
+ import "./chunk-UYTYNCMZ.js";
34
+ import "./chunk-4FJSAUKB.js";
35
+ import "./chunk-MIRKTVH4.js";
36
+ import "./chunk-S37PZD6I.js";
37
+ import "./chunk-NT3ZYB5S.js";
38
+ import "./chunk-R5U7XKVJ.js";
34
39
  export {
35
40
  __resetQueryCache,
36
41
  calculateDelay,
@@ -54,5 +59,6 @@ export {
54
59
  syncAdapter,
55
60
  throttle,
56
61
  withLoader,
57
- withRetry
62
+ withRetry,
63
+ withholdTransfer
58
64
  };