sibujs 1.4.0 → 2.0.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.
- package/README.md +105 -119
- package/dist/browser.cjs +288 -80
- package/dist/browser.d.cts +19 -9
- package/dist/browser.d.ts +19 -9
- package/dist/browser.js +6 -6
- package/dist/build.cjs +1019 -313
- package/dist/build.d.cts +1 -1
- package/dist/build.d.ts +1 -1
- package/dist/build.js +15 -13
- package/dist/cdn.global.js +17 -16
- package/dist/chunk-2RA7SHDA.js +65 -0
- package/dist/chunk-2UPRY23K.js +80 -0
- package/dist/chunk-3JHCYHWN.js +125 -0
- package/dist/{chunk-ZWKZCBO6.js → chunk-3LR7GLWQ.js} +154 -33
- package/dist/{chunk-3AIRKM3B.js → chunk-3NSGB5JN.js} +115 -34
- package/dist/{chunk-3ARAQO7B.js → chunk-52YJLLRO.js} +29 -6
- package/dist/chunk-54EDRCEF.js +93 -0
- package/dist/chunk-7JDB7I65.js +1327 -0
- package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
- package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
- package/dist/{chunk-WR5D4EGH.js → chunk-GTBNNBJ6.js} +14 -2
- package/dist/chunk-HB24TBAF.js +121 -0
- package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
- package/dist/{chunk-JAKHTMQU.js → chunk-JA6667UN.js} +206 -46
- package/dist/{chunk-77L6NL3X.js → chunk-JXMMDLBY.js} +306 -183
- package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
- package/dist/{chunk-F3FA4F32.js → chunk-KLRMB5ZS.js} +135 -79
- package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
- package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
- package/dist/{chunk-TSOKIX5Z.js → chunk-MIUAXB7K.js} +126 -74
- package/dist/{chunk-QWZG56ET.js → chunk-ND2664SF.js} +558 -190
- package/dist/{chunk-JCI5M6U6.js → chunk-O2MNQFLP.js} +261 -79
- package/dist/{chunk-EWFVA3TJ.js → chunk-R73P76YZ.js} +1 -1
- package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
- package/dist/chunk-UCS6AMJ7.js +79 -0
- package/dist/{chunk-ZD6OAMTH.js → chunk-VLPPXTYG.js} +90 -35
- package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
- package/dist/{contracts-xo5ckdRP.d.cts → contracts-ey_Qh8ef.d.cts} +7 -8
- package/dist/{contracts-xo5ckdRP.d.ts → contracts-ey_Qh8ef.d.ts} +7 -8
- package/dist/{customElement-D2DJp_xn.d.cts → customElement-CPfIrbvg.d.cts} +18 -9
- package/dist/{customElement-D2DJp_xn.d.ts → customElement-CPfIrbvg.d.ts} +18 -9
- package/dist/data.cjs +452 -100
- package/dist/data.d.cts +20 -2
- package/dist/data.d.ts +20 -2
- package/dist/data.js +11 -9
- package/dist/devtools.cjs +535 -247
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +34 -30
- package/dist/ecosystem.cjs +499 -143
- package/dist/ecosystem.d.cts +13 -11
- package/dist/ecosystem.d.ts +13 -11
- package/dist/ecosystem.js +12 -11
- package/dist/extras.cjs +3639 -1629
- package/dist/extras.d.cts +11 -11
- package/dist/extras.d.ts +11 -11
- package/dist/extras.js +58 -45
- package/dist/index.cjs +1023 -313
- package/dist/index.d.cts +128 -55
- package/dist/index.d.ts +128 -55
- package/dist/index.js +28 -16
- package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
- package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
- package/dist/motion.cjs +90 -36
- package/dist/motion.d.cts +1 -1
- package/dist/motion.d.ts +1 -1
- package/dist/motion.js +4 -4
- package/dist/patterns.cjs +414 -81
- package/dist/patterns.d.cts +53 -20
- package/dist/patterns.d.ts +53 -20
- package/dist/patterns.js +7 -7
- package/dist/performance.cjs +364 -108
- package/dist/performance.d.cts +29 -17
- package/dist/performance.d.ts +29 -17
- package/dist/performance.js +13 -6
- package/dist/plugin-D30wlGW5.d.cts +71 -0
- package/dist/plugin-D30wlGW5.d.ts +71 -0
- package/dist/plugins.cjs +652 -271
- package/dist/plugins.d.cts +13 -6
- package/dist/plugins.d.ts +13 -6
- package/dist/plugins.js +116 -50
- package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
- package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
- package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
- package/dist/ssr.cjs +648 -219
- package/dist/ssr.d.cts +27 -7
- package/dist/ssr.d.ts +27 -7
- package/dist/ssr.js +12 -11
- package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.cts} +9 -1
- package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.ts} +9 -1
- package/dist/testing.cjs +252 -63
- package/dist/testing.d.cts +17 -4
- package/dist/testing.d.ts +17 -4
- package/dist/testing.js +100 -44
- package/dist/ui.cjs +576 -168
- package/dist/ui.d.cts +13 -16
- package/dist/ui.d.ts +13 -16
- package/dist/ui.js +20 -17
- package/dist/widgets.cjs +1001 -93
- package/dist/widgets.d.cts +104 -2
- package/dist/widgets.d.ts +104 -2
- package/dist/widgets.js +9 -7
- package/package.json +8 -2
- package/dist/chunk-32DY64NT.js +0 -282
- package/dist/chunk-3CRQALYP.js +0 -877
- package/dist/chunk-4EI4AG32.js +0 -482
- package/dist/chunk-4MYMUBRS.js +0 -21
- package/dist/chunk-6HLLIF3K.js +0 -398
- package/dist/chunk-6LSNVCS2.js +0 -937
- package/dist/chunk-6SA3QQES.js +0 -61
- package/dist/chunk-7BF6TK55.js +0 -1097
- package/dist/chunk-7TQKR4PP.js +0 -294
- package/dist/chunk-7V26P53V.js +0 -712
- package/dist/chunk-AZ3ISID5.js +0 -298
- package/dist/chunk-B7SWRFUT.js +0 -332
- package/dist/chunk-BGN5ZMP4.js +0 -26
- package/dist/chunk-BTU3TJDS.js +0 -365
- package/dist/chunk-BW3WT46K.js +0 -937
- package/dist/chunk-C6KFWOFV.js +0 -616
- package/dist/chunk-CHF5OHIA.js +0 -61
- package/dist/chunk-CHJ27IGK.js +0 -26
- package/dist/chunk-CMBFNA7L.js +0 -27
- package/dist/chunk-DAHRH4ON.js +0 -331
- package/dist/chunk-DKOHBI74.js +0 -924
- package/dist/chunk-DTCOOBMX.js +0 -725
- package/dist/chunk-EBGIRKQY.js +0 -616
- package/dist/chunk-EUZND3CB.js +0 -27
- package/dist/chunk-EVCZO745.js +0 -365
- package/dist/chunk-FGOEVHY3.js +0 -60
- package/dist/chunk-G3BOQPVO.js +0 -365
- package/dist/chunk-GCOK2LC3.js +0 -282
- package/dist/chunk-HGMJFBC7.js +0 -654
- package/dist/chunk-K5ZUMYVS.js +0 -89
- package/dist/chunk-KQPDEVVS.js +0 -398
- package/dist/chunk-L6JRBDNS.js +0 -60
- package/dist/chunk-LA6KQEDU.js +0 -712
- package/dist/chunk-MDVXJWFN.js +0 -304
- package/dist/chunk-MEZVEBPN.js +0 -2008
- package/dist/chunk-MK4ERFYL.js +0 -2249
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/chunk-MQ5GOYPH.js +0 -2249
- package/dist/chunk-N6IZB6KJ.js +0 -567
- package/dist/chunk-NEKUBFPT.js +0 -60
- package/dist/chunk-NHUC2QWH.js +0 -282
- package/dist/chunk-NMRUZALC.js +0 -1097
- package/dist/chunk-NYVAC6P5.js +0 -37
- package/dist/chunk-OF7UZIVB.js +0 -725
- package/dist/chunk-P6W3STU4.js +0 -2249
- package/dist/chunk-PBHF5WKN.js +0 -616
- package/dist/chunk-PTQJDMRT.js +0 -146
- package/dist/chunk-PZEGYCF5.js +0 -61
- package/dist/chunk-QBMDLBU2.js +0 -975
- package/dist/chunk-RQGQSLQK.js +0 -725
- package/dist/chunk-SDLZDHKP.js +0 -107
- package/dist/chunk-TNQWPPE6.js +0 -37
- package/dist/chunk-UHNL42EF.js +0 -2730
- package/dist/chunk-UNXCEF6S.js +0 -21
- package/dist/chunk-V2XTI523.js +0 -347
- package/dist/chunk-VAU366PN.js +0 -2241
- package/dist/chunk-VMVDTCXB.js +0 -712
- package/dist/chunk-VRW3FULF.js +0 -725
- package/dist/chunk-WADYRCO2.js +0 -304
- package/dist/chunk-WILQZRO4.js +0 -282
- package/dist/chunk-WUHJISPP.js +0 -298
- package/dist/chunk-XYU6TZOW.js +0 -182
- package/dist/chunk-Y6GP4QGG.js +0 -276
- package/dist/chunk-YECR7UIA.js +0 -347
- package/dist/chunk-YUTWTI4B.js +0 -654
- package/dist/chunk-Z65KYU7I.js +0 -26
- package/dist/chunk-Z6POF5YC.js +0 -975
- package/dist/chunk-ZBJP6WFL.js +0 -482
- package/dist/contracts-DDrwxvJ-.d.cts +0 -245
- package/dist/contracts-DDrwxvJ-.d.ts +0 -245
- package/dist/contracts-DOrhwbke.d.cts +0 -245
- package/dist/contracts-DOrhwbke.d.ts +0 -245
- package/dist/customElement-BKQfbSZQ.d.cts +0 -262
- package/dist/customElement-BKQfbSZQ.d.ts +0 -262
- package/dist/customElement-yz8uyk-0.d.cts +0 -308
- package/dist/customElement-yz8uyk-0.d.ts +0 -308
- package/dist/introspect-Cb0zgpi2.d.cts +0 -477
- package/dist/introspect-Y2xNXGSf.d.ts +0 -477
- package/dist/plugin-Bek4RhJY.d.cts +0 -43
- package/dist/plugin-Bek4RhJY.d.ts +0 -43
- package/dist/ssr-3RXHP5ES.js +0 -38
- package/dist/ssr-6GIMY5MX.js +0 -38
- package/dist/ssr-BA6sxxUd.d.cts +0 -135
- package/dist/ssr-BA6sxxUd.d.ts +0 -135
- package/dist/ssr-WKUPVSSK.js +0 -36
- package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
- package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
package/dist/data.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// data.ts
|
|
21
21
|
var data_exports = {};
|
|
22
22
|
__export(data_exports, {
|
|
23
|
+
__resetQueryCache: () => __resetQueryCache,
|
|
23
24
|
calculateDelay: () => calculateDelay,
|
|
24
25
|
clearQueryCache: () => clearQueryCache,
|
|
25
26
|
debounce: () => debounce,
|
|
@@ -50,12 +51,12 @@ function isDev() {
|
|
|
50
51
|
var _isDev = isDev();
|
|
51
52
|
function devAssert(condition, message) {
|
|
52
53
|
if (_isDev && !condition) {
|
|
53
|
-
throw new Error(`[
|
|
54
|
+
throw new Error(`[SibuJS] ${message}`);
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
function devWarn(message) {
|
|
57
58
|
if (_isDev) {
|
|
58
|
-
console.warn(`[
|
|
59
|
+
console.warn(`[SibuJS] ${message}`);
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
@@ -65,11 +66,11 @@ var subscriberStack = new Array(32);
|
|
|
65
66
|
var stackCapacity = 32;
|
|
66
67
|
var stackTop = -1;
|
|
67
68
|
var currentSubscriber = null;
|
|
68
|
-
var signalSubscribers = /* @__PURE__ */ new WeakMap();
|
|
69
69
|
var SUBS = "__s";
|
|
70
70
|
var notifyDepth = 0;
|
|
71
71
|
var pendingQueue = [];
|
|
72
72
|
var pendingSet = /* @__PURE__ */ new Set();
|
|
73
|
+
var propagateStack = [];
|
|
73
74
|
function safeInvoke(sub) {
|
|
74
75
|
try {
|
|
75
76
|
sub();
|
|
@@ -78,6 +79,15 @@ function safeInvoke(sub) {
|
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
var trackingSuspended = false;
|
|
82
|
+
function retrack(effectFn, subscriber) {
|
|
83
|
+
const prev = currentSubscriber;
|
|
84
|
+
currentSubscriber = subscriber;
|
|
85
|
+
try {
|
|
86
|
+
effectFn();
|
|
87
|
+
} finally {
|
|
88
|
+
currentSubscriber = prev;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
81
91
|
function track(effectFn, subscriber) {
|
|
82
92
|
if (!subscriber) subscriber = effectFn;
|
|
83
93
|
cleanup(subscriber);
|
|
@@ -116,7 +126,6 @@ function recordDependency(signal2) {
|
|
|
116
126
|
let subs = signal2[SUBS];
|
|
117
127
|
if (!subs) {
|
|
118
128
|
subs = /* @__PURE__ */ new Set();
|
|
119
|
-
signalSubscribers.set(signal2, subs);
|
|
120
129
|
signal2[SUBS] = subs;
|
|
121
130
|
}
|
|
122
131
|
subs.add(currentSubscriber);
|
|
@@ -138,57 +147,71 @@ function queueSignalNotification(signal2) {
|
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
149
|
}
|
|
150
|
+
var maxDrainIterations = 1e5;
|
|
141
151
|
function drainNotificationQueue() {
|
|
142
152
|
if (notifyDepth > 0) return;
|
|
143
153
|
notifyDepth++;
|
|
144
154
|
try {
|
|
145
155
|
let i = 0;
|
|
146
156
|
while (i < pendingQueue.length) {
|
|
157
|
+
if (i >= maxDrainIterations) {
|
|
158
|
+
if (typeof console !== "undefined") {
|
|
159
|
+
console.error(
|
|
160
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
147
165
|
safeInvoke(pendingQueue[i]);
|
|
148
166
|
i++;
|
|
149
167
|
}
|
|
150
168
|
} finally {
|
|
151
|
-
pendingQueue.length = 0;
|
|
152
|
-
pendingSet.clear();
|
|
153
169
|
notifyDepth--;
|
|
170
|
+
if (notifyDepth === 0) {
|
|
171
|
+
pendingQueue.length = 0;
|
|
172
|
+
pendingSet.clear();
|
|
173
|
+
}
|
|
154
174
|
}
|
|
155
175
|
}
|
|
156
176
|
function propagateDirty(sub) {
|
|
157
177
|
sub();
|
|
158
|
-
|
|
159
|
-
|
|
178
|
+
const rootSig = sub._sig;
|
|
179
|
+
if (!rootSig) return;
|
|
180
|
+
const stack = propagateStack;
|
|
181
|
+
const baseLen = stack.length;
|
|
182
|
+
stack.push(rootSig);
|
|
183
|
+
while (stack.length > baseLen) {
|
|
184
|
+
const sig = stack.pop();
|
|
160
185
|
const first = sig.__f;
|
|
161
186
|
if (first) {
|
|
162
187
|
if (first._c) {
|
|
163
188
|
const nSig = first._sig;
|
|
164
|
-
nSig._d
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (!pendingSet.has(first)) {
|
|
189
|
+
if (!nSig._d) {
|
|
190
|
+
nSig._d = true;
|
|
191
|
+
stack.push(nSig);
|
|
192
|
+
}
|
|
193
|
+
} else if (!pendingSet.has(first)) {
|
|
169
194
|
pendingSet.add(first);
|
|
170
195
|
pendingQueue.push(first);
|
|
171
196
|
}
|
|
172
|
-
|
|
197
|
+
continue;
|
|
173
198
|
}
|
|
174
199
|
const subs = sig[SUBS];
|
|
175
|
-
if (!subs)
|
|
176
|
-
let nextSig;
|
|
200
|
+
if (!subs) continue;
|
|
177
201
|
for (const s of subs) {
|
|
178
202
|
if (s._c) {
|
|
179
|
-
s();
|
|
180
203
|
const nSig = s._sig;
|
|
181
|
-
if (nSig && !
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
204
|
+
if (nSig && !nSig._d) {
|
|
205
|
+
nSig._d = true;
|
|
206
|
+
stack.push(nSig);
|
|
207
|
+
} else if (!nSig) {
|
|
208
|
+
s();
|
|
185
209
|
}
|
|
186
210
|
} else if (!pendingSet.has(s)) {
|
|
187
211
|
pendingSet.add(s);
|
|
188
212
|
pendingQueue.push(s);
|
|
189
213
|
}
|
|
190
214
|
}
|
|
191
|
-
sig = nextSig;
|
|
192
215
|
}
|
|
193
216
|
}
|
|
194
217
|
function notifySubscribers(signal2) {
|
|
@@ -212,13 +235,23 @@ function notifySubscribers(signal2) {
|
|
|
212
235
|
}
|
|
213
236
|
let i = 0;
|
|
214
237
|
while (i < pendingQueue.length) {
|
|
238
|
+
if (i >= maxDrainIterations) {
|
|
239
|
+
if (typeof console !== "undefined") {
|
|
240
|
+
console.error(
|
|
241
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
215
246
|
safeInvoke(pendingQueue[i]);
|
|
216
247
|
i++;
|
|
217
248
|
}
|
|
218
249
|
} finally {
|
|
219
|
-
pendingQueue.length = 0;
|
|
220
|
-
pendingSet.clear();
|
|
221
250
|
notifyDepth--;
|
|
251
|
+
if (notifyDepth === 0) {
|
|
252
|
+
pendingQueue.length = 0;
|
|
253
|
+
pendingSet.clear();
|
|
254
|
+
}
|
|
222
255
|
}
|
|
223
256
|
return;
|
|
224
257
|
}
|
|
@@ -238,30 +271,48 @@ function notifySubscribers(signal2) {
|
|
|
238
271
|
notifyDepth++;
|
|
239
272
|
try {
|
|
240
273
|
let directCount = 0;
|
|
274
|
+
let hasComputedSub = false;
|
|
241
275
|
for (const sub of subs) {
|
|
276
|
+
if (sub._c) hasComputedSub = true;
|
|
242
277
|
pendingQueue[directCount++] = sub;
|
|
243
278
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
279
|
+
if (!hasComputedSub) {
|
|
280
|
+
for (let i2 = 0; i2 < directCount; i2++) {
|
|
281
|
+
safeInvoke(pendingQueue[i2]);
|
|
247
282
|
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
283
|
+
} else {
|
|
284
|
+
for (let i2 = 0; i2 < directCount; i2++) {
|
|
285
|
+
if (pendingQueue[i2]._c) {
|
|
286
|
+
propagateDirty(pendingQueue[i2]);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
for (let i2 = 0; i2 < directCount; i2++) {
|
|
290
|
+
const sub = pendingQueue[i2];
|
|
291
|
+
if (!sub._c && !pendingSet.has(sub)) {
|
|
292
|
+
pendingSet.add(sub);
|
|
293
|
+
safeInvoke(sub);
|
|
253
294
|
}
|
|
254
295
|
}
|
|
255
296
|
}
|
|
256
297
|
let i = directCount;
|
|
257
298
|
while (i < pendingQueue.length) {
|
|
299
|
+
if (i - directCount >= maxDrainIterations) {
|
|
300
|
+
if (typeof console !== "undefined") {
|
|
301
|
+
console.error(
|
|
302
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
258
307
|
safeInvoke(pendingQueue[i]);
|
|
259
308
|
i++;
|
|
260
309
|
}
|
|
261
310
|
} finally {
|
|
262
|
-
pendingQueue.length = 0;
|
|
263
|
-
pendingSet.clear();
|
|
264
311
|
notifyDepth--;
|
|
312
|
+
if (notifyDepth === 0) {
|
|
313
|
+
pendingQueue.length = 0;
|
|
314
|
+
pendingSet.clear();
|
|
315
|
+
}
|
|
265
316
|
}
|
|
266
317
|
}
|
|
267
318
|
function cleanup(subscriber) {
|
|
@@ -272,7 +323,9 @@ function cleanup(subscriber) {
|
|
|
272
323
|
if (subs) {
|
|
273
324
|
subs.delete(subscriber);
|
|
274
325
|
if (singleDep.__f === subscriber) {
|
|
275
|
-
singleDep.__f = void 0;
|
|
326
|
+
singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
|
|
327
|
+
} else if (subs.size === 1 && singleDep.__f === void 0) {
|
|
328
|
+
singleDep.__f = subs.values().next().value;
|
|
276
329
|
}
|
|
277
330
|
}
|
|
278
331
|
sub._dep = void 0;
|
|
@@ -285,7 +338,9 @@ function cleanup(subscriber) {
|
|
|
285
338
|
if (subs) {
|
|
286
339
|
subs.delete(subscriber);
|
|
287
340
|
if (signal2.__f === subscriber) {
|
|
288
|
-
signal2.__f = void 0;
|
|
341
|
+
signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
|
|
342
|
+
} else if (subs.size === 1 && signal2.__f === void 0) {
|
|
343
|
+
signal2.__f = subs.values().next().value;
|
|
289
344
|
}
|
|
290
345
|
}
|
|
291
346
|
}
|
|
@@ -296,6 +351,7 @@ function cleanup(subscriber) {
|
|
|
296
351
|
function derived(getter, options) {
|
|
297
352
|
devAssert(typeof getter === "function", "derived: argument must be a getter function.");
|
|
298
353
|
const debugName = options?.name;
|
|
354
|
+
const equals = options?.equals;
|
|
299
355
|
const cs = {};
|
|
300
356
|
cs._d = false;
|
|
301
357
|
cs._g = getter;
|
|
@@ -306,25 +362,56 @@ function derived(getter, options) {
|
|
|
306
362
|
markDirty._c = 1;
|
|
307
363
|
markDirty._sig = cs;
|
|
308
364
|
track(() => {
|
|
309
|
-
|
|
310
|
-
|
|
365
|
+
let threw = true;
|
|
366
|
+
try {
|
|
367
|
+
cs._v = getter();
|
|
368
|
+
cs._d = false;
|
|
369
|
+
threw = false;
|
|
370
|
+
} finally {
|
|
371
|
+
if (threw) cs._d = true;
|
|
372
|
+
}
|
|
311
373
|
}, markDirty);
|
|
312
374
|
const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
375
|
+
let evaluating = false;
|
|
313
376
|
function computedGetter() {
|
|
377
|
+
if (evaluating) {
|
|
378
|
+
throw new Error(
|
|
379
|
+
`[SibuJS] Circular dependency detected in derived${debugName ? ` "${debugName}"` : ""}. A derived signal cannot read itself (directly or through a chain).`
|
|
380
|
+
);
|
|
381
|
+
}
|
|
314
382
|
if (trackingSuspended) {
|
|
315
383
|
if (cs._d) {
|
|
316
|
-
|
|
317
|
-
|
|
384
|
+
evaluating = true;
|
|
385
|
+
let threw = true;
|
|
386
|
+
try {
|
|
387
|
+
retrack(() => {
|
|
388
|
+
cs._v = getter();
|
|
389
|
+
cs._d = false;
|
|
390
|
+
threw = false;
|
|
391
|
+
}, markDirty);
|
|
392
|
+
} finally {
|
|
393
|
+
evaluating = false;
|
|
394
|
+
if (threw) cs._d = true;
|
|
395
|
+
}
|
|
318
396
|
}
|
|
319
397
|
return cs._v;
|
|
320
398
|
}
|
|
321
399
|
recordDependency(cs);
|
|
322
400
|
if (cs._d) {
|
|
323
401
|
const oldValue = cs._v;
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
402
|
+
evaluating = true;
|
|
403
|
+
let threw = true;
|
|
404
|
+
try {
|
|
405
|
+
retrack(() => {
|
|
406
|
+
const next = getter();
|
|
407
|
+
cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
|
|
408
|
+
cs._d = false;
|
|
409
|
+
threw = false;
|
|
410
|
+
}, markDirty);
|
|
411
|
+
} finally {
|
|
412
|
+
evaluating = false;
|
|
413
|
+
if (threw) cs._d = true;
|
|
414
|
+
}
|
|
328
415
|
if (hook && oldValue !== cs._v) {
|
|
329
416
|
hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
330
417
|
}
|
|
@@ -341,9 +428,28 @@ function derived(getter, options) {
|
|
|
341
428
|
}
|
|
342
429
|
|
|
343
430
|
// src/core/ssr-context.ts
|
|
344
|
-
var
|
|
431
|
+
var als = null;
|
|
432
|
+
try {
|
|
433
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
434
|
+
const req = Function("return typeof require==='function'?require:null")();
|
|
435
|
+
if (req) {
|
|
436
|
+
const mod = req("node:async_hooks");
|
|
437
|
+
als = new mod.AsyncLocalStorage();
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
} catch {
|
|
441
|
+
als = null;
|
|
442
|
+
}
|
|
443
|
+
var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
|
|
444
|
+
function getSSRStore() {
|
|
445
|
+
if (als) {
|
|
446
|
+
const s = als.getStore();
|
|
447
|
+
if (s) return s;
|
|
448
|
+
}
|
|
449
|
+
return fallbackStore;
|
|
450
|
+
}
|
|
345
451
|
function isSSR() {
|
|
346
|
-
return
|
|
452
|
+
return getSSRStore().ssr;
|
|
347
453
|
}
|
|
348
454
|
|
|
349
455
|
// src/core/signals/effect.ts
|
|
@@ -353,26 +459,86 @@ function effect(effectFn, options) {
|
|
|
353
459
|
if (isSSR()) return () => {
|
|
354
460
|
};
|
|
355
461
|
const onError = options?.onError;
|
|
462
|
+
let userCleanups = [];
|
|
463
|
+
const onCleanup = (fn) => {
|
|
464
|
+
userCleanups.push(fn);
|
|
465
|
+
};
|
|
466
|
+
const runUserCleanups = () => {
|
|
467
|
+
if (userCleanups.length === 0) return;
|
|
468
|
+
const list = userCleanups;
|
|
469
|
+
userCleanups = [];
|
|
470
|
+
for (let i = list.length - 1; i >= 0; i--) {
|
|
471
|
+
try {
|
|
472
|
+
list[i]();
|
|
473
|
+
} catch (err) {
|
|
474
|
+
if (typeof console !== "undefined") {
|
|
475
|
+
console.warn("[SibuJS effect] onCleanup threw:", err);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
const invokeBody = () => effectFn(onCleanup);
|
|
356
481
|
const wrappedFn = onError ? () => {
|
|
357
482
|
try {
|
|
358
|
-
|
|
483
|
+
invokeBody();
|
|
359
484
|
} catch (err) {
|
|
360
485
|
onError(err);
|
|
361
486
|
}
|
|
362
|
-
} :
|
|
487
|
+
} : invokeBody;
|
|
363
488
|
let cleanupHandle = () => {
|
|
364
489
|
};
|
|
490
|
+
let running = false;
|
|
365
491
|
const subscriber = () => {
|
|
366
|
-
|
|
367
|
-
|
|
492
|
+
if (running) {
|
|
493
|
+
if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
|
|
494
|
+
console.warn(
|
|
495
|
+
"[SibuJS] effect re-entered itself while running \u2014 the triggering update will be ignored. Wrap mutual writes in `batch()` or split the effect to avoid this."
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
running = true;
|
|
501
|
+
try {
|
|
502
|
+
runUserCleanups();
|
|
503
|
+
cleanupHandle();
|
|
504
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
505
|
+
} finally {
|
|
506
|
+
running = false;
|
|
507
|
+
}
|
|
368
508
|
};
|
|
369
|
-
|
|
509
|
+
running = true;
|
|
510
|
+
try {
|
|
511
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
512
|
+
} finally {
|
|
513
|
+
running = false;
|
|
514
|
+
}
|
|
370
515
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
371
516
|
if (hook) hook.emit("effect:create", { effectFn });
|
|
517
|
+
let disposed = false;
|
|
372
518
|
return () => {
|
|
519
|
+
if (disposed) return;
|
|
520
|
+
disposed = true;
|
|
373
521
|
const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
374
|
-
if (h)
|
|
375
|
-
|
|
522
|
+
if (h) {
|
|
523
|
+
try {
|
|
524
|
+
h.emit("effect:destroy", { effectFn });
|
|
525
|
+
} catch {
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
try {
|
|
529
|
+
runUserCleanups();
|
|
530
|
+
} catch (err) {
|
|
531
|
+
if (typeof console !== "undefined") {
|
|
532
|
+
console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
cleanupHandle();
|
|
537
|
+
} catch (err) {
|
|
538
|
+
if (typeof console !== "undefined") {
|
|
539
|
+
console.warn("[SibuJS effect] dispose threw:", err);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
376
542
|
};
|
|
377
543
|
}
|
|
378
544
|
|
|
@@ -396,10 +562,13 @@ function enqueueBatchedSignal(signal2) {
|
|
|
396
562
|
return true;
|
|
397
563
|
}
|
|
398
564
|
function flushBatch() {
|
|
399
|
-
|
|
400
|
-
|
|
565
|
+
try {
|
|
566
|
+
for (const signal2 of pendingSignals) {
|
|
567
|
+
queueSignalNotification(signal2);
|
|
568
|
+
}
|
|
569
|
+
} finally {
|
|
570
|
+
pendingSignals.clear();
|
|
401
571
|
}
|
|
402
|
-
pendingSignals.clear();
|
|
403
572
|
drainNotificationQueue();
|
|
404
573
|
}
|
|
405
574
|
|
|
@@ -456,10 +625,12 @@ function calculateDelay(attempt, strategy, baseDelay, maxDelay, jitter) {
|
|
|
456
625
|
break;
|
|
457
626
|
}
|
|
458
627
|
delay = Math.min(delay, maxDelay);
|
|
628
|
+
if (!Number.isFinite(delay)) delay = Number.MAX_SAFE_INTEGER;
|
|
459
629
|
if (jitter > 0) {
|
|
460
630
|
const jitterRange = delay * jitter;
|
|
461
631
|
delay += (Math.random() * 2 - 1) * jitterRange;
|
|
462
632
|
}
|
|
633
|
+
if (!Number.isFinite(delay) || Number.isNaN(delay)) delay = 0;
|
|
463
634
|
return Math.max(0, delay);
|
|
464
635
|
}
|
|
465
636
|
async function withRetry(fn, options, onRetry, signal2) {
|
|
@@ -473,6 +644,7 @@ async function withRetry(fn, options, onRetry, signal2) {
|
|
|
473
644
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
474
645
|
if (signal2?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
475
646
|
try {
|
|
647
|
+
if (signal2?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
476
648
|
return await fn();
|
|
477
649
|
} catch (error) {
|
|
478
650
|
lastError = error;
|
|
@@ -480,9 +652,13 @@ async function withRetry(fn, options, onRetry, signal2) {
|
|
|
480
652
|
const delay = calculateDelay(attempt, strategy, baseDelay, maxDelay, jitter);
|
|
481
653
|
onRetry?.(error, attempt, delay);
|
|
482
654
|
await new Promise((resolve, reject) => {
|
|
483
|
-
|
|
655
|
+
let onAbort = null;
|
|
656
|
+
const timer = setTimeout(() => {
|
|
657
|
+
if (onAbort && signal2) signal2.removeEventListener("abort", onAbort);
|
|
658
|
+
resolve();
|
|
659
|
+
}, delay);
|
|
484
660
|
if (signal2) {
|
|
485
|
-
|
|
661
|
+
onAbort = () => {
|
|
486
662
|
clearTimeout(timer);
|
|
487
663
|
reject(new DOMException("Aborted", "AbortError"));
|
|
488
664
|
};
|
|
@@ -550,24 +726,46 @@ function query(key, fetcher, options = {}) {
|
|
|
550
726
|
let entry = queryCache.get(key2);
|
|
551
727
|
if (!entry) {
|
|
552
728
|
entry = getOrCreateEntry(key2);
|
|
553
|
-
entry.subscribers++;
|
|
554
729
|
entry.listeners.add(onCacheUpdate);
|
|
555
730
|
entry.refetchers.add(doFetch);
|
|
556
731
|
}
|
|
557
732
|
if (entry.promise) {
|
|
558
733
|
setIsFetching(true);
|
|
734
|
+
const captured = entry.promise;
|
|
559
735
|
try {
|
|
560
|
-
await
|
|
736
|
+
await captured;
|
|
737
|
+
if (disposed || currentKey !== key2) return;
|
|
738
|
+
if (entry.promise === captured) {
|
|
739
|
+
onCacheUpdate();
|
|
740
|
+
if (entry.error) onError?.(entry.error);
|
|
741
|
+
else if (entry.data !== void 0) onSuccess?.(entry.data);
|
|
742
|
+
}
|
|
561
743
|
} catch {
|
|
744
|
+
if (disposed || currentKey !== key2) return;
|
|
745
|
+
if (entry.promise === captured) {
|
|
746
|
+
onCacheUpdate();
|
|
747
|
+
if (entry.error) onError?.(entry.error);
|
|
748
|
+
}
|
|
749
|
+
} finally {
|
|
750
|
+
if (!disposed && currentKey === key2) onSettled?.();
|
|
562
751
|
}
|
|
563
|
-
onCacheUpdate();
|
|
564
752
|
return;
|
|
565
753
|
}
|
|
566
754
|
abortController?.abort();
|
|
567
755
|
abortController = new AbortController();
|
|
568
756
|
const signal2 = abortController.signal;
|
|
569
757
|
setIsFetching(true);
|
|
570
|
-
|
|
758
|
+
let promise;
|
|
759
|
+
try {
|
|
760
|
+
promise = withRetry(() => fetcher({ signal: signal2, key: key2 }), retryOptions, void 0, signal2);
|
|
761
|
+
} catch (err) {
|
|
762
|
+
setIsFetching(false);
|
|
763
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
764
|
+
entry.error = errorObj;
|
|
765
|
+
onError?.(errorObj);
|
|
766
|
+
onSettled?.();
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
571
769
|
entry.promise = promise;
|
|
572
770
|
try {
|
|
573
771
|
const result = await promise;
|
|
@@ -629,13 +827,15 @@ function query(key, fetcher, options = {}) {
|
|
|
629
827
|
oldEntry.subscribers--;
|
|
630
828
|
if (oldEntry.subscribers <= 0 && cacheTime >= 0) {
|
|
631
829
|
const oldKey = currentKey;
|
|
830
|
+
if (oldEntry.gcTimer !== null) clearTimeout(oldEntry.gcTimer);
|
|
632
831
|
oldEntry.gcTimer = setTimeout(() => queryCache.delete(oldKey), cacheTime);
|
|
633
832
|
}
|
|
634
833
|
}
|
|
635
834
|
}
|
|
835
|
+
const keyChanged = currentKey !== key2;
|
|
636
836
|
currentKey = key2;
|
|
637
837
|
const entry = getOrCreateEntry(key2, initialData);
|
|
638
|
-
entry.subscribers++;
|
|
838
|
+
if (keyChanged) entry.subscribers++;
|
|
639
839
|
if (entry.gcTimer !== null) {
|
|
640
840
|
clearTimeout(entry.gcTimer);
|
|
641
841
|
entry.gcTimer = null;
|
|
@@ -650,6 +850,11 @@ function query(key, fetcher, options = {}) {
|
|
|
650
850
|
setError(entry.error);
|
|
651
851
|
});
|
|
652
852
|
}
|
|
853
|
+
if (!keyChanged && currentKey === key2 && entry.data !== void 0) {
|
|
854
|
+
const isDataStale2 = entry.dataUpdatedAt === 0 || Date.now() - entry.dataUpdatedAt >= staleTime;
|
|
855
|
+
if (enabled && isDataStale2 && !entry.promise) doFetch();
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
653
858
|
const isDataStale = entry.dataUpdatedAt === 0 || Date.now() - entry.dataUpdatedAt >= staleTime;
|
|
654
859
|
if (enabled && (entry.data === void 0 || isDataStale)) {
|
|
655
860
|
doFetch();
|
|
@@ -677,6 +882,7 @@ function query(key, fetcher, options = {}) {
|
|
|
677
882
|
}
|
|
678
883
|
}
|
|
679
884
|
function dispose() {
|
|
885
|
+
if (disposed) return;
|
|
680
886
|
disposed = true;
|
|
681
887
|
abortController?.abort();
|
|
682
888
|
effectCleanup();
|
|
@@ -689,12 +895,17 @@ function query(key, fetcher, options = {}) {
|
|
|
689
895
|
entry.subscribers--;
|
|
690
896
|
if (entry.subscribers <= 0 && cacheTime >= 0) {
|
|
691
897
|
const key2 = currentKey;
|
|
898
|
+
if (entry.gcTimer !== null) clearTimeout(entry.gcTimer);
|
|
692
899
|
entry.gcTimer = setTimeout(() => queryCache.delete(key2), cacheTime);
|
|
693
900
|
}
|
|
694
901
|
}
|
|
695
902
|
}
|
|
696
|
-
if (focusHandler
|
|
697
|
-
|
|
903
|
+
if (focusHandler && typeof globalThis.removeEventListener === "function") {
|
|
904
|
+
globalThis.removeEventListener("focus", focusHandler);
|
|
905
|
+
}
|
|
906
|
+
if (onlineHandler && typeof globalThis.removeEventListener === "function") {
|
|
907
|
+
globalThis.removeEventListener("online", onlineHandler);
|
|
908
|
+
}
|
|
698
909
|
}
|
|
699
910
|
return {
|
|
700
911
|
data,
|
|
@@ -738,7 +949,19 @@ function clearQueryCache() {
|
|
|
738
949
|
}
|
|
739
950
|
queryCache.clear();
|
|
740
951
|
for (const listener of activeListeners) listener();
|
|
741
|
-
for (const refetcher of activeRefetchers)
|
|
952
|
+
for (const refetcher of activeRefetchers) {
|
|
953
|
+
refetcher().catch((err) => {
|
|
954
|
+
if (typeof console !== "undefined") {
|
|
955
|
+
console.warn("[SibuJS query] refetch after clearQueryCache failed:", err);
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
function __resetQueryCache() {
|
|
961
|
+
for (const entry of queryCache.values()) {
|
|
962
|
+
if (entry.gcTimer) clearTimeout(entry.gcTimer);
|
|
963
|
+
}
|
|
964
|
+
queryCache.clear();
|
|
742
965
|
}
|
|
743
966
|
|
|
744
967
|
// src/data/mutation.ts
|
|
@@ -749,7 +972,9 @@ function mutation(mutationFn, options = {}) {
|
|
|
749
972
|
const [status, setStatus] = signal("idle");
|
|
750
973
|
const isSuccess = derived(() => status() === "success");
|
|
751
974
|
const isIdle = derived(() => status() === "idle");
|
|
975
|
+
let runId = 0;
|
|
752
976
|
async function execute(variables) {
|
|
977
|
+
const myRun = ++runId;
|
|
753
978
|
let context2;
|
|
754
979
|
batch(() => {
|
|
755
980
|
setLoading(true);
|
|
@@ -761,6 +986,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
761
986
|
context2 = await options.onMutate(variables);
|
|
762
987
|
}
|
|
763
988
|
const result = await withRetry(() => mutationFn(variables), options.retry);
|
|
989
|
+
if (myRun !== runId) return result;
|
|
764
990
|
batch(() => {
|
|
765
991
|
setData(result);
|
|
766
992
|
setLoading(false);
|
|
@@ -771,6 +997,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
771
997
|
return result;
|
|
772
998
|
} catch (err) {
|
|
773
999
|
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
1000
|
+
if (myRun !== runId) throw errorObj;
|
|
774
1001
|
batch(() => {
|
|
775
1002
|
setError(errorObj);
|
|
776
1003
|
setLoading(false);
|
|
@@ -782,6 +1009,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
782
1009
|
}
|
|
783
1010
|
}
|
|
784
1011
|
function reset() {
|
|
1012
|
+
runId++;
|
|
785
1013
|
batch(() => {
|
|
786
1014
|
setData(void 0);
|
|
787
1015
|
setError(void 0);
|
|
@@ -796,7 +1024,10 @@ function mutation(mutationFn, options = {}) {
|
|
|
796
1024
|
isSuccess,
|
|
797
1025
|
isIdle,
|
|
798
1026
|
mutate: (variables) => {
|
|
799
|
-
execute(variables).catch(() => {
|
|
1027
|
+
execute(variables).catch((err) => {
|
|
1028
|
+
if (typeof console !== "undefined") {
|
|
1029
|
+
console.warn("[SibuJS mutation] mutate() failed; check `.error()` signal or onError option.", err);
|
|
1030
|
+
}
|
|
800
1031
|
});
|
|
801
1032
|
},
|
|
802
1033
|
mutateAsync: execute,
|
|
@@ -832,11 +1063,13 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
832
1063
|
const hasPreviousPage = derived(() => prevPageParam() !== void 0);
|
|
833
1064
|
let abortController = null;
|
|
834
1065
|
let disposed = false;
|
|
1066
|
+
let runId = 0;
|
|
835
1067
|
async function fetchPage(pageParam, direction) {
|
|
836
1068
|
if (disposed) return;
|
|
837
1069
|
abortController?.abort();
|
|
838
1070
|
abortController = new AbortController();
|
|
839
1071
|
const signal2 = abortController.signal;
|
|
1072
|
+
const myRun = ++runId;
|
|
840
1073
|
batch(() => {
|
|
841
1074
|
setIsFetching(true);
|
|
842
1075
|
if (direction === "next") setIsFetchingNext(true);
|
|
@@ -845,7 +1078,7 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
845
1078
|
});
|
|
846
1079
|
try {
|
|
847
1080
|
const page = await withRetry(() => fetcher({ signal: signal2, pageParam }), retryOptions, void 0, signal2);
|
|
848
|
-
if (disposed) return;
|
|
1081
|
+
if (disposed || myRun !== runId) return;
|
|
849
1082
|
const currentPages = pages();
|
|
850
1083
|
let newPages;
|
|
851
1084
|
if (direction === "prev") {
|
|
@@ -865,7 +1098,7 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
865
1098
|
});
|
|
866
1099
|
onSuccess?.(newPages);
|
|
867
1100
|
} catch (err) {
|
|
868
|
-
if (disposed) return;
|
|
1101
|
+
if (disposed || myRun !== runId) return;
|
|
869
1102
|
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
870
1103
|
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
871
1104
|
batch(() => {
|
|
@@ -880,9 +1113,12 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
880
1113
|
const effectCleanup = effect(() => {
|
|
881
1114
|
resolveKey();
|
|
882
1115
|
if (enabled) {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1116
|
+
abortController?.abort();
|
|
1117
|
+
batch(() => {
|
|
1118
|
+
setPages([]);
|
|
1119
|
+
setNextPageParam(initialPageParam);
|
|
1120
|
+
setPrevPageParam(void 0);
|
|
1121
|
+
});
|
|
886
1122
|
fetchPage(initialPageParam, "initial");
|
|
887
1123
|
}
|
|
888
1124
|
});
|
|
@@ -1031,7 +1267,10 @@ function resource(sourceOrFetcher, fetcherOrOptions, maybeOptions) {
|
|
|
1031
1267
|
options.onSuccess?.(result);
|
|
1032
1268
|
} catch (err) {
|
|
1033
1269
|
if (version !== fetchVersion || disposed) return;
|
|
1034
|
-
if (err instanceof DOMException && err.name === "AbortError")
|
|
1270
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
1271
|
+
if (version === fetchVersion) setLoading(false);
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1035
1274
|
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
1036
1275
|
batch(() => {
|
|
1037
1276
|
setError(errorObj);
|
|
@@ -1116,18 +1355,57 @@ function idbPut(db, store, item) {
|
|
|
1116
1355
|
tx.onerror = () => reject(tx.error);
|
|
1117
1356
|
});
|
|
1118
1357
|
}
|
|
1119
|
-
function
|
|
1358
|
+
function idbPutWithChange(db, item, change) {
|
|
1359
|
+
return new Promise((resolve, reject) => {
|
|
1360
|
+
const tx = db.transaction(["items", "_changes"], "readwrite");
|
|
1361
|
+
tx.objectStore("items").put(item);
|
|
1362
|
+
tx.objectStore("_changes").put(change);
|
|
1363
|
+
tx.oncomplete = () => resolve();
|
|
1364
|
+
tx.onerror = () => reject(tx.error);
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
function idbDeleteWithChange(db, key, change) {
|
|
1368
|
+
return new Promise((resolve, reject) => {
|
|
1369
|
+
const tx = db.transaction(["items", "_changes"], "readwrite");
|
|
1370
|
+
tx.objectStore("items").delete(key);
|
|
1371
|
+
tx.objectStore("_changes").put(change);
|
|
1372
|
+
tx.oncomplete = () => resolve();
|
|
1373
|
+
tx.onerror = () => reject(tx.error);
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
function idbGetAllWithKeys(db, store) {
|
|
1377
|
+
return new Promise((resolve, reject) => {
|
|
1378
|
+
const tx = db.transaction(store, "readonly");
|
|
1379
|
+
const out = [];
|
|
1380
|
+
const req = tx.objectStore(store).openCursor();
|
|
1381
|
+
req.onsuccess = () => {
|
|
1382
|
+
const cursor = req.result;
|
|
1383
|
+
if (cursor) {
|
|
1384
|
+
out.push({ key: cursor.primaryKey, value: cursor.value });
|
|
1385
|
+
cursor.continue();
|
|
1386
|
+
} else {
|
|
1387
|
+
resolve(out);
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
req.onerror = () => reject(req.error);
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
function idbDeleteKeys(db, store, keys) {
|
|
1394
|
+
if (keys.length === 0) return Promise.resolve();
|
|
1120
1395
|
return new Promise((resolve, reject) => {
|
|
1121
1396
|
const tx = db.transaction(store, "readwrite");
|
|
1122
|
-
tx.objectStore(store)
|
|
1397
|
+
const objStore = tx.objectStore(store);
|
|
1398
|
+
for (const k of keys) objStore.delete(k);
|
|
1123
1399
|
tx.oncomplete = () => resolve();
|
|
1124
1400
|
tx.onerror = () => reject(tx.error);
|
|
1125
1401
|
});
|
|
1126
1402
|
}
|
|
1127
|
-
function
|
|
1403
|
+
function idbPutMany(db, store, items) {
|
|
1404
|
+
if (items.length === 0) return Promise.resolve();
|
|
1128
1405
|
return new Promise((resolve, reject) => {
|
|
1129
1406
|
const tx = db.transaction(store, "readwrite");
|
|
1130
|
-
tx.objectStore(store)
|
|
1407
|
+
const objStore = tx.objectStore(store);
|
|
1408
|
+
for (const item of items) objStore.put(item);
|
|
1131
1409
|
tx.oncomplete = () => resolve();
|
|
1132
1410
|
tx.onerror = () => reject(tx.error);
|
|
1133
1411
|
});
|
|
@@ -1150,15 +1428,13 @@ async function offlineStore(options) {
|
|
|
1150
1428
|
setPendingCount(changes.length);
|
|
1151
1429
|
}
|
|
1152
1430
|
async function put(item) {
|
|
1153
|
-
await
|
|
1154
|
-
await idbPut(db, "_changes", { type: "put", item, timestamp: Date.now() });
|
|
1431
|
+
await idbPutWithChange(db, item, { type: "put", item, timestamp: Date.now() });
|
|
1155
1432
|
await refreshData();
|
|
1156
1433
|
}
|
|
1157
1434
|
async function remove(key) {
|
|
1158
1435
|
const existing = await idbGet(db, "items", key);
|
|
1159
1436
|
if (existing) {
|
|
1160
|
-
await
|
|
1161
|
-
await idbPut(db, "_changes", { type: "delete", item: existing, timestamp: Date.now() });
|
|
1437
|
+
await idbDeleteWithChange(db, key, { type: "delete", item: existing, timestamp: Date.now() });
|
|
1162
1438
|
await refreshData();
|
|
1163
1439
|
}
|
|
1164
1440
|
}
|
|
@@ -1169,25 +1445,45 @@ async function offlineStore(options) {
|
|
|
1169
1445
|
return data().filter(filter);
|
|
1170
1446
|
}
|
|
1171
1447
|
async function sync() {
|
|
1172
|
-
if (!adapter || isSyncing()) return;
|
|
1448
|
+
if (!adapter || isSyncing() || closed) return;
|
|
1173
1449
|
setIsSyncing(true);
|
|
1174
1450
|
try {
|
|
1175
|
-
const
|
|
1176
|
-
if (
|
|
1177
|
-
|
|
1451
|
+
const snapshot = await idbGetAllWithKeys(db, "_changes");
|
|
1452
|
+
if (closed) return;
|
|
1453
|
+
if (snapshot.length > 0) {
|
|
1454
|
+
const result = await adapter.push(snapshot.map((e) => e.value));
|
|
1455
|
+
if (closed) return;
|
|
1178
1456
|
if (result.ok) {
|
|
1179
|
-
await
|
|
1457
|
+
await idbDeleteKeys(
|
|
1458
|
+
db,
|
|
1459
|
+
"_changes",
|
|
1460
|
+
snapshot.map((e) => e.key)
|
|
1461
|
+
);
|
|
1462
|
+
if (closed) return;
|
|
1180
1463
|
}
|
|
1181
1464
|
}
|
|
1182
1465
|
const remoteItems = await adapter.pull(lastSynced());
|
|
1183
|
-
|
|
1184
|
-
|
|
1466
|
+
if (closed) return;
|
|
1467
|
+
const pendingChanges = await idbGetAll(db, "_changes");
|
|
1468
|
+
if (closed) return;
|
|
1469
|
+
const pendingKeys = /* @__PURE__ */ new Set();
|
|
1470
|
+
for (const c of pendingChanges) {
|
|
1471
|
+
const k = c.item[keyPath];
|
|
1472
|
+
if (k != null) pendingKeys.add(k);
|
|
1185
1473
|
}
|
|
1474
|
+
const safeRemote = remoteItems.filter((item) => {
|
|
1475
|
+
const k = item[keyPath];
|
|
1476
|
+
return k == null || !pendingKeys.has(k);
|
|
1477
|
+
});
|
|
1478
|
+
await idbPutMany(db, "items", safeRemote);
|
|
1479
|
+
if (closed) return;
|
|
1186
1480
|
const now = Date.now();
|
|
1187
1481
|
await idbPut(db, "_meta", now);
|
|
1482
|
+
if (closed) return;
|
|
1188
1483
|
setLastSynced(now);
|
|
1189
1484
|
await refreshData();
|
|
1190
|
-
} catch {
|
|
1485
|
+
} catch (err) {
|
|
1486
|
+
if (typeof console !== "undefined") console.warn("[offlineStore] sync failed", err);
|
|
1191
1487
|
} finally {
|
|
1192
1488
|
setIsSyncing(false);
|
|
1193
1489
|
}
|
|
@@ -1195,13 +1491,21 @@ async function offlineStore(options) {
|
|
|
1195
1491
|
function attach(newAdapter) {
|
|
1196
1492
|
adapter = newAdapter;
|
|
1197
1493
|
}
|
|
1494
|
+
let onlineHandler = null;
|
|
1495
|
+
let closed = false;
|
|
1198
1496
|
function close() {
|
|
1497
|
+
closed = true;
|
|
1498
|
+
if (onlineHandler && typeof window !== "undefined") {
|
|
1499
|
+
window.removeEventListener("online", onlineHandler);
|
|
1500
|
+
onlineHandler = null;
|
|
1501
|
+
}
|
|
1199
1502
|
db.close();
|
|
1200
1503
|
}
|
|
1201
1504
|
if (autoSync && typeof window !== "undefined") {
|
|
1202
|
-
|
|
1505
|
+
onlineHandler = () => {
|
|
1203
1506
|
sync();
|
|
1204
|
-
}
|
|
1507
|
+
};
|
|
1508
|
+
window.addEventListener("online", onlineHandler);
|
|
1205
1509
|
}
|
|
1206
1510
|
return {
|
|
1207
1511
|
data,
|
|
@@ -1224,9 +1528,11 @@ function syncAdapter(config) {
|
|
|
1224
1528
|
// src/core/rendering/context.ts
|
|
1225
1529
|
function context(defaultValue) {
|
|
1226
1530
|
const [getValue, setValue] = signal(defaultValue);
|
|
1227
|
-
|
|
1531
|
+
const ctx = {
|
|
1228
1532
|
provide(value) {
|
|
1533
|
+
const previous2 = getValue();
|
|
1229
1534
|
setValue(value);
|
|
1535
|
+
return () => setValue(previous2);
|
|
1230
1536
|
},
|
|
1231
1537
|
use() {
|
|
1232
1538
|
return getValue;
|
|
@@ -1236,8 +1542,18 @@ function context(defaultValue) {
|
|
|
1236
1542
|
},
|
|
1237
1543
|
set(value) {
|
|
1238
1544
|
setValue(value);
|
|
1545
|
+
},
|
|
1546
|
+
withContext(value, fn) {
|
|
1547
|
+
const previous2 = getValue();
|
|
1548
|
+
setValue(value);
|
|
1549
|
+
try {
|
|
1550
|
+
return fn();
|
|
1551
|
+
} finally {
|
|
1552
|
+
setValue(previous2);
|
|
1553
|
+
}
|
|
1239
1554
|
}
|
|
1240
1555
|
};
|
|
1556
|
+
return ctx;
|
|
1241
1557
|
}
|
|
1242
1558
|
|
|
1243
1559
|
// src/data/routeLoader.ts
|
|
@@ -1258,9 +1574,16 @@ function loaderData() {
|
|
|
1258
1574
|
error: resource2.error
|
|
1259
1575
|
};
|
|
1260
1576
|
}
|
|
1261
|
-
async function preloadRoute(route, context2) {
|
|
1577
|
+
async function preloadRoute(route, context2, callerSignal) {
|
|
1262
1578
|
if (!route.loader) return void 0;
|
|
1263
1579
|
const controller = new AbortController();
|
|
1580
|
+
if (callerSignal) {
|
|
1581
|
+
if (callerSignal.aborted) {
|
|
1582
|
+
controller.abort();
|
|
1583
|
+
} else {
|
|
1584
|
+
callerSignal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1264
1587
|
return route.loader(context2, { signal: controller.signal });
|
|
1265
1588
|
}
|
|
1266
1589
|
|
|
@@ -1275,7 +1598,7 @@ function validateWsUrl(raw) {
|
|
|
1275
1598
|
function socket(url, options) {
|
|
1276
1599
|
const autoReconnect = options?.autoReconnect ?? false;
|
|
1277
1600
|
const reconnectDelay = options?.reconnectDelay ?? 1e3;
|
|
1278
|
-
const maxReconnects = options?.maxReconnects ??
|
|
1601
|
+
const maxReconnects = options?.maxReconnects ?? 10;
|
|
1279
1602
|
const heartbeat = options?.heartbeat;
|
|
1280
1603
|
const protocols = options?.protocols;
|
|
1281
1604
|
const [data, setData] = signal(null);
|
|
@@ -1285,6 +1608,7 @@ function socket(url, options) {
|
|
|
1285
1608
|
let reconnectTimer = null;
|
|
1286
1609
|
let heartbeatTimer = null;
|
|
1287
1610
|
let disposed = false;
|
|
1611
|
+
let manuallyClosed = false;
|
|
1288
1612
|
function getUrl() {
|
|
1289
1613
|
return typeof url === "function" ? url() : url;
|
|
1290
1614
|
}
|
|
@@ -1308,11 +1632,18 @@ function socket(url, options) {
|
|
|
1308
1632
|
ws.onclose = () => {
|
|
1309
1633
|
setStatus("closed");
|
|
1310
1634
|
stopHeartbeat();
|
|
1311
|
-
|
|
1635
|
+
const wasManual = manuallyClosed;
|
|
1636
|
+
manuallyClosed = false;
|
|
1637
|
+
if (autoReconnect && !disposed && !wasManual && reconnectCount < maxReconnects) {
|
|
1638
|
+
const cap = 3e4;
|
|
1639
|
+
const delay = Math.min(cap, reconnectDelay * 2 ** reconnectCount);
|
|
1640
|
+
const jittered = delay * (0.5 + Math.random() * 0.5);
|
|
1312
1641
|
reconnectCount++;
|
|
1313
1642
|
reconnectTimer = setTimeout(() => {
|
|
1643
|
+
reconnectTimer = null;
|
|
1644
|
+
if (disposed || manuallyClosed) return;
|
|
1314
1645
|
connect();
|
|
1315
|
-
},
|
|
1646
|
+
}, jittered);
|
|
1316
1647
|
}
|
|
1317
1648
|
};
|
|
1318
1649
|
ws.onerror = () => {
|
|
@@ -1339,6 +1670,7 @@ function socket(url, options) {
|
|
|
1339
1670
|
}
|
|
1340
1671
|
}
|
|
1341
1672
|
function close() {
|
|
1673
|
+
manuallyClosed = true;
|
|
1342
1674
|
if (reconnectTimer !== null) {
|
|
1343
1675
|
clearTimeout(reconnectTimer);
|
|
1344
1676
|
reconnectTimer = null;
|
|
@@ -1358,13 +1690,24 @@ function socket(url, options) {
|
|
|
1358
1690
|
}
|
|
1359
1691
|
|
|
1360
1692
|
// src/utils/sanitize.ts
|
|
1693
|
+
var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
1361
1694
|
function sanitizeUrl(url) {
|
|
1362
1695
|
const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
|
|
1363
1696
|
if (!trimmed) return "";
|
|
1364
1697
|
const lower = trimmed.toLowerCase();
|
|
1365
|
-
|
|
1366
|
-
|
|
1698
|
+
let schemeEnd = -1;
|
|
1699
|
+
for (let i = 0; i < lower.length; i++) {
|
|
1700
|
+
const ch = lower.charCodeAt(i);
|
|
1701
|
+
if (ch === 58) {
|
|
1702
|
+
schemeEnd = i;
|
|
1703
|
+
break;
|
|
1704
|
+
}
|
|
1705
|
+
if (ch === 47 || ch === 63 || ch === 35) break;
|
|
1367
1706
|
}
|
|
1707
|
+
if (schemeEnd === -1) return trimmed;
|
|
1708
|
+
const scheme = lower.slice(0, schemeEnd + 1);
|
|
1709
|
+
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return trimmed;
|
|
1710
|
+
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
1368
1711
|
return trimmed;
|
|
1369
1712
|
}
|
|
1370
1713
|
|
|
@@ -1376,12 +1719,16 @@ function validateSseUrl(raw) {
|
|
|
1376
1719
|
}
|
|
1377
1720
|
function stream(url, options) {
|
|
1378
1721
|
const autoReconnect = options?.autoReconnect ?? false;
|
|
1722
|
+
const maxReconnects = options?.maxReconnects ?? 10;
|
|
1723
|
+
const baseMs = options?.reconnectBaseMs ?? 1e3;
|
|
1724
|
+
const maxMs = options?.reconnectMaxMs ?? 3e4;
|
|
1379
1725
|
const [data, setData] = signal(null);
|
|
1380
1726
|
const [event, setEvent] = signal(null);
|
|
1381
1727
|
const [status, setStatus] = signal("connecting");
|
|
1382
1728
|
let source = null;
|
|
1383
1729
|
let disposed = false;
|
|
1384
1730
|
let reconnectTimer = null;
|
|
1731
|
+
let attempts = 0;
|
|
1385
1732
|
function connect() {
|
|
1386
1733
|
if (disposed) return;
|
|
1387
1734
|
const safeUrl = validateSseUrl(url);
|
|
@@ -1395,6 +1742,7 @@ function stream(url, options) {
|
|
|
1395
1742
|
});
|
|
1396
1743
|
source.onopen = () => {
|
|
1397
1744
|
setStatus("open");
|
|
1745
|
+
attempts = 0;
|
|
1398
1746
|
};
|
|
1399
1747
|
source.onmessage = (evt) => {
|
|
1400
1748
|
setData(evt.data);
|
|
@@ -1404,11 +1752,14 @@ function stream(url, options) {
|
|
|
1404
1752
|
if (source && source.readyState === EventSource.CLOSED) {
|
|
1405
1753
|
setStatus("closed");
|
|
1406
1754
|
source = null;
|
|
1407
|
-
if (autoReconnect && !disposed) {
|
|
1755
|
+
if (autoReconnect && !disposed && attempts < maxReconnects) {
|
|
1756
|
+
const delay = Math.min(maxMs, baseMs * 2 ** attempts);
|
|
1757
|
+
const jittered = delay * (0.5 + Math.random() * 0.5);
|
|
1758
|
+
attempts++;
|
|
1408
1759
|
reconnectTimer = setTimeout(() => {
|
|
1409
1760
|
reconnectTimer = null;
|
|
1410
1761
|
connect();
|
|
1411
|
-
},
|
|
1762
|
+
}, jittered);
|
|
1412
1763
|
}
|
|
1413
1764
|
}
|
|
1414
1765
|
};
|
|
@@ -1433,6 +1784,7 @@ function stream(url, options) {
|
|
|
1433
1784
|
}
|
|
1434
1785
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1435
1786
|
0 && (module.exports = {
|
|
1787
|
+
__resetQueryCache,
|
|
1436
1788
|
calculateDelay,
|
|
1437
1789
|
clearQueryCache,
|
|
1438
1790
|
debounce,
|