sibujs 4.5.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 (109) hide show
  1. package/dist/browser.cjs +309 -129
  2. package/dist/browser.d.cts +46 -14
  3. package/dist/browser.d.ts +46 -14
  4. package/dist/browser.js +8 -6
  5. package/dist/build.cjs +184 -72
  6. package/dist/build.js +15 -16
  7. package/dist/cdn.dev.global.js +12 -12
  8. package/dist/cdn.full.dev.global.js +11 -11
  9. package/dist/cdn.full.global.js +10 -10
  10. package/dist/cdn.global.js +12 -12
  11. package/dist/{chunk-IXKSNWV5.js → chunk-2INLLLMZ.js} +1 -1
  12. package/dist/chunk-3ISI6ACU.js +44 -0
  13. package/dist/{chunk-ONOHFDLG.js → chunk-47M47FOM.js} +3 -3
  14. package/dist/chunk-5HZXGZ6T.js +24 -0
  15. package/dist/{chunk-KKLW7YWL.js → chunk-5MT6SJ3P.js} +275 -144
  16. package/dist/{chunk-UGRX3S57.js → chunk-5Q4R7HCL.js} +12 -3
  17. package/dist/{chunk-S373NSMK.js → chunk-7GQCWFOE.js} +150 -59
  18. package/dist/{chunk-FTIR4QW2.js → chunk-7NCARGJW.js} +6 -8
  19. package/dist/{chunk-5DXA2J44.js → chunk-7XHATCIH.js} +5 -2
  20. package/dist/{chunk-VZKNK2V7.js → chunk-AIF3Z2T7.js} +296 -38
  21. package/dist/{chunk-4PMLNECI.js → chunk-BAAG6ZTI.js} +98 -29
  22. package/dist/{chunk-XZZOBQAY.js → chunk-D33YTSX5.js} +2 -2
  23. package/dist/{chunk-TBYTO6BS.js → chunk-DKGBBKOF.js} +136 -80
  24. package/dist/{chunk-NIOYEGBQ.js → chunk-HURREPU2.js} +27 -13
  25. package/dist/{chunk-GW3SCCZG.js → chunk-HYXDKS4N.js} +153 -110
  26. package/dist/chunk-J6FW5TV6.js +233 -0
  27. package/dist/{chunk-PCT43HW3.js → chunk-JSXPZCET.js} +1 -1
  28. package/dist/chunk-NYNYSPK7.js +318 -0
  29. package/dist/{chunk-RJE2BNI4.js → chunk-ORMZXBKQ.js} +108 -45
  30. package/dist/{chunk-OMJJM3KM.js → chunk-OXUY2A6L.js} +287 -130
  31. package/dist/{chunk-3JZ4L5TJ.js → chunk-PK6FK2G2.js} +181 -66
  32. package/dist/{chunk-RBTPLM32.js → chunk-QE4TTDU3.js} +2 -2
  33. package/dist/{chunk-2DCGACUU.js → chunk-SXXVZMKZ.js} +251 -66
  34. package/dist/{chunk-R25EFXXC.js → chunk-TUCPL2HB.js} +3 -3
  35. package/dist/{chunk-7LN645I6.js → chunk-UZQ6ALFS.js} +3 -3
  36. package/dist/{chunk-KEISJXBU.js → chunk-VVWPJ543.js} +6 -8
  37. package/dist/{chunk-RIXRAYIU.js → chunk-XC4MEKGA.js} +3 -3
  38. package/dist/{chunk-B3WHI2QA.js → chunk-XRRZKZYX.js} +55 -31
  39. package/dist/{contracts-DBdg9J_a.d.cts → contracts-DRIuclVT.d.cts} +10 -2
  40. package/dist/{contracts-DBdg9J_a.d.ts → contracts-DRIuclVT.d.ts} +10 -2
  41. package/dist/{customElement-OB9CIsc5.d.cts → customElement-MmInOW1U.d.cts} +21 -0
  42. package/dist/{customElement-OB9CIsc5.d.ts → customElement-MmInOW1U.d.ts} +21 -0
  43. package/dist/data.cjs +213 -117
  44. package/dist/data.d.cts +47 -9
  45. package/dist/data.d.ts +47 -9
  46. package/dist/data.js +12 -9
  47. package/dist/devtools.cjs +81 -57
  48. package/dist/devtools.js +7 -8
  49. package/dist/dispose-GEIG2KOF.js +28 -0
  50. package/dist/ecosystem.cjs +309 -104
  51. package/dist/ecosystem.d.cts +19 -3
  52. package/dist/ecosystem.d.ts +19 -3
  53. package/dist/ecosystem.js +12 -12
  54. package/dist/extras.cjs +2133 -863
  55. package/dist/extras.d.cts +10 -9
  56. package/dist/extras.d.ts +10 -9
  57. package/dist/extras.js +39 -28
  58. package/dist/index.cjs +184 -72
  59. package/dist/index.d.cts +22 -5
  60. package/dist/index.d.ts +22 -5
  61. package/dist/index.js +24 -27
  62. package/dist/motion.cjs +107 -41
  63. package/dist/motion.js +5 -5
  64. package/dist/patterns.cjs +317 -39
  65. package/dist/patterns.d.cts +27 -9
  66. package/dist/patterns.d.ts +27 -9
  67. package/dist/patterns.js +8 -8
  68. package/dist/performance.cjs +308 -216
  69. package/dist/performance.d.cts +2 -2
  70. package/dist/performance.d.ts +2 -2
  71. package/dist/performance.js +8 -9
  72. package/dist/plugin-DVgSnTfK.d.cts +112 -0
  73. package/dist/plugin-DVgSnTfK.d.ts +112 -0
  74. package/dist/plugins.cjs +549 -202
  75. package/dist/plugins.d.cts +3 -3
  76. package/dist/plugins.d.ts +3 -3
  77. package/dist/plugins.js +35 -23
  78. package/dist/signal-EotCj4hS.d.cts +110 -0
  79. package/dist/signal-EotCj4hS.d.ts +110 -0
  80. package/dist/{ssr-BiPRdZ6n.d.cts → ssr-Bli9XRW5.d.cts} +5 -0
  81. package/dist/{ssr-BiPRdZ6n.d.ts → ssr-Bli9XRW5.d.ts} +5 -0
  82. package/dist/{ssr-Y7XOEPEN.js → ssr-XOTUASDO.js} +4 -5
  83. package/dist/ssr.cjs +176 -72
  84. package/dist/ssr.d.cts +9 -3
  85. package/dist/ssr.d.ts +9 -3
  86. package/dist/ssr.js +11 -12
  87. package/dist/{startup-BMpaiMhP.d.ts → startup-BLfSeL15.d.cts} +73 -22
  88. package/dist/{startup-BMpaiMhP.d.cts → startup-BLfSeL15.d.ts} +73 -22
  89. package/dist/{tagFactory-DVoDpHye.d.ts → tagFactory-DFstCLQV.d.cts} +2 -100
  90. package/dist/{tagFactory-DVoDpHye.d.cts → tagFactory-DkaNVUNV.d.ts} +2 -100
  91. package/dist/testing.cjs +2484 -2185
  92. package/dist/testing.d.cts +56 -5
  93. package/dist/testing.d.ts +56 -5
  94. package/dist/testing.js +580 -307
  95. package/dist/ui.cjs +707 -317
  96. package/dist/ui.d.cts +40 -7
  97. package/dist/ui.d.ts +40 -7
  98. package/dist/ui.js +151 -56
  99. package/dist/widgets.cjs +246 -278
  100. package/dist/widgets.js +9 -10
  101. package/package.json +1 -1
  102. package/dist/chunk-2WLZ6757.js +0 -149
  103. package/dist/chunk-CCSJMTRN.js +0 -15
  104. package/dist/chunk-QKRPLZ2V.js +0 -108
  105. package/dist/chunk-VUF4ALSW.js +0 -60
  106. package/dist/chunk-WWV3SJ3L.js +0 -131
  107. package/dist/dispose-46BOMMQJ.js +0 -19
  108. package/dist/plugin-D30wlGW5.d.cts +0 -71
  109. package/dist/plugin-D30wlGW5.d.ts +0 -71
@@ -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;
@@ -162,6 +165,7 @@ function retrack(effectFn, subscriber) {
162
165
  }
163
166
  currentSubscriber = subscriber;
164
167
  const sub = subscriber;
168
+ if (sub._cap === void 0) sub._cap = currentDisposerCapture();
165
169
  const epoch = ++subscriberEpochCounter;
166
170
  sub._epoch = epoch;
167
171
  sub._structDirty = false;
@@ -353,7 +357,12 @@ function drainQueue() {
353
357
  quarantined.add(sub);
354
358
  continue;
355
359
  }
356
- safeInvoke(sub);
360
+ const pushed = beginDisposerCapture(sub._cap ?? null);
361
+ try {
362
+ safeInvoke(sub);
363
+ } finally {
364
+ if (pushed) endDisposerCapture();
365
+ }
357
366
  }
358
367
  }
359
368
  function drainNotificationQueue() {
@@ -489,7 +498,7 @@ function forEachSubscriber(signal, visit) {
489
498
  }
490
499
 
491
500
  // src/reactivity/track.ts
492
- var _runtimeVersion = true ? "4.5.0" : "dev";
501
+ var _runtimeVersion = true ? "4.6.0" : "dev";
493
502
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
494
503
  function resolveReactiveApi() {
495
504
  const g = globalThis;