@bakery-framework/core 2.0.0-alpha.13 → 2.0.0-alpha.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bakery-framework/core",
3
- "version": "2.0.0-alpha.13",
3
+ "version": "2.0.0-alpha.15",
4
4
  "description": "Bakery framework core: handlers, router, config, session, caches, logger, compiler.",
5
5
  "keywords": [
6
6
  "bakery",
@@ -29,6 +29,41 @@ export function checkCacheVersion(): Promise<void> {
29
29
  return done
30
30
  }
31
31
 
32
+ /** Every field that decides whether a compiled artifact is still valid. */
33
+ export interface CacheMarker {
34
+ mode: string
35
+ version: string
36
+ framework: string
37
+ runtime: string
38
+ }
39
+
40
+ /**
41
+ * Whether a marker describes a cache the current process can still use.
42
+ *
43
+ * Exported and called rather than restated, which is the point. The tests
44
+ * beside this file used to write the comparison out a second time and assert
45
+ * on their own copy - so they passed whichever fields the real code compared,
46
+ * and would have gone on passing if one were dropped. Adding `runtime` is what
47
+ * made that visible: three tests agreed the marker "carries all three fields"
48
+ * while the code had four.
49
+ *
50
+ * A missing field reads as stale, which is the intended upgrade path. A marker
51
+ * written before a field existed describes a cache built under conditions
52
+ * nobody recorded, and one wipe is cheaper than guessing.
53
+ */
54
+ export function isCacheStale(
55
+ prev: Partial<CacheMarker> | null | undefined,
56
+ current: CacheMarker,
57
+ ): boolean {
58
+ if (!prev) return true
59
+ return (
60
+ prev.mode !== current.mode ||
61
+ prev.version !== current.version ||
62
+ prev.framework !== current.framework ||
63
+ prev.runtime !== current.runtime
64
+ )
65
+ }
66
+
32
67
  /** Test seam: forget that the check ran, so a fixture can exercise it again. */
33
68
  export function __resetCacheVersionCheck(): void {
34
69
  done = null
@@ -55,17 +90,32 @@ async function run(): Promise<void> {
55
90
  // framework version, with nothing to invalidate it.
56
91
  version: getAppVersion(),
57
92
  framework: getFrameworkVersion(),
93
+ // **And the runtime, for exactly the same reason one level down.**
94
+ //
95
+ // This directory holds *compiled and bundled output* - `html/`, `static/`,
96
+ // `ts_cache/`, the console bundle. Bun's transpiler and bundler produce it,
97
+ // so a Bun upgrade changes what a correct entry looks like, and nothing
98
+ // here used to notice.
99
+ //
100
+ // Not hypothetical, and found the day it happened. Bun 1.4.1 reworked the
101
+ // bundler's barrel optimisation across ten commits: 1.4.0 emptied a
102
+ // `sideEffects: false` re-export entry to `export { a };` with no
103
+ // declaration, which is the husk `compiler.ts` carries a repair for. So a
104
+ // cache written by 1.4.0 can hold a husk that the running 1.4.2 would
105
+ // never have produced, and would have served it for the life of the
106
+ // install. 1.4.1 is worse in a quieter way: a bundle it built can rename a
107
+ // `let` onto a function parameter's name and compute **wrong values**
108
+ // while loading perfectly (oven-sh/bun#41354).
109
+ //
110
+ // `Bun.version` rather than `Bun.revision`: a canary build of the same
111
+ // version is a real distinction, but invalidating on every canary would
112
+ // wipe the cache of anyone tracking one, and the failure this prevents is
113
+ // a released bundler change.
114
+ runtime: Bun.version,
58
115
  }
59
116
 
60
117
  const [err, prev] = await Try.catch(() => Bun.file(markerPath).json())
61
- const stale =
62
- err ||
63
- !prev ||
64
- prev.mode !== current.mode ||
65
- prev.version !== current.version ||
66
- prev.framework !== current.framework
67
-
68
- if (!stale) return
118
+ if (!err && !isCacheStale(prev, current)) return
69
119
 
70
120
  const survivors = await wipe(cacheDir)
71
121
  if (!fs.exists(cacheDir)) await fs.mkdir(cacheDir)