canopycms 0.0.56 → 0.0.58

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 (272) hide show
  1. package/dist/ai/json-to-markdown.js +74 -3
  2. package/dist/ai/json-to-markdown.js.map +1 -1
  3. package/dist/api/__test__/mock-client.d.ts +9 -5
  4. package/dist/api/__test__/mock-client.d.ts.map +1 -1
  5. package/dist/api/__test__/mock-client.js +15 -7
  6. package/dist/api/__test__/mock-client.js.map +1 -1
  7. package/dist/api/assets.d.ts +100 -36
  8. package/dist/api/assets.d.ts.map +1 -1
  9. package/dist/api/assets.js +338 -51
  10. package/dist/api/assets.js.map +1 -1
  11. package/dist/api/branch.d.ts +6 -0
  12. package/dist/api/branch.d.ts.map +1 -1
  13. package/dist/api/branch.js +63 -19
  14. package/dist/api/branch.js.map +1 -1
  15. package/dist/api/client.d.ts +16 -5
  16. package/dist/api/client.d.ts.map +1 -1
  17. package/dist/api/client.js +24 -6
  18. package/dist/api/client.js.map +1 -1
  19. package/dist/api/content.d.ts +2 -2
  20. package/dist/api/entries.d.ts +4 -4
  21. package/dist/api/entries.d.ts.map +1 -1
  22. package/dist/api/entries.js +10 -2
  23. package/dist/api/entries.js.map +1 -1
  24. package/dist/api/index.d.ts +1 -1
  25. package/dist/api/index.d.ts.map +1 -1
  26. package/dist/api/index.js.map +1 -1
  27. package/dist/api/route-builder.d.ts +9 -0
  28. package/dist/api/route-builder.d.ts.map +1 -1
  29. package/dist/api/route-builder.js +1 -0
  30. package/dist/api/route-builder.js.map +1 -1
  31. package/dist/api/schema.d.ts +4 -4
  32. package/dist/api/types.d.ts +11 -1
  33. package/dist/api/types.d.ts.map +1 -1
  34. package/dist/assets/asset-prefixes.d.ts +31 -0
  35. package/dist/assets/asset-prefixes.d.ts.map +1 -0
  36. package/dist/assets/asset-prefixes.js +20 -0
  37. package/dist/assets/asset-prefixes.js.map +1 -0
  38. package/dist/assets/asset-src.d.ts +23 -0
  39. package/dist/assets/asset-src.d.ts.map +1 -0
  40. package/dist/assets/asset-src.js +28 -0
  41. package/dist/assets/asset-src.js.map +1 -0
  42. package/dist/assets/asset-url.d.ts +35 -0
  43. package/dist/assets/asset-url.d.ts.map +1 -0
  44. package/dist/assets/asset-url.js +77 -0
  45. package/dist/assets/asset-url.js.map +1 -0
  46. package/dist/assets/factory.d.ts +18 -0
  47. package/dist/assets/factory.d.ts.map +1 -0
  48. package/dist/assets/factory.js +42 -0
  49. package/dist/assets/factory.js.map +1 -0
  50. package/dist/assets/finalize.d.ts +36 -0
  51. package/dist/assets/finalize.d.ts.map +1 -0
  52. package/dist/assets/finalize.js +72 -0
  53. package/dist/assets/finalize.js.map +1 -0
  54. package/dist/assets/index.d.ts +20 -0
  55. package/dist/assets/index.d.ts.map +1 -0
  56. package/dist/assets/index.js +19 -0
  57. package/dist/assets/index.js.map +1 -0
  58. package/dist/assets/keys.d.ts +56 -0
  59. package/dist/assets/keys.d.ts.map +1 -0
  60. package/dist/assets/keys.js +88 -0
  61. package/dist/assets/keys.js.map +1 -0
  62. package/dist/assets/pipeline.d.ts +50 -0
  63. package/dist/assets/pipeline.d.ts.map +1 -0
  64. package/dist/assets/pipeline.js +202 -0
  65. package/dist/assets/pipeline.js.map +1 -0
  66. package/dist/assets/store-local.d.ts +84 -0
  67. package/dist/assets/store-local.d.ts.map +1 -0
  68. package/dist/assets/store-local.js +254 -0
  69. package/dist/assets/store-local.js.map +1 -0
  70. package/dist/assets/store-s3.d.ts +71 -0
  71. package/dist/assets/store-s3.d.ts.map +1 -0
  72. package/dist/assets/store-s3.js +183 -0
  73. package/dist/assets/store-s3.js.map +1 -0
  74. package/dist/assets/svg-sanitizer.d.ts +37 -0
  75. package/dist/assets/svg-sanitizer.d.ts.map +1 -0
  76. package/dist/assets/svg-sanitizer.js +222 -0
  77. package/dist/assets/svg-sanitizer.js.map +1 -0
  78. package/dist/assets/transform-directives.d.ts +97 -0
  79. package/dist/assets/transform-directives.d.ts.map +1 -0
  80. package/dist/assets/transform-directives.js +267 -0
  81. package/dist/assets/transform-directives.js.map +1 -0
  82. package/dist/assets/transform.d.ts +51 -0
  83. package/dist/assets/transform.d.ts.map +1 -0
  84. package/dist/assets/transform.js +190 -0
  85. package/dist/assets/transform.js.map +1 -0
  86. package/dist/assets/types.d.ts +82 -0
  87. package/dist/assets/types.d.ts.map +1 -0
  88. package/dist/assets/types.js +10 -0
  89. package/dist/assets/types.js.map +1 -0
  90. package/dist/authorization/groups/schema.d.ts +2 -2
  91. package/dist/authorization/permissions/schema.d.ts +2 -2
  92. package/dist/branch-metadata.d.ts +71 -6
  93. package/dist/branch-metadata.d.ts.map +1 -1
  94. package/dist/branch-metadata.js +132 -116
  95. package/dist/branch-metadata.js.map +1 -1
  96. package/dist/branch-registry.d.ts +78 -9
  97. package/dist/branch-registry.d.ts.map +1 -1
  98. package/dist/branch-registry.js +155 -29
  99. package/dist/branch-registry.js.map +1 -1
  100. package/dist/branch-schema-cache.d.ts +126 -11
  101. package/dist/branch-schema-cache.d.ts.map +1 -1
  102. package/dist/branch-schema-cache.js +208 -58
  103. package/dist/branch-schema-cache.js.map +1 -1
  104. package/dist/cli/generate-ai-content.js +1993 -1506
  105. package/dist/cli/init.js +16 -4
  106. package/dist/cli/migrate.d.ts.map +1 -1
  107. package/dist/cli/migrate.js +25 -0
  108. package/dist/cli/migrate.js.map +1 -1
  109. package/dist/cli/sync.js +5 -5
  110. package/dist/cli/sync.js.map +1 -1
  111. package/dist/comment-store.d.ts +45 -15
  112. package/dist/comment-store.d.ts.map +1 -1
  113. package/dist/comment-store.js +80 -101
  114. package/dist/comment-store.js.map +1 -1
  115. package/dist/config/helpers.d.ts.map +1 -1
  116. package/dist/config/helpers.js +2 -1
  117. package/dist/config/helpers.js.map +1 -1
  118. package/dist/config/index.d.ts +2 -2
  119. package/dist/config/index.d.ts.map +1 -1
  120. package/dist/config/index.js +1 -1
  121. package/dist/config/index.js.map +1 -1
  122. package/dist/config/schemas/config.d.ts +10 -0
  123. package/dist/config/schemas/config.d.ts.map +1 -1
  124. package/dist/config/schemas/field.d.ts +38 -3
  125. package/dist/config/schemas/field.d.ts.map +1 -1
  126. package/dist/config/schemas/field.js +18 -0
  127. package/dist/config/schemas/field.js.map +1 -1
  128. package/dist/config/schemas/media.d.ts +8 -0
  129. package/dist/config/schemas/media.d.ts.map +1 -1
  130. package/dist/config/schemas/media.js +9 -0
  131. package/dist/config/schemas/media.js.map +1 -1
  132. package/dist/config/types.d.ts +43 -3
  133. package/dist/config/types.d.ts.map +1 -1
  134. package/dist/config/types.js +4 -1
  135. package/dist/config/types.js.map +1 -1
  136. package/dist/content-index-generation.d.ts +40 -4
  137. package/dist/content-index-generation.d.ts.map +1 -1
  138. package/dist/content-index-generation.js +70 -73
  139. package/dist/content-index-generation.js.map +1 -1
  140. package/dist/content-store.d.ts +63 -0
  141. package/dist/content-store.d.ts.map +1 -1
  142. package/dist/content-store.js +421 -194
  143. package/dist/content-store.js.map +1 -1
  144. package/dist/editor/CanopyEditor.d.ts.map +1 -1
  145. package/dist/editor/CanopyEditor.js +1 -1
  146. package/dist/editor/CanopyEditor.js.map +1 -1
  147. package/dist/editor/Editor.d.ts +2 -0
  148. package/dist/editor/Editor.d.ts.map +1 -1
  149. package/dist/editor/Editor.js +82 -80
  150. package/dist/editor/Editor.js.map +1 -1
  151. package/dist/editor/FormRenderer.d.ts.map +1 -1
  152. package/dist/editor/FormRenderer.js +9 -0
  153. package/dist/editor/FormRenderer.js.map +1 -1
  154. package/dist/editor/components/EditorSidebar.d.ts +6 -1
  155. package/dist/editor/components/EditorSidebar.d.ts.map +1 -1
  156. package/dist/editor/components/EditorSidebar.js +4 -3
  157. package/dist/editor/components/EditorSidebar.js.map +1 -1
  158. package/dist/editor/context/AssetContext.d.ts +25 -0
  159. package/dist/editor/context/AssetContext.d.ts.map +1 -0
  160. package/dist/editor/context/AssetContext.js +26 -0
  161. package/dist/editor/context/AssetContext.js.map +1 -0
  162. package/dist/editor/context/index.d.ts +1 -0
  163. package/dist/editor/context/index.d.ts.map +1 -1
  164. package/dist/editor/context/index.js +1 -0
  165. package/dist/editor/context/index.js.map +1 -1
  166. package/dist/editor/fields/ImageField.d.ts +22 -0
  167. package/dist/editor/fields/ImageField.d.ts.map +1 -0
  168. package/dist/editor/fields/ImageField.js +100 -0
  169. package/dist/editor/fields/ImageField.js.map +1 -0
  170. package/dist/editor/fields/MarkdownField.d.ts.map +1 -1
  171. package/dist/editor/fields/MarkdownField.js +30 -4
  172. package/dist/editor/fields/MarkdownField.js.map +1 -1
  173. package/dist/editor/fields/MdxImageDialog.d.ts +16 -0
  174. package/dist/editor/fields/MdxImageDialog.d.ts.map +1 -0
  175. package/dist/editor/fields/MdxImageDialog.js +73 -0
  176. package/dist/editor/fields/MdxImageDialog.js.map +1 -0
  177. package/dist/editor/media/AssetCard.d.ts +21 -0
  178. package/dist/editor/media/AssetCard.d.ts.map +1 -0
  179. package/dist/editor/media/AssetCard.js +41 -0
  180. package/dist/editor/media/AssetCard.js.map +1 -0
  181. package/dist/editor/media/CropStep.d.ts +26 -0
  182. package/dist/editor/media/CropStep.d.ts.map +1 -0
  183. package/dist/editor/media/CropStep.js +38 -0
  184. package/dist/editor/media/CropStep.js.map +1 -0
  185. package/dist/editor/media/MediaLibrary.d.ts +22 -0
  186. package/dist/editor/media/MediaLibrary.d.ts.map +1 -0
  187. package/dist/editor/media/MediaLibrary.js +17 -0
  188. package/dist/editor/media/MediaLibrary.js.map +1 -0
  189. package/dist/editor/media/MediaLibraryBody.d.ts +17 -0
  190. package/dist/editor/media/MediaLibraryBody.d.ts.map +1 -0
  191. package/dist/editor/media/MediaLibraryBody.js +133 -0
  192. package/dist/editor/media/MediaLibraryBody.js.map +1 -0
  193. package/dist/editor/media/crop-math.d.ts +37 -0
  194. package/dist/editor/media/crop-math.d.ts.map +1 -0
  195. package/dist/editor/media/crop-math.js +62 -0
  196. package/dist/editor/media/crop-math.js.map +1 -0
  197. package/dist/editor/media/upload-asset.d.ts +31 -0
  198. package/dist/editor/media/upload-asset.d.ts.map +1 -0
  199. package/dist/editor/media/upload-asset.js +56 -0
  200. package/dist/editor/media/upload-asset.js.map +1 -0
  201. package/dist/editor/media/upload-constants.d.ts +27 -0
  202. package/dist/editor/media/upload-constants.d.ts.map +1 -0
  203. package/dist/editor/media/upload-constants.js +40 -0
  204. package/dist/editor/media/upload-constants.js.map +1 -0
  205. package/dist/editor/media/useAssetUpload.d.ts +19 -0
  206. package/dist/editor/media/useAssetUpload.d.ts.map +1 -0
  207. package/dist/editor/media/useAssetUpload.js +53 -0
  208. package/dist/editor/media/useAssetUpload.js.map +1 -0
  209. package/dist/editor/media/xhr-upload.d.ts +20 -0
  210. package/dist/editor/media/xhr-upload.d.ts.map +1 -0
  211. package/dist/editor/media/xhr-upload.js +42 -0
  212. package/dist/editor/media/xhr-upload.js.map +1 -0
  213. package/dist/editor/theme.d.ts +2 -1
  214. package/dist/editor/theme.d.ts.map +1 -1
  215. package/dist/editor/theme.js +1 -0
  216. package/dist/editor/theme.js.map +1 -1
  217. package/dist/entry-schema.d.ts +19 -0
  218. package/dist/entry-schema.d.ts.map +1 -1
  219. package/dist/entry-schema.js.map +1 -1
  220. package/dist/git-manager.d.ts +15 -10
  221. package/dist/git-manager.d.ts.map +1 -1
  222. package/dist/git-manager.js +16 -11
  223. package/dist/git-manager.js.map +1 -1
  224. package/dist/http/handler.d.ts +5 -2
  225. package/dist/http/handler.d.ts.map +1 -1
  226. package/dist/http/handler.js +13 -4
  227. package/dist/http/handler.js.map +1 -1
  228. package/dist/http/index.d.ts +2 -2
  229. package/dist/http/index.d.ts.map +1 -1
  230. package/dist/http/index.js +1 -1
  231. package/dist/http/index.js.map +1 -1
  232. package/dist/http/router.d.ts +14 -1
  233. package/dist/http/router.d.ts.map +1 -1
  234. package/dist/http/router.js +4 -1
  235. package/dist/http/router.js.map +1 -1
  236. package/dist/http/types.d.ts +40 -0
  237. package/dist/http/types.d.ts.map +1 -1
  238. package/dist/http/types.js +9 -0
  239. package/dist/http/types.js.map +1 -1
  240. package/dist/index.d.ts +3 -0
  241. package/dist/index.d.ts.map +1 -1
  242. package/dist/index.js +4 -0
  243. package/dist/index.js.map +1 -1
  244. package/dist/resource-generation.d.ts +54 -0
  245. package/dist/resource-generation.d.ts.map +1 -0
  246. package/dist/resource-generation.js +156 -0
  247. package/dist/resource-generation.js.map +1 -0
  248. package/dist/schema/schema-store.d.ts +31 -4
  249. package/dist/schema/schema-store.d.ts.map +1 -1
  250. package/dist/schema/schema-store.js +47 -8
  251. package/dist/schema/schema-store.js.map +1 -1
  252. package/dist/server.d.ts +45 -0
  253. package/dist/server.d.ts.map +1 -1
  254. package/dist/server.js +41 -0
  255. package/dist/server.js.map +1 -1
  256. package/dist/sync-core.js +2 -2
  257. package/dist/sync-core.js.map +1 -1
  258. package/dist/utils/occ-json-write.d.ts +100 -0
  259. package/dist/utils/occ-json-write.d.ts.map +1 -0
  260. package/dist/utils/occ-json-write.js +234 -0
  261. package/dist/utils/occ-json-write.js.map +1 -0
  262. package/dist/validation/entry-validator.d.ts.map +1 -1
  263. package/dist/validation/entry-validator.js +56 -1
  264. package/dist/validation/entry-validator.js.map +1 -1
  265. package/dist/worker/cms-worker.d.ts.map +1 -1
  266. package/dist/worker/cms-worker.js +21 -3
  267. package/dist/worker/cms-worker.js.map +1 -1
  268. package/package.json +13 -1
  269. package/dist/asset-store.d.ts +0 -32
  270. package/dist/asset-store.d.ts.map +0 -1
  271. package/dist/asset-store.js +0 -85
  272. package/dist/asset-store.js.map +0 -1
@@ -3,16 +3,24 @@ import path from 'node:path';
3
3
  import { resolveSchema, isValidSchema } from './schema/resolver.js';
4
4
  import { flattenSchema } from './config/flatten.js';
5
5
  import { isBuildMode } from './build-mode.js';
6
+ import { bumpResourceGeneration, readResourceGeneration, isGenerationCurrent, } from './resource-generation.js';
6
7
  /** Bump when BranchSchemaCacheEntry shape changes to auto-invalidate stale caches */
7
- const SCHEMA_CACHE_VERSION = 2;
8
+ const SCHEMA_CACHE_VERSION = 3;
8
9
  /** Minimum interval between mtime staleness checks (ms) */
9
10
  const MTIME_CHECK_DEBOUNCE_MS = 1000;
11
+ /** resource-generation.ts resource key for the schema cache's marker. */
12
+ export const SCHEMA_GENERATION_RESOURCE = 'schema';
10
13
  /**
11
14
  * In dev mode, check whether any .collection.json file under dir has been
12
15
  * modified more recently than cachedAt. Returns true if stale.
13
16
  *
14
17
  * Uses a single recursive readdir to find all .collection.json files,
15
18
  * then stats only those files.
19
+ *
20
+ * This is a dev-only convenience for out-of-band hand edits made directly to
21
+ * .collection.json files outside the CMS (which don't go through SchemaOps
22
+ * and therefore never bump the generation marker below). It is not needed for
23
+ * prod correctness: every mutation path that matters in prod bumps the marker.
16
24
  */
17
25
  async function isStaleByMtime(dir, cachedAt) {
18
26
  let entries;
@@ -39,17 +47,75 @@ async function isStaleByMtime(dir, cachedAt) {
39
47
  return false;
40
48
  }
41
49
  /**
42
- * Manages per-branch schema caching with lazy loading and automatic invalidation.
50
+ * Manages per-branch schema caching with lazy loading and automatic
51
+ * invalidation.
43
52
  *
44
- * Caching Strategy:
45
- * - File-based cache at {branchRoot}/.canopy-meta/schema-cache.json (no in-memory layer
46
- * — intentional: matches prod behavior and keeps cache coherent across Lambda invocations)
47
- * - Invalidation: Writers create .stale marker, causing cache regeneration on next access
53
+ * ## Cross-process freshness (resource-generation.ts marker protocol)
54
+ *
55
+ * Several warm Lambda containers plus the EC2 worker can share one
56
+ * branch-clone root over EFS, each with its own copy of
57
+ * `schema-cache.json`. There is no shared memory and no cross-host file
58
+ * watching, so freshness is coordinated via the generic on-disk generation
59
+ * marker in resource-generation.ts: every cached snapshot embeds the marker
60
+ * token it was resolved against, and every read cheaply re-checks the live
61
+ * marker before trusting the cache. See that module's doc comment for the
62
+ * full protocol and residual staleness windows (A/B/C/E).
63
+ *
64
+ * BranchSchemaCache is the "durable snapshot consumer" case called out there:
65
+ * a resolve whose scan is served from stale NFS dentry/attribute caches can
66
+ * record a FRESH token over STALE data (window E), and because the result is
67
+ * written to `schema-cache.json`, that staleness becomes durable and shared
68
+ * with every other host that reads the marker - not just one process's
69
+ * memory. `loadFromCacheOrResolve` mitigates this the same way
70
+ * BranchRegistry does:
48
71
  *
49
- * Multi-User Support:
50
- * - User A modifies schema via SchemaOps → writes .stale marker
51
- * - User B loads schema later → sees .stale marker → regenerates cache
52
- * - Atomic file operations prevent corruption during concurrent access
72
+ * - The marker is captured strictly BEFORE `resolveFresh()` runs, and the
73
+ * captured token (not one read after resolving) is what gets embedded in
74
+ * the persisted snapshot. A bump landing mid-resolve therefore leaves the
75
+ * embedded token older than the live marker, forcing a re-resolve on the
76
+ * next read instead of silently resurrecting stale schema.
77
+ * - A snapshot is only persisted when the marker read itself succeeded
78
+ * (`{ ok: true }`). If the read fails for a reason other than "never
79
+ * bumped", we cannot attribute a token to this resolve, and stamping the
80
+ * snapshot with an unattributable token would make it indistinguishable
81
+ * from a correctly-attributed one to every future reader. The fresh result
82
+ * is still served to this caller; it just isn't written durably.
83
+ * - invalidate() bumps the marker with `mustSucceed: true`: an explicit
84
+ * invalidation (e.g. after a schema mutation) must not silently fail and
85
+ * leave every reader confidently stale with no bounding backstop.
86
+ * invalidate() itself does NOT eager-regenerate - it isn't given the
87
+ * entrySchemaRegistry/contentRootName that resolveSchema needs. The
88
+ * eager re-resolve (window-E mitigation, mirroring BranchRegistry's
89
+ * eager regen) lives one level up in SchemaOps.invalidateSchemaCache()
90
+ * (schema/schema-store.ts), which has those arguments and calls
91
+ * {@link resolveAndPersist} (NOT getSchema()) right after invalidating -
92
+ * so every SchemaOps mutation re-resolves on the mutating host via a scan
93
+ * that is GUARANTEED to run, not merely likely to run. getSchema() would
94
+ * be the wrong call here: its cache-read fast path can short-circuit
95
+ * through a snapshot a DIFFERENT concurrent host just wrote (see
96
+ * resolveAndPersist()'s doc comment for the exact race), silently
97
+ * skipping the one scan this eager re-resolve exists to guarantee. (The
98
+ * editor's follow-up schema GET is a separate Lambda invocation with no
99
+ * container affinity, so it could not serve this purpose either.)
100
+ * Callers of invalidate() that bypass SchemaOps (api/schema.ts's explicit
101
+ * invalidate endpoint; the bulk-mutation bump in
102
+ * invalidateBranchContentCaches) accept the lazy next-read regen.
103
+ *
104
+ * This is also why prod needs no mtime walk: the dev-only mtime check below
105
+ * exists solely to catch hand edits to .collection.json made outside the CMS
106
+ * (which bypass SchemaOps and therefore never bump the marker). Every
107
+ * mutation path that matters in prod - SchemaOps writes, git working-tree
108
+ * rewrites (checkout/merge/rebase/sync/migrate) - bumps the marker via
109
+ * SchemaOps.invalidateSchemaCache() or the combined
110
+ * invalidateBranchContentCaches() helper in content-index-generation.ts, so
111
+ * the marker alone is a sufficient prod backstop.
112
+ *
113
+ * Caching Strategy:
114
+ * - File-based cache at {branchRoot}/.canopy-meta/schema-cache.json (no
115
+ * in-memory layer - intentional: matches prod behavior and keeps cache
116
+ * coherent across Lambda invocations)
117
+ * - Invalidation: invalidate() bumps the cross-process generation marker;
118
+ * every reader sharing this branchRoot re-resolves at its next access.
53
119
  */
54
120
  export class BranchSchemaCache {
55
121
  constructor(mode = 'prod') {
@@ -80,6 +146,15 @@ export class BranchSchemaCache {
80
146
  async getSchema(branchRoot, entrySchemaRegistry, contentRootName = 'content') {
81
147
  return this.loadFromCacheOrResolve(branchRoot, entrySchemaRegistry, contentRootName);
82
148
  }
149
+ /**
150
+ * Resolve the schema from disk. Wrapped in a protected method (rather than
151
+ * calling the imported resolveSchema directly) so tests can subclass and
152
+ * override with a deferred/blocking implementation to simulate cross-process
153
+ * interleavings — mirrors BranchRegistry's scanBranchDirectories() hook.
154
+ */
155
+ async resolveFresh(contentRoot, entrySchemaRegistry) {
156
+ return resolveSchema(contentRoot, entrySchemaRegistry);
157
+ }
83
158
  /**
84
159
  * Load schema from cache or resolve fresh if cache is missing or stale.
85
160
  */
@@ -91,43 +166,71 @@ export class BranchSchemaCache {
91
166
  if (!skipDiskCache) {
92
167
  const cacheDir = path.join(branchRoot, '.canopy-meta');
93
168
  const cachePath = path.join(cacheDir, 'schema-cache.json');
94
- const stalePath = path.join(cacheDir, 'schema-cache.stale');
95
- // Check if cache exists and is not marked stale
96
169
  let cacheData = null;
97
170
  try {
98
- const staleExists = await fs
99
- .access(stalePath)
100
- .then(() => true)
101
- .catch(() => false);
102
- if (!staleExists) {
103
- const cacheContent = await fs.readFile(cachePath, 'utf-8');
104
- cacheData = JSON.parse(cacheContent);
105
- }
171
+ const cacheContent = await fs.readFile(cachePath, 'utf-8');
172
+ cacheData = JSON.parse(cacheContent);
106
173
  }
107
174
  catch {
108
175
  // Cache doesn't exist or can't be read
109
176
  cacheData = null;
110
177
  }
178
+ // Strict version check: a truthy-only check would accept a persisted
179
+ // pre-marker snapshot (no `generation` field) left on EFS after a
180
+ // rolling deploy, and `cacheData.generation` would then be `undefined`
181
+ // rather than a real token or explicit `null`, breaking the freshness
182
+ // comparison below.
111
183
  if (cacheData && cacheData.version === SCHEMA_CACHE_VERSION) {
112
- // In dev mode, also check file mtimes so direct schema edits (outside the CMS) are picked up.
113
- // Debounce: skip the walk if we checked this contentRoot within the last second.
114
- const now = Date.now();
115
- const lastCheck = this.lastMtimeCheck.get(contentRoot) ?? 0;
116
- if (this.devMode &&
117
- now - lastCheck >= MTIME_CHECK_DEBOUNCE_MS &&
118
- (await isStaleByMtime(contentRoot, new Date(cacheData.cachedAt)))) {
119
- this.lastMtimeCheck.set(contentRoot, now);
120
- cacheData = null;
184
+ const read = await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
185
+ if (isGenerationCurrent(cacheData.generation, read)) {
186
+ // In dev mode, also check file mtimes so direct schema edits (outside the CMS) are picked up.
187
+ // Debounce: skip the walk if we checked this contentRoot within the last second.
188
+ const now = Date.now();
189
+ const lastCheck = this.lastMtimeCheck.get(contentRoot) ?? 0;
190
+ if (this.devMode &&
191
+ now - lastCheck >= MTIME_CHECK_DEBOUNCE_MS &&
192
+ (await isStaleByMtime(contentRoot, new Date(cacheData.cachedAt)))) {
193
+ this.lastMtimeCheck.set(contentRoot, now);
194
+ cacheData = null;
195
+ }
196
+ else {
197
+ if (this.devMode)
198
+ this.lastMtimeCheck.set(contentRoot, now);
199
+ return { schema: cacheData.schema, flatSchema: cacheData.flatSchema };
200
+ }
121
201
  }
122
202
  else {
123
- if (this.devMode)
124
- this.lastMtimeCheck.set(contentRoot, now);
125
- return { schema: cacheData.schema, flatSchema: cacheData.flatSchema };
203
+ // Marker mismatch (or unreadable) — treat as a cache miss.
204
+ cacheData = null;
126
205
  }
127
206
  }
207
+ else {
208
+ cacheData = null;
209
+ }
128
210
  }
129
- // Cache miss, stale, or build mode - resolve fresh
130
- const result = await resolveSchema(contentRoot, entrySchemaRegistry);
211
+ // Cache miss, stale, or build mode - resolve fresh (and persist, subject
212
+ // to the same skip-persist rule) via the shared resolve half.
213
+ return this.resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, {
214
+ skipDiskCache,
215
+ });
216
+ }
217
+ /**
218
+ * Resolve the schema fresh from disk and persist it (subject to the
219
+ * skip-persist rule below), UNCONDITIONALLY -- never through the cache-read
220
+ * fast path in {@link loadFromCacheOrResolve}. Shared by that method's
221
+ * cache-miss fallback and by {@link resolveAndPersist}.
222
+ */
223
+ async resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, options) {
224
+ const { skipDiskCache } = options;
225
+ const contentRoot = path.join(branchRoot, contentRootName);
226
+ // Capture the marker strictly BEFORE resolving: a bump landing mid-resolve
227
+ // then differs from the token recorded below, forcing a re-resolve on the
228
+ // next read instead of silently persisting a snapshot that embeds a fresh
229
+ // token over pre-mutation data.
230
+ const read = skipDiskCache
231
+ ? null
232
+ : await readResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE);
233
+ const result = await this.resolveFresh(contentRoot, entrySchemaRegistry);
131
234
  // Validate schema has content
132
235
  if (!isValidSchema(result.schema)) {
133
236
  throw new Error(`No schema found in ${contentRoot}. Create .collection.json files ` +
@@ -138,41 +241,88 @@ export class BranchSchemaCache {
138
241
  if (!skipDiskCache) {
139
242
  const cacheDir = path.join(branchRoot, '.canopy-meta');
140
243
  const cachePath = path.join(cacheDir, 'schema-cache.json');
141
- const stalePath = path.join(cacheDir, 'schema-cache.stale');
142
- // Save to cache
143
- await fs.mkdir(cacheDir, { recursive: true });
144
- const newCache = {
145
- version: SCHEMA_CACHE_VERSION,
146
- schema: result.schema,
147
- flatSchema,
148
- cachedAt: new Date().toISOString(),
149
- };
150
- // Atomic write: write to temp file, then rename
151
- const tmpPath = path.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
152
- await fs.writeFile(tmpPath, JSON.stringify(newCache, null, 2), 'utf-8');
153
- await fs.rename(tmpPath, cachePath);
154
- // Remove stale marker if exists
155
- try {
156
- await fs.unlink(stalePath);
157
- }
158
- catch {
159
- // Stale marker may not exist - that's fine
244
+ // Opportunistic cleanup of the legacy .stale marker file from the old
245
+ // rename-based invalidation scheme (e.g. a process upgraded mid-flight
246
+ // may find one left over from before the deploy). Not load-bearing.
247
+ await fs.unlink(path.join(cacheDir, 'schema-cache.stale')).catch(() => { });
248
+ if (read && read.ok) {
249
+ const newCache = {
250
+ version: SCHEMA_CACHE_VERSION,
251
+ schema: result.schema,
252
+ flatSchema,
253
+ cachedAt: new Date().toISOString(),
254
+ generation: read.token,
255
+ };
256
+ // Atomic write: write to temp file, then rename. Clean up the temp
257
+ // file on a failed rename (matches every other atomic write in the
258
+ // codebase, e.g. utils/atomic-write.ts) so a transient rename error
259
+ // doesn't leak a stray `.tmp` file into `.canopy-meta/` forever.
260
+ await fs.mkdir(cacheDir, { recursive: true });
261
+ const tmpPath = path.join(cacheDir, `schema-cache.tmp.${Date.now()}.${Math.random()}.json`);
262
+ await fs.writeFile(tmpPath, JSON.stringify(newCache, null, 2), 'utf-8');
263
+ try {
264
+ await fs.rename(tmpPath, cachePath);
265
+ }
266
+ catch (err) {
267
+ await fs.unlink(tmpPath).catch(() => { });
268
+ throw err;
269
+ }
160
270
  }
271
+ // else: the marker couldn't be read for a reason other than "never
272
+ // bumped" - we cannot attribute a token to this resolve, and stamping
273
+ // the snapshot with an unattributable token would make it
274
+ // indistinguishable from a correctly-attributed one to every future
275
+ // reader. Serve the fresh result without persisting it; the next read
276
+ // retries the marker read and, on success, resolves and persists
277
+ // normally.
161
278
  }
162
279
  return { schema: result.schema, flatSchema };
163
280
  }
164
281
  /**
165
- * Invalidate cache for a branch (creates .stale marker).
282
+ * Resolve the schema fresh from disk and persist it, SKIPPING the cache
283
+ * read entirely -- unlike {@link getSchema}, which can short-circuit
284
+ * through a cache HIT. That distinction matters for eager re-resolve after
285
+ * invalidation (see {@link invalidate}'s doc comment and
286
+ * `SchemaOps.invalidateSchemaCache()` in schema/schema-store.ts, the sole
287
+ * intended caller): the whole point of an eager re-resolve is to guarantee
288
+ * ONE scan that is coherent with the mutation this host just made. A plain
289
+ * `getSchema()` call right after `invalidate()` is NOT that guarantee --
290
+ * `getSchema()`'s cache-read fast path (`loadFromCacheOrResolve`) can still
291
+ * return a snapshot written by a DIFFERENT, concurrent host: if that
292
+ * foreign host's own eager re-resolve raced this one and embedded the
293
+ * (now-current) marker token over ITS OWN stale-NFS-cache scan (the
294
+ * window-E case this class's doc comment describes), this host's
295
+ * `getSchema()` would happily accept that foreign snapshot as "current"
296
+ * and skip the one scan this call was specifically trying to guarantee.
297
+ * `resolveAndPersist()` never reads the cache file at all, so it cannot be
298
+ * short-circuited that way.
299
+ */
300
+ async resolveAndPersist(branchRoot, entrySchemaRegistry, contentRootName = 'content') {
301
+ const skipDiskCache = this.skipDiskCache(branchRoot);
302
+ return this.resolveFreshAndPersist(branchRoot, entrySchemaRegistry, contentRootName, {
303
+ skipDiskCache,
304
+ });
305
+ }
306
+ /**
307
+ * Invalidate cache for a branch by bumping the cross-process generation
308
+ * marker (resource-generation.ts). Every process sharing this branchRoot
309
+ * will re-resolve at its next read.
310
+ *
311
+ * The bump must succeed: a swallowed failure here would leave the schema
312
+ * cache stale indefinitely with no bounding backstop (unlike
313
+ * BranchRegistry, there is no get-miss backstop for a resolved schema).
314
+ *
315
+ * No eager regeneration here (unlike BranchRegistry.invalidate()): this
316
+ * method isn't given the entrySchemaRegistry/contentRootName resolveSchema
317
+ * needs. See the class doc comment for why the mutating request's own
318
+ * follow-up schema read closes the same window-E gap instead.
166
319
  *
167
320
  * @param branchRoot - Root directory of the branch
168
321
  */
169
322
  async invalidate(branchRoot) {
170
323
  if (this.skipDiskCache(branchRoot))
171
324
  return;
172
- const cacheDir = path.join(branchRoot, '.canopy-meta');
173
- const stalePath = path.join(cacheDir, 'schema-cache.stale');
174
- await fs.mkdir(cacheDir, { recursive: true });
175
- await fs.writeFile(stalePath, '', 'utf-8');
325
+ await bumpResourceGeneration(branchRoot, SCHEMA_GENERATION_RESOURCE, { mustSucceed: true });
176
326
  }
177
327
  }
178
328
  //# sourceMappingURL=branch-schema-cache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch-schema-cache.js","sourceRoot":"","sources":["../src/branch-schema-cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"branch-schema-cache.js","sourceRoot":"","sources":["../src/branch-schema-cache.ts"],"names":[],"mappings":"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"}