sibujs 3.4.0 → 4.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/LICENSE +21 -21
- package/README.md +118 -15
- package/dist/browser.cjs +410 -101
- package/dist/browser.d.cts +50 -5
- package/dist/browser.d.ts +50 -5
- package/dist/browser.js +8 -6
- package/dist/build.cjs +777 -385
- package/dist/build.js +15 -15
- package/dist/cdn.global.js +11 -7
- package/dist/{chunk-JCO7AHNU.js → chunk-3EKJK5FZ.js} +73 -34
- package/dist/chunk-4MFZMLUU.js +147 -0
- package/dist/chunk-52XFPGSN.js +123 -0
- package/dist/chunk-5INI7D2L.js +194 -0
- package/dist/{chunk-OAVXAFAY.js → chunk-6LG2T7LO.js} +5 -5
- package/dist/{chunk-OOUQUCNN.js → chunk-ACBT6UZS.js} +57 -22
- package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
- package/dist/chunk-DHDZ7IVN.js +109 -0
- package/dist/{chunk-JNGGM2XE.js → chunk-DQVUBVNX.js} +16 -25
- package/dist/{chunk-AXFWGY32.js → chunk-DR7H6UGM.js} +232 -67
- package/dist/{chunk-WSGLJYFI.js → chunk-E62UADKL.js} +9 -3
- package/dist/{chunk-3Z2NGWQI.js → chunk-ES2GERY2.js} +1 -1
- package/dist/{chunk-S3V6ZXPI.js → chunk-EWEE7NBF.js} +115 -41
- package/dist/{chunk-3DVGCW7O.js → chunk-F64ZPCFE.js} +8 -8
- package/dist/{chunk-APFRCIRI.js → chunk-GCSGGA3Q.js} +295 -198
- package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
- package/dist/{chunk-ELXMRSVN.js → chunk-NF3LYCQH.js} +259 -124
- package/dist/chunk-O3QQ3XOL.js +61 -0
- package/dist/{chunk-BUKYCWHX.js → chunk-PBQEW5VW.js} +14 -10
- package/dist/{chunk-H5FI5WDP.js → chunk-RRIDJQ5C.js} +3 -3
- package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
- package/dist/{chunk-ODXVQ3CS.js → chunk-VFHIVEPF.js} +309 -188
- package/dist/chunk-VPP2FONR.js +142 -0
- package/dist/{chunk-KZBEVFXZ.js → chunk-W55YHPEP.js} +5 -3
- package/dist/{chunk-FKQG7FTY.js → chunk-WN6WDFCB.js} +4 -4
- package/dist/{chunk-CEBWDD63.js → chunk-WOOMUJFT.js} +228 -86
- package/dist/{chunk-ITWCTZYH.js → chunk-Z2CE42DB.js} +19 -25
- package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.cts} +6 -6
- package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.ts} +6 -6
- package/dist/{customElement-CPfIrbvg.d.ts → customElement-CKLoO63w.d.cts} +73 -11
- package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.ts} +73 -11
- package/dist/data.cjs +483 -205
- package/dist/data.d.cts +139 -7
- package/dist/data.d.ts +139 -7
- package/dist/data.js +9 -9
- package/dist/devtools.cjs +222 -87
- package/dist/devtools.js +8 -8
- package/dist/dispose-4FZ6OFXR.js +19 -0
- package/dist/ecosystem.cjs +419 -175
- package/dist/ecosystem.js +11 -11
- package/dist/extras.cjs +1981 -765
- package/dist/extras.d.cts +7 -7
- package/dist/extras.d.ts +7 -7
- package/dist/extras.js +29 -26
- package/dist/index.cjs +784 -385
- package/dist/index.d.cts +299 -28
- package/dist/index.d.ts +299 -28
- package/dist/index.js +33 -18
- package/dist/motion.cjs +180 -50
- package/dist/motion.d.cts +26 -0
- package/dist/motion.d.ts +26 -0
- package/dist/motion.js +5 -5
- package/dist/patterns.cjs +437 -170
- package/dist/patterns.d.cts +60 -13
- package/dist/patterns.d.ts +60 -13
- package/dist/patterns.js +7 -7
- package/dist/performance.cjs +333 -148
- package/dist/performance.d.cts +55 -7
- package/dist/performance.d.ts +55 -7
- package/dist/performance.js +9 -9
- package/dist/plugins.cjs +1374 -576
- package/dist/plugins.d.cts +227 -9
- package/dist/plugins.d.ts +227 -9
- package/dist/plugins.js +613 -321
- package/dist/{ssr-D62yFwuw.d.cts → ssr-BiPRdZ6n.d.cts} +44 -15
- package/dist/{ssr-D62yFwuw.d.ts → ssr-BiPRdZ6n.d.ts} +44 -15
- package/dist/{ssr-2PPULEK2.js → ssr-JFP5535P.js} +5 -4
- package/dist/ssr.cjs +1104 -443
- package/dist/ssr.d.cts +230 -20
- package/dist/ssr.d.ts +230 -20
- package/dist/ssr.js +15 -12
- package/dist/{startup-0Qv6aosO.d.cts → startup-BMpaiMhP.d.cts} +1 -1
- package/dist/{startup-0Qv6aosO.d.ts → startup-BMpaiMhP.d.ts} +1 -1
- package/dist/testing.cjs +205 -63
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +8 -10
- package/dist/ui.cjs +640 -199
- package/dist/ui.d.cts +2 -2
- package/dist/ui.d.ts +2 -2
- package/dist/ui.js +10 -10
- package/dist/widgets.cjs +207 -82
- package/dist/widgets.js +9 -9
- package/package.json +12 -7
- package/dist/chunk-5VGSK6D2.js +0 -80
- package/dist/chunk-COY6PUD2.js +0 -34
- package/dist/chunk-K35BAR4P.js +0 -96
- package/dist/chunk-L3GAGWCC.js +0 -111
- package/dist/chunk-RT3IYFN2.js +0 -38
package/dist/performance.cjs
CHANGED
|
@@ -252,8 +252,95 @@ function devWarn(message) {
|
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
+
// src/core/errors.ts
|
|
256
|
+
var ERROR_STATE_KEY = /* @__PURE__ */ Symbol.for("sibujs.runtime-errors.v1");
|
|
257
|
+
function state() {
|
|
258
|
+
const g = globalThis;
|
|
259
|
+
const existing = g[ERROR_STATE_KEY];
|
|
260
|
+
if (existing) return existing;
|
|
261
|
+
const created = { handler: null, handlerDepth: 0 };
|
|
262
|
+
g[ERROR_STATE_KEY] = created;
|
|
263
|
+
return created;
|
|
264
|
+
}
|
|
265
|
+
function normalizeError(value) {
|
|
266
|
+
if (value instanceof Error) return value;
|
|
267
|
+
const message = typeof value === "string" ? value : `Non-Error value thrown: ${safeStringify(value)}`;
|
|
268
|
+
return new Error(message, { cause: value });
|
|
269
|
+
}
|
|
270
|
+
function safeStringify(value) {
|
|
271
|
+
if (typeof value === "symbol") return value.toString();
|
|
272
|
+
try {
|
|
273
|
+
return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
|
|
274
|
+
} catch {
|
|
275
|
+
return Object.prototype.toString.call(value);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function describe(context) {
|
|
279
|
+
return context.name ? `${context.phase} "${context.name}"` : context.phase;
|
|
280
|
+
}
|
|
281
|
+
var REACTIVE_REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
282
|
+
function untrackedRun(fn) {
|
|
283
|
+
const api = globalThis[REACTIVE_REGISTRY_KEY];
|
|
284
|
+
return api?.untracked ? api.untracked(fn) : fn();
|
|
285
|
+
}
|
|
286
|
+
var PROPAGATE_EVENT = "sibu:error-propagate";
|
|
287
|
+
function claimedByBoundary(error, context) {
|
|
288
|
+
const raw = context.node;
|
|
289
|
+
if (!raw || typeof CustomEvent === "undefined") return false;
|
|
290
|
+
const target = resolveEventTarget(raw);
|
|
291
|
+
if (!target) return false;
|
|
292
|
+
try {
|
|
293
|
+
const event = new CustomEvent(PROPAGATE_EVENT, {
|
|
294
|
+
bubbles: true,
|
|
295
|
+
cancelable: true,
|
|
296
|
+
detail: { error, context }
|
|
297
|
+
});
|
|
298
|
+
return target.dispatchEvent(event) === false;
|
|
299
|
+
} catch {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function resolveEventTarget(node) {
|
|
304
|
+
const ELEMENT_NODE = 1;
|
|
305
|
+
let current = node;
|
|
306
|
+
while (current) {
|
|
307
|
+
if (current.nodeType === ELEMENT_NODE && typeof current.dispatchEvent === "function") {
|
|
308
|
+
return current;
|
|
309
|
+
}
|
|
310
|
+
current = current.parentNode;
|
|
311
|
+
}
|
|
312
|
+
const self = node;
|
|
313
|
+
return typeof self.dispatchEvent === "function" ? self : null;
|
|
314
|
+
}
|
|
315
|
+
function defaultReport(error, context) {
|
|
316
|
+
if (typeof console === "undefined") return;
|
|
317
|
+
console.error(`[SibuJS] Uncaught error during ${describe(context)}: ${error.message}`, error);
|
|
318
|
+
}
|
|
319
|
+
function reportError(error, context) {
|
|
320
|
+
const err = normalizeError(error);
|
|
321
|
+
untrackedRun(() => {
|
|
322
|
+
if (claimedByBoundary(err, context)) return;
|
|
323
|
+
const s = state();
|
|
324
|
+
const handler = s.handler;
|
|
325
|
+
if (handler && s.handlerDepth === 0) {
|
|
326
|
+
s.handlerDepth++;
|
|
327
|
+
try {
|
|
328
|
+
handler(error instanceof Error ? error : err, context);
|
|
329
|
+
return;
|
|
330
|
+
} catch (handlerError) {
|
|
331
|
+
if (typeof console !== "undefined") {
|
|
332
|
+
const detail = handlerError instanceof Error ? handlerError.message : String(handlerError);
|
|
333
|
+
console.error(`[SibuJS] runtime error handler itself threw: ${detail}`, handlerError);
|
|
334
|
+
}
|
|
335
|
+
} finally {
|
|
336
|
+
s.handlerDepth--;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
defaultReport(err, context);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
255
343
|
// src/reactivity/track-core.ts
|
|
256
|
-
var _isDev2 = isDev();
|
|
257
344
|
var POOL_MAX = 4096;
|
|
258
345
|
var nodePool = [];
|
|
259
346
|
function createNode() {
|
|
@@ -261,6 +348,7 @@ function createNode() {
|
|
|
261
348
|
sig: null,
|
|
262
349
|
sub: null,
|
|
263
350
|
epoch: 0,
|
|
351
|
+
depVersion: 0,
|
|
264
352
|
sigPrev: null,
|
|
265
353
|
sigNext: null,
|
|
266
354
|
subPrev: null,
|
|
@@ -345,9 +433,28 @@ function safeInvoke(sub) {
|
|
|
345
433
|
try {
|
|
346
434
|
sub();
|
|
347
435
|
} catch (err) {
|
|
348
|
-
|
|
436
|
+
const s = sub;
|
|
437
|
+
reportError(err, { phase: s._errorPhase ?? "effect", name: s.__name, node: s._errorNode });
|
|
349
438
|
}
|
|
350
439
|
}
|
|
440
|
+
function depsChanged(sub) {
|
|
441
|
+
let node = sub.depsHead ?? null;
|
|
442
|
+
if (node === null) return true;
|
|
443
|
+
while (node !== null) {
|
|
444
|
+
const sig = node.sig;
|
|
445
|
+
if (sig === null) return true;
|
|
446
|
+
if (sig._d === true && sig._validate !== void 0) {
|
|
447
|
+
try {
|
|
448
|
+
sig._validate();
|
|
449
|
+
} catch {
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (node.depVersion !== sig.__v) return true;
|
|
454
|
+
node = node.subNext;
|
|
455
|
+
}
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
351
458
|
var suspendDepth = 0;
|
|
352
459
|
var trackingSuspended = false;
|
|
353
460
|
function suspendTracking() {
|
|
@@ -428,7 +535,7 @@ function track(effectFn, subscriber) {
|
|
|
428
535
|
const sub = subscriber;
|
|
429
536
|
return sub._dispose ?? (sub._dispose = () => cleanup(subscriber));
|
|
430
537
|
}
|
|
431
|
-
function reactiveBinding(commit) {
|
|
538
|
+
function reactiveBinding(commit, ownerNode) {
|
|
432
539
|
const run = () => {
|
|
433
540
|
const s = subscriber;
|
|
434
541
|
if (s._disposed || s._reentrant) return;
|
|
@@ -444,13 +551,17 @@ function reactiveBinding(commit) {
|
|
|
444
551
|
subscriber.depsTail = null;
|
|
445
552
|
subscriber._epoch = 0;
|
|
446
553
|
subscriber._structDirty = false;
|
|
554
|
+
subscriber._hasComputedDep = false;
|
|
447
555
|
subscriber._runEpoch = 0;
|
|
448
556
|
subscriber._runs = 0;
|
|
449
557
|
subscriber._reentrant = false;
|
|
450
558
|
subscriber._disposed = false;
|
|
559
|
+
subscriber._errorPhase = "binding";
|
|
560
|
+
subscriber._errorNode = ownerNode;
|
|
451
561
|
run();
|
|
452
562
|
return subscriber._dispose ?? (subscriber._dispose = () => {
|
|
453
563
|
subscriber._disposed = true;
|
|
564
|
+
subscriber._errorNode = void 0;
|
|
454
565
|
cleanup(subscriber);
|
|
455
566
|
});
|
|
456
567
|
}
|
|
@@ -462,9 +573,12 @@ function recordDependency(signal2) {
|
|
|
462
573
|
const active = sig.__activeNode ?? null;
|
|
463
574
|
if (active !== null && active.sub === sub) {
|
|
464
575
|
active.epoch = epoch;
|
|
576
|
+
active.depVersion = sig.__v ?? Number.NaN;
|
|
465
577
|
return;
|
|
466
578
|
}
|
|
579
|
+
if (sig._validate !== void 0) sub._hasComputedDep = true;
|
|
467
580
|
const node = allocNode(signal2, sub, epoch);
|
|
581
|
+
node.depVersion = sig.__v ?? Number.NaN;
|
|
468
582
|
node.prevActive = active;
|
|
469
583
|
sig.__activeNode = node;
|
|
470
584
|
linkSub(sub, node);
|
|
@@ -483,9 +597,10 @@ function cleanup(subscriber) {
|
|
|
483
597
|
node = next;
|
|
484
598
|
}
|
|
485
599
|
}
|
|
486
|
-
var maxSubscriberRepeats =
|
|
600
|
+
var maxSubscriberRepeats = 1e3;
|
|
487
601
|
var maxDrainIterations = 1e6;
|
|
488
602
|
var drainEpoch = 0;
|
|
603
|
+
var quarantined = /* @__PURE__ */ new Set();
|
|
489
604
|
function setMaxSubscriberRepeats(n) {
|
|
490
605
|
const prev = maxSubscriberRepeats;
|
|
491
606
|
if (Number.isFinite(n) && n > 0) maxSubscriberRepeats = Math.floor(n);
|
|
@@ -507,19 +622,21 @@ function tickRepeat(sub) {
|
|
|
507
622
|
return s._runs > maxSubscriberRepeats;
|
|
508
623
|
}
|
|
509
624
|
function cycleError(sub) {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
`
|
|
514
|
-
)
|
|
515
|
-
|
|
625
|
+
const name = sub.__name ?? "<unnamed>";
|
|
626
|
+
reportError(
|
|
627
|
+
new Error(
|
|
628
|
+
`subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. This subscriber is quarantined for the rest of this update; other pending work still runs.`
|
|
629
|
+
),
|
|
630
|
+
{ phase: "scheduler", name }
|
|
631
|
+
);
|
|
516
632
|
}
|
|
517
633
|
function absoluteDrainError() {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
`
|
|
521
|
-
)
|
|
522
|
-
|
|
634
|
+
reportError(
|
|
635
|
+
new Error(
|
|
636
|
+
`Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
|
|
637
|
+
),
|
|
638
|
+
{ phase: "scheduler" }
|
|
639
|
+
);
|
|
523
640
|
}
|
|
524
641
|
function drainQueue() {
|
|
525
642
|
let i = 0;
|
|
@@ -529,11 +646,14 @@ function drainQueue() {
|
|
|
529
646
|
break;
|
|
530
647
|
}
|
|
531
648
|
const sub = pendingQueue[i++];
|
|
649
|
+
pendingSet.delete(sub);
|
|
650
|
+
if (quarantined.size > 0 && quarantined.has(sub)) continue;
|
|
651
|
+
if (sub._hasComputedDep === true && !depsChanged(sub)) continue;
|
|
532
652
|
if (tickRepeat(sub)) {
|
|
533
653
|
cycleError(sub);
|
|
534
|
-
|
|
654
|
+
quarantined.add(sub);
|
|
655
|
+
continue;
|
|
535
656
|
}
|
|
536
|
-
pendingSet.delete(sub);
|
|
537
657
|
safeInvoke(sub);
|
|
538
658
|
}
|
|
539
659
|
}
|
|
@@ -548,6 +668,7 @@ function drainNotificationQueue() {
|
|
|
548
668
|
if (notifyDepth === 0) {
|
|
549
669
|
pendingQueue.length = 0;
|
|
550
670
|
pendingSet.clear();
|
|
671
|
+
if (quarantined.size > 0) quarantined.clear();
|
|
551
672
|
}
|
|
552
673
|
}
|
|
553
674
|
}
|
|
@@ -641,6 +762,7 @@ function notifySubscribers(signal2) {
|
|
|
641
762
|
if (notifyDepth === 0) {
|
|
642
763
|
pendingQueue.length = 0;
|
|
643
764
|
pendingSet.clear();
|
|
765
|
+
if (quarantined.size > 0) quarantined.clear();
|
|
644
766
|
}
|
|
645
767
|
}
|
|
646
768
|
}
|
|
@@ -667,14 +789,14 @@ function forEachSubscriber(signal2, visit) {
|
|
|
667
789
|
}
|
|
668
790
|
|
|
669
791
|
// src/reactivity/track.ts
|
|
670
|
-
var
|
|
671
|
-
var _runtimeVersion = true ? "
|
|
792
|
+
var _isDev2 = isDev();
|
|
793
|
+
var _runtimeVersion = true ? "4.0.0" : "dev";
|
|
672
794
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
673
795
|
function resolveReactiveApi() {
|
|
674
796
|
const g = globalThis;
|
|
675
797
|
const existing = g[REGISTRY_KEY];
|
|
676
798
|
if (existing) {
|
|
677
|
-
if (
|
|
799
|
+
if (_isDev2 && !existing.__dupWarned) {
|
|
678
800
|
existing.__dupWarned = true;
|
|
679
801
|
devWarn(
|
|
680
802
|
`Multiple instances of the reactive runtime detected on this page (active: ${existing.version}, duplicate: ${_runtimeVersion}). Reactivity still works \u2014 all copies share the first one \u2014 but de-duplicate sibujs in your bundler (e.g. Vite optimizeDeps.exclude: ['sibujs'] or resolve.dedupe: ['sibujs']).`
|
|
@@ -734,20 +856,24 @@ function detectSSRShared() {
|
|
|
734
856
|
const getBuiltin = process.getBuiltinModule;
|
|
735
857
|
if (typeof getBuiltin === "function") {
|
|
736
858
|
mod = getBuiltin("node:async_hooks");
|
|
737
|
-
} else {
|
|
738
|
-
|
|
739
|
-
if (req) mod = req("node:async_hooks");
|
|
859
|
+
} else if (typeof require === "function") {
|
|
860
|
+
mod = require("async_hooks");
|
|
740
861
|
}
|
|
741
862
|
if (mod) detected = new mod.AsyncLocalStorage();
|
|
742
863
|
}
|
|
743
864
|
} catch {
|
|
744
865
|
detected = null;
|
|
745
866
|
}
|
|
746
|
-
return {
|
|
867
|
+
return {
|
|
868
|
+
als: detected,
|
|
869
|
+
fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
|
|
870
|
+
fallbackDepth: 0
|
|
871
|
+
};
|
|
747
872
|
}
|
|
748
873
|
var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
|
|
749
874
|
var als = _shared.als;
|
|
750
875
|
var fallbackStore = _shared.fallbackStore;
|
|
876
|
+
_shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
|
|
751
877
|
function getSSRStore() {
|
|
752
878
|
if (als) {
|
|
753
879
|
const s = als.getStore();
|
|
@@ -770,7 +896,7 @@ function flushUserCleanups(ctx) {
|
|
|
770
896
|
try {
|
|
771
897
|
list[i]();
|
|
772
898
|
} catch (err) {
|
|
773
|
-
|
|
899
|
+
reportError(err, { phase: "cleanup" });
|
|
774
900
|
}
|
|
775
901
|
}
|
|
776
902
|
}
|
|
@@ -783,11 +909,12 @@ function drainReruns(ctx) {
|
|
|
783
909
|
} while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
|
|
784
910
|
if (ctx.rerunPending) {
|
|
785
911
|
ctx.rerunPending = false;
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
`
|
|
789
|
-
)
|
|
790
|
-
|
|
912
|
+
reportError(
|
|
913
|
+
new Error(
|
|
914
|
+
`effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
|
|
915
|
+
),
|
|
916
|
+
{ phase: "effect" }
|
|
917
|
+
);
|
|
791
918
|
}
|
|
792
919
|
}
|
|
793
920
|
function disposeEffect(ctx) {
|
|
@@ -864,6 +991,8 @@ function effect(effectFn, options) {
|
|
|
864
991
|
sub.depsTail = null;
|
|
865
992
|
sub._epoch = 0;
|
|
866
993
|
sub._structDirty = false;
|
|
994
|
+
sub._hasComputedDep = false;
|
|
995
|
+
sub._errorPhase = "effect";
|
|
867
996
|
sub._runEpoch = 0;
|
|
868
997
|
sub._runs = 0;
|
|
869
998
|
ctx.subscriber = sub;
|
|
@@ -932,70 +1061,72 @@ var isBatching = API2.isBatching;
|
|
|
932
1061
|
|
|
933
1062
|
// src/core/signals/signal.ts
|
|
934
1063
|
var _g2 = globalThis;
|
|
935
|
-
var
|
|
1064
|
+
var _isDev3 = isDev();
|
|
936
1065
|
function signal(initial, options) {
|
|
937
|
-
const
|
|
1066
|
+
const state2 = {
|
|
938
1067
|
value: initial,
|
|
939
1068
|
__v: 0,
|
|
940
1069
|
__sc: 0,
|
|
941
1070
|
subsHead: null,
|
|
942
1071
|
subsTail: null,
|
|
943
1072
|
__activeNode: null,
|
|
944
|
-
__name: void 0
|
|
1073
|
+
__name: void 0,
|
|
1074
|
+
_d: false,
|
|
1075
|
+
_validate: void 0
|
|
945
1076
|
};
|
|
946
|
-
const debugName =
|
|
1077
|
+
const debugName = _isDev3 ? options?.name : void 0;
|
|
947
1078
|
const equalsFn = options?.equals;
|
|
948
|
-
if (debugName)
|
|
1079
|
+
if (debugName) state2.__name = debugName;
|
|
949
1080
|
function get() {
|
|
950
|
-
recordDependency2(
|
|
951
|
-
return
|
|
1081
|
+
recordDependency2(state2);
|
|
1082
|
+
return state2.value;
|
|
952
1083
|
}
|
|
953
|
-
get.__signal =
|
|
1084
|
+
get.__signal = state2;
|
|
954
1085
|
if (debugName) get.__name = debugName;
|
|
955
1086
|
let set;
|
|
956
1087
|
if (equalsFn) {
|
|
957
1088
|
set = (next) => {
|
|
958
|
-
const prev =
|
|
1089
|
+
const prev = state2.value;
|
|
959
1090
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
960
1091
|
if (equalsFn(prev, newValue)) return;
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
if (
|
|
1092
|
+
state2.value = newValue;
|
|
1093
|
+
state2.__v++;
|
|
1094
|
+
if (_isDev3) {
|
|
964
1095
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
965
|
-
if (hook) hook.emit("signal:update", { signal:
|
|
1096
|
+
if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
966
1097
|
}
|
|
967
|
-
if (!enqueueBatchedSignal(
|
|
968
|
-
notifySubscribers2(
|
|
1098
|
+
if (!enqueueBatchedSignal(state2)) {
|
|
1099
|
+
notifySubscribers2(state2);
|
|
969
1100
|
}
|
|
970
1101
|
};
|
|
971
|
-
} else if (
|
|
1102
|
+
} else if (_isDev3) {
|
|
972
1103
|
set = (next) => {
|
|
973
|
-
const prev =
|
|
1104
|
+
const prev = state2.value;
|
|
974
1105
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
975
1106
|
if (Object.is(newValue, prev)) return;
|
|
976
|
-
|
|
977
|
-
|
|
1107
|
+
state2.value = newValue;
|
|
1108
|
+
state2.__v++;
|
|
978
1109
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
979
|
-
if (hook) hook.emit("signal:update", { signal:
|
|
980
|
-
if (!enqueueBatchedSignal(
|
|
981
|
-
notifySubscribers2(
|
|
1110
|
+
if (hook) hook.emit("signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
1111
|
+
if (!enqueueBatchedSignal(state2)) {
|
|
1112
|
+
notifySubscribers2(state2);
|
|
982
1113
|
}
|
|
983
1114
|
};
|
|
984
1115
|
} else {
|
|
985
1116
|
set = (next) => {
|
|
986
|
-
const prev =
|
|
1117
|
+
const prev = state2.value;
|
|
987
1118
|
const newValue = typeof next === "function" ? next(prev) : next;
|
|
988
1119
|
if (Object.is(newValue, prev)) return;
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
if (!enqueueBatchedSignal(
|
|
992
|
-
notifySubscribers2(
|
|
1120
|
+
state2.value = newValue;
|
|
1121
|
+
state2.__v++;
|
|
1122
|
+
if (!enqueueBatchedSignal(state2)) {
|
|
1123
|
+
notifySubscribers2(state2);
|
|
993
1124
|
}
|
|
994
1125
|
};
|
|
995
1126
|
}
|
|
996
|
-
if (
|
|
1127
|
+
if (_isDev3) {
|
|
997
1128
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
998
|
-
if (hook) hook.emit("signal:create", { signal:
|
|
1129
|
+
if (hook) hook.emit("signal:create", { signal: state2, name: debugName, getter: get, initial });
|
|
999
1130
|
}
|
|
1000
1131
|
return [get, set];
|
|
1001
1132
|
}
|
|
@@ -1041,15 +1172,84 @@ function uniqueId(suffix) {
|
|
|
1041
1172
|
return suffix ? `${id}-${suffix}` : id;
|
|
1042
1173
|
}
|
|
1043
1174
|
|
|
1175
|
+
// src/core/rendering/dispose.ts
|
|
1176
|
+
var elementDisposers = /* @__PURE__ */ new WeakMap();
|
|
1177
|
+
var MAX_DRAIN_TEARDOWNS = 1e4;
|
|
1178
|
+
function reportDrainRunaway(label, executed, remaining) {
|
|
1179
|
+
if (typeof console === "undefined") return;
|
|
1180
|
+
console.error(
|
|
1181
|
+
`[SibuJS ${label}] runaway cleanup: stopped after running ${executed} teardowns with ${remaining} still queued. Cleanup production did not stabilize before the teardown safety ceiling was reached \u2014 the remaining work was NOT run.`,
|
|
1182
|
+
{ executed, remaining }
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
var _isDev4 = isDev();
|
|
1186
|
+
var activeBindingCount = 0;
|
|
1187
|
+
function dispose(node) {
|
|
1188
|
+
const stack = [node];
|
|
1189
|
+
const order = [];
|
|
1190
|
+
while (stack.length > 0) {
|
|
1191
|
+
const current = stack.pop();
|
|
1192
|
+
order.push(current);
|
|
1193
|
+
const children = Array.from(current.childNodes);
|
|
1194
|
+
for (let i = 0; i < children.length; i++) {
|
|
1195
|
+
stack.push(children[i]);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
for (let i = order.length - 1; i >= 0; i--) {
|
|
1199
|
+
const current = order[i];
|
|
1200
|
+
if (elementDisposers.has(current)) {
|
|
1201
|
+
let executed = 0;
|
|
1202
|
+
let runaway = false;
|
|
1203
|
+
while (!runaway) {
|
|
1204
|
+
const pending = elementDisposers.get(current);
|
|
1205
|
+
if (!pending || pending.length === 0) break;
|
|
1206
|
+
const snapshot = pending.slice();
|
|
1207
|
+
elementDisposers.delete(current);
|
|
1208
|
+
if (_isDev4) activeBindingCount -= snapshot.length;
|
|
1209
|
+
for (let i2 = 0; i2 < snapshot.length; i2++) {
|
|
1210
|
+
if (executed >= MAX_DRAIN_TEARDOWNS) {
|
|
1211
|
+
const rest = snapshot.slice(i2);
|
|
1212
|
+
const added = elementDisposers.get(current);
|
|
1213
|
+
elementDisposers.set(current, added ? rest.concat(added) : rest);
|
|
1214
|
+
if (_isDev4) activeBindingCount += rest.length;
|
|
1215
|
+
reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
|
|
1216
|
+
runaway = true;
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
1219
|
+
executed++;
|
|
1220
|
+
try {
|
|
1221
|
+
snapshot[i2]();
|
|
1222
|
+
} catch (err) {
|
|
1223
|
+
reportError(err, { phase: "cleanup", name: "disposer" });
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
function replaceChildrenSafely(parent, ...next) {
|
|
1231
|
+
for (let i = 0; i < next.length; i++) {
|
|
1232
|
+
const node = next[i];
|
|
1233
|
+
node.parentNode?.removeChild(node);
|
|
1234
|
+
}
|
|
1235
|
+
const current = Array.from(parent.childNodes);
|
|
1236
|
+
for (let i = 0; i < current.length; i++) {
|
|
1237
|
+
dispose(current[i]);
|
|
1238
|
+
}
|
|
1239
|
+
parent.replaceChildren(...next);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1044
1242
|
// src/utils/sanitize.ts
|
|
1045
1243
|
function stripControlChars(value) {
|
|
1046
1244
|
return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
|
|
1047
1245
|
}
|
|
1048
1246
|
var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
1247
|
+
var OUTER_TRIM = /^[\x00-\x20\x7f-\x9f]+|[\x00-\x20\x7f-\x9f]+$/g;
|
|
1049
1248
|
function sanitizeUrl(url) {
|
|
1050
|
-
const
|
|
1051
|
-
if (!
|
|
1052
|
-
const
|
|
1249
|
+
const probe = stripControlChars(url).trim();
|
|
1250
|
+
if (!probe) return "";
|
|
1251
|
+
const output = url.replace(OUTER_TRIM, "");
|
|
1252
|
+
const lower = probe.toLowerCase();
|
|
1053
1253
|
let schemeEnd = -1;
|
|
1054
1254
|
for (let i = 0; i < lower.length; i++) {
|
|
1055
1255
|
const ch = lower.charCodeAt(i);
|
|
@@ -1059,11 +1259,11 @@ function sanitizeUrl(url) {
|
|
|
1059
1259
|
}
|
|
1060
1260
|
if (ch === 47 || ch === 63 || ch === 35) break;
|
|
1061
1261
|
}
|
|
1062
|
-
if (schemeEnd === -1) return
|
|
1262
|
+
if (schemeEnd === -1) return output;
|
|
1063
1263
|
const scheme = lower.slice(0, schemeEnd + 1);
|
|
1064
|
-
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return
|
|
1264
|
+
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return output;
|
|
1065
1265
|
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
1066
|
-
return
|
|
1266
|
+
return output;
|
|
1067
1267
|
}
|
|
1068
1268
|
|
|
1069
1269
|
// src/performance/domRecycler.ts
|
|
@@ -1106,7 +1306,7 @@ var DOMPool = class {
|
|
|
1106
1306
|
this.pools.set(tag, pool);
|
|
1107
1307
|
}
|
|
1108
1308
|
if (pool.length >= this.maxSize) return;
|
|
1109
|
-
element
|
|
1309
|
+
replaceChildrenSafely(element);
|
|
1110
1310
|
element.className = "";
|
|
1111
1311
|
element.removeAttribute("style");
|
|
1112
1312
|
element.removeAttribute("id");
|
|
@@ -1244,8 +1444,9 @@ function normalizedStore(schema) {
|
|
|
1244
1444
|
ids: [],
|
|
1245
1445
|
entities: {}
|
|
1246
1446
|
});
|
|
1447
|
+
const idOf = (entity) => String(entity[idKey]);
|
|
1247
1448
|
function add(entity) {
|
|
1248
|
-
const id =
|
|
1449
|
+
const id = idOf(entity);
|
|
1249
1450
|
setState((prev) => {
|
|
1250
1451
|
const ids = prev.ids.includes(id) ? prev.ids : [...prev.ids, id];
|
|
1251
1452
|
return {
|
|
@@ -1259,7 +1460,7 @@ function normalizedStore(schema) {
|
|
|
1259
1460
|
const nextIds = [...prev.ids];
|
|
1260
1461
|
const nextEntities = { ...prev.entities };
|
|
1261
1462
|
for (const entity of entities) {
|
|
1262
|
-
const id =
|
|
1463
|
+
const id = idOf(entity);
|
|
1263
1464
|
if (!nextIds.includes(id)) {
|
|
1264
1465
|
nextIds.push(id);
|
|
1265
1466
|
}
|
|
@@ -1269,12 +1470,12 @@ function normalizedStore(schema) {
|
|
|
1269
1470
|
});
|
|
1270
1471
|
}
|
|
1271
1472
|
function get(id) {
|
|
1272
|
-
const
|
|
1273
|
-
return
|
|
1473
|
+
const state2 = getState();
|
|
1474
|
+
return state2.entities[id];
|
|
1274
1475
|
}
|
|
1275
1476
|
function getAll() {
|
|
1276
|
-
const
|
|
1277
|
-
return
|
|
1477
|
+
const state2 = getState();
|
|
1478
|
+
return state2.ids.map((id) => state2.entities[id]);
|
|
1278
1479
|
}
|
|
1279
1480
|
function update(id, partial) {
|
|
1280
1481
|
setState((prev) => {
|
|
@@ -1300,8 +1501,8 @@ function normalizedStore(schema) {
|
|
|
1300
1501
|
});
|
|
1301
1502
|
}
|
|
1302
1503
|
function select(predicate) {
|
|
1303
|
-
const
|
|
1304
|
-
return
|
|
1504
|
+
const state2 = getState();
|
|
1505
|
+
return state2.ids.map((id) => state2.entities[id]).filter(predicate);
|
|
1305
1506
|
}
|
|
1306
1507
|
return { add, addMany, get, getAll, update, remove, select, getState };
|
|
1307
1508
|
}
|
|
@@ -1361,58 +1562,6 @@ function denormalize(id, entities, schema) {
|
|
|
1361
1562
|
return result;
|
|
1362
1563
|
}
|
|
1363
1564
|
|
|
1364
|
-
// src/core/rendering/dispose.ts
|
|
1365
|
-
var elementDisposers = /* @__PURE__ */ new WeakMap();
|
|
1366
|
-
var _isDev7 = isDev();
|
|
1367
|
-
var activeBindingCount = 0;
|
|
1368
|
-
function dispose(node) {
|
|
1369
|
-
const stack = [node];
|
|
1370
|
-
const order = [];
|
|
1371
|
-
while (stack.length > 0) {
|
|
1372
|
-
const current = stack.pop();
|
|
1373
|
-
order.push(current);
|
|
1374
|
-
const children = Array.from(current.childNodes);
|
|
1375
|
-
for (let i = 0; i < children.length; i++) {
|
|
1376
|
-
stack.push(children[i]);
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
for (let i = order.length - 1; i >= 0; i--) {
|
|
1380
|
-
const current = order[i];
|
|
1381
|
-
const disposers = elementDisposers.get(current);
|
|
1382
|
-
if (disposers) {
|
|
1383
|
-
const snapshot = disposers.slice();
|
|
1384
|
-
elementDisposers.delete(current);
|
|
1385
|
-
if (_isDev7) activeBindingCount -= snapshot.length;
|
|
1386
|
-
for (const d of snapshot) {
|
|
1387
|
-
try {
|
|
1388
|
-
d();
|
|
1389
|
-
} catch (err) {
|
|
1390
|
-
if (_isDev7 && typeof console !== "undefined") {
|
|
1391
|
-
console.warn("[SibuJS] Disposer threw during cleanup:", err);
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
let extraPasses = 0;
|
|
1396
|
-
while (extraPasses++ < 8) {
|
|
1397
|
-
const added = elementDisposers.get(current);
|
|
1398
|
-
if (!added || added.length === 0) break;
|
|
1399
|
-
const moreSnapshot = added.slice();
|
|
1400
|
-
elementDisposers.delete(current);
|
|
1401
|
-
if (_isDev7) activeBindingCount -= moreSnapshot.length;
|
|
1402
|
-
for (const d of moreSnapshot) {
|
|
1403
|
-
try {
|
|
1404
|
-
d();
|
|
1405
|
-
} catch (err) {
|
|
1406
|
-
if (_isDev7 && typeof console !== "undefined") {
|
|
1407
|
-
console.warn("[SibuJS] Disposer threw during cleanup:", err);
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
1565
|
// src/performance/chunkLoader.ts
|
|
1417
1566
|
function clearChildren(el) {
|
|
1418
1567
|
while (el.firstChild) {
|
|
@@ -1433,7 +1582,14 @@ function createChunkRegistry(config = {}) {
|
|
|
1433
1582
|
} = config;
|
|
1434
1583
|
const cache = /* @__PURE__ */ new Map();
|
|
1435
1584
|
const pending = /* @__PURE__ */ new Map();
|
|
1436
|
-
const preloaded = /* @__PURE__ */ new
|
|
1585
|
+
const preloaded = /* @__PURE__ */ new Map();
|
|
1586
|
+
function notify(name, run) {
|
|
1587
|
+
try {
|
|
1588
|
+
run();
|
|
1589
|
+
} catch (err) {
|
|
1590
|
+
reportError(err, { phase: "async", name: `chunkRegistry(${name})` });
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1437
1593
|
function evict() {
|
|
1438
1594
|
while (cache.size >= maxCacheSize) {
|
|
1439
1595
|
let lru = null;
|
|
@@ -1488,30 +1644,47 @@ function createChunkRegistry(config = {}) {
|
|
|
1488
1644
|
cached.lastAccess = Date.now();
|
|
1489
1645
|
return cached.value;
|
|
1490
1646
|
}
|
|
1491
|
-
const
|
|
1492
|
-
if (
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
pending.delete(id);
|
|
1499
|
-
onLoadEnd?.(id);
|
|
1500
|
-
return value;
|
|
1501
|
-
}).catch((err) => {
|
|
1502
|
-
pending.delete(id);
|
|
1503
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
1504
|
-
onLoadError?.(id, error);
|
|
1505
|
-
throw error;
|
|
1647
|
+
const existing = pending.get(id);
|
|
1648
|
+
if (existing) return existing.promise;
|
|
1649
|
+
let resolveOuter;
|
|
1650
|
+
let rejectOuter;
|
|
1651
|
+
const outcome = new Promise((resolve, reject) => {
|
|
1652
|
+
resolveOuter = resolve;
|
|
1653
|
+
rejectOuter = reject;
|
|
1506
1654
|
});
|
|
1507
|
-
|
|
1508
|
-
|
|
1655
|
+
const entry = { promise: outcome };
|
|
1656
|
+
pending.set(id, entry);
|
|
1657
|
+
const owns = () => pending.get(id) === entry;
|
|
1658
|
+
notify("onLoadStart", () => onLoadStart?.(id));
|
|
1659
|
+
void loadWithRetry(id, loader).then(
|
|
1660
|
+
(value) => {
|
|
1661
|
+
if (owns()) {
|
|
1662
|
+
pending.delete(id);
|
|
1663
|
+
evict();
|
|
1664
|
+
const now = Date.now();
|
|
1665
|
+
cache.set(id, { value, timestamp: now, lastAccess: now, accessCount: 1 });
|
|
1666
|
+
}
|
|
1667
|
+
notify("onLoadEnd", () => onLoadEnd?.(id));
|
|
1668
|
+
resolveOuter(value);
|
|
1669
|
+
},
|
|
1670
|
+
(err) => {
|
|
1671
|
+
if (owns()) pending.delete(id);
|
|
1672
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1673
|
+
notify("onLoadError", () => onLoadError?.(id, error));
|
|
1674
|
+
rejectOuter(error);
|
|
1675
|
+
}
|
|
1676
|
+
).catch((internal) => {
|
|
1677
|
+
reportError(internal, { phase: "async", name: "chunkRegistry(settlement)" });
|
|
1678
|
+
rejectOuter(internal);
|
|
1679
|
+
});
|
|
1680
|
+
return outcome;
|
|
1509
1681
|
}
|
|
1510
1682
|
function preloadFn(id, loader) {
|
|
1511
1683
|
if (cache.has(id) || pending.has(id) || preloaded.has(id)) return;
|
|
1512
|
-
|
|
1684
|
+
const marker = {};
|
|
1685
|
+
preloaded.set(id, marker);
|
|
1513
1686
|
loadFn(id, loader).catch(() => {
|
|
1514
|
-
preloaded.delete(id);
|
|
1687
|
+
if (preloaded.get(id) === marker) preloaded.delete(id);
|
|
1515
1688
|
});
|
|
1516
1689
|
}
|
|
1517
1690
|
return {
|
|
@@ -1545,21 +1718,33 @@ function createChunkRegistry(config = {}) {
|
|
|
1545
1718
|
return void 0;
|
|
1546
1719
|
},
|
|
1547
1720
|
/**
|
|
1548
|
-
* Invalidate a cached chunk.
|
|
1721
|
+
* Invalidate a cached chunk, and supersede any load still in flight for it.
|
|
1722
|
+
*
|
|
1723
|
+
* In-flight work is not cancelled — the loader API takes no abort signal, so
|
|
1724
|
+
* claiming cancellation would be a lie. It is *superseded*: it still settles
|
|
1725
|
+
* for whoever called `load()`, but it can no longer write to the cache, and
|
|
1726
|
+
* a subsequent `load(id, …)` starts fresh work rather than adopting it.
|
|
1549
1727
|
*/
|
|
1550
1728
|
invalidate(id) {
|
|
1551
1729
|
cache.delete(id);
|
|
1552
1730
|
preloaded.delete(id);
|
|
1731
|
+
pending.delete(id);
|
|
1553
1732
|
},
|
|
1554
1733
|
/**
|
|
1555
|
-
* Clear all cached chunks.
|
|
1734
|
+
* Clear all cached chunks, and supersede every load still in flight.
|
|
1735
|
+
*
|
|
1736
|
+
* Same barrier as `invalidate`, applied to every key at once.
|
|
1556
1737
|
*/
|
|
1557
1738
|
clear() {
|
|
1558
1739
|
cache.clear();
|
|
1559
1740
|
preloaded.clear();
|
|
1741
|
+
pending.clear();
|
|
1560
1742
|
},
|
|
1561
1743
|
/**
|
|
1562
1744
|
* Get cache statistics.
|
|
1745
|
+
*
|
|
1746
|
+
* Describes currently OWNED state: superseded loads are already absent from
|
|
1747
|
+
* `pending`, so the counts never include work whose result will be discarded.
|
|
1563
1748
|
*/
|
|
1564
1749
|
stats() {
|
|
1565
1750
|
return {
|