sibujs 3.1.0 → 3.2.1
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 +235 -147
- package/dist/build.js +35 -24
- package/dist/cdn.global.js +7 -7
- package/dist/{chunk-WYU7CYJ3.js → chunk-2C4E3HBM.js} +5 -5
- package/dist/{chunk-3DYB5B3S.js → chunk-4JCAUOLN.js} +45 -23
- package/dist/{chunk-2HAGQWDV.js → chunk-5N74TKLD.js} +1 -1
- package/dist/{chunk-SVVAUX7J.js → chunk-7XDYVJLE.js} +19 -9
- package/dist/{chunk-2N2UL7O4.js → chunk-BGNLPNGV.js} +20 -12
- package/dist/{chunk-RK4BQG25.js → chunk-C427DVQF.js} +1 -1
- package/dist/{chunk-ZIBE2SAT.js → chunk-FDY42FIU.js} +3 -2
- package/dist/{chunk-GQ7RRFPU.js → chunk-FOI23UJL.js} +11 -1
- package/dist/{chunk-2RA7SHDA.js → chunk-GOJMFRBL.js} +20 -4
- package/dist/{chunk-IVOUCSZL.js → chunk-GOUM4JCT.js} +6 -6
- package/dist/chunk-H3SRKIYX.js +17 -0
- package/dist/{chunk-3DJH25UO.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-SC437AMI.js → chunk-JYXOEYI4.js} +12 -18
- package/dist/{chunk-KB3BA2XK.js → chunk-NFYWLRUO.js} +11 -18
- package/dist/{chunk-QNQY5DUS.js → chunk-NPIEEKPT.js} +20 -11
- package/dist/{chunk-UYX2NDOH.js → chunk-OYLPZO4N.js} +33 -15
- package/dist/{chunk-LYTCUZ7H.js → chunk-RDRSWYNP.js} +1 -1
- package/dist/{chunk-2ZJ7TSW4.js → chunk-RLUJL2MV.js} +4 -8
- package/dist/{chunk-CR4MXPHB.js → chunk-V2MTG5FT.js} +99 -36
- package/dist/{chunk-CNZ35WI2.js → chunk-VJE6DDYM.js} +2 -2
- package/dist/{chunk-PMSDFTK3.js → chunk-VOCE4NNK.js} +157 -75
- package/dist/{chunk-WKUXSE7V.js → chunk-X67UYC74.js} +12 -11
- package/dist/{chunk-EFOAE5NC.js → chunk-YFDGQWDA.js} +1 -1
- package/dist/{chunk-3U4ZVXVD.js → chunk-Z2FWAE4B.js} +6 -2
- package/dist/data.cjs +190 -94
- 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 +123 -63
- package/dist/ecosystem.js +9 -9
- package/dist/extras.cjs +380 -196
- package/dist/extras.d.cts +2 -2
- package/dist/extras.d.ts +2 -2
- package/dist/extras.js +27 -24
- package/dist/index.cjs +214 -136
- 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 +45 -40
- 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 +234 -160
- package/dist/plugins.d.cts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +127 -69
- 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 +145 -66
- 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 +54 -38
- package/dist/ui.js +10 -9
- package/dist/widgets.cjs +40 -24
- package/dist/widgets.js +8 -8
- package/package.json +3 -1
package/dist/data.cjs
CHANGED
|
@@ -210,7 +210,7 @@ function track(effectFn, subscriber) {
|
|
|
210
210
|
function reactiveBinding(commit) {
|
|
211
211
|
const run = () => {
|
|
212
212
|
const s = subscriber;
|
|
213
|
-
if (s._reentrant) return;
|
|
213
|
+
if (s._disposed || s._reentrant) return;
|
|
214
214
|
s._reentrant = true;
|
|
215
215
|
try {
|
|
216
216
|
retrack(commit, subscriber);
|
|
@@ -226,8 +226,12 @@ function reactiveBinding(commit) {
|
|
|
226
226
|
subscriber._runEpoch = 0;
|
|
227
227
|
subscriber._runs = 0;
|
|
228
228
|
subscriber._reentrant = false;
|
|
229
|
+
subscriber._disposed = false;
|
|
229
230
|
run();
|
|
230
|
-
return subscriber._dispose ?? (subscriber._dispose = () =>
|
|
231
|
+
return subscriber._dispose ?? (subscriber._dispose = () => {
|
|
232
|
+
subscriber._disposed = true;
|
|
233
|
+
cleanup(subscriber);
|
|
234
|
+
});
|
|
231
235
|
}
|
|
232
236
|
function recordDependency(signal2) {
|
|
233
237
|
if (!currentSubscriber) return;
|
|
@@ -417,6 +421,7 @@ function derived(getter, options) {
|
|
|
417
421
|
const equals = options?.equals;
|
|
418
422
|
const cs = {};
|
|
419
423
|
cs._d = false;
|
|
424
|
+
cs._init = false;
|
|
420
425
|
cs._g = getter;
|
|
421
426
|
cs.__v = 0;
|
|
422
427
|
const markDirty = () => {
|
|
@@ -425,11 +430,18 @@ function derived(getter, options) {
|
|
|
425
430
|
};
|
|
426
431
|
markDirty._c = 1;
|
|
427
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
|
+
};
|
|
428
439
|
track(() => {
|
|
429
440
|
let threw = true;
|
|
430
441
|
try {
|
|
431
442
|
cs._v = getter();
|
|
432
443
|
cs._d = false;
|
|
444
|
+
cs._init = true;
|
|
433
445
|
threw = false;
|
|
434
446
|
} finally {
|
|
435
447
|
if (threw) cs._d = true;
|
|
@@ -445,20 +457,13 @@ function derived(getter, options) {
|
|
|
445
457
|
}
|
|
446
458
|
if (trackingSuspended) {
|
|
447
459
|
if (cs._d) {
|
|
460
|
+
const prev = cs._v;
|
|
448
461
|
evaluating = true;
|
|
449
|
-
let threw = true;
|
|
450
462
|
try {
|
|
451
|
-
|
|
452
|
-
retrack(() => {
|
|
453
|
-
const next = getter();
|
|
454
|
-
cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
|
|
455
|
-
cs._d = false;
|
|
456
|
-
threw = false;
|
|
457
|
-
}, markDirty);
|
|
463
|
+
retrack(recompute, markDirty);
|
|
458
464
|
if (!Object.is(prev, cs._v)) cs.__v++;
|
|
459
465
|
} finally {
|
|
460
466
|
evaluating = false;
|
|
461
|
-
if (threw) cs._d = true;
|
|
462
467
|
}
|
|
463
468
|
}
|
|
464
469
|
return cs._v;
|
|
@@ -467,18 +472,11 @@ function derived(getter, options) {
|
|
|
467
472
|
if (cs._d) {
|
|
468
473
|
const oldValue = cs._v;
|
|
469
474
|
evaluating = true;
|
|
470
|
-
let threw = true;
|
|
471
475
|
try {
|
|
472
|
-
retrack(
|
|
473
|
-
const next = getter();
|
|
474
|
-
cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
|
|
475
|
-
cs._d = false;
|
|
476
|
-
threw = false;
|
|
477
|
-
}, markDirty);
|
|
476
|
+
retrack(recompute, markDirty);
|
|
478
477
|
if (!Object.is(oldValue, cs._v)) cs.__v++;
|
|
479
478
|
} finally {
|
|
480
479
|
evaluating = false;
|
|
481
|
-
if (threw) cs._d = true;
|
|
482
480
|
}
|
|
483
481
|
if (hook && oldValue !== cs._v) {
|
|
484
482
|
hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
@@ -499,11 +497,15 @@ function derived(getter, options) {
|
|
|
499
497
|
var als = null;
|
|
500
498
|
try {
|
|
501
499
|
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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");
|
|
506
507
|
}
|
|
508
|
+
if (mod) als = new mod.AsyncLocalStorage();
|
|
507
509
|
}
|
|
508
510
|
} catch {
|
|
509
511
|
als = null;
|
|
@@ -519,6 +521,17 @@ function getSSRStore() {
|
|
|
519
521
|
function isSSR() {
|
|
520
522
|
return getSSRStore().ssr;
|
|
521
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
|
+
}
|
|
522
535
|
|
|
523
536
|
// src/core/signals/effect.ts
|
|
524
537
|
var _g = globalThis;
|
|
@@ -605,6 +618,7 @@ function effect(effectFn, options) {
|
|
|
605
618
|
ctx.fn(ctx.onCleanup);
|
|
606
619
|
};
|
|
607
620
|
const sub = (() => {
|
|
621
|
+
if (ctx.disposed) return;
|
|
608
622
|
if (ctx.running) {
|
|
609
623
|
ctx.rerunPending = true;
|
|
610
624
|
return;
|
|
@@ -801,9 +815,12 @@ async function withRetry(fn, options, onRetry, signal2) {
|
|
|
801
815
|
}
|
|
802
816
|
|
|
803
817
|
// src/data/query.ts
|
|
804
|
-
var
|
|
805
|
-
function
|
|
806
|
-
|
|
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);
|
|
807
824
|
if (!entry) {
|
|
808
825
|
entry = {
|
|
809
826
|
data: initialData,
|
|
@@ -815,7 +832,7 @@ function getOrCreateEntry(key, initialData) {
|
|
|
815
832
|
listeners: /* @__PURE__ */ new Set(),
|
|
816
833
|
refetchers: /* @__PURE__ */ new Set()
|
|
817
834
|
};
|
|
818
|
-
|
|
835
|
+
cache.set(key, entry);
|
|
819
836
|
}
|
|
820
837
|
return entry;
|
|
821
838
|
}
|
|
@@ -835,6 +852,7 @@ function query(key, fetcher, options = {}) {
|
|
|
835
852
|
select
|
|
836
853
|
} = options;
|
|
837
854
|
const resolveKey = typeof key === "function" ? key : () => key;
|
|
855
|
+
const cache = getActiveQueryCache();
|
|
838
856
|
const [data, setData] = signal(initialData);
|
|
839
857
|
const [isFetching, setIsFetching] = signal(false);
|
|
840
858
|
const [error, setError] = signal(void 0);
|
|
@@ -846,16 +864,16 @@ function query(key, fetcher, options = {}) {
|
|
|
846
864
|
const isStale = derived(() => {
|
|
847
865
|
data();
|
|
848
866
|
if (!currentKey) return true;
|
|
849
|
-
const entry =
|
|
867
|
+
const entry = cache.get(currentKey);
|
|
850
868
|
if (!entry || entry.dataUpdatedAt === 0) return true;
|
|
851
869
|
return Date.now() - entry.dataUpdatedAt >= staleTime;
|
|
852
870
|
});
|
|
853
871
|
async function doFetch() {
|
|
854
872
|
if (disposed || !currentKey || !enabled) return;
|
|
855
873
|
const key2 = currentKey;
|
|
856
|
-
let entry =
|
|
874
|
+
let entry = cache.get(key2);
|
|
857
875
|
if (!entry) {
|
|
858
|
-
entry = getOrCreateEntry(key2);
|
|
876
|
+
entry = getOrCreateEntry(cache, key2);
|
|
859
877
|
entry.listeners.add(onCacheUpdate);
|
|
860
878
|
entry.refetchers.add(doFetch);
|
|
861
879
|
}
|
|
@@ -930,7 +948,7 @@ function query(key, fetcher, options = {}) {
|
|
|
930
948
|
}
|
|
931
949
|
function onCacheUpdate() {
|
|
932
950
|
if (disposed || !currentKey) return;
|
|
933
|
-
const entry =
|
|
951
|
+
const entry = cache.get(currentKey);
|
|
934
952
|
if (!entry) {
|
|
935
953
|
batch(() => {
|
|
936
954
|
setData(void 0);
|
|
@@ -950,7 +968,7 @@ function query(key, fetcher, options = {}) {
|
|
|
950
968
|
const effectCleanup = effect(() => {
|
|
951
969
|
const key2 = resolveKey();
|
|
952
970
|
if (currentKey !== null && currentKey !== key2) {
|
|
953
|
-
const oldEntry =
|
|
971
|
+
const oldEntry = cache.get(currentKey);
|
|
954
972
|
if (oldEntry) {
|
|
955
973
|
oldEntry.listeners.delete(onCacheUpdate);
|
|
956
974
|
oldEntry.refetchers.delete(doFetch);
|
|
@@ -958,13 +976,13 @@ function query(key, fetcher, options = {}) {
|
|
|
958
976
|
if (oldEntry.subscribers <= 0 && cacheTime >= 0) {
|
|
959
977
|
const oldKey = currentKey;
|
|
960
978
|
if (oldEntry.gcTimer !== null) clearTimeout(oldEntry.gcTimer);
|
|
961
|
-
oldEntry.gcTimer = setTimeout(() =>
|
|
979
|
+
oldEntry.gcTimer = setTimeout(() => cache.delete(oldKey), cacheTime);
|
|
962
980
|
}
|
|
963
981
|
}
|
|
964
982
|
}
|
|
965
983
|
const keyChanged = currentKey !== key2;
|
|
966
984
|
currentKey = key2;
|
|
967
|
-
const entry = getOrCreateEntry(key2, initialData);
|
|
985
|
+
const entry = getOrCreateEntry(cache, key2, initialData);
|
|
968
986
|
if (keyChanged) entry.subscribers++;
|
|
969
987
|
if (entry.gcTimer !== null) {
|
|
970
988
|
clearTimeout(entry.gcTimer);
|
|
@@ -1018,7 +1036,7 @@ function query(key, fetcher, options = {}) {
|
|
|
1018
1036
|
effectCleanup();
|
|
1019
1037
|
if (intervalTimer) clearInterval(intervalTimer);
|
|
1020
1038
|
if (currentKey) {
|
|
1021
|
-
const entry =
|
|
1039
|
+
const entry = cache.get(currentKey);
|
|
1022
1040
|
if (entry) {
|
|
1023
1041
|
entry.listeners.delete(onCacheUpdate);
|
|
1024
1042
|
entry.refetchers.delete(doFetch);
|
|
@@ -1026,7 +1044,7 @@ function query(key, fetcher, options = {}) {
|
|
|
1026
1044
|
if (entry.subscribers <= 0 && cacheTime >= 0) {
|
|
1027
1045
|
const key2 = currentKey;
|
|
1028
1046
|
if (entry.gcTimer !== null) clearTimeout(entry.gcTimer);
|
|
1029
|
-
entry.gcTimer = setTimeout(() =>
|
|
1047
|
+
entry.gcTimer = setTimeout(() => cache.delete(key2), cacheTime);
|
|
1030
1048
|
}
|
|
1031
1049
|
}
|
|
1032
1050
|
}
|
|
@@ -1049,7 +1067,7 @@ function query(key, fetcher, options = {}) {
|
|
|
1049
1067
|
}
|
|
1050
1068
|
function invalidateQueries(keyOrPredicate) {
|
|
1051
1069
|
const predicate = typeof keyOrPredicate === "function" ? keyOrPredicate : (k) => k === keyOrPredicate;
|
|
1052
|
-
for (const [key, entry] of
|
|
1070
|
+
for (const [key, entry] of getActiveQueryCache().entries()) {
|
|
1053
1071
|
if (predicate(key)) {
|
|
1054
1072
|
entry.dataUpdatedAt = 0;
|
|
1055
1073
|
for (const refetcher of entry.refetchers) refetcher();
|
|
@@ -1057,10 +1075,10 @@ function invalidateQueries(keyOrPredicate) {
|
|
|
1057
1075
|
}
|
|
1058
1076
|
}
|
|
1059
1077
|
function getQueryData(key) {
|
|
1060
|
-
return
|
|
1078
|
+
return getActiveQueryCache().get(key)?.data;
|
|
1061
1079
|
}
|
|
1062
1080
|
function setQueryData(key, data) {
|
|
1063
|
-
const entry =
|
|
1081
|
+
const entry = getActiveQueryCache().get(key);
|
|
1064
1082
|
if (!entry) return;
|
|
1065
1083
|
const newData = typeof data === "function" ? data(entry.data) : data;
|
|
1066
1084
|
entry.data = newData;
|
|
@@ -1070,14 +1088,15 @@ function setQueryData(key, data) {
|
|
|
1070
1088
|
function clearQueryCache() {
|
|
1071
1089
|
const activeListeners = [];
|
|
1072
1090
|
const activeRefetchers = [];
|
|
1073
|
-
|
|
1091
|
+
const activeCache = getActiveQueryCache();
|
|
1092
|
+
for (const entry of activeCache.values()) {
|
|
1074
1093
|
if (entry.gcTimer) clearTimeout(entry.gcTimer);
|
|
1075
1094
|
if (entry.subscribers > 0) {
|
|
1076
1095
|
for (const listener of entry.listeners) activeListeners.push(listener);
|
|
1077
1096
|
for (const refetcher of entry.refetchers) activeRefetchers.push(refetcher);
|
|
1078
1097
|
}
|
|
1079
1098
|
}
|
|
1080
|
-
|
|
1099
|
+
activeCache.clear();
|
|
1081
1100
|
for (const listener of activeListeners) listener();
|
|
1082
1101
|
for (const refetcher of activeRefetchers) {
|
|
1083
1102
|
refetcher().catch((err) => {
|
|
@@ -1088,10 +1107,11 @@ function clearQueryCache() {
|
|
|
1088
1107
|
}
|
|
1089
1108
|
}
|
|
1090
1109
|
function __resetQueryCache() {
|
|
1091
|
-
|
|
1110
|
+
const activeCache = getActiveQueryCache();
|
|
1111
|
+
for (const entry of activeCache.values()) {
|
|
1092
1112
|
if (entry.gcTimer) clearTimeout(entry.gcTimer);
|
|
1093
1113
|
}
|
|
1094
|
-
|
|
1114
|
+
activeCache.clear();
|
|
1095
1115
|
}
|
|
1096
1116
|
|
|
1097
1117
|
// src/data/mutation.ts
|
|
@@ -1103,7 +1123,11 @@ function mutation(mutationFn, options = {}) {
|
|
|
1103
1123
|
const isSuccess = derived(() => status() === "success");
|
|
1104
1124
|
const isIdle = derived(() => status() === "idle");
|
|
1105
1125
|
let runId = 0;
|
|
1126
|
+
let abortController = null;
|
|
1106
1127
|
async function execute(variables) {
|
|
1128
|
+
abortController?.abort();
|
|
1129
|
+
abortController = new AbortController();
|
|
1130
|
+
const signal2 = abortController.signal;
|
|
1107
1131
|
const myRun = ++runId;
|
|
1108
1132
|
let context2;
|
|
1109
1133
|
batch(() => {
|
|
@@ -1115,7 +1139,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
1115
1139
|
if (options.onMutate) {
|
|
1116
1140
|
context2 = await options.onMutate(variables);
|
|
1117
1141
|
}
|
|
1118
|
-
const result = await withRetry(() => mutationFn(variables), options.retry);
|
|
1142
|
+
const result = await withRetry(() => mutationFn(variables, signal2), options.retry, void 0, signal2);
|
|
1119
1143
|
if (myRun !== runId) return result;
|
|
1120
1144
|
batch(() => {
|
|
1121
1145
|
setData(result);
|
|
@@ -1127,6 +1151,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
1127
1151
|
return result;
|
|
1128
1152
|
} catch (err) {
|
|
1129
1153
|
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
1154
|
+
if (errorObj instanceof DOMException && errorObj.name === "AbortError") throw errorObj;
|
|
1130
1155
|
if (myRun !== runId) throw errorObj;
|
|
1131
1156
|
batch(() => {
|
|
1132
1157
|
setError(errorObj);
|
|
@@ -1140,6 +1165,8 @@ function mutation(mutationFn, options = {}) {
|
|
|
1140
1165
|
}
|
|
1141
1166
|
function reset() {
|
|
1142
1167
|
runId++;
|
|
1168
|
+
abortController?.abort();
|
|
1169
|
+
abortController = null;
|
|
1143
1170
|
batch(() => {
|
|
1144
1171
|
setData(void 0);
|
|
1145
1172
|
setError(void 0);
|
|
@@ -1155,6 +1182,7 @@ function mutation(mutationFn, options = {}) {
|
|
|
1155
1182
|
isIdle,
|
|
1156
1183
|
mutate: (variables) => {
|
|
1157
1184
|
execute(variables).catch((err) => {
|
|
1185
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
1158
1186
|
if (typeof console !== "undefined") {
|
|
1159
1187
|
console.warn("[SibuJS mutation] mutate() failed; check `.error()` signal or onError option.", err);
|
|
1160
1188
|
}
|
|
@@ -1171,6 +1199,7 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1171
1199
|
getNextPageParam,
|
|
1172
1200
|
getPreviousPageParam,
|
|
1173
1201
|
initialPageParam = 0,
|
|
1202
|
+
maxPages,
|
|
1174
1203
|
enabled = true,
|
|
1175
1204
|
retry: retryOptions,
|
|
1176
1205
|
onSuccess,
|
|
@@ -1194,8 +1223,9 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1194
1223
|
let abortController = null;
|
|
1195
1224
|
let disposed = false;
|
|
1196
1225
|
let runId = 0;
|
|
1197
|
-
|
|
1198
|
-
|
|
1226
|
+
let inFlight = null;
|
|
1227
|
+
function fetchPage(pageParam, direction) {
|
|
1228
|
+
if (disposed) return Promise.resolve();
|
|
1199
1229
|
abortController?.abort();
|
|
1200
1230
|
abortController = new AbortController();
|
|
1201
1231
|
const signal2 = abortController.signal;
|
|
@@ -1206,39 +1236,44 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1206
1236
|
if (direction === "prev") setIsFetchingPrev(true);
|
|
1207
1237
|
setError(void 0);
|
|
1208
1238
|
});
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
newPages
|
|
1216
|
-
|
|
1217
|
-
|
|
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);
|
|
1218
1270
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
setIsFetching(false);
|
|
1226
|
-
setIsFetchingNext(false);
|
|
1227
|
-
setIsFetchingPrev(false);
|
|
1228
|
-
});
|
|
1229
|
-
onSuccess?.(newPages);
|
|
1230
|
-
} catch (err) {
|
|
1231
|
-
if (disposed || myRun !== runId) return;
|
|
1232
|
-
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
1233
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
1234
|
-
batch(() => {
|
|
1235
|
-
setError(errorObj);
|
|
1236
|
-
setIsFetching(false);
|
|
1237
|
-
setIsFetchingNext(false);
|
|
1238
|
-
setIsFetchingPrev(false);
|
|
1239
|
-
});
|
|
1240
|
-
onError?.(errorObj);
|
|
1241
|
-
}
|
|
1271
|
+
})();
|
|
1272
|
+
inFlight = promise;
|
|
1273
|
+
void promise.finally(() => {
|
|
1274
|
+
if (inFlight === promise) inFlight = null;
|
|
1275
|
+
});
|
|
1276
|
+
return promise;
|
|
1242
1277
|
}
|
|
1243
1278
|
const effectCleanup = effect(() => {
|
|
1244
1279
|
resolveKey();
|
|
@@ -1253,11 +1288,13 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1253
1288
|
}
|
|
1254
1289
|
});
|
|
1255
1290
|
function fetchNextPage() {
|
|
1291
|
+
if (inFlight) return inFlight;
|
|
1256
1292
|
const param = nextPageParam();
|
|
1257
1293
|
if (param === void 0) return Promise.resolve();
|
|
1258
1294
|
return fetchPage(param, "next");
|
|
1259
1295
|
}
|
|
1260
1296
|
function fetchPreviousPage() {
|
|
1297
|
+
if (inFlight) return inFlight;
|
|
1261
1298
|
const param = prevPageParam();
|
|
1262
1299
|
if (param === void 0) return Promise.resolve();
|
|
1263
1300
|
return fetchPage(param, "prev");
|
|
@@ -1296,13 +1333,17 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
1296
1333
|
function previous(getter) {
|
|
1297
1334
|
const [previous2, setPrevious] = signal(void 0);
|
|
1298
1335
|
let current = getter();
|
|
1299
|
-
effect(() => {
|
|
1336
|
+
const stop = effect(() => {
|
|
1300
1337
|
const next = getter();
|
|
1301
1338
|
if (!Object.is(next, current)) {
|
|
1302
1339
|
setPrevious(current);
|
|
1303
1340
|
current = next;
|
|
1304
1341
|
}
|
|
1305
1342
|
});
|
|
1343
|
+
Object.defineProperty(previous2, "dispose", {
|
|
1344
|
+
value: stop,
|
|
1345
|
+
enumerable: false
|
|
1346
|
+
});
|
|
1306
1347
|
return previous2;
|
|
1307
1348
|
}
|
|
1308
1349
|
|
|
@@ -1310,7 +1351,7 @@ function previous(getter) {
|
|
|
1310
1351
|
function debounce(getter, delay) {
|
|
1311
1352
|
const [debounced, setDebounced] = signal(getter());
|
|
1312
1353
|
let timer = null;
|
|
1313
|
-
effect(() => {
|
|
1354
|
+
const stop = effect(() => {
|
|
1314
1355
|
const value = getter();
|
|
1315
1356
|
if (timer !== null) clearTimeout(timer);
|
|
1316
1357
|
timer = setTimeout(() => {
|
|
@@ -1318,6 +1359,16 @@ function debounce(getter, delay) {
|
|
|
1318
1359
|
timer = null;
|
|
1319
1360
|
}, delay);
|
|
1320
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
|
+
});
|
|
1321
1372
|
return debounced;
|
|
1322
1373
|
}
|
|
1323
1374
|
|
|
@@ -1327,7 +1378,8 @@ function throttle(getter, interval) {
|
|
|
1327
1378
|
let cooldown = false;
|
|
1328
1379
|
let pending = null;
|
|
1329
1380
|
let lastEmitted = getter();
|
|
1330
|
-
|
|
1381
|
+
let timer = null;
|
|
1382
|
+
const stop = effect(() => {
|
|
1331
1383
|
const value = getter();
|
|
1332
1384
|
if (!cooldown) {
|
|
1333
1385
|
if (!Object.is(value, lastEmitted)) {
|
|
@@ -1335,7 +1387,8 @@ function throttle(getter, interval) {
|
|
|
1335
1387
|
lastEmitted = value;
|
|
1336
1388
|
cooldown = true;
|
|
1337
1389
|
pending = null;
|
|
1338
|
-
setTimeout(() => {
|
|
1390
|
+
timer = setTimeout(() => {
|
|
1391
|
+
timer = null;
|
|
1339
1392
|
cooldown = false;
|
|
1340
1393
|
if (pending !== null) {
|
|
1341
1394
|
const trailingValue = pending.value;
|
|
@@ -1349,6 +1402,16 @@ function throttle(getter, interval) {
|
|
|
1349
1402
|
pending = { value };
|
|
1350
1403
|
}
|
|
1351
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
|
+
});
|
|
1352
1415
|
return throttled;
|
|
1353
1416
|
}
|
|
1354
1417
|
|
|
@@ -1477,28 +1540,45 @@ function idbGet(db, store, key) {
|
|
|
1477
1540
|
req.onerror = () => reject(req.error);
|
|
1478
1541
|
});
|
|
1479
1542
|
}
|
|
1480
|
-
function idbPut(db, store, item) {
|
|
1543
|
+
function idbPut(db, store, item, key) {
|
|
1481
1544
|
return new Promise((resolve, reject) => {
|
|
1482
1545
|
const tx = db.transaction(store, "readwrite");
|
|
1483
|
-
tx.objectStore(store).put(item);
|
|
1546
|
+
if (key !== void 0) tx.objectStore(store).put(item, key);
|
|
1547
|
+
else tx.objectStore(store).put(item);
|
|
1484
1548
|
tx.oncomplete = () => resolve();
|
|
1485
1549
|
tx.onerror = () => reject(tx.error);
|
|
1486
1550
|
});
|
|
1487
1551
|
}
|
|
1488
|
-
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) {
|
|
1489
1569
|
return new Promise((resolve, reject) => {
|
|
1490
1570
|
const tx = db.transaction(["items", "_changes"], "readwrite");
|
|
1491
1571
|
tx.objectStore("items").put(item);
|
|
1492
|
-
tx
|
|
1572
|
+
coalesceAndAddChange(tx, change, keyPath);
|
|
1493
1573
|
tx.oncomplete = () => resolve();
|
|
1494
1574
|
tx.onerror = () => reject(tx.error);
|
|
1495
1575
|
});
|
|
1496
1576
|
}
|
|
1497
|
-
function idbDeleteWithChange(db, key, change) {
|
|
1577
|
+
function idbDeleteWithChange(db, key, change, keyPath) {
|
|
1498
1578
|
return new Promise((resolve, reject) => {
|
|
1499
1579
|
const tx = db.transaction(["items", "_changes"], "readwrite");
|
|
1500
1580
|
tx.objectStore("items").delete(key);
|
|
1501
|
-
tx
|
|
1581
|
+
coalesceAndAddChange(tx, change, keyPath);
|
|
1502
1582
|
tx.oncomplete = () => resolve();
|
|
1503
1583
|
tx.onerror = () => reject(tx.error);
|
|
1504
1584
|
});
|
|
@@ -1558,13 +1638,18 @@ async function offlineStore(options) {
|
|
|
1558
1638
|
setPendingCount(changes.length);
|
|
1559
1639
|
}
|
|
1560
1640
|
async function put(item) {
|
|
1561
|
-
await idbPutWithChange(db, item, { type: "put", item, timestamp: Date.now() });
|
|
1641
|
+
await idbPutWithChange(db, item, { type: "put", item, timestamp: Date.now() }, keyPath);
|
|
1562
1642
|
await refreshData();
|
|
1563
1643
|
}
|
|
1564
1644
|
async function remove(key) {
|
|
1565
1645
|
const existing = await idbGet(db, "items", key);
|
|
1566
1646
|
if (existing) {
|
|
1567
|
-
await idbDeleteWithChange(
|
|
1647
|
+
await idbDeleteWithChange(
|
|
1648
|
+
db,
|
|
1649
|
+
key,
|
|
1650
|
+
{ type: "delete", item: existing, timestamp: Date.now() },
|
|
1651
|
+
keyPath
|
|
1652
|
+
);
|
|
1568
1653
|
await refreshData();
|
|
1569
1654
|
}
|
|
1570
1655
|
}
|
|
@@ -1590,6 +1675,8 @@ async function offlineStore(options) {
|
|
|
1590
1675
|
snapshot.map((e) => e.key)
|
|
1591
1676
|
);
|
|
1592
1677
|
if (closed) return;
|
|
1678
|
+
} else if (typeof console !== "undefined") {
|
|
1679
|
+
console.warn(`[offlineStore] push rejected by adapter${result.error ? `: ${result.error}` : ""}`);
|
|
1593
1680
|
}
|
|
1594
1681
|
}
|
|
1595
1682
|
const remoteItems = await adapter.pull(lastSynced());
|
|
@@ -1608,7 +1695,7 @@ async function offlineStore(options) {
|
|
|
1608
1695
|
await idbPutMany(db, "items", safeRemote);
|
|
1609
1696
|
if (closed) return;
|
|
1610
1697
|
const now = Date.now();
|
|
1611
|
-
await idbPut(db, "_meta", now);
|
|
1698
|
+
await idbPut(db, "_meta", now, "lastSynced");
|
|
1612
1699
|
if (closed) return;
|
|
1613
1700
|
setLastSynced(now);
|
|
1614
1701
|
await refreshData();
|
|
@@ -1707,14 +1794,20 @@ function loaderData() {
|
|
|
1707
1794
|
async function preloadRoute(route, context2, callerSignal) {
|
|
1708
1795
|
if (!route.loader) return void 0;
|
|
1709
1796
|
const controller = new AbortController();
|
|
1797
|
+
let onAbort = null;
|
|
1710
1798
|
if (callerSignal) {
|
|
1711
1799
|
if (callerSignal.aborted) {
|
|
1712
1800
|
controller.abort();
|
|
1713
1801
|
} else {
|
|
1714
|
-
|
|
1802
|
+
onAbort = () => controller.abort();
|
|
1803
|
+
callerSignal.addEventListener("abort", onAbort, { once: true });
|
|
1715
1804
|
}
|
|
1716
1805
|
}
|
|
1717
|
-
|
|
1806
|
+
try {
|
|
1807
|
+
return await route.loader(context2, { signal: controller.signal });
|
|
1808
|
+
} finally {
|
|
1809
|
+
if (onAbort) callerSignal?.removeEventListener("abort", onAbort);
|
|
1810
|
+
}
|
|
1718
1811
|
}
|
|
1719
1812
|
|
|
1720
1813
|
// src/ui/socket.ts
|
|
@@ -1820,9 +1913,12 @@ function socket(url, options) {
|
|
|
1820
1913
|
}
|
|
1821
1914
|
|
|
1822
1915
|
// src/utils/sanitize.ts
|
|
1916
|
+
function stripControlChars(value) {
|
|
1917
|
+
return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
|
|
1918
|
+
}
|
|
1823
1919
|
var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
1824
1920
|
function sanitizeUrl(url) {
|
|
1825
|
-
const trimmed = url
|
|
1921
|
+
const trimmed = stripControlChars(url).trim();
|
|
1826
1922
|
if (!trimmed) return "";
|
|
1827
1923
|
const lower = trimmed.toLowerCase();
|
|
1828
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 */
|