canopycms 0.0.55 → 0.0.57
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/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/content.d.ts +2 -2
- 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/github-sync.d.ts.map +1 -1
- package/dist/api/github-sync.js +28 -7
- package/dist/api/github-sync.js.map +1 -1
- package/dist/auth/caching-auth-plugin.d.ts +8 -1
- package/dist/auth/caching-auth-plugin.d.ts.map +1 -1
- package/dist/auth/caching-auth-plugin.js +6 -1
- package/dist/auth/caching-auth-plugin.js.map +1 -1
- package/dist/auth/plugin.d.ts +19 -10
- package/dist/auth/plugin.d.ts.map +1 -1
- package/dist/auth/plugin.js +12 -10
- package/dist/auth/plugin.js.map +1 -1
- 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/build/generate-ai-content.d.ts.map +1 -1
- package/dist/build/generate-ai-content.js +7 -0
- package/dist/build/generate-ai-content.js.map +1 -1
- package/dist/cli/generate-ai-content.js +2358 -1556
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +16 -8
- package/dist/cli/init.js.map +1 -1
- 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/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +6 -3
- package/dist/cli/templates.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 +3 -0
- package/dist/config/helpers.js.map +1 -1
- package/dist/config/schemas/config.d.ts +3 -4
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/config.js +6 -3
- package/dist/config/schemas/config.js.map +1 -1
- package/dist/config/types.d.ts +6 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config-test.d.ts +5 -3
- package/dist/config-test.d.ts.map +1 -1
- package/dist/config-test.js +9 -1
- package/dist/config-test.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-listing.d.ts +3 -1
- package/dist/content-listing.d.ts.map +1 -1
- package/dist/content-listing.js +1 -0
- package/dist/content-listing.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 -184
- package/dist/content-store.js.map +1 -1
- package/dist/editor/Editor.d.ts.map +1 -1
- package/dist/editor/Editor.js +19 -15
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/hooks/useDraftManager.d.ts +7 -0
- package/dist/editor/hooks/useDraftManager.d.ts.map +1 -1
- package/dist/editor/hooks/useDraftManager.js +69 -31
- package/dist/editor/hooks/useDraftManager.js.map +1 -1
- package/dist/editor/hooks/useSchemaManager.d.ts +34 -10
- package/dist/editor/hooks/useSchemaManager.d.ts.map +1 -1
- package/dist/editor/hooks/useSchemaManager.js +20 -24
- package/dist/editor/hooks/useSchemaManager.js.map +1 -1
- package/dist/editor/schema-editor/CollectionEditor.d.ts +6 -5
- package/dist/editor/schema-editor/CollectionEditor.d.ts.map +1 -1
- package/dist/editor/schema-editor/CollectionEditor.js +9 -4
- package/dist/editor/schema-editor/CollectionEditor.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/github-service.d.ts +63 -7
- package/dist/github-service.d.ts.map +1 -1
- package/dist/github-service.js +147 -39
- package/dist/github-service.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 +29 -2
- 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/services.js +4 -0
- package/dist/services.js.map +1 -1
- package/dist/static/index.d.ts +32 -0
- package/dist/static/index.d.ts.map +1 -1
- package/dist/static/index.js +90 -0
- package/dist/static/index.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/worker/cms-worker.d.ts +6 -3
- package/dist/worker/cms-worker.d.ts.map +1 -1
- package/dist/worker/cms-worker.js +42 -41
- package/dist/worker/cms-worker.js.map +1 -1
- package/package.json +2 -1
package/dist/github-service.d.ts
CHANGED
|
@@ -1,4 +1,28 @@
|
|
|
1
|
+
import { Octokit } from '@octokit/rest';
|
|
1
2
|
import type { CanopyConfig } from './config';
|
|
3
|
+
/**
|
|
4
|
+
* Retry primary rate limits at most twice and only for short waits; beyond
|
|
5
|
+
* that, task-level retry/backoff (worker) or the caller's error path takes
|
|
6
|
+
* over. The worker's task timeout would abort a longer in-request wait
|
|
7
|
+
* anyway.
|
|
8
|
+
*/
|
|
9
|
+
export declare const shouldRetryRateLimit: (retryAfter: number, retryCount: number) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Secondary (abuse-detection) rate limits are stricter to trip and usually
|
|
12
|
+
* signal we're hammering the API too fast — retry at most once, and only for
|
|
13
|
+
* a short wait.
|
|
14
|
+
*/
|
|
15
|
+
export declare const shouldRetrySecondaryRateLimit: (retryAfter: number, retryCount: number) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Create an Octokit instance with the throttling plugin attached, so it
|
|
18
|
+
* proactively respects GitHub's `retry-after` guidance on rate limits
|
|
19
|
+
* instead of failing immediately (see cms-worker.ts isPermanentTaskFailure
|
|
20
|
+
* for the safety net this doesn't cover: exhausted plugin retries and
|
|
21
|
+
* errors the plugin never sees, like non-403 network failures).
|
|
22
|
+
*/
|
|
23
|
+
export declare function createCanopyOctokit(options: {
|
|
24
|
+
auth: string;
|
|
25
|
+
}): Octokit;
|
|
2
26
|
export interface GitHubServiceOptions {
|
|
3
27
|
token: string;
|
|
4
28
|
owner: string;
|
|
@@ -18,6 +42,39 @@ export interface PullRequestDetails {
|
|
|
18
42
|
merged: boolean;
|
|
19
43
|
draft: boolean;
|
|
20
44
|
}
|
|
45
|
+
export interface CreateOrUpdatePullRequestParams {
|
|
46
|
+
octokit: Octokit;
|
|
47
|
+
owner: string;
|
|
48
|
+
repo: string;
|
|
49
|
+
head: string;
|
|
50
|
+
base: string;
|
|
51
|
+
title: string;
|
|
52
|
+
body: string;
|
|
53
|
+
/** Convert a pre-existing draft PR to ready-for-review after updating it. */
|
|
54
|
+
markReadyIfDraft?: boolean;
|
|
55
|
+
/** Forwarded to all GitHub requests (worker task-timeout abort). */
|
|
56
|
+
signal?: AbortSignal;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create or update a pull request (idempotent — GIT-H1).
|
|
60
|
+
*
|
|
61
|
+
* If an open PR already exists from head to base, update it and return its
|
|
62
|
+
* number/url instead of erroring. This makes PR submission safely
|
|
63
|
+
* retryable: if a caller crashes after GitHub creates the PR but before it
|
|
64
|
+
* persists the returned PR number, calling this again recovers the
|
|
65
|
+
* existing PR instead of hitting the 422 that a blind create would throw on
|
|
66
|
+
* a duplicate, which previously wedged the branch in 'sync-failed'
|
|
67
|
+
* permanently.
|
|
68
|
+
*
|
|
69
|
+
* Shared by `GitHubService.createOrUpdatePR` (direct-API callers) and the
|
|
70
|
+
* worker's `push-and-create-or-update-pr` task, so the list->tiebreak->
|
|
71
|
+
* update/create logic and the draft->ready conversion live in one place.
|
|
72
|
+
*/
|
|
73
|
+
export declare function createOrUpdatePullRequest(params: CreateOrUpdatePullRequestParams): Promise<{
|
|
74
|
+
number: number;
|
|
75
|
+
url: string;
|
|
76
|
+
created: boolean;
|
|
77
|
+
}>;
|
|
21
78
|
/**
|
|
22
79
|
* Service for interacting with GitHub API (pull requests, branches, etc.)
|
|
23
80
|
*/
|
|
@@ -41,19 +98,18 @@ export declare class GitHubService {
|
|
|
41
98
|
/**
|
|
42
99
|
* Create or update a pull request (idempotent — GIT-H1).
|
|
43
100
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* existing PR instead of hitting the 422 that `createPullRequest` would
|
|
49
|
-
* throw on a duplicate, which previously wedged the branch in
|
|
50
|
-
* 'sync-failed' permanently.
|
|
101
|
+
* Thin delegate to the module-level `createOrUpdatePullRequest` helper
|
|
102
|
+
* (shared with the worker's `push-and-create-or-update-pr` task) bound to
|
|
103
|
+
* this instance's octokit/owner/repo. See that function's doc comment for
|
|
104
|
+
* the idempotency rationale.
|
|
51
105
|
*/
|
|
52
106
|
createOrUpdatePR(options: {
|
|
53
107
|
head: string;
|
|
54
108
|
base: string;
|
|
55
109
|
title: string;
|
|
56
110
|
body: string;
|
|
111
|
+
/** Convert a pre-existing draft PR to ready-for-review after updating it. */
|
|
112
|
+
markReadyIfDraft?: boolean;
|
|
57
113
|
}): Promise<{
|
|
58
114
|
number: number;
|
|
59
115
|
url: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-service.d.ts","sourceRoot":"","sources":["../src/github-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"github-service.d.ts","sourceRoot":"","sources":["../src/github-service.ts"],"names":[],"mappings":"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"}
|
package/dist/github-service.js
CHANGED
|
@@ -1,11 +1,149 @@
|
|
|
1
1
|
import { Octokit } from '@octokit/rest';
|
|
2
|
+
import { throttling } from '@octokit/plugin-throttling';
|
|
2
3
|
import { operatingStrategy } from './operating-mode/index.js';
|
|
4
|
+
import { getErrorMessage } from './utils/error.js';
|
|
5
|
+
const ThrottledOctokit = Octokit.plugin(throttling);
|
|
6
|
+
/**
|
|
7
|
+
* Retry primary rate limits at most twice and only for short waits; beyond
|
|
8
|
+
* that, task-level retry/backoff (worker) or the caller's error path takes
|
|
9
|
+
* over. The worker's task timeout would abort a longer in-request wait
|
|
10
|
+
* anyway.
|
|
11
|
+
*/
|
|
12
|
+
export const shouldRetryRateLimit = (retryAfter, retryCount) => retryCount < 2 && retryAfter <= 60;
|
|
13
|
+
/**
|
|
14
|
+
* Secondary (abuse-detection) rate limits are stricter to trip and usually
|
|
15
|
+
* signal we're hammering the API too fast — retry at most once, and only for
|
|
16
|
+
* a short wait.
|
|
17
|
+
*/
|
|
18
|
+
export const shouldRetrySecondaryRateLimit = (retryAfter, retryCount) => retryCount < 1 && retryAfter <= 60;
|
|
19
|
+
/**
|
|
20
|
+
* Create an Octokit instance with the throttling plugin attached, so it
|
|
21
|
+
* proactively respects GitHub's `retry-after` guidance on rate limits
|
|
22
|
+
* instead of failing immediately (see cms-worker.ts isPermanentTaskFailure
|
|
23
|
+
* for the safety net this doesn't cover: exhausted plugin retries and
|
|
24
|
+
* errors the plugin never sees, like non-403 network failures).
|
|
25
|
+
*/
|
|
26
|
+
export function createCanopyOctokit(options) {
|
|
27
|
+
return new ThrottledOctokit({
|
|
28
|
+
auth: options.auth,
|
|
29
|
+
throttle: {
|
|
30
|
+
onRateLimit: (retryAfter, requestOptions, _octokit, retryCount) => {
|
|
31
|
+
console.warn(`CanopyCMS: GitHub primary rate limit hit for ${requestOptions.method} ${requestOptions.url} ` +
|
|
32
|
+
`(retryAfter=${retryAfter}s, retryCount=${retryCount})`);
|
|
33
|
+
return shouldRetryRateLimit(retryAfter, retryCount);
|
|
34
|
+
},
|
|
35
|
+
onSecondaryRateLimit: (retryAfter, requestOptions, _octokit, retryCount) => {
|
|
36
|
+
console.warn(`CanopyCMS: GitHub secondary rate limit hit for ${requestOptions.method} ${requestOptions.url} ` +
|
|
37
|
+
`(retryAfter=${retryAfter}s, retryCount=${retryCount})`);
|
|
38
|
+
return shouldRetrySecondaryRateLimit(retryAfter, retryCount);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create or update a pull request (idempotent — GIT-H1).
|
|
45
|
+
*
|
|
46
|
+
* If an open PR already exists from head to base, update it and return its
|
|
47
|
+
* number/url instead of erroring. This makes PR submission safely
|
|
48
|
+
* retryable: if a caller crashes after GitHub creates the PR but before it
|
|
49
|
+
* persists the returned PR number, calling this again recovers the
|
|
50
|
+
* existing PR instead of hitting the 422 that a blind create would throw on
|
|
51
|
+
* a duplicate, which previously wedged the branch in 'sync-failed'
|
|
52
|
+
* permanently.
|
|
53
|
+
*
|
|
54
|
+
* Shared by `GitHubService.createOrUpdatePR` (direct-API callers) and the
|
|
55
|
+
* worker's `push-and-create-or-update-pr` task, so the list->tiebreak->
|
|
56
|
+
* update/create logic and the draft->ready conversion live in one place.
|
|
57
|
+
*/
|
|
58
|
+
export async function createOrUpdatePullRequest(params) {
|
|
59
|
+
const { octokit, owner, repo, head, base, title, body, markReadyIfDraft, signal } = params;
|
|
60
|
+
// CONDITIONAL spread: when no signal is passed, request objects below are
|
|
61
|
+
// byte-identical to the pre-refactor call sites (exact toHaveBeenCalledWith
|
|
62
|
+
// assertions in github-service.test.ts depend on this).
|
|
63
|
+
const requestOption = signal ? { request: { signal } } : {};
|
|
64
|
+
// Check if an open PR already exists for this head/base
|
|
65
|
+
const existingPRs = await octokit.pulls.list({
|
|
66
|
+
owner,
|
|
67
|
+
repo,
|
|
68
|
+
head: `${owner}:${head}`,
|
|
69
|
+
base,
|
|
70
|
+
state: 'open',
|
|
71
|
+
...requestOption,
|
|
72
|
+
});
|
|
73
|
+
if (existingPRs.data.length > 0) {
|
|
74
|
+
// GIT-M5: GitHub disallows more than one open PR for a given
|
|
75
|
+
// head+base pair, so this should always be a single match. Guard
|
|
76
|
+
// against blindly trusting array order anyway — if more than one is
|
|
77
|
+
// ever returned, warn and prefer the most recently updated instead of
|
|
78
|
+
// an arbitrary one.
|
|
79
|
+
let existing = existingPRs.data[0];
|
|
80
|
+
if (existingPRs.data.length > 1) {
|
|
81
|
+
existing = [...existingPRs.data].sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())[0];
|
|
82
|
+
console.warn(`CanopyCMS: Found ${existingPRs.data.length} open PRs for ${head} -> ${base}; updating the most recently updated (#${existing.number})`);
|
|
83
|
+
}
|
|
84
|
+
await octokit.pulls.update({
|
|
85
|
+
owner,
|
|
86
|
+
repo,
|
|
87
|
+
pull_number: existing.number,
|
|
88
|
+
title,
|
|
89
|
+
body,
|
|
90
|
+
...requestOption,
|
|
91
|
+
});
|
|
92
|
+
// Only a pre-existing PR can be a draft on this path — pulls.create
|
|
93
|
+
// above is never called with draft: true, so a newly created PR is
|
|
94
|
+
// never draft and needs no conversion.
|
|
95
|
+
if (markReadyIfDraft && existing.draft) {
|
|
96
|
+
// Use GraphQL API for draft conversion (not available in REST API).
|
|
97
|
+
// Read the node id straight off the list payload — no extra pulls.get.
|
|
98
|
+
//
|
|
99
|
+
// Best-effort: the push + pulls.update above already succeeded, so the
|
|
100
|
+
// submit itself is done. A fine-grained token that can update PRs but
|
|
101
|
+
// lacks this mutation's scope throws a GraphqlResponseError, which
|
|
102
|
+
// carries no numeric HTTP status (the GraphQL endpoint responds 200
|
|
103
|
+
// even for a mutation-level failure) — the worker's
|
|
104
|
+
// isPermanentTaskFailure would classify that as transient and retry
|
|
105
|
+
// the whole re-push until the retry cap, wedging the branch in
|
|
106
|
+
// 'sync-failed' even though the PR already exists and is current.
|
|
107
|
+
// Warn and continue instead of letting this sink an already-succeeded
|
|
108
|
+
// submit.
|
|
109
|
+
try {
|
|
110
|
+
await octokit.graphql(`
|
|
111
|
+
mutation($pullRequestId: ID!) {
|
|
112
|
+
markPullRequestReadyForReview(input: {pullRequestId: $pullRequestId}) {
|
|
113
|
+
pullRequest {
|
|
114
|
+
id
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
`, {
|
|
119
|
+
pullRequestId: existing.node_id,
|
|
120
|
+
...requestOption,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
console.warn(`CanopyCMS: Failed to convert PR #${existing.number} to ready for review (the PR update itself succeeded; continuing):`, getErrorMessage(err));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return { number: existing.number, url: existing.html_url, created: false };
|
|
128
|
+
}
|
|
129
|
+
// Create new PR
|
|
130
|
+
const pr = await octokit.pulls.create({
|
|
131
|
+
owner,
|
|
132
|
+
repo,
|
|
133
|
+
head,
|
|
134
|
+
base,
|
|
135
|
+
title,
|
|
136
|
+
body,
|
|
137
|
+
...requestOption,
|
|
138
|
+
});
|
|
139
|
+
return { number: pr.data.number, url: pr.data.html_url, created: true };
|
|
140
|
+
}
|
|
3
141
|
/**
|
|
4
142
|
* Service for interacting with GitHub API (pull requests, branches, etc.)
|
|
5
143
|
*/
|
|
6
144
|
export class GitHubService {
|
|
7
145
|
constructor(options) {
|
|
8
|
-
this.octokit =
|
|
146
|
+
this.octokit = createCanopyOctokit({ auth: options.token });
|
|
9
147
|
this.owner = options.owner;
|
|
10
148
|
this.repo = options.repo;
|
|
11
149
|
this.baseBranch = options.baseBranch ?? 'main';
|
|
@@ -43,53 +181,23 @@ export class GitHubService {
|
|
|
43
181
|
/**
|
|
44
182
|
* Create or update a pull request (idempotent — GIT-H1).
|
|
45
183
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* existing PR instead of hitting the 422 that `createPullRequest` would
|
|
51
|
-
* throw on a duplicate, which previously wedged the branch in
|
|
52
|
-
* 'sync-failed' permanently.
|
|
184
|
+
* Thin delegate to the module-level `createOrUpdatePullRequest` helper
|
|
185
|
+
* (shared with the worker's `push-and-create-or-update-pr` task) bound to
|
|
186
|
+
* this instance's octokit/owner/repo. See that function's doc comment for
|
|
187
|
+
* the idempotency rationale.
|
|
53
188
|
*/
|
|
54
189
|
async createOrUpdatePR(options) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
owner: this.owner,
|
|
58
|
-
repo: this.repo,
|
|
59
|
-
head: `${this.owner}:${options.head}`,
|
|
60
|
-
base: options.base,
|
|
61
|
-
state: 'open',
|
|
62
|
-
});
|
|
63
|
-
if (existingPRs.data.length > 0) {
|
|
64
|
-
// GIT-M5: GitHub disallows more than one open PR for a given
|
|
65
|
-
// head+base pair, so this should always be a single match. Guard
|
|
66
|
-
// against blindly trusting array order anyway — if more than one is
|
|
67
|
-
// ever returned, warn and prefer the most recently updated instead of
|
|
68
|
-
// an arbitrary one.
|
|
69
|
-
let pr = existingPRs.data[0];
|
|
70
|
-
if (existingPRs.data.length > 1) {
|
|
71
|
-
pr = [...existingPRs.data].sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())[0];
|
|
72
|
-
console.warn(`CanopyCMS: Found ${existingPRs.data.length} open PRs for ${options.head} -> ${options.base}; updating the most recently updated (#${pr.number})`);
|
|
73
|
-
}
|
|
74
|
-
await this.octokit.pulls.update({
|
|
75
|
-
owner: this.owner,
|
|
76
|
-
repo: this.repo,
|
|
77
|
-
pull_number: pr.number,
|
|
78
|
-
title: options.title,
|
|
79
|
-
body: options.body,
|
|
80
|
-
});
|
|
81
|
-
return { number: pr.number, url: pr.html_url };
|
|
82
|
-
}
|
|
83
|
-
// Create new PR
|
|
84
|
-
const pr = await this.octokit.pulls.create({
|
|
190
|
+
const result = await createOrUpdatePullRequest({
|
|
191
|
+
octokit: this.octokit,
|
|
85
192
|
owner: this.owner,
|
|
86
193
|
repo: this.repo,
|
|
87
194
|
head: options.head,
|
|
88
195
|
base: options.base,
|
|
89
196
|
title: options.title,
|
|
90
197
|
body: options.body,
|
|
198
|
+
markReadyIfDraft: options.markReadyIfDraft,
|
|
91
199
|
});
|
|
92
|
-
return { number:
|
|
200
|
+
return { number: result.number, url: result.url };
|
|
93
201
|
}
|
|
94
202
|
/**
|
|
95
203
|
* Get pull request details
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-service.js","sourceRoot":"","sources":["../src/github-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"github-service.js","sourceRoot":"","sources":["../src/github-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Absolute path of the generation marker for `resource` under `root`. */
|
|
2
|
+
export declare function resourceGenerationPath(root: string, resource: string): string;
|
|
3
|
+
export interface BumpResourceGenerationOptions {
|
|
4
|
+
/**
|
|
5
|
+
* When true, a failed bump rethrows instead of being logged and swallowed.
|
|
6
|
+
* Use this for callers where a lost bump means indefinitely stale durable
|
|
7
|
+
* data with no bounding backstop (e.g. a registry's invalidate()) — those
|
|
8
|
+
* callers must not silently succeed while leaving stale readers unaware.
|
|
9
|
+
* Default false (hint flavor): log-warn and swallow, since the mutation
|
|
10
|
+
* itself is already durable and a lost bump only degrades to pre-marker
|
|
11
|
+
* staleness behavior plus whatever backstop the consumer has.
|
|
12
|
+
*/
|
|
13
|
+
mustSucceed?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Record on disk that `resource` changed under `root`, so consumers in OTHER
|
|
17
|
+
* processes rebuild. Must be called AFTER the filesystem mutation.
|
|
18
|
+
*
|
|
19
|
+
* Returns the token written, or null if the write failed and `mustSucceed`
|
|
20
|
+
* was not set (logged and swallowed).
|
|
21
|
+
*/
|
|
22
|
+
export declare function bumpResourceGeneration(root: string, resource: string, options?: BumpResourceGenerationOptions): Promise<string | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Result of reading a generation marker. `ok: false` means the read failed
|
|
25
|
+
* for a reason OTHER than "marker doesn't exist yet" — callers should treat
|
|
26
|
+
* this as "force regenerate" rather than folding it into a token value,
|
|
27
|
+
* because a legitimate snapshot can embed `token: null` (a fresh clone,
|
|
28
|
+
* regenerated before any bump ever occurred) and that must stay
|
|
29
|
+
* distinguishable from "we don't actually know the current token".
|
|
30
|
+
*/
|
|
31
|
+
export type GenerationReadResult = {
|
|
32
|
+
ok: true;
|
|
33
|
+
token: string | null;
|
|
34
|
+
} | {
|
|
35
|
+
ok: false;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Read the current generation token for `resource` under `root`.
|
|
39
|
+
*
|
|
40
|
+
* ENOENT maps to `{ok: true, token: null}` — a valid "never bumped" state,
|
|
41
|
+
* distinct from every real token. Any OTHER read error maps to `{ok: false}`
|
|
42
|
+
* (logged) so callers can force-regenerate instead of trusting a null they
|
|
43
|
+
* cannot actually attribute to "never bumped".
|
|
44
|
+
*/
|
|
45
|
+
export declare function readResourceGeneration(root: string, resource: string): Promise<GenerationReadResult>;
|
|
46
|
+
/**
|
|
47
|
+
* True when a previously-captured snapshot token is still current: the read
|
|
48
|
+
* succeeded AND its token matches the snapshot's. A failed read (`ok: false`)
|
|
49
|
+
* is never current, even if the snapshot's token happens to be null — an
|
|
50
|
+
* unreadable marker means we cannot vouch for freshness either way, and the
|
|
51
|
+
* safe default is to treat it as stale.
|
|
52
|
+
*/
|
|
53
|
+
export declare function isGenerationCurrent(snapshotToken: string | null, read: GenerationReadResult): boolean;
|
|
54
|
+
//# sourceMappingURL=resource-generation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-generation.d.ts","sourceRoot":"","sources":["../src/resource-generation.ts"],"names":[],"mappings":"AAqGA,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,MAAM,WAAW,6BAA6B;IAC5C;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,6BAA6B,GACtC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAA;AAErF;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC,CAW/B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAET"}
|
|
@@ -0,0 +1,156 @@
|
|
|
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 { createDebugLogger } from './utils/debug.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generalized cross-process generation marker for any on-disk resource that
|
|
9
|
+
* is durably cached under a branch-clone (or similar) root.
|
|
10
|
+
*
|
|
11
|
+
* Some in-process cache is kept per resource per process (an in-memory index,
|
|
12
|
+
* a parsed schema, a registry snapshot). Within one process, mutating code can
|
|
13
|
+
* invalidate that cache directly. Across processes (several warm Lambda
|
|
14
|
+
* containers + the EC2 worker sharing branch clones on EFS) there is no
|
|
15
|
+
* shared memory and no cross-host file watching, so the shared filesystem
|
|
16
|
+
* itself is the coordination medium: every operation that mutates the
|
|
17
|
+
* resource also rewrites a small marker file with a fresh random token, and
|
|
18
|
+
* every consumer cheaply re-reads that marker (throttled) to decide whether
|
|
19
|
+
* its cached snapshot is still current.
|
|
20
|
+
*
|
|
21
|
+
* The marker for a given `resource` lives at {root}/.canopy-meta/{resource}.generation:
|
|
22
|
+
* `.canopy-meta/` is the established per-clone internal dir — dot-prefixed (so
|
|
23
|
+
* content and index scans skip it) and excluded from git via .git/info/exclude.
|
|
24
|
+
*
|
|
25
|
+
* ## Why a random token instead of a monotonic counter
|
|
26
|
+
*
|
|
27
|
+
* Readers only need "did it change since I captured it", so inequality against
|
|
28
|
+
* the captured value suffices. A counter would need read-modify-write, which
|
|
29
|
+
* silently loses concurrent bumps without a lock (two bumpers read 5, both
|
|
30
|
+
* write 6 — a reader that recorded 6 after the first bump never learns of the
|
|
31
|
+
* second mutation). A unique token per bump has no lost-update problem, needs
|
|
32
|
+
* no lock, and avoids NFS mtime-granularity / cross-host clock-skew issues.
|
|
33
|
+
* Each bump is a single atomic temp-file + rename.
|
|
34
|
+
*
|
|
35
|
+
* ## Ordering protocol (correctness)
|
|
36
|
+
*
|
|
37
|
+
* - Bumpers write the marker strictly AFTER their filesystem mutations.
|
|
38
|
+
* - Readers capture the marker token strictly BEFORE scanning/rebuilding the
|
|
39
|
+
* resource, and record it only after the rebuild completes. A bump landing
|
|
40
|
+
* mid-rebuild therefore leaves the recorded token older than the file,
|
|
41
|
+
* forcing another rebuild on the next probe.
|
|
42
|
+
*
|
|
43
|
+
* ## Consistency guarantees and residual staleness windows (EFS/NFSv4)
|
|
44
|
+
*
|
|
45
|
+
* Guaranteed: any completed mutation that bumps the marker is observed by
|
|
46
|
+
* every consumer on that root at its next freshness probe. Residual windows
|
|
47
|
+
* (bounded in practice by per-request lifetimes and, where implemented, a
|
|
48
|
+
* suspicious-lookup backstop):
|
|
49
|
+
*
|
|
50
|
+
* - (A) NFS attribute caching (benign direction): another host may not see a
|
|
51
|
+
* new marker for up to the attribute-cache timeout (~3-60s on default EFS
|
|
52
|
+
* mounts; `noac` cannot be assumed). The reader acts on a stale token and
|
|
53
|
+
* keeps a stale snapshot until the cache expires.
|
|
54
|
+
* - (B) Probe throttle: however long the consumer debounces freshness checks.
|
|
55
|
+
* - (C) Self-adoption: after its own mutation a consumer adopts the token it
|
|
56
|
+
* wrote; if a concurrent foreign bump landed just before ours, we miss that
|
|
57
|
+
* one notification (window: from our last token observation to our rename).
|
|
58
|
+
* - (E) Fresh-token/stale-scan (malignant direction, cross-host only): NFS
|
|
59
|
+
* revalidates the marker file on open, but a rebuild's reads may be served
|
|
60
|
+
* from dentry/attribute caches — a rebuild can record a NEW token against
|
|
61
|
+
* PRE-mutation data, leaving that consumer confidently stale until the next
|
|
62
|
+
* bump. Structurally unfixable with a filesystem marker; bounded by
|
|
63
|
+
* per-request lifetimes and any backstop the consumer implements.
|
|
64
|
+
*
|
|
65
|
+
* ## Guarantee delta for DURABLE snapshot consumers (registry / schema-cache)
|
|
66
|
+
*
|
|
67
|
+
* The in-memory ContentIdIndex tolerates window (E) because a stale index is
|
|
68
|
+
* scoped to one process's memory: it self-heals on the next probe or process
|
|
69
|
+
* recycle, and a wrong-file write is independently guarded by ContentStore's
|
|
70
|
+
* existence check. Consumers that persist a durable snapshot ALONGSIDE this
|
|
71
|
+
* marker — a branch registry list, a resolved-schema cache file — do not get
|
|
72
|
+
* that same containment. If such a consumer's regeneration scan is served
|
|
73
|
+
* from stale NFS dentry/attribute caches, window (E) produces a snapshot that
|
|
74
|
+
* embeds a FRESH token over STALE data, and that snapshot is written to disk.
|
|
75
|
+
* Every other host that reads the marker sees the fresh token, concludes the
|
|
76
|
+
* durable snapshot is current, and serves the stale data too — this is now a
|
|
77
|
+
* durable, SHARED staleness visible to all hosts until the next bump, not a
|
|
78
|
+
* transient one-process condition. A random token cannot distinguish "fresh
|
|
79
|
+
* token over fresh data" from "fresh token over stale data" — the token only
|
|
80
|
+
* proves a bump happened, not that the bumping host's own scan observed it.
|
|
81
|
+
*
|
|
82
|
+
* Durable-snapshot consumers must therefore implement mitigations this module
|
|
83
|
+
* cannot provide on their behalf:
|
|
84
|
+
*
|
|
85
|
+
* - Eager regeneration on the mutating host, performed immediately after its
|
|
86
|
+
* own bump (in the same request/operation). That host's own scan is
|
|
87
|
+
* necessarily coherent with the mutation it just made (no NFS round trip
|
|
88
|
+
* was needed to observe its own writes), so regenerating there rather than
|
|
89
|
+
* waiting for a lazy pull on some other host avoids handing window (E) a
|
|
90
|
+
* chance to run at all for the common case.
|
|
91
|
+
* - A get-miss / suspicious-lookup backstop: if a consumer looks up something
|
|
92
|
+
* that "should" exist per the durable snapshot but is missing (or vice
|
|
93
|
+
* versa), that mismatch is a signal to force a fresh regeneration rather
|
|
94
|
+
* than trusting the token match, bounding how long a bad snapshot survives.
|
|
95
|
+
*/
|
|
96
|
+
const log = createDebugLogger({ prefix: 'ResourceGeneration' });
|
|
97
|
+
const META_DIR = '.canopy-meta';
|
|
98
|
+
/** Absolute path of the generation marker for `resource` under `root`. */
|
|
99
|
+
export function resourceGenerationPath(root, resource) {
|
|
100
|
+
return path.resolve(root, META_DIR, `${resource}.generation`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Record on disk that `resource` changed under `root`, so consumers in OTHER
|
|
104
|
+
* processes rebuild. Must be called AFTER the filesystem mutation.
|
|
105
|
+
*
|
|
106
|
+
* Returns the token written, or null if the write failed and `mustSucceed`
|
|
107
|
+
* was not set (logged and swallowed).
|
|
108
|
+
*/
|
|
109
|
+
export async function bumpResourceGeneration(root, resource, options) {
|
|
110
|
+
const token = randomUUID();
|
|
111
|
+
try {
|
|
112
|
+
await atomicWriteFile(resourceGenerationPath(root, resource), token);
|
|
113
|
+
return token;
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
log.warn('generation', `Failed to bump ${resource} generation for ${root}`, {
|
|
117
|
+
error: getErrorMessage(err),
|
|
118
|
+
});
|
|
119
|
+
if (options?.mustSucceed)
|
|
120
|
+
throw err;
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Read the current generation token for `resource` under `root`.
|
|
126
|
+
*
|
|
127
|
+
* ENOENT maps to `{ok: true, token: null}` — a valid "never bumped" state,
|
|
128
|
+
* distinct from every real token. Any OTHER read error maps to `{ok: false}`
|
|
129
|
+
* (logged) so callers can force-regenerate instead of trusting a null they
|
|
130
|
+
* cannot actually attribute to "never bumped".
|
|
131
|
+
*/
|
|
132
|
+
export async function readResourceGeneration(root, resource) {
|
|
133
|
+
try {
|
|
134
|
+
const token = await fs.readFile(resourceGenerationPath(root, resource), 'utf-8');
|
|
135
|
+
return { ok: true, token };
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
if (isNodeError(err) && err.code === 'ENOENT')
|
|
139
|
+
return { ok: true, token: null };
|
|
140
|
+
log.warn('generation', `Failed to read ${resource} generation for ${root}`, {
|
|
141
|
+
error: getErrorMessage(err),
|
|
142
|
+
});
|
|
143
|
+
return { ok: false };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* True when a previously-captured snapshot token is still current: the read
|
|
148
|
+
* succeeded AND its token matches the snapshot's. A failed read (`ok: false`)
|
|
149
|
+
* is never current, even if the snapshot's token happens to be null — an
|
|
150
|
+
* unreadable marker means we cannot vouch for freshness either way, and the
|
|
151
|
+
* safe default is to treat it as stale.
|
|
152
|
+
*/
|
|
153
|
+
export function isGenerationCurrent(snapshotToken, read) {
|
|
154
|
+
return read.ok && read.token === snapshotToken;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=resource-generation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-generation.js","sourceRoot":"","sources":["../src/resource-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,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAEH,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAA;AAE/D,MAAM,QAAQ,GAAG,cAAc,CAAA;AAE/B,0EAA0E;AAC1E,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,QAAgB;IACnE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,QAAQ,aAAa,CAAC,CAAA;AAC/D,CAAC;AAeD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAY,EACZ,QAAgB,EAChB,OAAuC;IAEvC,MAAM,KAAK,GAAG,UAAU,EAAE,CAAA;IAC1B,IAAI,CAAC;QACH,MAAM,eAAe,CAAC,sBAAsB,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAA;QACpE,OAAO,KAAK,CAAA;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,kBAAkB,QAAQ,mBAAmB,IAAI,EAAE,EAAE;YAC1E,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC;SAC5B,CAAC,CAAA;QACF,IAAI,OAAO,EAAE,WAAW;YAAE,MAAM,GAAG,CAAA;QACnC,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAYD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAY,EACZ,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAA;QAChF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;QAC/E,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,kBAAkB,QAAQ,mBAAmB,IAAI,EAAE,EAAE;YAC1E,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC;SAC5B,CAAC,CAAA;QACF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;IACtB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,aAA4B,EAC5B,IAA0B;IAE1B,OAAO,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,KAAK,aAAa,CAAA;AAChD,CAAC"}
|
|
@@ -160,8 +160,28 @@ export declare class SchemaOps {
|
|
|
160
160
|
private readonly services?;
|
|
161
161
|
constructor(contentRoot: string, entrySchemaRegistry: EntrySchemaRegistry, services?: CanopyServices | undefined);
|
|
162
162
|
/**
|
|
163
|
-
* Invalidate schema cache for this branch after mutations
|
|
164
|
-
*
|
|
163
|
+
* Invalidate schema cache for this branch after mutations, then eagerly
|
|
164
|
+
* re-resolve on THIS host.
|
|
165
|
+
*
|
|
166
|
+
* The eager re-resolve is the durable-snapshot window-E mitigation (see
|
|
167
|
+
* BranchSchemaCache's class docs): the mutating host's own scan is
|
|
168
|
+
* necessarily coherent with the mutation it just made, whereas the
|
|
169
|
+
* editor's follow-up schema read is a separate Lambda invocation with no
|
|
170
|
+
* container affinity — exactly the lazy foreign-host pull whose scan can
|
|
171
|
+
* be served from stale NFS caches and durably persist a fresh-token
|
|
172
|
+
* snapshot of pre-mutation schema. Regen failures are logged and
|
|
173
|
+
* swallowed (mirroring BranchRegistry.invalidate()): the bump alone
|
|
174
|
+
* already restored correctness for every future reader, and a mutation
|
|
175
|
+
* that leaves no valid schema behind (e.g. deleting the last collection)
|
|
176
|
+
* must not fail the request over an uncacheable resolve.
|
|
177
|
+
*
|
|
178
|
+
* Uses `resolveAndPersist()`, NOT `getSchema()`: getSchema()'s cache-read
|
|
179
|
+
* fast path can return a snapshot a DIFFERENT, concurrent host just wrote
|
|
180
|
+
* (its own eager re-resolve, raced against this one, embedding the
|
|
181
|
+
* now-current marker token over ITS OWN stale-NFS-cache scan) — silently
|
|
182
|
+
* skipping the one scan this call exists to guarantee. resolveAndPersist()
|
|
183
|
+
* never reads the cache file, so it cannot be short-circuited that way.
|
|
184
|
+
* See BranchSchemaCache.resolveAndPersist()'s doc comment for the full race.
|
|
165
185
|
*/
|
|
166
186
|
private invalidateSchemaCache;
|
|
167
187
|
/**
|
|
@@ -171,6 +191,13 @@ export declare class SchemaOps {
|
|
|
171
191
|
* indexes for this branch: in-process via the registry and cross-process via
|
|
172
192
|
* the on-disk generation marker. ContentStores (and the marker) are rooted
|
|
173
193
|
* at the branch root, the contentRoot's parent.
|
|
194
|
+
*
|
|
195
|
+
* Uses the combined invalidateBranchContentCaches() helper rather than the
|
|
196
|
+
* content-index-only invalidateContentIndexesDurable(): every call site here
|
|
197
|
+
* is already followed by its own invalidateSchemaCache() call below, so this
|
|
198
|
+
* double-bumps the schema generation marker. That's harmless (bumps are
|
|
199
|
+
* idempotent hints, not counters) and keeps this call uniform with the other
|
|
200
|
+
* bulk-mutation call sites that use the combined helper.
|
|
174
201
|
*/
|
|
175
202
|
private invalidateContentIdIndexes;
|
|
176
203
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-store.d.ts","sourceRoot":"","sources":["../../src/schema/schema-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"schema-store.d.ts","sourceRoot":"","sources":["../../src/schema/schema-store.ts"],"names":[],"mappings":"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"}
|