sibujs 4.4.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +11 -0
  2. package/dist/browser.cjs +339 -130
  3. package/dist/browser.d.cts +61 -16
  4. package/dist/browser.d.ts +61 -16
  5. package/dist/browser.js +8 -6
  6. package/dist/build.cjs +273 -82
  7. package/dist/build.js +15 -16
  8. package/dist/cdn.dev.global.js +12 -12
  9. package/dist/cdn.full.dev.global.js +11 -11
  10. package/dist/cdn.full.global.js +10 -10
  11. package/dist/cdn.global.js +12 -12
  12. package/dist/{chunk-IXKSNWV5.js → chunk-2INLLLMZ.js} +1 -1
  13. package/dist/chunk-3ISI6ACU.js +44 -0
  14. package/dist/{chunk-VCTAEPSB.js → chunk-47M47FOM.js} +11 -3
  15. package/dist/chunk-5HZXGZ6T.js +24 -0
  16. package/dist/{chunk-KKLW7YWL.js → chunk-5MT6SJ3P.js} +275 -144
  17. package/dist/{chunk-3BTTCZ5J.js → chunk-5Q4R7HCL.js} +42 -4
  18. package/dist/{chunk-ADM46X22.js → chunk-7GQCWFOE.js} +157 -61
  19. package/dist/{chunk-4Z3SPQ67.js → chunk-7NCARGJW.js} +16 -8
  20. package/dist/{chunk-5DXA2J44.js → chunk-7XHATCIH.js} +5 -2
  21. package/dist/{chunk-LQFGQNMV.js → chunk-AIF3Z2T7.js} +302 -39
  22. package/dist/{chunk-UCALUKB5.js → chunk-BAAG6ZTI.js} +98 -29
  23. package/dist/{chunk-NVNJH22U.js → chunk-D33YTSX5.js} +2 -2
  24. package/dist/{chunk-M2F7TZHH.js → chunk-DKGBBKOF.js} +136 -80
  25. package/dist/{chunk-NIOYEGBQ.js → chunk-HURREPU2.js} +27 -13
  26. package/dist/{chunk-HFCOH2GN.js → chunk-HYXDKS4N.js} +153 -110
  27. package/dist/chunk-J6FW5TV6.js +233 -0
  28. package/dist/{chunk-36S2YPP4.js → chunk-JSXPZCET.js} +1 -1
  29. package/dist/chunk-NYNYSPK7.js +318 -0
  30. package/dist/{chunk-HQSEH5F6.js → chunk-ORMZXBKQ.js} +108 -45
  31. package/dist/{chunk-LYVUX7NT.js → chunk-OXUY2A6L.js} +287 -130
  32. package/dist/{chunk-6GSIXTWX.js → chunk-PK6FK2G2.js} +187 -66
  33. package/dist/{chunk-W2EQ7X2L.js → chunk-QE4TTDU3.js} +47 -9
  34. package/dist/{chunk-XLO7SLIX.js → chunk-SXXVZMKZ.js} +262 -70
  35. package/dist/{chunk-R25EFXXC.js → chunk-TUCPL2HB.js} +3 -3
  36. package/dist/{chunk-RR7M3FHM.js → chunk-UZQ6ALFS.js} +3 -3
  37. package/dist/{chunk-PNIRUQ4C.js → chunk-VVWPJ543.js} +6 -8
  38. package/dist/{chunk-7GIHSAWB.js → chunk-XC4MEKGA.js} +3 -3
  39. package/dist/{chunk-SKPTERHP.js → chunk-XRRZKZYX.js} +55 -31
  40. package/dist/{contracts-DBdg9J_a.d.cts → contracts-DRIuclVT.d.cts} +10 -2
  41. package/dist/{contracts-DBdg9J_a.d.ts → contracts-DRIuclVT.d.ts} +10 -2
  42. package/dist/{customElement-CNZxEB9G.d.ts → customElement-MmInOW1U.d.cts} +59 -10
  43. package/dist/{customElement-CNZxEB9G.d.cts → customElement-MmInOW1U.d.ts} +59 -10
  44. package/dist/data.cjs +293 -125
  45. package/dist/data.d.cts +47 -9
  46. package/dist/data.d.ts +47 -9
  47. package/dist/data.js +12 -9
  48. package/dist/devtools.cjs +121 -58
  49. package/dist/devtools.js +7 -8
  50. package/dist/dispose-GEIG2KOF.js +28 -0
  51. package/dist/ecosystem.cjs +391 -112
  52. package/dist/ecosystem.d.cts +31 -7
  53. package/dist/ecosystem.d.ts +31 -7
  54. package/dist/ecosystem.js +12 -12
  55. package/dist/extras.cjs +2250 -879
  56. package/dist/extras.d.cts +10 -9
  57. package/dist/extras.d.ts +10 -9
  58. package/dist/extras.js +39 -28
  59. package/dist/index.cjs +273 -82
  60. package/dist/index.d.cts +44 -154
  61. package/dist/index.d.ts +44 -154
  62. package/dist/index.js +24 -27
  63. package/dist/motion.cjs +137 -42
  64. package/dist/motion.js +5 -5
  65. package/dist/patterns.cjs +397 -48
  66. package/dist/patterns.d.cts +32 -9
  67. package/dist/patterns.d.ts +32 -9
  68. package/dist/patterns.js +8 -8
  69. package/dist/performance.cjs +338 -217
  70. package/dist/performance.d.cts +2 -2
  71. package/dist/performance.d.ts +2 -2
  72. package/dist/performance.js +8 -9
  73. package/dist/plugin-DVgSnTfK.d.cts +112 -0
  74. package/dist/plugin-DVgSnTfK.d.ts +112 -0
  75. package/dist/plugins.cjs +587 -203
  76. package/dist/plugins.d.cts +3 -3
  77. package/dist/plugins.d.ts +3 -3
  78. package/dist/plugins.js +35 -23
  79. package/dist/signal-EotCj4hS.d.cts +110 -0
  80. package/dist/signal-EotCj4hS.d.ts +110 -0
  81. package/dist/{ssr-BiPRdZ6n.d.cts → ssr-Bli9XRW5.d.cts} +5 -0
  82. package/dist/{ssr-BiPRdZ6n.d.ts → ssr-Bli9XRW5.d.ts} +5 -0
  83. package/dist/{ssr-Y7XOEPEN.js → ssr-XOTUASDO.js} +4 -5
  84. package/dist/ssr.cjs +214 -73
  85. package/dist/ssr.d.cts +9 -3
  86. package/dist/ssr.d.ts +9 -3
  87. package/dist/ssr.js +11 -12
  88. package/dist/{startup-BMpaiMhP.d.ts → startup-BLfSeL15.d.cts} +73 -22
  89. package/dist/{startup-BMpaiMhP.d.cts → startup-BLfSeL15.d.ts} +73 -22
  90. package/dist/tagFactory-DFstCLQV.d.cts +117 -0
  91. package/dist/tagFactory-DkaNVUNV.d.ts +117 -0
  92. package/dist/testing.cjs +2481 -2153
  93. package/dist/testing.d.cts +56 -5
  94. package/dist/testing.d.ts +56 -5
  95. package/dist/testing.js +580 -307
  96. package/dist/ui.cjs +798 -328
  97. package/dist/ui.d.cts +40 -7
  98. package/dist/ui.d.ts +40 -7
  99. package/dist/ui.js +151 -56
  100. package/dist/widgets.cjs +319 -285
  101. package/dist/widgets.js +9 -10
  102. package/package.json +2 -2
  103. package/dist/chunk-2WLZ6757.js +0 -149
  104. package/dist/chunk-7NBDXVHS.js +0 -60
  105. package/dist/chunk-CCSJMTRN.js +0 -15
  106. package/dist/chunk-QKRPLZ2V.js +0 -108
  107. package/dist/chunk-WWV3SJ3L.js +0 -131
  108. package/dist/dispose-46BOMMQJ.js +0 -19
  109. package/dist/plugin-D30wlGW5.d.cts +0 -71
  110. package/dist/plugin-D30wlGW5.d.ts +0 -71
  111. package/dist/tagFactory-Bzupt4Pj.d.cts +0 -55
  112. package/dist/tagFactory-Bzupt4Pj.d.ts +0 -55
@@ -1,39 +1,54 @@
1
1
  import {
2
2
  renderToString
3
- } from "./chunk-NIOYEGBQ.js";
3
+ } from "./chunk-HURREPU2.js";
4
+ import {
5
+ globalSingleton
6
+ } from "./chunk-7ZHH77QA.js";
7
+ import {
8
+ reportError
9
+ } from "./chunk-NYNYSPK7.js";
4
10
 
5
11
  // src/plugins/modular.ts
6
12
  function createModuleRegistry() {
7
13
  const modules = /* @__PURE__ */ new Map();
8
- function resolveInternal(name, stack) {
14
+ const resolving = [];
15
+ function resolveInternal(name) {
9
16
  const entry = modules.get(name);
10
17
  if (!entry) {
11
18
  throw new Error(`[ModuleRegistry] Module "${name}" is not registered.`);
12
19
  }
13
- if (entry.loaded) {
20
+ if (entry.state === "loaded") {
14
21
  return entry.value;
15
22
  }
16
- if (stack.has(name)) {
17
- const cycle = [...stack, name].join(" -> ");
23
+ if (entry.state === "resolving") {
24
+ const cycle = [...resolving.slice(resolving.indexOf(name)), name].join(" -> ");
18
25
  throw new Error(`[ModuleRegistry] Circular dependency detected: ${cycle}`);
19
26
  }
20
- stack.add(name);
21
- for (const dep of entry.deps) {
22
- resolveInternal(dep, stack);
27
+ entry.state = "resolving";
28
+ resolving.push(name);
29
+ try {
30
+ for (const dep of entry.deps) {
31
+ resolveInternal(dep);
32
+ }
33
+ entry.value = entry.factory();
34
+ entry.state = "loaded";
35
+ return entry.value;
36
+ } catch (err) {
37
+ entry.state = "unloaded";
38
+ entry.value = void 0;
39
+ throw err;
40
+ } finally {
41
+ resolving.pop();
23
42
  }
24
- stack.delete(name);
25
- entry.value = entry.factory();
26
- entry.loaded = true;
27
- return entry.value;
28
43
  }
29
44
  return {
30
45
  /** Register a module with its factory function and optional dependencies */
31
46
  register(name, factory, deps = []) {
32
- modules.set(name, { factory, deps, loaded: false });
47
+ modules.set(name, { factory, deps, state: "unloaded" });
33
48
  },
34
49
  /** Resolve a module, loading its dependencies first */
35
50
  resolve(name) {
36
- return resolveInternal(name, /* @__PURE__ */ new Set());
51
+ return resolveInternal(name);
37
52
  },
38
53
  /** Check if a module is registered */
39
54
  has(name) {
@@ -68,7 +83,7 @@ function createModuleRegistry() {
68
83
  /** Reset all loaded modules back to unloaded state (useful for testing) */
69
84
  reset() {
70
85
  for (const entry of modules.values()) {
71
- entry.loaded = false;
86
+ entry.state = "unloaded";
72
87
  entry.value = void 0;
73
88
  }
74
89
  }
@@ -96,46 +111,83 @@ function createBundle(modules) {
96
111
  function lazyModule(loader) {
97
112
  let cached;
98
113
  let loadedFlag = false;
99
- const handle = {
114
+ let inFlight = null;
115
+ return {
100
116
  get loaded() {
101
117
  return loadedFlag;
102
118
  },
103
- async get() {
104
- if (loadedFlag) return cached;
105
- cached = await loader();
106
- loadedFlag = true;
107
- return cached;
119
+ get() {
120
+ if (loadedFlag) return Promise.resolve(cached);
121
+ if (inFlight) return inFlight;
122
+ let started;
123
+ try {
124
+ started = Promise.resolve(loader());
125
+ } catch (err) {
126
+ started = Promise.reject(err);
127
+ }
128
+ const attempt = started.then(
129
+ (value) => {
130
+ cached = value;
131
+ loadedFlag = true;
132
+ if (inFlight === attempt) inFlight = null;
133
+ return value;
134
+ },
135
+ (err) => {
136
+ if (inFlight === attempt) inFlight = null;
137
+ throw err;
138
+ }
139
+ );
140
+ inFlight = attempt;
141
+ return attempt;
108
142
  }
109
143
  };
110
- return handle;
111
144
  }
145
+ var MODULE_ENTRY_POINTS = {
146
+ main: "./index.ts",
147
+ data: "./data.ts",
148
+ browser: "./browser.ts",
149
+ patterns: "./patterns.ts",
150
+ motion: "./motion.ts",
151
+ ui: "./ui.ts",
152
+ widgets: "./widgets.ts",
153
+ ssr: "./ssr.ts",
154
+ devtools: "./devtools.ts",
155
+ performance: "./performance.ts",
156
+ ecosystem: "./ecosystem.ts",
157
+ plugins: "./plugins.ts",
158
+ build: "./build.ts",
159
+ testing: "./testing.ts",
160
+ extras: "./extras.ts"
161
+ };
162
+ var CDN_ENTRY_POINTS = {
163
+ cdn: "./dist/cdn.global.js",
164
+ "cdn-dev": "./dist/cdn.dev.global.js",
165
+ "cdn-full": "./dist/cdn.full.global.js",
166
+ "cdn-full-dev": "./dist/cdn.full.dev.global.js"
167
+ };
112
168
  var packageInfo = {
113
- name: "sibu",
114
- version: "1.0.0",
115
- entryPoints: {
116
- main: "./index.ts",
117
- core: "./src/core/html.ts",
118
- hooks: "./src/core/signals/signal.ts",
119
- router: "./src/plugins/router.ts",
120
- i18n: "./src/plugins/i18n.ts",
121
- testing: "./src/testing/index.ts",
122
- ssr: "./src/core/ssr.ts"
123
- },
169
+ name: "sibujs",
170
+ version: true ? "4.6.0" : "dev",
171
+ entryPoints: MODULE_ENTRY_POINTS,
124
172
  /**
125
- * Generate a package.json `exports` map for Node.js subpath exports.
126
- * Maps each entry point to its import, require, and types paths.
173
+ * Generate the package.json `exports` map. Module entries resolve to the
174
+ * `.js` (ESM), `.cjs` and `.d.ts` files tsup emits into `dist/`; CDN entries
175
+ * resolve to their prebuilt global script.
127
176
  */
128
177
  generateExportsMap() {
129
178
  const exportsMap = {};
130
- for (const [name, sourcePath] of Object.entries(this.entryPoints)) {
179
+ for (const [name, sourcePath] of Object.entries(MODULE_ENTRY_POINTS)) {
131
180
  const distPath = sourcePath.replace(/^\.\//, "./dist/").replace(/\.ts$/, "");
132
181
  const subpath = name === "main" ? "." : `./${name}`;
133
182
  exportsMap[subpath] = {
134
- import: `${distPath}.mjs`,
135
- require: `${distPath}.cjs`,
136
- types: `${distPath}.d.ts`
183
+ types: `${distPath}.d.ts`,
184
+ import: `${distPath}.js`,
185
+ require: `${distPath}.cjs`
137
186
  };
138
187
  }
188
+ for (const [name, file] of Object.entries(CDN_ENTRY_POINTS)) {
189
+ exportsMap[`./${name}`] = { default: file };
190
+ }
139
191
  return exportsMap;
140
192
  }
141
193
  };
@@ -260,29 +312,26 @@ var env = {
260
312
  };
261
313
 
262
314
  // src/plugins/versioning.ts
263
- var VERSION = "1.0.0";
315
+ var VERSION = true ? "4.6.0" : "dev";
316
+ var NUM = "(?:0|[1-9]\\d*)";
317
+ var PRE_ID = `(?:${NUM}|\\d*[a-zA-Z-][0-9a-zA-Z-]*)`;
318
+ var BUILD_ID = "[0-9a-zA-Z-]+";
319
+ var SEMVER_PATTERN = new RegExp(
320
+ `^(${NUM})(?:\\.(${NUM})(?:\\.(${NUM})(?:-(${PRE_ID}(?:\\.${PRE_ID})*))?(?:\\+(${BUILD_ID}(?:\\.${BUILD_ID})*))?)?)?$`
321
+ );
264
322
  function parseSemVer(version) {
265
- const trimmed = version.trim().replace(/^v/i, "");
266
- const prereleaseIndex = trimmed.indexOf("-");
267
- let main;
268
- let prerelease;
269
- if (prereleaseIndex !== -1) {
270
- main = trimmed.slice(0, prereleaseIndex);
271
- prerelease = trimmed.slice(prereleaseIndex + 1);
272
- } else {
273
- main = trimmed;
274
- }
275
- const parts = main.split(".");
276
- const major = parseInt(parts[0], 10);
277
- const minor = parseInt(parts[1] || "0", 10);
278
- const patch = parseInt(parts[2] || "0", 10);
279
- if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch)) {
323
+ const trimmed = String(version).trim().replace(/^v/i, "");
324
+ const match = SEMVER_PATTERN.exec(trimmed);
325
+ if (!match) {
280
326
  throw new Error(`[Versioning] Invalid semver string: "${version}"`);
281
327
  }
282
- const result = { major, minor, patch };
283
- if (prerelease !== void 0) {
284
- result.prerelease = prerelease;
285
- }
328
+ const result = {
329
+ major: Number(match[1]),
330
+ minor: match[2] === void 0 ? 0 : Number(match[2]),
331
+ patch: match[3] === void 0 ? 0 : Number(match[3])
332
+ };
333
+ if (match[4] !== void 0) result.prerelease = match[4];
334
+ if (match[5] !== void 0) result.build = match[5];
286
335
  return result;
287
336
  }
288
337
  function compareSemVer(a, b) {
@@ -365,82 +414,154 @@ function satisfies(version, range) {
365
414
  const target = parseSemVer(exactStr);
366
415
  return compareSemVer(v, target) === 0;
367
416
  }
417
+ var MigrationStorageError = class extends Error {
418
+ constructor(version, cause) {
419
+ const reason = cause instanceof Error ? cause.message : String(cause);
420
+ super(`[Versioning] Migration ${version} completed, but recording it in storage failed: ${reason}`);
421
+ this.name = "MigrationStorageError";
422
+ this.version = version;
423
+ this.cause = cause;
424
+ }
425
+ };
426
+ var _migrationQueues = globalSingleton(
427
+ /* @__PURE__ */ Symbol.for("sibujs.migrationQueues.v1"),
428
+ () => /* @__PURE__ */ new WeakMap()
429
+ );
430
+ var NO_STORAGE = {};
368
431
  function createMigrationRunner(config) {
369
432
  const storageKey = config.storageKey || "__sibu_migration_version__";
370
433
  const sortedMigrations = [...config.migrations].sort((a, b) => compareSemVer(a.version, b.version));
371
434
  function getStorage() {
435
+ if (config.storage) return config.storage;
372
436
  try {
373
437
  return typeof localStorage !== "undefined" ? localStorage : null;
374
438
  } catch {
375
439
  return null;
376
440
  }
377
441
  }
442
+ function getAppliedVersion() {
443
+ const storage = getStorage();
444
+ if (!storage) return null;
445
+ return storage.getItem(storageKey);
446
+ }
447
+ function getPending() {
448
+ const appliedVersion = getAppliedVersion();
449
+ if (!appliedVersion) {
450
+ return sortedMigrations.filter((m) => compareSemVer(m.version, config.currentVersion) <= 0);
451
+ }
452
+ return sortedMigrations.filter(
453
+ (m) => compareSemVer(m.version, appliedVersion) > 0 && compareSemVer(m.version, config.currentVersion) <= 0
454
+ );
455
+ }
456
+ function writeApplied(version, migrationVersion) {
457
+ const storage = getStorage();
458
+ if (!storage) return;
459
+ try {
460
+ if (version === null) storage.removeItem(storageKey);
461
+ else storage.setItem(storageKey, version);
462
+ } catch (e) {
463
+ throw new MigrationStorageError(migrationVersion, e);
464
+ }
465
+ }
466
+ function serialize(operation) {
467
+ const identity = getStorage() ?? NO_STORAGE;
468
+ let queues = _migrationQueues.get(identity);
469
+ if (!queues) {
470
+ queues = /* @__PURE__ */ new Map();
471
+ _migrationQueues.set(identity, queues);
472
+ }
473
+ const run = (queues.get(storageKey) ?? Promise.resolve()).then(operation, operation);
474
+ const tail = run.then(
475
+ () => void 0,
476
+ () => void 0
477
+ );
478
+ queues.set(storageKey, tail);
479
+ const settled = queues;
480
+ tail.then(() => {
481
+ if (settled.get(storageKey) === tail) settled.delete(storageKey);
482
+ });
483
+ return run;
484
+ }
378
485
  return {
379
486
  /** Get the last applied migration version from storage */
380
- getAppliedVersion() {
381
- const storage = getStorage();
382
- if (!storage) return null;
383
- return storage.getItem(storageKey);
384
- },
487
+ getAppliedVersion,
385
488
  /** Get pending migrations that haven't been applied */
386
- getPending() {
387
- const appliedVersion = this.getAppliedVersion();
388
- if (!appliedVersion) {
389
- return sortedMigrations.filter((m) => compareSemVer(m.version, config.currentVersion) <= 0);
390
- }
391
- return sortedMigrations.filter(
392
- (m) => compareSemVer(m.version, appliedVersion) > 0 && compareSemVer(m.version, config.currentVersion) <= 0
393
- );
394
- },
395
- /** Run all pending migrations in order */
396
- async migrate() {
397
- const pending = this.getPending();
398
- const applied = [];
399
- const errors = [];
400
- for (const migration of pending) {
489
+ getPending,
490
+ /**
491
+ * Run all pending migrations in order. Concurrent calls (and calls racing
492
+ * `rollback()`) run one after another, each recomputing what is pending —
493
+ * on this runner and on every other runner in this realm sharing its
494
+ * storage and storage key.
495
+ */
496
+ migrate() {
497
+ return serialize(async () => {
498
+ const applied = [];
499
+ const errors = [];
500
+ let pending;
401
501
  try {
402
- await migration.up();
403
- applied.push(migration.version);
404
- const storage = getStorage();
405
- if (storage) {
406
- storage.setItem(storageKey, migration.version);
407
- }
502
+ pending = getPending();
408
503
  } catch (e) {
409
504
  errors.push({
410
- version: migration.version,
505
+ version: getAppliedVersion() ?? "",
411
506
  error: e instanceof Error ? e : new Error(String(e))
412
507
  });
413
- break;
508
+ return { applied, errors };
414
509
  }
415
- }
416
- return { applied, errors };
510
+ for (const migration of pending) {
511
+ try {
512
+ await migration.up();
513
+ } catch (e) {
514
+ errors.push({
515
+ version: migration.version,
516
+ error: e instanceof Error ? e : new Error(String(e))
517
+ });
518
+ break;
519
+ }
520
+ applied.push(migration.version);
521
+ try {
522
+ writeApplied(migration.version, migration.version);
523
+ } catch (e) {
524
+ errors.push({ version: migration.version, error: e });
525
+ break;
526
+ }
527
+ }
528
+ return { applied, errors };
529
+ });
417
530
  },
418
- /** Rollback to a specific version */
419
- async rollback(targetVersion) {
420
- const appliedVersion = this.getAppliedVersion();
421
- const rolledBack = [];
422
- if (!appliedVersion) {
423
- return { rolledBack };
424
- }
425
- const toRollback = sortedMigrations.filter((m) => compareSemVer(m.version, targetVersion) > 0 && compareSemVer(m.version, appliedVersion) <= 0).reverse();
426
- for (const migration of toRollback) {
427
- if (!migration.down) {
428
- throw new Error(
429
- `[Versioning] Migration ${migration.version} ("${migration.description}") does not have a down() function and cannot be rolled back.`
430
- );
531
+ /**
532
+ * Rollback to a specific version.
533
+ *
534
+ * The applied version is checkpointed after EVERY successful `down()`, so a
535
+ * rollback that fails part-way leaves storage describing what is actually
536
+ * still applied, and a retry does not repeat completed `down()` steps.
537
+ * Throws the failing `down()`'s error, a missing-`down()` error, or a
538
+ * {@link MigrationStorageError} if a checkpoint cannot be written.
539
+ */
540
+ rollback(targetVersion) {
541
+ return serialize(async () => {
542
+ const appliedVersion = getAppliedVersion();
543
+ const rolledBack = [];
544
+ if (!appliedVersion) {
545
+ return { rolledBack };
431
546
  }
432
- await migration.down();
433
- rolledBack.push(migration.version);
434
- }
435
- const storage = getStorage();
436
- if (storage) {
437
- if (targetVersion === "0.0.0") {
438
- storage.removeItem(storageKey);
439
- } else {
440
- storage.setItem(storageKey, targetVersion);
547
+ const toRollback = sortedMigrations.filter((m) => compareSemVer(m.version, targetVersion) > 0 && compareSemVer(m.version, appliedVersion) <= 0).reverse();
548
+ for (const migration of toRollback) {
549
+ if (!migration.down) {
550
+ throw new Error(
551
+ `[Versioning] Migration ${migration.version} ("${migration.description}") does not have a down() function and cannot be rolled back.`
552
+ );
553
+ }
441
554
  }
442
- }
443
- return { rolledBack };
555
+ for (const migration of toRollback) {
556
+ await migration.down();
557
+ rolledBack.push(migration.version);
558
+ const index = sortedMigrations.indexOf(migration);
559
+ const previous = index > 0 ? sortedMigrations[index - 1].version : null;
560
+ writeApplied(previous, migration.version);
561
+ }
562
+ writeApplied(targetVersion === "0.0.0" ? null : targetVersion, targetVersion);
563
+ return { rolledBack };
564
+ });
444
565
  }
445
566
  };
446
567
  }
@@ -490,28 +611,43 @@ function preloadCritical(resources) {
490
611
  document.head.appendChild(link);
491
612
  }
492
613
  }
493
- function prerenderRoutes(routes, options) {
494
- const maxCacheSize = options?.maxCacheSize ?? 50;
495
- const cacheTTL = options?.cacheTTL ?? 0;
496
- const cache = /* @__PURE__ */ new Map();
497
- function isValid(entry) {
498
- if (cacheTTL === 0) return true;
499
- return Date.now() - entry.timestamp < cacheTTL;
614
+ function assertCacheSize(name, value) {
615
+ if (!Number.isInteger(value) || value < 0) {
616
+ throw new RangeError(`[Startup] ${name} must be a non-negative integer, got ${value}`);
617
+ }
618
+ }
619
+ function makeRoomFor(cache, key, maxSize, isValid) {
620
+ if (maxSize === 0) return false;
621
+ if (cache.has(key)) return true;
622
+ if (cache.size < maxSize) return true;
623
+ for (const [k, entry] of cache) {
624
+ if (!isValid(entry)) cache.delete(k);
500
625
  }
501
- function evictOldest() {
502
- if (cache.size < maxCacheSize) return;
626
+ while (cache.size >= maxSize) {
503
627
  let oldestKey = null;
504
628
  let oldestTime = Infinity;
505
- for (const [key, entry] of cache) {
629
+ for (const [k, entry] of cache) {
506
630
  if (entry.timestamp < oldestTime) {
507
631
  oldestTime = entry.timestamp;
508
- oldestKey = key;
632
+ oldestKey = k;
509
633
  }
510
634
  }
511
- if (oldestKey) cache.delete(oldestKey);
635
+ if (oldestKey === null) break;
636
+ cache.delete(oldestKey);
637
+ }
638
+ return true;
639
+ }
640
+ function prerenderRoutes(routes, options) {
641
+ const maxCacheSize = options?.maxCacheSize ?? 50;
642
+ const cacheTTL = options?.cacheTTL ?? 0;
643
+ assertCacheSize("maxCacheSize", maxCacheSize);
644
+ const cache = /* @__PURE__ */ new Map();
645
+ function isValid(entry) {
646
+ if (cacheTTL === 0) return true;
647
+ return Date.now() - entry.timestamp < cacheTTL;
512
648
  }
513
649
  for (const route of routes) {
514
- evictOldest();
650
+ if (!makeRoomFor(cache, route.path, maxCacheSize, isValid)) break;
515
651
  const html = renderToString(route.component());
516
652
  cache.set(route.path, { html, timestamp: Date.now() });
517
653
  }
@@ -563,6 +699,7 @@ function prerenderRoutes(routes, options) {
563
699
  function createSSRCache(config) {
564
700
  const maxSize = config?.maxSize ?? 100;
565
701
  const defaultTTL = config?.defaultTTL ?? 6e4;
702
+ assertCacheSize("maxSize", maxSize);
566
703
  const cache = /* @__PURE__ */ new Map();
567
704
  let hits = 0;
568
705
  let misses = 0;
@@ -570,18 +707,6 @@ function createSSRCache(config) {
570
707
  if (entry.ttl === 0) return true;
571
708
  return Date.now() - entry.timestamp < entry.ttl;
572
709
  }
573
- function evictOldest() {
574
- if (cache.size < maxSize) return;
575
- let oldestKey = null;
576
- let oldestTime = Infinity;
577
- for (const [key, entry] of cache) {
578
- if (entry.timestamp < oldestTime) {
579
- oldestTime = entry.timestamp;
580
- oldestKey = key;
581
- }
582
- }
583
- if (oldestKey) cache.delete(oldestKey);
584
- }
585
710
  return {
586
711
  /** Get cached HTML for a key, or undefined if not cached or expired */
587
712
  get(key) {
@@ -600,7 +725,7 @@ function createSSRCache(config) {
600
725
  },
601
726
  /** Cache an HTML string with an optional TTL override */
602
727
  set(key, html, ttl) {
603
- evictOldest();
728
+ if (!makeRoomFor(cache, key, maxSize, isValid)) return;
604
729
  cache.set(key, {
605
730
  html,
606
731
  timestamp: Date.now(),
@@ -633,25 +758,30 @@ function createSSRCache(config) {
633
758
  }
634
759
  };
635
760
  }
761
+ var DEFER_IDLE_TIMEOUT_MS = 2e3;
636
762
  function deferNonCritical(tasks) {
637
763
  if (tasks.length === 0) return;
638
- const schedule = typeof requestIdleCallback !== "undefined" ? requestIdleCallback : (cb) => setTimeout(cb, 1);
764
+ const schedule = typeof requestIdleCallback !== "undefined" ? (cb) => {
765
+ requestIdleCallback(cb, { timeout: DEFER_IDLE_TIMEOUT_MS });
766
+ } : (cb) => {
767
+ setTimeout(cb, 1);
768
+ };
639
769
  const queue = [...tasks];
640
770
  let index = 0;
641
771
  function processNext(deadline) {
772
+ let ranOne = false;
642
773
  while (index < queue.length) {
643
- if (deadline && deadline.timeRemaining() < 1) {
774
+ if (ranOne && deadline && deadline.timeRemaining() < 1) {
644
775
  schedule(processNext);
645
776
  return;
646
777
  }
647
778
  try {
648
779
  queue[index]();
649
780
  } catch (e) {
650
- if (typeof console !== "undefined") {
651
- console.error("[Startup] Deferred task failed:", e);
652
- }
781
+ reportError(e, { phase: "scheduler", name: "deferNonCritical" });
653
782
  }
654
783
  index++;
784
+ ranOne = true;
655
785
  }
656
786
  }
657
787
  schedule(processNext);
@@ -714,6 +844,7 @@ export {
714
844
  parseSemVer,
715
845
  compareSemVer,
716
846
  satisfies,
847
+ MigrationStorageError,
717
848
  createMigrationRunner,
718
849
  checkCompatibility,
719
850
  preloadCritical,
@@ -1,8 +1,11 @@
1
1
  import {
2
2
  DEV,
3
+ beginDisposerCapture,
4
+ currentDisposerCapture,
3
5
  devWarn,
6
+ endDisposerCapture,
4
7
  reportError
5
- } from "./chunk-2WLZ6757.js";
8
+ } from "./chunk-NYNYSPK7.js";
6
9
 
7
10
  // src/reactivity/track-core.ts
8
11
  var POOL_MAX = 4096;
@@ -151,8 +154,18 @@ function untracked(fn) {
151
154
  var subscriberEpochCounter = 0;
152
155
  function retrack(effectFn, subscriber) {
153
156
  const prev = currentSubscriber;
157
+ let savedDepth = 0;
158
+ let savedSuspendSub = null;
159
+ if (trackingSuspended) {
160
+ savedDepth = suspendDepth;
161
+ savedSuspendSub = suspendSavedSub;
162
+ suspendDepth = 0;
163
+ suspendSavedSub = null;
164
+ trackingSuspended = false;
165
+ }
154
166
  currentSubscriber = subscriber;
155
167
  const sub = subscriber;
168
+ if (sub._cap === void 0) sub._cap = currentDisposerCapture();
156
169
  const epoch = ++subscriberEpochCounter;
157
170
  sub._epoch = epoch;
158
171
  sub._structDirty = false;
@@ -165,6 +178,11 @@ function retrack(effectFn, subscriber) {
165
178
  effectFn();
166
179
  } finally {
167
180
  currentSubscriber = prev;
181
+ if (savedDepth !== 0) {
182
+ suspendDepth = savedDepth;
183
+ suspendSavedSub = savedSuspendSub;
184
+ trackingSuspended = true;
185
+ }
168
186
  let node = sub.depsHead ?? null;
169
187
  while (node !== null) {
170
188
  const next = node.subNext;
@@ -184,11 +202,25 @@ function track(effectFn, subscriber) {
184
202
  if (!subscriber) return reactiveBinding(effectFn);
185
203
  cleanup(subscriber);
186
204
  const prev = currentSubscriber;
205
+ let savedDepth = 0;
206
+ let savedSuspendSub = null;
207
+ if (trackingSuspended) {
208
+ savedDepth = suspendDepth;
209
+ savedSuspendSub = suspendSavedSub;
210
+ suspendDepth = 0;
211
+ suspendSavedSub = null;
212
+ trackingSuspended = false;
213
+ }
187
214
  currentSubscriber = subscriber;
188
215
  try {
189
216
  effectFn();
190
217
  } finally {
191
218
  currentSubscriber = prev;
219
+ if (savedDepth !== 0) {
220
+ suspendDepth = savedDepth;
221
+ suspendSavedSub = savedSuspendSub;
222
+ trackingSuspended = true;
223
+ }
192
224
  const sub2 = subscriber;
193
225
  for (let n = sub2.depsHead ?? null; n !== null; n = n.subNext) {
194
226
  const sig = n.sig;
@@ -325,7 +357,12 @@ function drainQueue() {
325
357
  quarantined.add(sub);
326
358
  continue;
327
359
  }
328
- safeInvoke(sub);
360
+ const pushed = beginDisposerCapture(sub._cap ?? null);
361
+ try {
362
+ safeInvoke(sub);
363
+ } finally {
364
+ if (pushed) endDisposerCapture();
365
+ }
329
366
  }
330
367
  }
331
368
  function drainNotificationQueue() {
@@ -359,8 +396,9 @@ function propagateDirty(sub) {
359
396
  if (s._c) {
360
397
  const nSig = s._sig;
361
398
  if (nSig) {
362
- if (!nSig._d) {
399
+ if (!nSig._d || nSig._f === true) {
363
400
  nSig._d = true;
401
+ nSig._f = false;
364
402
  stack.push(nSig);
365
403
  }
366
404
  } else {
@@ -460,7 +498,7 @@ function forEachSubscriber(signal, visit) {
460
498
  }
461
499
 
462
500
  // src/reactivity/track.ts
463
- var _runtimeVersion = true ? "4.4.0" : "dev";
501
+ var _runtimeVersion = true ? "4.6.0" : "dev";
464
502
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
465
503
  function resolveReactiveApi() {
466
504
  const g = globalThis;