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.
- package/dist/ai/json-to-markdown.js +74 -3
- package/dist/ai/json-to-markdown.js.map +1 -1
- package/dist/api/__test__/mock-client.d.ts +9 -5
- package/dist/api/__test__/mock-client.d.ts.map +1 -1
- package/dist/api/__test__/mock-client.js +15 -7
- package/dist/api/__test__/mock-client.js.map +1 -1
- package/dist/api/assets.d.ts +100 -36
- package/dist/api/assets.d.ts.map +1 -1
- package/dist/api/assets.js +338 -51
- package/dist/api/assets.js.map +1 -1
- package/dist/api/branch.d.ts +6 -0
- package/dist/api/branch.d.ts.map +1 -1
- package/dist/api/branch.js +63 -19
- package/dist/api/branch.js.map +1 -1
- package/dist/api/client.d.ts +16 -5
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +24 -6
- package/dist/api/client.js.map +1 -1
- package/dist/api/content.d.ts +2 -2
- package/dist/api/entries.d.ts +4 -4
- package/dist/api/entries.d.ts.map +1 -1
- package/dist/api/entries.js +10 -2
- package/dist/api/entries.js.map +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/route-builder.d.ts +9 -0
- package/dist/api/route-builder.d.ts.map +1 -1
- package/dist/api/route-builder.js +1 -0
- package/dist/api/route-builder.js.map +1 -1
- package/dist/api/schema.d.ts +4 -4
- package/dist/api/types.d.ts +11 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/assets/asset-prefixes.d.ts +31 -0
- package/dist/assets/asset-prefixes.d.ts.map +1 -0
- package/dist/assets/asset-prefixes.js +20 -0
- package/dist/assets/asset-prefixes.js.map +1 -0
- package/dist/assets/asset-src.d.ts +23 -0
- package/dist/assets/asset-src.d.ts.map +1 -0
- package/dist/assets/asset-src.js +28 -0
- package/dist/assets/asset-src.js.map +1 -0
- package/dist/assets/asset-url.d.ts +35 -0
- package/dist/assets/asset-url.d.ts.map +1 -0
- package/dist/assets/asset-url.js +77 -0
- package/dist/assets/asset-url.js.map +1 -0
- package/dist/assets/factory.d.ts +18 -0
- package/dist/assets/factory.d.ts.map +1 -0
- package/dist/assets/factory.js +42 -0
- package/dist/assets/factory.js.map +1 -0
- package/dist/assets/finalize.d.ts +36 -0
- package/dist/assets/finalize.d.ts.map +1 -0
- package/dist/assets/finalize.js +72 -0
- package/dist/assets/finalize.js.map +1 -0
- package/dist/assets/index.d.ts +20 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +19 -0
- package/dist/assets/index.js.map +1 -0
- package/dist/assets/keys.d.ts +56 -0
- package/dist/assets/keys.d.ts.map +1 -0
- package/dist/assets/keys.js +88 -0
- package/dist/assets/keys.js.map +1 -0
- package/dist/assets/pipeline.d.ts +50 -0
- package/dist/assets/pipeline.d.ts.map +1 -0
- package/dist/assets/pipeline.js +202 -0
- package/dist/assets/pipeline.js.map +1 -0
- package/dist/assets/store-local.d.ts +84 -0
- package/dist/assets/store-local.d.ts.map +1 -0
- package/dist/assets/store-local.js +254 -0
- package/dist/assets/store-local.js.map +1 -0
- package/dist/assets/store-s3.d.ts +71 -0
- package/dist/assets/store-s3.d.ts.map +1 -0
- package/dist/assets/store-s3.js +183 -0
- package/dist/assets/store-s3.js.map +1 -0
- package/dist/assets/svg-sanitizer.d.ts +37 -0
- package/dist/assets/svg-sanitizer.d.ts.map +1 -0
- package/dist/assets/svg-sanitizer.js +222 -0
- package/dist/assets/svg-sanitizer.js.map +1 -0
- package/dist/assets/transform-directives.d.ts +97 -0
- package/dist/assets/transform-directives.d.ts.map +1 -0
- package/dist/assets/transform-directives.js +267 -0
- package/dist/assets/transform-directives.js.map +1 -0
- package/dist/assets/transform.d.ts +51 -0
- package/dist/assets/transform.d.ts.map +1 -0
- package/dist/assets/transform.js +190 -0
- package/dist/assets/transform.js.map +1 -0
- package/dist/assets/types.d.ts +82 -0
- package/dist/assets/types.d.ts.map +1 -0
- package/dist/assets/types.js +10 -0
- package/dist/assets/types.js.map +1 -0
- package/dist/authorization/groups/schema.d.ts +2 -2
- package/dist/authorization/permissions/schema.d.ts +2 -2
- package/dist/branch-metadata.d.ts +71 -6
- package/dist/branch-metadata.d.ts.map +1 -1
- package/dist/branch-metadata.js +132 -116
- package/dist/branch-metadata.js.map +1 -1
- package/dist/branch-registry.d.ts +78 -9
- package/dist/branch-registry.d.ts.map +1 -1
- package/dist/branch-registry.js +155 -29
- package/dist/branch-registry.js.map +1 -1
- package/dist/branch-schema-cache.d.ts +126 -11
- package/dist/branch-schema-cache.d.ts.map +1 -1
- package/dist/branch-schema-cache.js +208 -58
- package/dist/branch-schema-cache.js.map +1 -1
- package/dist/cli/generate-ai-content.js +1993 -1506
- package/dist/cli/init.js +16 -4
- package/dist/cli/migrate.d.ts.map +1 -1
- package/dist/cli/migrate.js +25 -0
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/sync.js +5 -5
- package/dist/cli/sync.js.map +1 -1
- package/dist/comment-store.d.ts +45 -15
- package/dist/comment-store.d.ts.map +1 -1
- package/dist/comment-store.js +80 -101
- package/dist/comment-store.js.map +1 -1
- package/dist/config/helpers.d.ts.map +1 -1
- package/dist/config/helpers.js +2 -1
- package/dist/config/helpers.js.map +1 -1
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/schemas/config.d.ts +10 -0
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/field.d.ts +38 -3
- package/dist/config/schemas/field.d.ts.map +1 -1
- package/dist/config/schemas/field.js +18 -0
- package/dist/config/schemas/field.js.map +1 -1
- package/dist/config/schemas/media.d.ts +8 -0
- package/dist/config/schemas/media.d.ts.map +1 -1
- package/dist/config/schemas/media.js +9 -0
- package/dist/config/schemas/media.js.map +1 -1
- package/dist/config/types.d.ts +43 -3
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +4 -1
- package/dist/config/types.js.map +1 -1
- package/dist/content-index-generation.d.ts +40 -4
- package/dist/content-index-generation.d.ts.map +1 -1
- package/dist/content-index-generation.js +70 -73
- package/dist/content-index-generation.js.map +1 -1
- package/dist/content-store.d.ts +63 -0
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +421 -194
- package/dist/content-store.js.map +1 -1
- package/dist/editor/CanopyEditor.d.ts.map +1 -1
- package/dist/editor/CanopyEditor.js +1 -1
- package/dist/editor/CanopyEditor.js.map +1 -1
- package/dist/editor/Editor.d.ts +2 -0
- package/dist/editor/Editor.d.ts.map +1 -1
- package/dist/editor/Editor.js +82 -80
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/FormRenderer.d.ts.map +1 -1
- package/dist/editor/FormRenderer.js +9 -0
- package/dist/editor/FormRenderer.js.map +1 -1
- package/dist/editor/components/EditorSidebar.d.ts +6 -1
- package/dist/editor/components/EditorSidebar.d.ts.map +1 -1
- package/dist/editor/components/EditorSidebar.js +4 -3
- package/dist/editor/components/EditorSidebar.js.map +1 -1
- package/dist/editor/context/AssetContext.d.ts +25 -0
- package/dist/editor/context/AssetContext.d.ts.map +1 -0
- package/dist/editor/context/AssetContext.js +26 -0
- package/dist/editor/context/AssetContext.js.map +1 -0
- package/dist/editor/context/index.d.ts +1 -0
- package/dist/editor/context/index.d.ts.map +1 -1
- package/dist/editor/context/index.js +1 -0
- package/dist/editor/context/index.js.map +1 -1
- package/dist/editor/fields/ImageField.d.ts +22 -0
- package/dist/editor/fields/ImageField.d.ts.map +1 -0
- package/dist/editor/fields/ImageField.js +100 -0
- package/dist/editor/fields/ImageField.js.map +1 -0
- package/dist/editor/fields/MarkdownField.d.ts.map +1 -1
- package/dist/editor/fields/MarkdownField.js +30 -4
- package/dist/editor/fields/MarkdownField.js.map +1 -1
- package/dist/editor/fields/MdxImageDialog.d.ts +16 -0
- package/dist/editor/fields/MdxImageDialog.d.ts.map +1 -0
- package/dist/editor/fields/MdxImageDialog.js +73 -0
- package/dist/editor/fields/MdxImageDialog.js.map +1 -0
- package/dist/editor/media/AssetCard.d.ts +21 -0
- package/dist/editor/media/AssetCard.d.ts.map +1 -0
- package/dist/editor/media/AssetCard.js +41 -0
- package/dist/editor/media/AssetCard.js.map +1 -0
- package/dist/editor/media/CropStep.d.ts +26 -0
- package/dist/editor/media/CropStep.d.ts.map +1 -0
- package/dist/editor/media/CropStep.js +38 -0
- package/dist/editor/media/CropStep.js.map +1 -0
- package/dist/editor/media/MediaLibrary.d.ts +22 -0
- package/dist/editor/media/MediaLibrary.d.ts.map +1 -0
- package/dist/editor/media/MediaLibrary.js +17 -0
- package/dist/editor/media/MediaLibrary.js.map +1 -0
- package/dist/editor/media/MediaLibraryBody.d.ts +17 -0
- package/dist/editor/media/MediaLibraryBody.d.ts.map +1 -0
- package/dist/editor/media/MediaLibraryBody.js +133 -0
- package/dist/editor/media/MediaLibraryBody.js.map +1 -0
- package/dist/editor/media/crop-math.d.ts +37 -0
- package/dist/editor/media/crop-math.d.ts.map +1 -0
- package/dist/editor/media/crop-math.js +62 -0
- package/dist/editor/media/crop-math.js.map +1 -0
- package/dist/editor/media/upload-asset.d.ts +31 -0
- package/dist/editor/media/upload-asset.d.ts.map +1 -0
- package/dist/editor/media/upload-asset.js +56 -0
- package/dist/editor/media/upload-asset.js.map +1 -0
- package/dist/editor/media/upload-constants.d.ts +27 -0
- package/dist/editor/media/upload-constants.d.ts.map +1 -0
- package/dist/editor/media/upload-constants.js +40 -0
- package/dist/editor/media/upload-constants.js.map +1 -0
- package/dist/editor/media/useAssetUpload.d.ts +19 -0
- package/dist/editor/media/useAssetUpload.d.ts.map +1 -0
- package/dist/editor/media/useAssetUpload.js +53 -0
- package/dist/editor/media/useAssetUpload.js.map +1 -0
- package/dist/editor/media/xhr-upload.d.ts +20 -0
- package/dist/editor/media/xhr-upload.d.ts.map +1 -0
- package/dist/editor/media/xhr-upload.js +42 -0
- package/dist/editor/media/xhr-upload.js.map +1 -0
- package/dist/editor/theme.d.ts +2 -1
- package/dist/editor/theme.d.ts.map +1 -1
- package/dist/editor/theme.js +1 -0
- package/dist/editor/theme.js.map +1 -1
- package/dist/entry-schema.d.ts +19 -0
- package/dist/entry-schema.d.ts.map +1 -1
- package/dist/entry-schema.js.map +1 -1
- package/dist/git-manager.d.ts +15 -10
- package/dist/git-manager.d.ts.map +1 -1
- package/dist/git-manager.js +16 -11
- package/dist/git-manager.js.map +1 -1
- package/dist/http/handler.d.ts +5 -2
- package/dist/http/handler.d.ts.map +1 -1
- package/dist/http/handler.js +13 -4
- package/dist/http/handler.js.map +1 -1
- package/dist/http/index.d.ts +2 -2
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +1 -1
- package/dist/http/index.js.map +1 -1
- package/dist/http/router.d.ts +14 -1
- package/dist/http/router.d.ts.map +1 -1
- package/dist/http/router.js +4 -1
- package/dist/http/router.js.map +1 -1
- package/dist/http/types.d.ts +40 -0
- package/dist/http/types.d.ts.map +1 -1
- package/dist/http/types.js +9 -0
- package/dist/http/types.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/resource-generation.d.ts +54 -0
- package/dist/resource-generation.d.ts.map +1 -0
- package/dist/resource-generation.js +156 -0
- package/dist/resource-generation.js.map +1 -0
- package/dist/schema/schema-store.d.ts +31 -4
- package/dist/schema/schema-store.d.ts.map +1 -1
- package/dist/schema/schema-store.js +47 -8
- package/dist/schema/schema-store.js.map +1 -1
- package/dist/server.d.ts +45 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +41 -0
- package/dist/server.js.map +1 -1
- package/dist/sync-core.js +2 -2
- package/dist/sync-core.js.map +1 -1
- package/dist/utils/occ-json-write.d.ts +100 -0
- package/dist/utils/occ-json-write.d.ts.map +1 -0
- package/dist/utils/occ-json-write.js +234 -0
- package/dist/utils/occ-json-write.js.map +1 -0
- package/dist/validation/entry-validator.d.ts.map +1 -1
- package/dist/validation/entry-validator.js +56 -1
- package/dist/validation/entry-validator.js.map +1 -1
- package/dist/worker/cms-worker.d.ts.map +1 -1
- package/dist/worker/cms-worker.js +21 -3
- package/dist/worker/cms-worker.js.map +1 -1
- package/package.json +13 -1
- package/dist/asset-store.d.ts +0 -32
- package/dist/asset-store.d.ts.map +0 -1
- package/dist/asset-store.js +0 -85
- 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 =
|
|
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
|
|
50
|
+
* Manages per-branch schema caching with lazy loading and automatic
|
|
51
|
+
* invalidation.
|
|
43
52
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* -
|
|
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
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
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
|
|
99
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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
|
-
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAM5B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"branch-schema-cache.js","sourceRoot":"","sources":["../src/branch-schema-cache.ts"],"names":[],"mappings":"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"}
|