sibujs 3.0.0 → 3.2.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 +6 -0
- package/dist/browser.cjs +16 -8
- package/dist/browser.js +6 -5
- package/dist/build.cjs +276 -150
- package/dist/build.js +35 -24
- package/dist/cdn.global.js +7 -7
- package/dist/{chunk-RJIRT46U.js → chunk-2C4E3HBM.js} +5 -5
- package/dist/{chunk-XDKP4T7G.js → chunk-4JCAUOLN.js} +45 -23
- package/dist/{chunk-VSNLICTS.js → chunk-5N74TKLD.js} +1 -1
- package/dist/{chunk-XVYB3J6C.js → chunk-7XDYVJLE.js} +19 -9
- package/dist/{chunk-L52H775O.js → chunk-BGNLPNGV.js} +20 -12
- package/dist/{chunk-6QZO7MMG.js → chunk-C427DVQF.js} +1 -1
- package/dist/{chunk-5WD7BYTZ.js → chunk-FDY42FIU.js} +3 -2
- package/dist/{chunk-4YTVESDX.js → chunk-FOI23UJL.js} +11 -1
- package/dist/{chunk-2RA7SHDA.js → chunk-GOJMFRBL.js} +20 -4
- package/dist/{chunk-2KM2724A.js → chunk-GOUM4JCT.js} +6 -6
- package/dist/chunk-H3SRKIYX.js +17 -0
- package/dist/{chunk-NEWH4O5U.js → chunk-H6PCHJZQ.js} +2 -2
- package/dist/{chunk-UCS6AMJ7.js → chunk-HMJFCBRR.js} +26 -3
- package/dist/{chunk-JYD2PWXH.js → chunk-HXMS4SNP.js} +22 -15
- package/dist/{chunk-DF3GTP4Q.js → chunk-JYXOEYI4.js} +12 -18
- package/dist/{chunk-KZA7ANXP.js → chunk-NFYWLRUO.js} +11 -18
- package/dist/{chunk-KH4OE6WY.js → chunk-NPIEEKPT.js} +20 -11
- package/dist/{chunk-V65KTDZW.js → chunk-OYLPZO4N.js} +33 -15
- package/dist/{chunk-LYTCUZ7H.js → chunk-RDRSWYNP.js} +1 -1
- package/dist/{chunk-UKMXT5T6.js → chunk-RLUJL2MV.js} +7 -12
- package/dist/{chunk-INBOWHQ3.js → chunk-V2MTG5FT.js} +99 -36
- package/dist/{chunk-CNZ35WI2.js → chunk-VJE6DDYM.js} +2 -2
- package/dist/{chunk-2JQUV4Y3.js → chunk-VOCE4NNK.js} +157 -75
- package/dist/{chunk-STFTTMO2.js → chunk-X67UYC74.js} +31 -12
- package/dist/{chunk-YMOIAHWA.js → chunk-YFDGQWDA.js} +1 -1
- package/dist/{chunk-L4DAT4WU.js → chunk-Z2FWAE4B.js} +28 -1
- package/dist/data.cjs +211 -93
- package/dist/data.d.cts +7 -1
- package/dist/data.d.ts +7 -1
- package/dist/data.js +8 -8
- package/dist/devtools.cjs +38 -10
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +6 -6
- package/dist/ecosystem.cjs +163 -65
- package/dist/ecosystem.js +9 -9
- package/dist/extras.cjs +420 -198
- package/dist/extras.d.cts +2 -2
- package/dist/extras.d.ts +2 -2
- package/dist/extras.js +27 -24
- package/dist/index.cjs +255 -139
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +15 -13
- package/dist/{introspect-BZWKvQUZ.d.ts → introspect-DOZfmC-4.d.ts} +1 -1
- package/dist/{introspect-DsJlDD2T.d.cts → introspect-RjLfIFpL.d.cts} +1 -1
- package/dist/motion.cjs +10 -0
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +66 -39
- package/dist/patterns.js +8 -7
- package/dist/performance.cjs +101 -25
- package/dist/performance.d.cts +2 -2
- package/dist/performance.d.ts +2 -2
- package/dist/performance.js +8 -7
- package/dist/plugins.cjs +243 -138
- package/dist/plugins.d.cts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +96 -45
- package/dist/{ssr-FXD2PPMC.js → ssr-2QDQ27EV.js} +5 -3
- package/dist/{ssr-CrVNy6Pa.d.cts → ssr-D62yFwuw.d.cts} +8 -1
- package/dist/{ssr-CrVNy6Pa.d.ts → ssr-D62yFwuw.d.ts} +8 -1
- package/dist/ssr.cjs +185 -68
- package/dist/ssr.d.cts +1 -1
- package/dist/ssr.d.ts +1 -1
- package/dist/ssr.js +12 -10
- package/dist/testing.cjs +9 -4
- package/dist/testing.js +3 -3
- package/dist/ui.cjs +76 -39
- package/dist/ui.js +10 -9
- package/dist/widgets.cjs +61 -23
- package/dist/widgets.js +8 -8
- package/package.json +3 -1
package/dist/data.cjs
CHANGED
|
@@ -189,7 +189,7 @@ function retrack(effectFn, subscriber) {
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
function track(effectFn, subscriber) {
|
|
192
|
-
if (!subscriber)
|
|
192
|
+
if (!subscriber) return reactiveBinding(effectFn);
|
|
193
193
|
cleanup(subscriber);
|
|
194
194
|
const prev = currentSubscriber;
|
|
195
195
|
currentSubscriber = subscriber;
|
|
@@ -207,6 +207,32 @@ function track(effectFn, subscriber) {
|
|
|
207
207
|
const sub = subscriber;
|
|
208
208
|
return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
|
|
209
209
|
}
|
|
210
|
+
function reactiveBinding(commit) {
|
|
211
|
+
const run = () => {
|
|
212
|
+
const s = subscriber;
|
|
213
|
+
if (s._disposed || s._reentrant) return;
|
|
214
|
+
s._reentrant = true;
|
|
215
|
+
try {
|
|
216
|
+
retrack(commit, subscriber);
|
|
217
|
+
} finally {
|
|
218
|
+
s._reentrant = false;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const subscriber = run;
|
|
222
|
+
subscriber.depsHead = null;
|
|
223
|
+
subscriber.depsTail = null;
|
|
224
|
+
subscriber._epoch = 0;
|
|
225
|
+
subscriber._structDirty = false;
|
|
226
|
+
subscriber._runEpoch = 0;
|
|
227
|
+
subscriber._runs = 0;
|
|
228
|
+
subscriber._reentrant = false;
|
|
229
|
+
subscriber._disposed = false;
|
|
230
|
+
run();
|
|
231
|
+
return subscriber._dispose ?? (subscriber._dispose = () => {
|
|
232
|
+
subscriber._disposed = true;
|
|
233
|
+
cleanup(subscriber);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
210
236
|
function recordDependency(signal2) {
|
|
211
237
|
if (!currentSubscriber) return;
|
|
212
238
|
const sub = currentSubscriber;
|
|
@@ -395,6 +421,7 @@ function derived(getter, options) {
|
|
|
395
421
|
const equals = options?.equals;
|
|
396
422
|
const cs = {};
|
|
397
423
|
cs._d = false;
|
|
424
|
+
cs._init = false;
|
|
398
425
|
cs._g = getter;
|
|
399
426
|
cs.__v = 0;
|
|
400
427
|
const markDirty = () => {
|
|
@@ -403,11 +430,18 @@ function derived(getter, options) {
|
|
|
403
430
|
};
|
|
404
431
|
markDirty._c = 1;
|
|
405
432
|
markDirty._sig = cs;
|
|
433
|
+
const recompute = () => {
|
|
434
|
+
const next = getter();
|
|
435
|
+
cs._v = equals && cs._init ? equals(cs._v, next) ? cs._v : next : next;
|
|
436
|
+
cs._d = false;
|
|
437
|
+
cs._init = true;
|
|
438
|
+
};
|
|
406
439
|
track(() => {
|
|
407
440
|
let threw = true;
|
|
408
441
|
try {
|
|
409
442
|
cs._v = getter();
|
|
410
443
|
cs._d = false;
|
|
444
|
+
cs._init = true;
|
|
411
445
|
threw = false;
|
|
412
446
|
} finally {
|
|
413
447
|
if (threw) cs._d = true;
|
|
@@ -423,20 +457,13 @@ function derived(getter, options) {
|
|
|
423
457
|
}
|
|
424
458
|
if (trackingSuspended) {
|
|
425
459
|
if (cs._d) {
|
|
460
|
+
const prev = cs._v;
|
|
426
461
|
evaluating = true;
|
|
427
|
-
let threw = true;
|
|
428
462
|
try {
|
|
429
|
-
|
|
430
|
-
retrack(() => {
|
|
431
|
-
const next = getter();
|
|
432
|
-
cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
|
|
433
|
-
cs._d = false;
|
|
434
|
-
threw = false;
|
|
435
|
-
}, markDirty);
|
|
463
|
+
retrack(recompute, markDirty);
|
|
436
464
|
if (!Object.is(prev, cs._v)) cs.__v++;
|
|
437
465
|
} finally {
|
|
438
466
|
evaluating = false;
|
|
439
|
-
if (threw) cs._d = true;
|
|
440
467
|
}
|
|
441
468
|
}
|
|
442
469
|
return cs._v;
|
|
@@ -445,18 +472,11 @@ function derived(getter, options) {
|
|
|
445
472
|
if (cs._d) {
|
|
446
473
|
const oldValue = cs._v;
|
|
447
474
|
evaluating = true;
|
|
448
|
-
let threw = true;
|
|
449
475
|
try {
|
|
450
|
-
retrack(
|
|
451
|
-
const next = getter();
|
|
452
|
-
cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
|
|
453
|
-
cs._d = false;
|
|
454
|
-
threw = false;
|
|
455
|
-
}, markDirty);
|
|
476
|
+
retrack(recompute, markDirty);
|
|
456
477
|
if (!Object.is(oldValue, cs._v)) cs.__v++;
|
|
457
478
|
} finally {
|
|
458
479
|
evaluating = false;
|
|
459
|
-
if (threw) cs._d = true;
|
|
460
480
|
}
|
|
461
481
|
if (hook && oldValue !== cs._v) {
|
|
462
482
|
hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
@@ -477,11 +497,15 @@ function derived(getter, options) {
|
|
|
477
497
|
var als = null;
|
|
478
498
|
try {
|
|
479
499
|
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
500
|
+
let mod = null;
|
|
501
|
+
const getBuiltin = process.getBuiltinModule;
|
|
502
|
+
if (typeof getBuiltin === "function") {
|
|
503
|
+
mod = getBuiltin("node:async_hooks");
|
|
504
|
+
} else {
|
|
505
|
+
const req = Function("return typeof require==='function'?require:null")();
|
|
506
|
+
if (req) mod = req("node:async_hooks");
|
|
484
507
|
}
|
|
508
|
+
if (mod) als = new mod.AsyncLocalStorage();
|
|
485
509
|
}
|
|
486
510
|
} catch {
|
|
487
511
|
als = null;
|
|
@@ -497,6 +521,17 @@ function getSSRStore() {
|
|
|
497
521
|
function isSSR() {
|
|
498
522
|
return getSSRStore().ssr;
|
|
499
523
|
}
|
|
524
|
+
function getRequestScopedCache(name) {
|
|
525
|
+
if (!isSSR()) return null;
|
|
526
|
+
const store = getSSRStore();
|
|
527
|
+
const caches = store.caches ?? (store.caches = /* @__PURE__ */ new Map());
|
|
528
|
+
let c = caches.get(name);
|
|
529
|
+
if (!c) {
|
|
530
|
+
c = /* @__PURE__ */ new Map();
|
|
531
|
+
caches.set(name, c);
|
|
532
|
+
}
|
|
533
|
+
return c;
|
|
534
|
+
}
|
|
500
535
|
|
|
501
536
|
// src/core/signals/effect.ts
|
|
502
537
|
var _g = globalThis;
|
|
@@ -583,6 +618,7 @@ function effect(effectFn, options) {
|
|
|
583
618
|
ctx.fn(ctx.onCleanup);
|
|
584
619
|
};
|
|
585
620
|
const sub = (() => {
|
|
621
|
+
if (ctx.disposed) return;
|
|
586
622
|
if (ctx.running) {
|
|
587
623
|
ctx.rerunPending = true;
|
|
588
624
|
return;
|
|
@@ -779,9 +815,12 @@ async function withRetry(fn, options, onRetry, signal2) {
|
|
|
779
815
|
}
|
|
780
816
|
|
|
781
817
|
// src/data/query.ts
|
|
782
|
-
var
|
|
783
|
-
function
|
|
784
|
-
|
|
818
|
+
var globalQueryCache = /* @__PURE__ */ new Map();
|
|
819
|
+
function getActiveQueryCache() {
|
|
820
|
+
return getRequestScopedCache("query") ?? globalQueryCache;
|
|
821
|
+
}
|
|
822
|
+
function getOrCreateEntry(cache, key, initialData) {
|
|
823
|
+
let entry = cache.get(key);
|
|
785
824
|
if (!entry) {
|
|
786
825
|
entry = {
|
|
787
826
|
data: initialData,
|
|
@@ -793,7 +832,7 @@ function getOrCreateEntry(key, initialData) {
|
|
|
793
832
|
listeners: /* @__PURE__ */ new Set(),
|
|
794
833
|
refetchers: /* @__PURE__ */ new Set()
|
|
795
834
|
};
|
|
796
|
-
|
|
835
|
+
cache.set(key, entry);
|
|
797
836
|
}
|
|
798
837
|
return entry;
|
|
799
838
|
}
|
|
@@ -813,6 +852,7 @@ function query(key, fetcher, options = {}) {
|
|
|
813
852
|
select
|
|
814
853
|
} = options;
|
|
815
854
|
const resolveKey = typeof key === "function" ? key : () => key;
|
|
855
|
+
const cache = getActiveQueryCache();
|
|
816
856
|
const [data, setData] = signal(initialData);
|
|
817
857
|
const [isFetching, setIsFetching] = signal(false);
|
|
818
858
|
const [error, setError] = signal(void 0);
|
|
@@ -824,16 +864,16 @@ function query(key, fetcher, options = {}) {
|
|
|
824
864
|
const isStale = derived(() => {
|
|
825
865
|
data();
|
|
826
866
|
if (!currentKey) return true;
|
|
827
|
-
const entry =
|
|
867
|
+
const entry = cache.get(currentKey);
|
|
828
868
|
if (!entry || entry.dataUpdatedAt === 0) return true;
|
|
829
869
|
return Date.now() - entry.dataUpdatedAt >= staleTime;
|
|
830
870
|
});
|
|
831
871
|
async function doFetch() {
|
|
832
872
|
if (disposed || !currentKey || !enabled) return;
|
|
833
873
|
const key2 = currentKey;
|
|
834
|
-
let entry =
|
|
874
|
+
let entry = cache.get(key2);
|
|
835
875
|
if (!entry) {
|
|
836
|
-
entry = getOrCreateEntry(key2);
|
|
876
|
+
entry = getOrCreateEntry(cache, key2);
|
|
837
877
|
entry.listeners.add(onCacheUpdate);
|
|
838
878
|
entry.refetchers.add(doFetch);
|
|
839
879
|
}
|
|
@@ -908,7 +948,7 @@ function query(key, fetcher, options = {}) {
|
|
|
908
948
|
}
|
|
909
949
|
function onCacheUpdate() {
|
|
910
950
|
if (disposed || !currentKey) return;
|
|
911
|
-
const entry =
|
|
951
|
+
const entry = cache.get(currentKey);
|
|
912
952
|
if (!entry) {
|
|
913
953
|
batch(() => {
|
|
914
954
|
setData(void 0);
|
|
@@ -928,7 +968,7 @@ function query(key, fetcher, options = {}) {
|
|
|
928
968
|
const effectCleanup = effect(() => {
|
|
929
969
|
const key2 = resolveKey();
|
|
930
970
|
if (currentKey !== null && currentKey !== key2) {
|
|
931
|
-
const oldEntry =
|
|
971
|
+
const oldEntry = cache.get(currentKey);
|
|
932
972
|
if (oldEntry) {
|
|
933
973
|
oldEntry.listeners.delete(onCacheUpdate);
|
|
934
974
|
oldEntry.refetchers.delete(doFetch);
|
|
@@ -936,13 +976,13 @@ function query(key, fetcher, options = {}) {
|
|
|
936
976
|
if (oldEntry.subscribers <= 0 && cacheTime >= 0) {
|
|
937
977
|
const oldKey = currentKey;
|
|
938
978
|
if (oldEntry.gcTimer !== null) clearTimeout(oldEntry.gcTimer);
|
|
939
|
-
oldEntry.gcTimer = setTimeout(() =>
|
|
979
|
+
oldEntry.gcTimer = setTimeout(() => cache.delete(oldKey), cacheTime);
|
|
940
980
|
}
|
|
941
981
|
}
|
|
942
982
|
}
|
|
943
983
|
const keyChanged = currentKey !== key2;
|
|
944
984
|
currentKey = key2;
|
|
945
|
-
const entry = getOrCreateEntry(key2, initialData);
|
|
985
|
+
const entry = getOrCreateEntry(cache, key2, initialData);
|
|
946
986
|
if (keyChanged) entry.subscribers++;
|
|
947
987
|
if (entry.gcTimer !== null) {
|
|
948
988
|
clearTimeout(entry.gcTimer);
|
|
@@ -996,7 +1036,7 @@ function query(key, fetcher, options = {}) {
|
|
|
996
1036
|
effectCleanup();
|
|
997
1037
|
if (intervalTimer) clearInterval(intervalTimer);
|
|
998
1038
|
if (currentKey) {
|
|
999
|
-
const entry =
|
|
1039
|
+
const entry = cache.get(currentKey);
|
|
1000
1040
|
if (entry) {
|
|
1001
1041
|
entry.listeners.delete(onCacheUpdate);
|
|
1002
1042
|
entry.refetchers.delete(doFetch);
|
|
@@ -1004,7 +1044,7 @@ function query(key, fetcher, options = {}) {
|
|
|
1004
1044
|
if (entry.subscribers <= 0 && cacheTime >= 0) {
|
|
1005
1045
|
const key2 = currentKey;
|
|
1006
1046
|
if (entry.gcTimer !== null) clearTimeout(entry.gcTimer);
|
|
1007
|
-
entry.gcTimer = setTimeout(() =>
|
|
1047
|
+
entry.gcTimer = setTimeout(() => cache.delete(key2), cacheTime);
|
|
1008
1048
|
}
|
|
1009
1049
|
}
|
|
1010
1050
|
}
|
|
@@ -1027,7 +1067,7 @@ function query(key, fetcher, options = {}) {
|
|
|
1027
1067
|
}
|
|
1028
1068
|
function invalidateQueries(keyOrPredicate) {
|
|
1029
1069
|
const predicate = typeof keyOrPredicate === "function" ? keyOrPredicate : (k) => k === keyOrPredicate;
|
|
1030
|
-
for (const [key, entry] of
|
|
1070
|
+
for (const [key, entry] of getActiveQueryCache().entries()) {
|
|
1031
1071
|
if (predicate(key)) {
|
|
1032
1072
|
entry.dataUpdatedAt = 0;
|
|
1033
1073
|
for (const refetcher of entry.refetchers) refetcher();
|
|
@@ -1035,10 +1075,10 @@ function invalidateQueries(keyOrPredicate) {
|
|
|
1035
1075
|
}
|
|
1036
1076
|
}
|
|
1037
1077
|
function getQueryData(key) {
|
|
1038
|
-
return
|
|
1078
|
+
return getActiveQueryCache().get(key)?.data;
|
|
1039
1079
|
}
|
|
1040
1080
|
function setQueryData(key, data) {
|
|
1041
|
-
const entry =
|
|
1081
|
+
const entry = getActiveQueryCache().get(key);
|
|
1042
1082
|
if (!entry) return;
|
|
1043
1083
|
const newData = typeof data === "function" ? data(entry.data) : data;
|
|
1044
1084
|
entry.data = newData;
|
|
@@ -1048,14 +1088,15 @@ function setQueryData(key, data) {
|
|
|
1048
1088
|
function clearQueryCache() {
|
|
1049
1089
|
const activeListeners = [];
|
|
1050
1090
|
const activeRefetchers = [];
|
|
1051
|
-
|
|
1091
|
+
const activeCache = getActiveQueryCache();
|
|
1092
|
+
for (const entry of activeCache.values()) {
|
|
1052
1093
|
if (entry.gcTimer) clearTimeout(entry.gcTimer);
|
|
1053
1094
|
if (entry.subscribers > 0) {
|
|
1054
1095
|
for (const listener of entry.listeners) activeListeners.push(listener);
|
|
1055
1096
|
for (const refetcher of entry.refetchers) activeRefetchers.push(refetcher);
|
|
1056
1097
|
}
|
|
1057
1098
|
}
|
|
1058
|
-
|
|
1099
|
+
activeCache.clear();
|
|
1059
1100
|
for (const listener of activeListeners) listener();
|
|
1060
1101
|
for (const refetcher of activeRefetchers) {
|
|
1061
1102
|
refetcher().catch((err) => {
|
|
@@ -1066,10 +1107,11 @@ function clearQueryCache() {
|
|
|
1066
1107
|
}
|
|
1067
1108
|
}
|
|
1068
1109
|
function __resetQueryCache() {
|
|
1069
|
-
|
|
1110
|
+
const activeCache = getActiveQueryCache();
|
|
1111
|
+
for (const entry of activeCache.values()) {
|
|
1070
1112
|
if (entry.gcTimer) clearTimeout(entry.gcTimer);
|
|
1071
1113
|
}
|
|
1072
|
-
|
|
1114
|
+
activeCache.clear();
|
|
1073
1115
|
}
|
|
1074
1116
|
|
|
1075
1117
|
// src/data/mutation.ts
|
|
@@ -1081,7 +1123,11 @@ function mutation(mutationFn, options = {}) {
|
|
|
1081
1123
|
const isSuccess = derived(() => status() === "success");
|
|
1082
1124
|
const isIdle = derived(() => status() === "idle");
|
|
1083
1125
|
let runId = 0;
|
|
1126
|
+
let abortController = null;
|
|
1084
1127
|
async function execute(variables) {
|
|
1128
|
+
abortController?.abort();
|
|
1129
|
+
abortController = new AbortController();
|
|
1130
|
+
const signal2 = abortController.signal;
|
|
1085
1131
|
const myRun = ++runId;
|
|
1086
1132
|
let context2;
|
|
1087
1133
|
batch(() => {
|
|
@@ -1093,7 +1139,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
1093
1139
|
if (options.onMutate) {
|
|
1094
1140
|
context2 = await options.onMutate(variables);
|
|
1095
1141
|
}
|
|
1096
|
-
const result = await withRetry(() => mutationFn(variables), options.retry);
|
|
1142
|
+
const result = await withRetry(() => mutationFn(variables, signal2), options.retry, void 0, signal2);
|
|
1097
1143
|
if (myRun !== runId) return result;
|
|
1098
1144
|
batch(() => {
|
|
1099
1145
|
setData(result);
|
|
@@ -1105,6 +1151,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
1105
1151
|
return result;
|
|
1106
1152
|
} catch (err) {
|
|
1107
1153
|
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
1154
|
+
if (errorObj instanceof DOMException && errorObj.name === "AbortError") throw errorObj;
|
|
1108
1155
|
if (myRun !== runId) throw errorObj;
|
|
1109
1156
|
batch(() => {
|
|
1110
1157
|
setError(errorObj);
|
|
@@ -1118,6 +1165,8 @@ function mutation(mutationFn, options = {}) {
|
|
|
1118
1165
|
}
|
|
1119
1166
|
function reset() {
|
|
1120
1167
|
runId++;
|
|
1168
|
+
abortController?.abort();
|
|
1169
|
+
abortController = null;
|
|
1121
1170
|
batch(() => {
|
|
1122
1171
|
setData(void 0);
|
|
1123
1172
|
setError(void 0);
|
|
@@ -1133,6 +1182,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
1133
1182
|
isIdle,
|
|
1134
1183
|
mutate: (variables) => {
|
|
1135
1184
|
execute(variables).catch((err) => {
|
|
1185
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
1136
1186
|
if (typeof console !== "undefined") {
|
|
1137
1187
|
console.warn("[SibuJS mutation] mutate() failed; check `.error()` signal or onError option.", err);
|
|
1138
1188
|
}
|
|
@@ -1149,6 +1199,7 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1149
1199
|
getNextPageParam,
|
|
1150
1200
|
getPreviousPageParam,
|
|
1151
1201
|
initialPageParam = 0,
|
|
1202
|
+
maxPages,
|
|
1152
1203
|
enabled = true,
|
|
1153
1204
|
retry: retryOptions,
|
|
1154
1205
|
onSuccess,
|
|
@@ -1172,8 +1223,9 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1172
1223
|
let abortController = null;
|
|
1173
1224
|
let disposed = false;
|
|
1174
1225
|
let runId = 0;
|
|
1175
|
-
|
|
1176
|
-
|
|
1226
|
+
let inFlight = null;
|
|
1227
|
+
function fetchPage(pageParam, direction) {
|
|
1228
|
+
if (disposed) return Promise.resolve();
|
|
1177
1229
|
abortController?.abort();
|
|
1178
1230
|
abortController = new AbortController();
|
|
1179
1231
|
const signal2 = abortController.signal;
|
|
@@ -1184,39 +1236,44 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1184
1236
|
if (direction === "prev") setIsFetchingPrev(true);
|
|
1185
1237
|
setError(void 0);
|
|
1186
1238
|
});
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
newPages
|
|
1194
|
-
|
|
1195
|
-
|
|
1239
|
+
const promise = (async () => {
|
|
1240
|
+
try {
|
|
1241
|
+
const page = await withRetry(() => fetcher({ signal: signal2, pageParam }), retryOptions, void 0, signal2);
|
|
1242
|
+
if (disposed || myRun !== runId) return;
|
|
1243
|
+
const currentPages = pages();
|
|
1244
|
+
let newPages = direction === "prev" ? [page, ...currentPages] : [...currentPages, page];
|
|
1245
|
+
if (maxPages != null && maxPages > 0 && newPages.length > maxPages) {
|
|
1246
|
+
newPages = direction === "prev" ? newPages.slice(0, maxPages) : newPages.slice(newPages.length - maxPages);
|
|
1247
|
+
}
|
|
1248
|
+
const nextParam = getNextPageParam(newPages[newPages.length - 1], newPages);
|
|
1249
|
+
const prevParam = getPreviousPageParam?.(newPages[0], newPages);
|
|
1250
|
+
batch(() => {
|
|
1251
|
+
setPages(newPages);
|
|
1252
|
+
setNextPageParam(nextParam);
|
|
1253
|
+
setPrevPageParam(prevParam);
|
|
1254
|
+
setIsFetching(false);
|
|
1255
|
+
setIsFetchingNext(false);
|
|
1256
|
+
setIsFetchingPrev(false);
|
|
1257
|
+
});
|
|
1258
|
+
onSuccess?.(newPages);
|
|
1259
|
+
} catch (err) {
|
|
1260
|
+
if (disposed || myRun !== runId) return;
|
|
1261
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
1262
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
1263
|
+
batch(() => {
|
|
1264
|
+
setError(errorObj);
|
|
1265
|
+
setIsFetching(false);
|
|
1266
|
+
setIsFetchingNext(false);
|
|
1267
|
+
setIsFetchingPrev(false);
|
|
1268
|
+
});
|
|
1269
|
+
onError?.(errorObj);
|
|
1196
1270
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
setIsFetching(false);
|
|
1204
|
-
setIsFetchingNext(false);
|
|
1205
|
-
setIsFetchingPrev(false);
|
|
1206
|
-
});
|
|
1207
|
-
onSuccess?.(newPages);
|
|
1208
|
-
} catch (err) {
|
|
1209
|
-
if (disposed || myRun !== runId) return;
|
|
1210
|
-
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
1211
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
1212
|
-
batch(() => {
|
|
1213
|
-
setError(errorObj);
|
|
1214
|
-
setIsFetching(false);
|
|
1215
|
-
setIsFetchingNext(false);
|
|
1216
|
-
setIsFetchingPrev(false);
|
|
1217
|
-
});
|
|
1218
|
-
onError?.(errorObj);
|
|
1219
|
-
}
|
|
1271
|
+
})();
|
|
1272
|
+
inFlight = promise;
|
|
1273
|
+
void promise.finally(() => {
|
|
1274
|
+
if (inFlight === promise) inFlight = null;
|
|
1275
|
+
});
|
|
1276
|
+
return promise;
|
|
1220
1277
|
}
|
|
1221
1278
|
const effectCleanup = effect(() => {
|
|
1222
1279
|
resolveKey();
|
|
@@ -1231,11 +1288,13 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1231
1288
|
}
|
|
1232
1289
|
});
|
|
1233
1290
|
function fetchNextPage() {
|
|
1291
|
+
if (inFlight) return inFlight;
|
|
1234
1292
|
const param = nextPageParam();
|
|
1235
1293
|
if (param === void 0) return Promise.resolve();
|
|
1236
1294
|
return fetchPage(param, "next");
|
|
1237
1295
|
}
|
|
1238
1296
|
function fetchPreviousPage() {
|
|
1297
|
+
if (inFlight) return inFlight;
|
|
1239
1298
|
const param = prevPageParam();
|
|
1240
1299
|
if (param === void 0) return Promise.resolve();
|
|
1241
1300
|
return fetchPage(param, "prev");
|
|
@@ -1274,13 +1333,17 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1274
1333
|
function previous(getter) {
|
|
1275
1334
|
const [previous2, setPrevious] = signal(void 0);
|
|
1276
1335
|
let current = getter();
|
|
1277
|
-
effect(() => {
|
|
1336
|
+
const stop = effect(() => {
|
|
1278
1337
|
const next = getter();
|
|
1279
1338
|
if (!Object.is(next, current)) {
|
|
1280
1339
|
setPrevious(current);
|
|
1281
1340
|
current = next;
|
|
1282
1341
|
}
|
|
1283
1342
|
});
|
|
1343
|
+
Object.defineProperty(previous2, "dispose", {
|
|
1344
|
+
value: stop,
|
|
1345
|
+
enumerable: false
|
|
1346
|
+
});
|
|
1284
1347
|
return previous2;
|
|
1285
1348
|
}
|
|
1286
1349
|
|
|
@@ -1288,7 +1351,7 @@ function previous(getter) {
|
|
|
1288
1351
|
function debounce(getter, delay) {
|
|
1289
1352
|
const [debounced, setDebounced] = signal(getter());
|
|
1290
1353
|
let timer = null;
|
|
1291
|
-
effect(() => {
|
|
1354
|
+
const stop = effect(() => {
|
|
1292
1355
|
const value = getter();
|
|
1293
1356
|
if (timer !== null) clearTimeout(timer);
|
|
1294
1357
|
timer = setTimeout(() => {
|
|
@@ -1296,6 +1359,16 @@ function debounce(getter, delay) {
|
|
|
1296
1359
|
timer = null;
|
|
1297
1360
|
}, delay);
|
|
1298
1361
|
});
|
|
1362
|
+
Object.defineProperty(debounced, "dispose", {
|
|
1363
|
+
value: () => {
|
|
1364
|
+
stop();
|
|
1365
|
+
if (timer !== null) {
|
|
1366
|
+
clearTimeout(timer);
|
|
1367
|
+
timer = null;
|
|
1368
|
+
}
|
|
1369
|
+
},
|
|
1370
|
+
enumerable: false
|
|
1371
|
+
});
|
|
1299
1372
|
return debounced;
|
|
1300
1373
|
}
|
|
1301
1374
|
|
|
@@ -1305,7 +1378,8 @@ function throttle(getter, interval) {
|
|
|
1305
1378
|
let cooldown = false;
|
|
1306
1379
|
let pending = null;
|
|
1307
1380
|
let lastEmitted = getter();
|
|
1308
|
-
|
|
1381
|
+
let timer = null;
|
|
1382
|
+
const stop = effect(() => {
|
|
1309
1383
|
const value = getter();
|
|
1310
1384
|
if (!cooldown) {
|
|
1311
1385
|
if (!Object.is(value, lastEmitted)) {
|
|
@@ -1313,7 +1387,8 @@ function throttle(getter, interval) {
|
|
|
1313
1387
|
lastEmitted = value;
|
|
1314
1388
|
cooldown = true;
|
|
1315
1389
|
pending = null;
|
|
1316
|
-
setTimeout(() => {
|
|
1390
|
+
timer = setTimeout(() => {
|
|
1391
|
+
timer = null;
|
|
1317
1392
|
cooldown = false;
|
|
1318
1393
|
if (pending !== null) {
|
|
1319
1394
|
const trailingValue = pending.value;
|
|
@@ -1327,6 +1402,16 @@ function throttle(getter, interval) {
|
|
|
1327
1402
|
pending = { value };
|
|
1328
1403
|
}
|
|
1329
1404
|
});
|
|
1405
|
+
Object.defineProperty(throttled, "dispose", {
|
|
1406
|
+
value: () => {
|
|
1407
|
+
stop();
|
|
1408
|
+
if (timer !== null) {
|
|
1409
|
+
clearTimeout(timer);
|
|
1410
|
+
timer = null;
|
|
1411
|
+
}
|
|
1412
|
+
},
|
|
1413
|
+
enumerable: false
|
|
1414
|
+
});
|
|
1330
1415
|
return throttled;
|
|
1331
1416
|
}
|
|
1332
1417
|
|
|
@@ -1455,28 +1540,45 @@ function idbGet(db, store, key) {
|
|
|
1455
1540
|
req.onerror = () => reject(req.error);
|
|
1456
1541
|
});
|
|
1457
1542
|
}
|
|
1458
|
-
function idbPut(db, store, item) {
|
|
1543
|
+
function idbPut(db, store, item, key) {
|
|
1459
1544
|
return new Promise((resolve, reject) => {
|
|
1460
1545
|
const tx = db.transaction(store, "readwrite");
|
|
1461
|
-
tx.objectStore(store).put(item);
|
|
1546
|
+
if (key !== void 0) tx.objectStore(store).put(item, key);
|
|
1547
|
+
else tx.objectStore(store).put(item);
|
|
1462
1548
|
tx.oncomplete = () => resolve();
|
|
1463
1549
|
tx.onerror = () => reject(tx.error);
|
|
1464
1550
|
});
|
|
1465
1551
|
}
|
|
1466
|
-
function
|
|
1552
|
+
function coalesceAndAddChange(tx, change, keyPath) {
|
|
1553
|
+
const store = tx.objectStore("_changes");
|
|
1554
|
+
const targetKey = change.item[keyPath];
|
|
1555
|
+
const cursorReq = store.openCursor();
|
|
1556
|
+
cursorReq.onsuccess = () => {
|
|
1557
|
+
const cursor = cursorReq.result;
|
|
1558
|
+
if (cursor) {
|
|
1559
|
+
const existing = cursor.value;
|
|
1560
|
+
const k = existing.item[keyPath];
|
|
1561
|
+
if (targetKey != null && k === targetKey) cursor.delete();
|
|
1562
|
+
cursor.continue();
|
|
1563
|
+
} else {
|
|
1564
|
+
store.put(change);
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
function idbPutWithChange(db, item, change, keyPath) {
|
|
1467
1569
|
return new Promise((resolve, reject) => {
|
|
1468
1570
|
const tx = db.transaction(["items", "_changes"], "readwrite");
|
|
1469
1571
|
tx.objectStore("items").put(item);
|
|
1470
|
-
tx
|
|
1572
|
+
coalesceAndAddChange(tx, change, keyPath);
|
|
1471
1573
|
tx.oncomplete = () => resolve();
|
|
1472
1574
|
tx.onerror = () => reject(tx.error);
|
|
1473
1575
|
});
|
|
1474
1576
|
}
|
|
1475
|
-
function idbDeleteWithChange(db, key, change) {
|
|
1577
|
+
function idbDeleteWithChange(db, key, change, keyPath) {
|
|
1476
1578
|
return new Promise((resolve, reject) => {
|
|
1477
1579
|
const tx = db.transaction(["items", "_changes"], "readwrite");
|
|
1478
1580
|
tx.objectStore("items").delete(key);
|
|
1479
|
-
tx
|
|
1581
|
+
coalesceAndAddChange(tx, change, keyPath);
|
|
1480
1582
|
tx.oncomplete = () => resolve();
|
|
1481
1583
|
tx.onerror = () => reject(tx.error);
|
|
1482
1584
|
});
|
|
@@ -1536,13 +1638,18 @@ async function offlineStore(options) {
|
|
|
1536
1638
|
setPendingCount(changes.length);
|
|
1537
1639
|
}
|
|
1538
1640
|
async function put(item) {
|
|
1539
|
-
await idbPutWithChange(db, item, { type: "put", item, timestamp: Date.now() });
|
|
1641
|
+
await idbPutWithChange(db, item, { type: "put", item, timestamp: Date.now() }, keyPath);
|
|
1540
1642
|
await refreshData();
|
|
1541
1643
|
}
|
|
1542
1644
|
async function remove(key) {
|
|
1543
1645
|
const existing = await idbGet(db, "items", key);
|
|
1544
1646
|
if (existing) {
|
|
1545
|
-
await idbDeleteWithChange(
|
|
1647
|
+
await idbDeleteWithChange(
|
|
1648
|
+
db,
|
|
1649
|
+
key,
|
|
1650
|
+
{ type: "delete", item: existing, timestamp: Date.now() },
|
|
1651
|
+
keyPath
|
|
1652
|
+
);
|
|
1546
1653
|
await refreshData();
|
|
1547
1654
|
}
|
|
1548
1655
|
}
|
|
@@ -1568,6 +1675,8 @@ async function offlineStore(options) {
|
|
|
1568
1675
|
snapshot.map((e) => e.key)
|
|
1569
1676
|
);
|
|
1570
1677
|
if (closed) return;
|
|
1678
|
+
} else if (typeof console !== "undefined") {
|
|
1679
|
+
console.warn(`[offlineStore] push rejected by adapter${result.error ? `: ${result.error}` : ""}`);
|
|
1571
1680
|
}
|
|
1572
1681
|
}
|
|
1573
1682
|
const remoteItems = await adapter.pull(lastSynced());
|
|
@@ -1586,7 +1695,7 @@ async function offlineStore(options) {
|
|
|
1586
1695
|
await idbPutMany(db, "items", safeRemote);
|
|
1587
1696
|
if (closed) return;
|
|
1588
1697
|
const now = Date.now();
|
|
1589
|
-
await idbPut(db, "_meta", now);
|
|
1698
|
+
await idbPut(db, "_meta", now, "lastSynced");
|
|
1590
1699
|
if (closed) return;
|
|
1591
1700
|
setLastSynced(now);
|
|
1592
1701
|
await refreshData();
|
|
@@ -1685,14 +1794,20 @@ function loaderData() {
|
|
|
1685
1794
|
async function preloadRoute(route, context2, callerSignal) {
|
|
1686
1795
|
if (!route.loader) return void 0;
|
|
1687
1796
|
const controller = new AbortController();
|
|
1797
|
+
let onAbort = null;
|
|
1688
1798
|
if (callerSignal) {
|
|
1689
1799
|
if (callerSignal.aborted) {
|
|
1690
1800
|
controller.abort();
|
|
1691
1801
|
} else {
|
|
1692
|
-
|
|
1802
|
+
onAbort = () => controller.abort();
|
|
1803
|
+
callerSignal.addEventListener("abort", onAbort, { once: true });
|
|
1693
1804
|
}
|
|
1694
1805
|
}
|
|
1695
|
-
|
|
1806
|
+
try {
|
|
1807
|
+
return await route.loader(context2, { signal: controller.signal });
|
|
1808
|
+
} finally {
|
|
1809
|
+
if (onAbort) callerSignal?.removeEventListener("abort", onAbort);
|
|
1810
|
+
}
|
|
1696
1811
|
}
|
|
1697
1812
|
|
|
1698
1813
|
// src/ui/socket.ts
|
|
@@ -1798,9 +1913,12 @@ function socket(url, options) {
|
|
|
1798
1913
|
}
|
|
1799
1914
|
|
|
1800
1915
|
// src/utils/sanitize.ts
|
|
1916
|
+
function stripControlChars(value) {
|
|
1917
|
+
return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
|
|
1918
|
+
}
|
|
1801
1919
|
var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
1802
1920
|
function sanitizeUrl(url) {
|
|
1803
|
-
const trimmed = url
|
|
1921
|
+
const trimmed = stripControlChars(url).trim();
|
|
1804
1922
|
if (!trimmed) return "";
|
|
1805
1923
|
const lower = trimmed.toLowerCase();
|
|
1806
1924
|
let schemeEnd = -1;
|
package/dist/data.d.cts
CHANGED
|
@@ -133,7 +133,7 @@ interface MutationResult<TData, TVariables> {
|
|
|
133
133
|
/** Reset state to idle */
|
|
134
134
|
reset: () => void;
|
|
135
135
|
}
|
|
136
|
-
declare function mutation<TData, TVariables = void, TContext = unknown>(mutationFn: (variables: TVariables) => Promise<TData>, options?: MutationOptions<TData, TVariables, TContext>): MutationResult<TData, TVariables>;
|
|
136
|
+
declare function mutation<TData, TVariables = void, TContext = unknown>(mutationFn: (variables: TVariables, signal?: AbortSignal) => Promise<TData>, options?: MutationOptions<TData, TVariables, TContext>): MutationResult<TData, TVariables>;
|
|
137
137
|
|
|
138
138
|
interface InfiniteQueryOptions<TData, TPageParam = number> {
|
|
139
139
|
/** Get the param for the next page. Return undefined to signal end. */
|
|
@@ -142,6 +142,12 @@ interface InfiniteQueryOptions<TData, TPageParam = number> {
|
|
|
142
142
|
getPreviousPageParam?: (firstPage: TData, allPages: TData[]) => TPageParam | undefined;
|
|
143
143
|
/** Initial page param. Default: 0 (for number) */
|
|
144
144
|
initialPageParam?: TPageParam;
|
|
145
|
+
/**
|
|
146
|
+
* Maximum number of pages to retain. When exceeded, the oldest page is
|
|
147
|
+
* dropped from the opposite end (sliding window) to bound memory. Unset =
|
|
148
|
+
* unbounded.
|
|
149
|
+
*/
|
|
150
|
+
maxPages?: number;
|
|
145
151
|
/** Whether to fetch on creation. Default: true */
|
|
146
152
|
enabled?: boolean;
|
|
147
153
|
/** Retry options */
|