canopycms 0.0.53 → 0.0.55
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/generate.d.ts.map +1 -1
- package/dist/ai/generate.js +68 -2
- package/dist/ai/generate.js.map +1 -1
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/json-to-markdown.d.ts.map +1 -1
- package/dist/ai/json-to-markdown.js +87 -0
- package/dist/ai/json-to-markdown.js.map +1 -1
- package/dist/ai/types.d.ts +54 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/api/assets.d.ts +14 -2
- package/dist/api/assets.d.ts.map +1 -1
- package/dist/api/assets.js +14 -3
- package/dist/api/assets.js.map +1 -1
- package/dist/api/branch-status.d.ts.map +1 -1
- package/dist/api/branch-status.js +8 -2
- package/dist/api/branch-status.js.map +1 -1
- package/dist/api/client.d.ts +2 -2
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +29 -14
- package/dist/api/client.js.map +1 -1
- package/dist/api/content.d.ts +2 -2
- package/dist/api/content.d.ts.map +1 -1
- package/dist/api/content.js +160 -26
- package/dist/api/content.js.map +1 -1
- package/dist/api/entries.d.ts.map +1 -1
- package/dist/api/entries.js +8 -4
- package/dist/api/entries.js.map +1 -1
- package/dist/api/github-sync.d.ts.map +1 -1
- package/dist/api/github-sync.js +21 -4
- package/dist/api/github-sync.js.map +1 -1
- package/dist/api/groups.d.ts.map +1 -1
- package/dist/api/groups.js +15 -5
- package/dist/api/groups.js.map +1 -1
- package/dist/api/permissions.d.ts +6 -6
- package/dist/api/permissions.d.ts.map +1 -1
- package/dist/api/permissions.js +24 -9
- package/dist/api/permissions.js.map +1 -1
- package/dist/api/request-body-hash.d.ts +33 -0
- package/dist/api/request-body-hash.d.ts.map +1 -0
- package/dist/api/request-body-hash.js +43 -0
- package/dist/api/request-body-hash.js.map +1 -0
- package/dist/api/resolve-references.d.ts.map +1 -1
- package/dist/api/resolve-references.js +8 -1
- package/dist/api/resolve-references.js.map +1 -1
- package/dist/api/schema.js +9 -9
- package/dist/api/schema.js.map +1 -1
- package/dist/api/settings-helpers.d.ts +14 -1
- package/dist/api/settings-helpers.d.ts.map +1 -1
- package/dist/api/settings-helpers.js +11 -2
- package/dist/api/settings-helpers.js.map +1 -1
- package/dist/api/types.d.ts +10 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/plugin.d.ts +26 -0
- package/dist/auth/plugin.d.ts.map +1 -1
- package/dist/auth/plugin.js +25 -1
- package/dist/auth/plugin.js.map +1 -1
- package/dist/authorization/helpers.d.ts +16 -0
- package/dist/authorization/helpers.d.ts.map +1 -1
- package/dist/authorization/helpers.js +18 -0
- package/dist/authorization/helpers.js.map +1 -1
- package/dist/authorization/index.d.ts +1 -1
- package/dist/authorization/index.d.ts.map +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/index.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +2 -1
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/generate-ai-content.js +834 -339
- package/dist/cli/init.d.ts +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +28 -9
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +88 -60
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/template-files/canopy.ts.template +2 -1
- package/dist/cli/template-files/edit-page.tsx.template +8 -1
- package/dist/cli/template-files/middleware.ts.template +18 -0
- package/dist/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +16 -4
- package/dist/cli/templates.js.map +1 -1
- package/dist/config/helpers.d.ts +9 -1
- package/dist/config/helpers.d.ts.map +1 -1
- package/dist/config/helpers.js +30 -75
- package/dist/config/helpers.js.map +1 -1
- package/dist/config/schemas/config.d.ts +5 -20
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/config.js +6 -2
- package/dist/config/schemas/config.js.map +1 -1
- package/dist/config/schemas/media.d.ts +1 -10
- package/dist/config/schemas/media.d.ts.map +1 -1
- package/dist/config/schemas/media.js +8 -6
- package/dist/config/schemas/media.js.map +1 -1
- package/dist/config/types.d.ts +0 -3
- package/dist/config/types.d.ts.map +1 -1
- package/dist/content-id-index.d.ts +12 -6
- package/dist/content-id-index.d.ts.map +1 -1
- package/dist/content-id-index.js +12 -6
- package/dist/content-id-index.js.map +1 -1
- package/dist/content-index-generation.d.ts +30 -0
- package/dist/content-index-generation.d.ts.map +1 -0
- package/dist/content-index-generation.js +131 -0
- package/dist/content-index-generation.js.map +1 -0
- package/dist/content-index-registry.d.ts +38 -0
- package/dist/content-index-registry.d.ts.map +1 -0
- package/dist/content-index-registry.js +53 -0
- package/dist/content-index-registry.js.map +1 -0
- package/dist/content-store.d.ts +130 -6
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +333 -31
- package/dist/content-store.js.map +1 -1
- package/dist/editor/Editor.d.ts.map +1 -1
- package/dist/editor/Editor.js +8 -4
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/FormRenderer.d.ts +7 -0
- package/dist/editor/FormRenderer.d.ts.map +1 -1
- package/dist/editor/FormRenderer.js +12 -3
- package/dist/editor/FormRenderer.js.map +1 -1
- package/dist/editor/components/EditorHeader.d.ts.map +1 -1
- package/dist/editor/components/EditorHeader.js +3 -4
- package/dist/editor/components/EditorHeader.js.map +1 -1
- package/dist/editor/components/EditorSidebar.d.ts.map +1 -1
- package/dist/editor/components/EditorSidebar.js +2 -4
- package/dist/editor/components/EditorSidebar.js.map +1 -1
- package/dist/editor/fields/ReferenceField.d.ts.map +1 -1
- package/dist/editor/fields/ReferenceField.js +19 -2
- package/dist/editor/fields/ReferenceField.js.map +1 -1
- package/dist/editor/group-manager/hooks/useGroupState.d.ts.map +1 -1
- package/dist/editor/group-manager/hooks/useGroupState.js +5 -2
- package/dist/editor/group-manager/hooks/useGroupState.js.map +1 -1
- package/dist/editor/hooks/useDraftManager.d.ts +8 -0
- package/dist/editor/hooks/useDraftManager.d.ts.map +1 -1
- package/dist/editor/hooks/useDraftManager.js +102 -1
- package/dist/editor/hooks/useDraftManager.js.map +1 -1
- package/dist/editor/hooks/useEntryManager.d.ts +9 -2
- package/dist/editor/hooks/useEntryManager.d.ts.map +1 -1
- package/dist/editor/hooks/useEntryManager.js +9 -3
- package/dist/editor/hooks/useEntryManager.js.map +1 -1
- package/dist/editor/hooks/useSchemaManager.d.ts.map +1 -1
- package/dist/editor/hooks/useSchemaManager.js +2 -1
- package/dist/editor/hooks/useSchemaManager.js.map +1 -1
- package/dist/editor/schema-editor/CollectionEditor.d.ts +4 -4
- package/dist/editor/schema-editor/CollectionEditor.d.ts.map +1 -1
- package/dist/editor/schema-editor/CollectionEditor.js +32 -12
- package/dist/editor/schema-editor/CollectionEditor.js.map +1 -1
- package/dist/entry-link-resolver.d.ts.map +1 -1
- package/dist/entry-link-resolver.js +5 -0
- package/dist/entry-link-resolver.js.map +1 -1
- package/dist/git-manager.d.ts +38 -3
- package/dist/git-manager.d.ts.map +1 -1
- package/dist/git-manager.js +141 -33
- package/dist/git-manager.js.map +1 -1
- package/dist/github-service.d.ts +13 -3
- package/dist/github-service.d.ts.map +1 -1
- package/dist/github-service.js +23 -7
- package/dist/github-service.js.map +1 -1
- package/dist/http/handler.d.ts +1 -1
- package/dist/http/handler.d.ts.map +1 -1
- package/dist/http/handler.js +36 -7
- package/dist/http/handler.js.map +1 -1
- package/dist/http/router.d.ts +11 -0
- package/dist/http/router.d.ts.map +1 -1
- package/dist/http/router.js +80 -16
- package/dist/http/router.js.map +1 -1
- package/dist/paths/validation.d.ts.map +1 -1
- package/dist/paths/validation.js +12 -0
- package/dist/paths/validation.js.map +1 -1
- package/dist/schema/schema-store.d.ts +9 -0
- package/dist/schema/schema-store.d.ts.map +1 -1
- package/dist/schema/schema-store.js +57 -8
- package/dist/schema/schema-store.js.map +1 -1
- package/dist/services.d.ts +1 -0
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +5 -2
- package/dist/services.js.map +1 -1
- package/dist/sync-core.d.ts.map +1 -1
- package/dist/sync-core.js +22 -9
- package/dist/sync-core.js.map +1 -1
- package/dist/user.d.ts +0 -18
- package/dist/user.d.ts.map +1 -1
- package/dist/user.js +7 -22
- package/dist/user.js.map +1 -1
- package/dist/utils/error.d.ts +8 -0
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.js +35 -7
- package/dist/utils/error.js.map +1 -1
- package/dist/validation/deletion-checker.d.ts.map +1 -1
- package/dist/validation/deletion-checker.js +6 -5
- package/dist/validation/deletion-checker.js.map +1 -1
- package/dist/validation/entry-validator.d.ts +67 -0
- package/dist/validation/entry-validator.d.ts.map +1 -0
- package/dist/validation/entry-validator.js +277 -0
- package/dist/validation/entry-validator.js.map +1 -0
- package/dist/validation/field-traversal.d.ts +23 -1
- package/dist/validation/field-traversal.d.ts.map +1 -1
- package/dist/validation/field-traversal.js +29 -9
- package/dist/validation/field-traversal.js.map +1 -1
- package/dist/worker/cms-worker.d.ts +67 -6
- package/dist/worker/cms-worker.d.ts.map +1 -1
- package/dist/worker/cms-worker.js +190 -67
- package/dist/worker/cms-worker.js.map +1 -1
- package/package.json +1 -2
- package/dist/editor/components/EditorContext.d.ts +0 -35
- package/dist/editor/components/EditorContext.d.ts.map +0 -1
- package/dist/editor/components/EditorContext.js +0 -19
- package/dist/editor/components/EditorContext.js.map +0 -1
- package/dist/editor/env.d.ts +0 -5
- package/dist/editor/env.d.ts.map +0 -1
- package/dist/editor/env.js +0 -5
- package/dist/editor/env.js.map +0 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { atomicWriteFile } from './utils/atomic-write.js';
|
|
5
|
+
import { getErrorMessage, isNodeError } from './utils/error.js';
|
|
6
|
+
import { invalidateContentIndexesForRoot } from './content-index-registry.js';
|
|
7
|
+
import { createDebugLogger } from './utils/debug.js';
|
|
8
|
+
/**
|
|
9
|
+
* Cross-process ContentId index generation marker.
|
|
10
|
+
*
|
|
11
|
+
* The ContentIdIndex is an in-memory map per ContentStore instance. Within one
|
|
12
|
+
* process, content-index-registry.ts invalidates stale indexes directly. Across
|
|
13
|
+
* processes (several warm Lambda containers + the EC2 worker sharing branch
|
|
14
|
+
* clones on EFS) there is no shared memory and no cross-host file watching, so
|
|
15
|
+
* the shared filesystem itself is the coordination medium: every operation that
|
|
16
|
+
* mutates indexed files under a branch-clone root also rewrites a small marker
|
|
17
|
+
* file with a fresh random token, and every ContentStore cheaply re-reads that
|
|
18
|
+
* marker (throttled) to decide whether its in-memory index is still current.
|
|
19
|
+
*
|
|
20
|
+
* The marker lives at {root}/.canopy-meta/content-index.generation:
|
|
21
|
+
* `.canopy-meta/` is the established per-clone internal dir — dot-prefixed (so
|
|
22
|
+
* content and index scans skip it) and excluded from git via .git/info/exclude.
|
|
23
|
+
*
|
|
24
|
+
* ## Why a random token instead of a monotonic counter
|
|
25
|
+
*
|
|
26
|
+
* Readers only need "did it change since I captured it", so inequality against
|
|
27
|
+
* the captured value suffices. A counter would need read-modify-write, which
|
|
28
|
+
* silently loses concurrent bumps without a lock (two bumpers read 5, both
|
|
29
|
+
* write 6 — a reader that recorded 6 after the first bump never learns of the
|
|
30
|
+
* second mutation). A unique token per bump has no lost-update problem, needs
|
|
31
|
+
* no lock, and avoids NFS mtime-granularity / cross-host clock-skew issues.
|
|
32
|
+
* Each bump is a single atomic temp-file + rename.
|
|
33
|
+
*
|
|
34
|
+
* ## Ordering protocol (correctness)
|
|
35
|
+
*
|
|
36
|
+
* - Bumpers write the marker strictly AFTER their filesystem mutations.
|
|
37
|
+
* - Readers capture the marker token strictly BEFORE scanning the tree, and
|
|
38
|
+
* record it only after the scan completes. A bump landing mid-scan therefore
|
|
39
|
+
* leaves the recorded token older than the file, forcing a rebuild on the
|
|
40
|
+
* next probe.
|
|
41
|
+
*
|
|
42
|
+
* ## Consistency guarantees and residual staleness windows (EFS/NFSv4)
|
|
43
|
+
*
|
|
44
|
+
* Guaranteed: any completed mutation that bumps the marker is observed by every
|
|
45
|
+
* store on that root at its next freshness probe. Residual windows, all bounded
|
|
46
|
+
* in practice by per-request ContentStore lifetimes and self-healed by the
|
|
47
|
+
* suspicious-lookup backstop in ContentStore:
|
|
48
|
+
*
|
|
49
|
+
* - (A) NFS attribute caching (benign direction): another host may not see a
|
|
50
|
+
* new marker for up to the attribute-cache timeout (~3-60s on default EFS
|
|
51
|
+
* mounts; `noac` cannot be assumed). The reader acts on a stale token and
|
|
52
|
+
* keeps a stale index until the cache expires.
|
|
53
|
+
* - (B) Probe throttle: up to ContentStore's indexFreshnessIntervalMs (1s).
|
|
54
|
+
* - (C) Self-adoption: after its own mutation a store adopts the token it
|
|
55
|
+
* wrote; if a concurrent foreign bump landed just before ours, we miss that
|
|
56
|
+
* one notification (window: from our last token observation to our rename).
|
|
57
|
+
* - (E) Fresh-token/stale-scan (malignant direction, cross-host only): NFS
|
|
58
|
+
* revalidates the marker file on open, but a rebuild's readdir calls may be
|
|
59
|
+
* served from dentry/attribute caches — a scan can record a NEW token against
|
|
60
|
+
* PRE-mutation directory listings, leaving that store confidently stale until
|
|
61
|
+
* the next bump. Structurally unfixable with a filesystem marker; bounded by
|
|
62
|
+
* per-request store lifetimes and the backstop.
|
|
63
|
+
*
|
|
64
|
+
* Wrong-file WRITE corruption (recreating a concurrently renamed entry →
|
|
65
|
+
* duplicate IDs) is prevented independently of this marker by the existence
|
|
66
|
+
* guard in ContentStore.write(), which consults the actual directory listing
|
|
67
|
+
* before recreating a missing expected file.
|
|
68
|
+
*/
|
|
69
|
+
const log = createDebugLogger({ prefix: 'ContentIndex' });
|
|
70
|
+
/** Matches BRANCH_META_DIR in branch-metadata.ts — the per-clone internal dir. */
|
|
71
|
+
const META_DIR = '.canopy-meta';
|
|
72
|
+
const GENERATION_FILE = 'content-index.generation';
|
|
73
|
+
/** Absolute path of the generation marker for a branch-clone root. */
|
|
74
|
+
export function contentIndexGenerationPath(root) {
|
|
75
|
+
return path.join(path.resolve(root), META_DIR, GENERATION_FILE);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Record on disk that indexed files under `root` changed, so ContentStores in
|
|
79
|
+
* OTHER processes rebuild. Must be called AFTER the filesystem mutation.
|
|
80
|
+
* Returns the token written, or null if the write failed (logged and swallowed:
|
|
81
|
+
* the content mutation is already durable; a lost bump degrades to the
|
|
82
|
+
* pre-marker staleness behavior plus the ContentStore backstop).
|
|
83
|
+
*/
|
|
84
|
+
export async function bumpContentIndexGeneration(root) {
|
|
85
|
+
const token = randomUUID();
|
|
86
|
+
try {
|
|
87
|
+
await atomicWriteFile(contentIndexGenerationPath(root), token);
|
|
88
|
+
return token;
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
log.warn('generation', `Failed to bump content index generation for ${root}`, {
|
|
92
|
+
error: getErrorMessage(err),
|
|
93
|
+
});
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Read the current generation token for `root`. Returns null if the marker
|
|
99
|
+
* does not exist yet (a valid state distinct from every token). Read errors
|
|
100
|
+
* other than ENOENT are logged and treated as null — the caller then rebuilds,
|
|
101
|
+
* which is the safe direction.
|
|
102
|
+
*/
|
|
103
|
+
export async function readContentIndexGeneration(root) {
|
|
104
|
+
try {
|
|
105
|
+
return await fs.readFile(contentIndexGenerationPath(root), 'utf-8');
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
if (isNodeError(err) && err.code === 'ENOENT')
|
|
109
|
+
return null;
|
|
110
|
+
log.warn('generation', `Failed to read content index generation for ${root}`, {
|
|
111
|
+
error: getErrorMessage(err),
|
|
112
|
+
});
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The single entry point for operations that mutate indexed files under a
|
|
118
|
+
* branch-clone root: git working-tree mutations, content sync, collection
|
|
119
|
+
* directory operations, CLI sync. Bumps the on-disk marker (cross-process),
|
|
120
|
+
* then invalidates in-process registered stores.
|
|
121
|
+
*
|
|
122
|
+
* Bump-before-invalidate: the in-process invalidation triggers a rebuild on
|
|
123
|
+
* next access, and that rebuild captures the marker token before scanning —
|
|
124
|
+
* writing the marker first lets the rebuild pick up the new token in the same
|
|
125
|
+
* pass instead of a redundant second rebuild.
|
|
126
|
+
*/
|
|
127
|
+
export async function invalidateContentIndexesDurable(root) {
|
|
128
|
+
await bumpContentIndexGeneration(root);
|
|
129
|
+
invalidateContentIndexesForRoot(root);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=content-index-generation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-index-generation.js","sourceRoot":"","sources":["../src/content-index-generation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC5D,OAAO,EAAE,+BAA+B,EAAE,MAAM,0BAA0B,CAAA;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAEH,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAA;AAEzD,kFAAkF;AAClF,MAAM,QAAQ,GAAG,cAAc,CAAA;AAC/B,MAAM,eAAe,GAAG,0BAA0B,CAAA;AAElD,sEAAsE;AACtE,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAA;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,IAAY;IAC3D,MAAM,KAAK,GAAG,UAAU,EAAE,CAAA;IAC1B,IAAI,CAAC;QACH,MAAM,eAAe,CAAC,0BAA0B,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAA;QAC9D,OAAO,KAAK,CAAA;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,+CAA+C,IAAI,EAAE,EAAE;YAC5E,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC;SAC5B,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,IAAY;IAC3D,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;IACrE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAA;QAC1D,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,+CAA+C,IAAI,EAAE,EAAE;YAC5E,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC;SAC5B,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,IAAY;IAChE,MAAM,0BAA0B,CAAC,IAAI,CAAC,CAAA;IACtC,+BAA+B,CAAC,IAAI,CAAC,CAAA;AACvC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-process registry connecting branch-mutating operations (git checkout/merge/rebase,
|
|
3
|
+
* content sync) to the ContentStore instances whose ContentId indexes those operations
|
|
4
|
+
* make stale.
|
|
5
|
+
*
|
|
6
|
+
* ContentStore registers itself (keyed by its resolved root) on construction. Operations
|
|
7
|
+
* that change files under a root — GitManager working-tree mutations, the worker's rebase
|
|
8
|
+
* loop, sync-core's content replacement — call invalidateContentIndexesForRoot() so the
|
|
9
|
+
* next index access rebuilds from disk instead of serving stale ID→path mappings.
|
|
10
|
+
*
|
|
11
|
+
* SCOPE: in-process only — the zero-latency path for stores in the same process.
|
|
12
|
+
* Cross-process divergence (e.g. Lambda + worker on shared EFS, each with its own
|
|
13
|
+
* registry) is handled by the on-disk generation marker in
|
|
14
|
+
* content-index-generation.ts; invalidateContentIndexesDurable() there combines
|
|
15
|
+
* both scopes and is what mutation sites should call.
|
|
16
|
+
*
|
|
17
|
+
* Stores are held via WeakRef so short-lived (per-request) instances can be garbage
|
|
18
|
+
* collected; a FinalizationRegistry prunes dead entries.
|
|
19
|
+
*/
|
|
20
|
+
/** Anything holding a rebuildable content index (in practice: ContentStore). */
|
|
21
|
+
export interface InvalidatableContentIndex {
|
|
22
|
+
invalidateIndex(): void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Register a content-index holder for invalidation when files under `root` change.
|
|
26
|
+
* Called by the ContentStore constructor.
|
|
27
|
+
*/
|
|
28
|
+
export declare function registerContentIndexForInvalidation(root: string, target: InvalidatableContentIndex): void;
|
|
29
|
+
/**
|
|
30
|
+
* Invalidate every registered content index rooted at `root` or below it.
|
|
31
|
+
* Prefix matching covers stores rooted at a subdirectory of the mutated repo
|
|
32
|
+
* (e.g. a store rooted at a branch clone inside a mutated workspace tree).
|
|
33
|
+
*
|
|
34
|
+
* Invalidation only marks indexes stale; the rebuild happens lazily on the next
|
|
35
|
+
* index access, so calling this for a root with no live stores is free.
|
|
36
|
+
*/
|
|
37
|
+
export declare function invalidateContentIndexesForRoot(root: string): void;
|
|
38
|
+
//# sourceMappingURL=content-index-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-index-registry.d.ts","sourceRoot":"","sources":["../src/content-index-registry.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,gFAAgF;AAChF,MAAM,WAAW,yBAAyB;IACxC,eAAe,IAAI,IAAI,CAAA;CACxB;AAcD;;;GAGG;AACH,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,yBAAyB,GAChC,IAAI,CAUN;AAED;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAelE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
const registry = new Map();
|
|
3
|
+
const finalization = new FinalizationRegistry(({ rootKey, ref }) => {
|
|
4
|
+
const refs = registry.get(rootKey);
|
|
5
|
+
if (!refs)
|
|
6
|
+
return;
|
|
7
|
+
refs.delete(ref);
|
|
8
|
+
if (refs.size === 0)
|
|
9
|
+
registry.delete(rootKey);
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Register a content-index holder for invalidation when files under `root` change.
|
|
13
|
+
* Called by the ContentStore constructor.
|
|
14
|
+
*/
|
|
15
|
+
export function registerContentIndexForInvalidation(root, target) {
|
|
16
|
+
const rootKey = path.resolve(root);
|
|
17
|
+
let refs = registry.get(rootKey);
|
|
18
|
+
if (!refs) {
|
|
19
|
+
refs = new Set();
|
|
20
|
+
registry.set(rootKey, refs);
|
|
21
|
+
}
|
|
22
|
+
const ref = new WeakRef(target);
|
|
23
|
+
refs.add(ref);
|
|
24
|
+
finalization.register(target, { rootKey, ref });
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Invalidate every registered content index rooted at `root` or below it.
|
|
28
|
+
* Prefix matching covers stores rooted at a subdirectory of the mutated repo
|
|
29
|
+
* (e.g. a store rooted at a branch clone inside a mutated workspace tree).
|
|
30
|
+
*
|
|
31
|
+
* Invalidation only marks indexes stale; the rebuild happens lazily on the next
|
|
32
|
+
* index access, so calling this for a root with no live stores is free.
|
|
33
|
+
*/
|
|
34
|
+
export function invalidateContentIndexesForRoot(root) {
|
|
35
|
+
const rootKey = path.resolve(root);
|
|
36
|
+
const prefix = rootKey + path.sep;
|
|
37
|
+
for (const [storeRoot, refs] of registry) {
|
|
38
|
+
if (storeRoot !== rootKey && !storeRoot.startsWith(prefix))
|
|
39
|
+
continue;
|
|
40
|
+
for (const ref of refs) {
|
|
41
|
+
const target = ref.deref();
|
|
42
|
+
if (target) {
|
|
43
|
+
target.invalidateIndex();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
refs.delete(ref);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (refs.size === 0)
|
|
50
|
+
registry.delete(storeRoot);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=content-index-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-index-registry.js","sourceRoot":"","sources":["../src/content-index-registry.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AA2B5B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmD,CAAA;AAE3E,MAAM,YAAY,GAAG,IAAI,oBAAoB,CAG1C,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE;IACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAClC,IAAI,CAAC,IAAI;QAAE,OAAM;IACjB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAChB,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;QAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AAC/C,CAAC,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,UAAU,mCAAmC,CACjD,IAAY,EACZ,MAAiC;IAEjC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,IAAI,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAChC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,IAAI,GAAG,EAAE,CAAA;QAChB,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAC7B,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IAC/B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACb,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAA;AACjD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,+BAA+B,CAAC,IAAY;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,MAAM,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,GAAG,CAAA;IACjC,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzC,IAAI,SAAS,KAAK,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,SAAQ;QACpE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,CAAA;YAC1B,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,eAAe,EAAE,CAAA;YAC1B,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAClB,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;YAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACjD,CAAC;AACH,CAAC"}
|
package/dist/content-store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FlatSchemaItem } from './config';
|
|
1
|
+
import type { FlatSchemaItem, EntryTypeConfig } from './config';
|
|
2
2
|
import { ContentIdIndex } from './content-id-index';
|
|
3
3
|
import { type LogicalPath, type PhysicalPath, type Slug, type ContentId } from './paths';
|
|
4
4
|
export type MarkdownDocument = {
|
|
@@ -50,17 +50,95 @@ export declare class ContentStoreError extends Error {
|
|
|
50
50
|
export declare class ContentConflictError extends Error {
|
|
51
51
|
constructor();
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the default entry type from a collection's entries array.
|
|
55
|
+
* Returns the entry marked as default, or the first one, or undefined if no entries.
|
|
56
|
+
*/
|
|
57
|
+
export declare function getDefaultEntryType(entries: readonly EntryTypeConfig[] | undefined): EntryTypeConfig | undefined;
|
|
58
|
+
export interface ContentStoreOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Minimum ms between on-disk generation-marker probes when the in-memory
|
|
61
|
+
* index is otherwise fresh (see content-index-generation.ts). The probe is
|
|
62
|
+
* one small readFile; the 1s default matches the schema-cache mtime
|
|
63
|
+
* debounce. Tests pass 0 for deterministic cross-process scenarios.
|
|
64
|
+
*/
|
|
65
|
+
indexFreshnessIntervalMs?: number;
|
|
66
|
+
}
|
|
53
67
|
export declare class ContentStore {
|
|
54
68
|
private readonly root;
|
|
55
69
|
private readonly schemaIndex;
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
|
|
70
|
+
/** Swapped wholesale on rebuild — in-flight callers keep their (older) snapshot. */
|
|
71
|
+
private _idIndex;
|
|
72
|
+
/** Bumped by invalidateIndex(); when it differs from loadedIndexGeneration the index is stale. */
|
|
73
|
+
private indexGeneration;
|
|
74
|
+
private loadedIndexGeneration;
|
|
59
75
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
76
|
+
* On-disk generation token (content-index-generation.ts) the current index
|
|
77
|
+
* was built against. undefined = never captured; null = marker absent at
|
|
78
|
+
* build time. Assigned only by the rebuild path and by guarded self-adoption
|
|
79
|
+
* after this store's own mutations.
|
|
80
|
+
*/
|
|
81
|
+
private loadedDiskGeneration;
|
|
82
|
+
private lastDiskProbeMs;
|
|
83
|
+
private lastForcedRefreshMs;
|
|
84
|
+
private readonly indexFreshnessIntervalMs;
|
|
85
|
+
/** In-flight index build, shared by concurrent idIndex() callers so scans never interleave. */
|
|
86
|
+
private indexBuild;
|
|
87
|
+
constructor(root: string, flatSchema: FlatSchemaItem[], options?: ContentStoreOptions);
|
|
88
|
+
/**
|
|
89
|
+
* Mark the ID index stale so the next idIndex() access rebuilds it from disk.
|
|
90
|
+
*
|
|
91
|
+
* Called (via content-index-registry) after in-process operations that change the
|
|
92
|
+
* working tree underneath this store — git checkout/merge/rebase, the worker's
|
|
93
|
+
* rebase loop, and sync-core's content replacement. Without this, ID→path lookups
|
|
94
|
+
* keep resolving to pre-mutation paths and saves can target moved/deleted files.
|
|
95
|
+
*
|
|
96
|
+
* Cheap: only bumps a generation counter; the rebuild happens lazily.
|
|
97
|
+
*/
|
|
98
|
+
invalidateIndex(): void;
|
|
99
|
+
/**
|
|
100
|
+
* Get the ID index, ensuring it's loaded and current first.
|
|
101
|
+
* Loads lazily on first access and rebuilds after invalidateIndex(); repeated
|
|
102
|
+
* accesses with no intervening invalidation reuse the already-built index,
|
|
103
|
+
* except for a throttled probe of the on-disk generation marker that detects
|
|
104
|
+
* mutations made by OTHER processes sharing this root (e.g. on EFS).
|
|
62
105
|
*/
|
|
63
106
|
idIndex(): Promise<ContentIdIndex>;
|
|
107
|
+
/**
|
|
108
|
+
* Throttle for the on-disk marker probe. Stamps the clock synchronously
|
|
109
|
+
* before the caller's readFile so concurrent idIndex() callers don't
|
|
110
|
+
* double-probe (and double-rebuild) on the same token change.
|
|
111
|
+
*/
|
|
112
|
+
private shouldProbeDiskGeneration;
|
|
113
|
+
/**
|
|
114
|
+
* After one of this store's own successful mutations: publish the change to
|
|
115
|
+
* other processes (bump the on-disk marker) and adopt the written token,
|
|
116
|
+
* since the in-memory index was already updated incrementally — avoiding a
|
|
117
|
+
* pointless self-rescan on the next probe. Adoption is skipped unless the
|
|
118
|
+
* index is quiescent and `updatedIndex` is still the live instance: if a
|
|
119
|
+
* rebuild raced with the mutation, its scan may predate our file change, so
|
|
120
|
+
* we leave the recorded token older and let the next probe observe our bump
|
|
121
|
+
* and trigger the healing rebuild.
|
|
122
|
+
*/
|
|
123
|
+
private recordOwnMutation;
|
|
124
|
+
/**
|
|
125
|
+
* Backstop for the residual staleness windows of the cross-process marker
|
|
126
|
+
* (NFS attribute caching, probe throttle, self-adoption — see
|
|
127
|
+
* content-index-generation.ts): force one rebuild in response to a
|
|
128
|
+
* suspicious lookup (an ID miss, or an index hit whose file is gone), but
|
|
129
|
+
* throttle how often a caller can force one. Time-boxed so genuinely
|
|
130
|
+
* dangling IDs cost at most one rescan per window. Returns true if a
|
|
131
|
+
* refresh was performed by THIS call; callers that lose the throttle race
|
|
132
|
+
* still benefit — idIndex() dedupes concurrent builds, so a caller that won
|
|
133
|
+
* the race rebuilds the index for everyone, and callers should still retry
|
|
134
|
+
* their lookup against the live index regardless of this return value.
|
|
135
|
+
*/
|
|
136
|
+
private refreshIndexForSuspiciousLookup;
|
|
137
|
+
/**
|
|
138
|
+
* Find the file in `dir` whose filename embeds `id`.
|
|
139
|
+
* Returns its root-relative path, or null if no such file (or no such dir).
|
|
140
|
+
*/
|
|
141
|
+
private findEntryPathById;
|
|
64
142
|
/**
|
|
65
143
|
* Get all schema items for iteration.
|
|
66
144
|
* Used internally by ReferenceResolver for path matching.
|
|
@@ -105,13 +183,47 @@ export declare class ContentStore {
|
|
|
105
183
|
/**
|
|
106
184
|
* Read an entry by its ID (UUID).
|
|
107
185
|
* Returns null if the ID doesn't exist or points to a collection.
|
|
186
|
+
*
|
|
187
|
+
* Suspicious results (ID missing from the index, or an index hit whose file
|
|
188
|
+
* is gone) trigger one forced index refresh and a retry — self-healing for
|
|
189
|
+
* mutations by other processes inside the marker's residual windows.
|
|
108
190
|
*/
|
|
109
191
|
readById(id: ContentId): Promise<ContentDocument | null>;
|
|
192
|
+
private readByIdOnce;
|
|
110
193
|
/**
|
|
111
194
|
* Get the ID for an entry given its collection and slug.
|
|
112
195
|
* Returns null if no ID exists yet.
|
|
113
196
|
*/
|
|
114
197
|
getIdForEntry(collectionPath: LogicalPath, slug: Slug): Promise<ContentId | null>;
|
|
198
|
+
/**
|
|
199
|
+
* Check whether a document already exists on disk for this collection+slug.
|
|
200
|
+
* Used by the write boundary to distinguish creates from edits (create
|
|
201
|
+
* scaffolds and maxItems enforcement).
|
|
202
|
+
*/
|
|
203
|
+
documentExists(collectionPath: LogicalPath, slug?: Slug | ''): Promise<boolean>;
|
|
204
|
+
/**
|
|
205
|
+
* Resolve the actual on-disk entry type of an existing collection entry, by
|
|
206
|
+
* inspecting its filename directly. Entry filenames embed their type
|
|
207
|
+
* (`{type}.{slug}.{id}.{ext}`) and it is immutable after creation — see the
|
|
208
|
+
* existing-file lookup in buildPaths(), which this mirrors. Returns
|
|
209
|
+
* undefined if no entry exists yet at this slug.
|
|
210
|
+
*
|
|
211
|
+
* Used at the API write boundary (api/content.ts) to validate an existing
|
|
212
|
+
* entry's payload against ITS real schema rather than a caller-supplied (or
|
|
213
|
+
* omitted/spoofed) `entryType` param — ContentStore.write() preserves the
|
|
214
|
+
* on-disk type regardless of what's requested, so validation must agree
|
|
215
|
+
* with what will actually be written (post-review M2).
|
|
216
|
+
*
|
|
217
|
+
* Cheap: one buildPaths() resolution plus a stat, no file content is read —
|
|
218
|
+
* same cost class as documentExists().
|
|
219
|
+
*/
|
|
220
|
+
getExistingEntryType(collectionPath: LogicalPath, slug?: Slug | ''): Promise<string | undefined>;
|
|
221
|
+
/**
|
|
222
|
+
* Count existing entries of a given entry type in a collection, by filename
|
|
223
|
+
* (entry filenames embed their type: `{type}.{slug}.{id}.{ext}`). Used to
|
|
224
|
+
* enforce `EntryTypeConfig.maxItems` server-side at the create boundary.
|
|
225
|
+
*/
|
|
226
|
+
countEntriesOfType(collectionPath: LogicalPath, entryTypeName: string): Promise<number>;
|
|
115
227
|
/**
|
|
116
228
|
* Delete an entry and remove it from the index.
|
|
117
229
|
*/
|
|
@@ -150,7 +262,19 @@ export declare class ContentStore {
|
|
|
150
262
|
* Resolve a single reference ID to full entry data.
|
|
151
263
|
* Returns null if the reference is invalid or missing.
|
|
152
264
|
* Includes id, slug, and collection fields for debugging.
|
|
265
|
+
*
|
|
266
|
+
* Suspicious results (ID missing from the index, or an index hit whose file
|
|
267
|
+
* is gone) trigger one forced index refresh and a retry — self-healing for
|
|
268
|
+
* mutations by other processes inside the marker's residual windows. The
|
|
269
|
+
* forced refresh itself is throttled (see refreshIndexForSuspiciousLookup),
|
|
270
|
+
* but the retry against the live index always runs regardless of whether
|
|
271
|
+
* this call won the throttle race: when a `list: true` reference array is
|
|
272
|
+
* resolved via Promise.all, every miss shares the same stale snapshot, and
|
|
273
|
+
* idIndex() dedupes concurrent builds — so a sibling call that wins the
|
|
274
|
+
* throttle and rebuilds heals every other miss in the same batch, not just
|
|
275
|
+
* the first.
|
|
153
276
|
*/
|
|
154
277
|
private resolveSingleReference;
|
|
278
|
+
private resolveSingleReferenceOnce;
|
|
155
279
|
}
|
|
156
280
|
//# sourceMappingURL=content-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-store.d.ts","sourceRoot":"","sources":["../src/content-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"content-store.d.ts","sourceRoot":"","sources":["../src/content-store.ts"],"names":[],"mappings":"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"}
|