canopycms 0.0.67 → 0.0.68-int.101
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/README.md +24 -17
- package/dist/ai/handler.js +8 -0
- package/dist/api/admin-branch-health.js +17 -20
- package/dist/api/admin.d.ts +30 -9
- package/dist/api/admin.js +32 -2
- package/dist/api/assets.js +84 -76
- package/dist/api/branch-create-window.d.ts +12 -0
- package/dist/api/branch-create-window.js +13 -0
- package/dist/api/branch-review.d.ts +3 -3
- package/dist/api/branch-review.js +14 -5
- package/dist/api/branch-status.d.ts +5 -5
- package/dist/api/branch-status.js +26 -6
- package/dist/api/branch-withdraw.d.ts +2 -2
- package/dist/api/branch-withdraw.js +7 -2
- package/dist/api/branch.d.ts +15 -2
- package/dist/api/branch.js +118 -92
- package/dist/api/client.d.ts +18 -6
- package/dist/api/client.js +79 -12
- package/dist/api/content.d.ts +6 -5
- package/dist/api/content.js +44 -41
- package/dist/api/entries.js +16 -15
- package/dist/api/github-sync.d.ts +19 -1
- package/dist/api/github-sync.js +57 -10
- package/dist/api/index.d.ts +1 -1
- package/dist/api/reference-options.js +1 -1
- package/dist/api/resolve-references.js +14 -40
- package/dist/api/settings-helpers.d.ts +1 -1
- package/dist/api/settings-helpers.js +1 -4
- package/dist/api/user.d.ts +3 -0
- package/dist/api/user.js +3 -0
- package/dist/assets/asset-url.d.ts +22 -16
- package/dist/assets/asset-url.js +42 -25
- package/dist/assets/factory.d.ts +5 -0
- package/dist/assets/factory.js +5 -0
- package/dist/assets/finalize.js +3 -0
- package/dist/assets/index.d.ts +1 -1
- package/dist/assets/materialize.d.ts +153 -0
- package/dist/assets/materialize.js +402 -0
- package/dist/assets/store-local.d.ts +19 -5
- package/dist/assets/store-local.js +69 -10
- package/dist/assets/store-s3.d.ts +38 -7
- package/dist/assets/store-s3.js +128 -22
- package/dist/assets/transform-directives.d.ts +52 -13
- package/dist/assets/transform-directives.js +87 -27
- package/dist/assets/transform.d.ts +3 -3
- package/dist/assets/transform.js +13 -8
- package/dist/assets/types.d.ts +31 -4
- package/dist/auth/file-based-auth-cache.js +7 -8
- package/dist/authorization/content.d.ts +5 -4
- package/dist/authorization/content.js +5 -5
- package/dist/authorization/path.d.ts +11 -6
- package/dist/authorization/path.js +11 -6
- package/dist/authorization/types.d.ts +2 -2
- package/dist/branch-health.d.ts +7 -1
- package/dist/branch-health.js +8 -3
- package/dist/branch-metadata.d.ts +5 -5
- package/dist/branch-metadata.js +44 -36
- package/dist/branch-provisioning.d.ts +167 -0
- package/dist/branch-provisioning.js +501 -0
- package/dist/branch-schema-cache.d.ts +5 -3
- package/dist/branch-schema-cache.js +29 -11
- package/dist/branch-sparse.d.ts +23 -0
- package/dist/branch-sparse.js +118 -0
- package/dist/branch-workspace.d.ts +42 -3
- package/dist/branch-workspace.js +240 -94
- package/dist/build/asset-refs.d.ts +93 -0
- package/dist/build/asset-refs.js +251 -0
- package/dist/build-identity.d.ts +3 -0
- package/dist/build-identity.js +13 -0
- package/dist/cli/asset-refs.d.ts +52 -0
- package/dist/cli/asset-refs.js +194 -0
- package/dist/cli/cli.d.ts +15 -1
- package/dist/cli/cli.js +5928 -2195
- package/dist/cli/configured-asset-store.d.ts +12 -0
- package/dist/cli/configured-asset-store.js +46 -0
- package/dist/cli/generate-ai-content.js +2185 -587
- package/dist/cli/github-app-manifest.d.ts +4 -3
- package/dist/cli/github-app-manifest.js +4 -3
- package/dist/cli/init.js +30 -27
- package/dist/cli/migrate.js +12 -8
- package/dist/cli/sync.js +83 -37
- package/dist/cli/template-files/Dockerfile.cms.template +8 -0
- package/dist/cli/template-files/cdk-app.ts.template +4 -0
- package/dist/cli/template-files/cms-stack.ts.template +23 -12
- package/dist/cli/template-files/deploy-cms.yml.template +2 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/config/helpers.js +1 -2
- package/dist/config/schemas/config.d.ts +19 -32
- package/dist/config/schemas/config.js +9 -11
- package/dist/config/schemas/field.js +1 -0
- package/dist/config/schemas/media.d.ts +4 -13
- package/dist/config/schemas/media.js +5 -8
- package/dist/config/schemas/url.d.ts +4 -20
- package/dist/config/schemas/url.js +6 -22
- package/dist/config/types.d.ts +30 -20
- package/dist/config/validation.d.ts +6 -0
- package/dist/config/validation.js +37 -0
- package/dist/content-listing.d.ts +12 -12
- package/dist/content-listing.js +10 -6
- package/dist/content-reader.d.ts +11 -2
- package/dist/content-reader.js +22 -14
- package/dist/content-store.d.ts +37 -9
- package/dist/content-store.js +70 -43
- package/dist/content-tree.d.ts +1 -1
- package/dist/content-tree.js +2 -2
- package/dist/context.d.ts +27 -9
- package/dist/context.js +154 -70
- package/dist/editor/BranchManager.d.ts +7 -1
- package/dist/editor/BranchManager.js +29 -14
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +2 -6
- package/dist/editor/Editor.d.ts +4 -3
- package/dist/editor/Editor.js +32 -22
- package/dist/editor/FormRenderer.js +34 -18
- package/dist/editor/PreviewFrame.d.ts +24 -0
- package/dist/editor/PreviewFrame.js +140 -0
- package/dist/editor/admin/SystemHealthPanel.js +47 -7
- package/dist/editor/components/BranchesDrawer.d.ts +9 -0
- package/dist/editor/components/BranchesDrawer.js +4 -0
- package/dist/editor/components/NoEditPermissionNotice.d.ts +10 -0
- package/dist/editor/components/NoEditPermissionNotice.js +17 -0
- package/dist/editor/context/AssetContext.d.ts +18 -35
- package/dist/editor/context/AssetContext.js +20 -29
- package/dist/editor/context/index.d.ts +1 -1
- package/dist/editor/context/index.js +1 -1
- package/dist/editor/editor-config.d.ts +1 -2
- package/dist/editor/editor-config.js +0 -23
- package/dist/editor/editor-utils.d.ts +24 -21
- package/dist/editor/editor-utils.js +75 -62
- package/dist/editor/fields/BlockField.d.ts +1 -0
- package/dist/editor/fields/BlockField.js +6 -4
- package/dist/editor/fields/CodeField.d.ts +1 -0
- package/dist/editor/fields/CodeField.js +2 -2
- package/dist/editor/fields/DateTimeField.d.ts +1 -0
- package/dist/editor/fields/DateTimeField.js +2 -2
- package/dist/editor/fields/FieldDescription.d.ts +16 -0
- package/dist/editor/fields/FieldDescription.js +11 -0
- package/dist/editor/fields/ImageField.d.ts +1 -0
- package/dist/editor/fields/ImageField.js +3 -2
- package/dist/editor/fields/InlineGroupField.js +4 -1
- package/dist/editor/fields/MarkdownField.d.ts +1 -0
- package/dist/editor/fields/MarkdownField.js +115 -20
- package/dist/editor/fields/NumberField.d.ts +1 -0
- package/dist/editor/fields/NumberField.js +2 -2
- package/dist/editor/fields/NumberListField.d.ts +1 -0
- package/dist/editor/fields/NumberListField.js +2 -2
- package/dist/editor/fields/ObjectField.d.ts +1 -0
- package/dist/editor/fields/ObjectField.js +5 -2
- package/dist/editor/fields/ReferenceField.d.ts +1 -0
- package/dist/editor/fields/ReferenceField.js +5 -4
- package/dist/editor/fields/SelectField.d.ts +1 -0
- package/dist/editor/fields/SelectField.js +2 -2
- package/dist/editor/fields/StringListField.d.ts +1 -0
- package/dist/editor/fields/StringListField.js +2 -2
- package/dist/editor/fields/TextField.d.ts +1 -0
- package/dist/editor/fields/TextField.js +2 -2
- package/dist/editor/fields/ToggleField.d.ts +1 -0
- package/dist/editor/fields/ToggleField.js +7 -4
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +3 -2
- package/dist/editor/fields/mdx-jsx-support.d.ts +1 -0
- package/dist/editor/fields/mdx-jsx-support.js +137 -0
- package/dist/editor/hooks/create-branch-request.d.ts +20 -0
- package/dist/editor/hooks/create-branch-request.js +52 -0
- package/dist/editor/hooks/useBranchActions.d.ts +13 -2
- package/dist/editor/hooks/useBranchActions.js +48 -17
- package/dist/editor/hooks/useBranchManager.d.ts +21 -0
- package/dist/editor/hooks/useBranchManager.js +204 -37
- package/dist/editor/hooks/useBranchesData.d.ts +6 -0
- package/dist/editor/hooks/useBranchesData.js +9 -3
- package/dist/editor/hooks/useCommentSystem.js +25 -6
- package/dist/editor/hooks/useDraftManager.d.ts +16 -1
- package/dist/editor/hooks/useDraftManager.js +193 -36
- package/dist/editor/hooks/useEntriesData.js +3 -3
- package/dist/editor/hooks/useEntryManager.d.ts +2 -1
- package/dist/editor/hooks/useEntryManager.js +34 -19
- package/dist/editor/media/AssetCard.d.ts +1 -1
- package/dist/editor/media/crop-math.d.ts +3 -4
- package/dist/editor/media/crop-math.js +11 -22
- package/dist/editor/media/editor-image-src.d.ts +7 -0
- package/dist/editor/media/editor-image-src.js +12 -0
- package/dist/editor/preview-asset-base.d.ts +8 -0
- package/dist/editor/preview-asset-base.js +13 -0
- package/dist/editor/preview-bridge.d.ts +9 -21
- package/dist/editor/preview-bridge.js +19 -139
- package/dist/editor/preview-path.d.ts +10 -0
- package/dist/editor/preview-path.js +20 -0
- package/dist/editor/theme.js +2 -2
- package/dist/entry-schema-registry.d.ts +4 -4
- package/dist/entry-schema-registry.js +10 -6
- package/dist/entry-schema.d.ts +27 -4
- package/dist/entry-schema.js +20 -3
- package/dist/git-manager.d.ts +173 -6
- package/dist/git-manager.js +594 -76
- package/dist/github-service.d.ts +15 -0
- package/dist/github-service.js +19 -1
- package/dist/http/handler.js +37 -13
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +2 -0
- package/dist/http/router.d.ts +2 -0
- package/dist/http/router.js +2 -1
- package/dist/http/types.d.ts +2 -0
- package/dist/http/worker-not-ready.d.ts +10 -0
- package/dist/http/worker-not-ready.js +24 -0
- package/dist/operating-mode/client-unsafe-strategy.js +0 -6
- package/dist/operating-mode/types.d.ts +1 -4
- package/dist/paths/branch-name.d.ts +5 -0
- package/dist/paths/branch-name.js +9 -0
- package/dist/paths/branch.d.ts +6 -2
- package/dist/paths/branch.js +16 -10
- package/dist/paths/index.d.ts +3 -3
- package/dist/paths/index.js +3 -3
- package/dist/paths/normalize.d.ts +7 -0
- package/dist/paths/normalize.js +9 -0
- package/dist/paths/validation.js +0 -2
- package/dist/preview.d.ts +8 -0
- package/dist/preview.js +7 -0
- package/dist/reference-resolver.d.ts +5 -21
- package/dist/reference-resolver.js +9 -44
- package/dist/resolve-canopy-user.js +2 -1
- package/dist/schema/schema-store.d.ts +54 -31
- package/dist/schema/schema-store.js +77 -31
- package/dist/server.d.ts +64 -9
- package/dist/server.js +48 -8
- package/dist/services.d.ts +18 -6
- package/dist/services.js +85 -70
- package/dist/settings-workspace.d.ts +23 -3
- package/dist/settings-workspace.js +197 -45
- package/dist/static/seo.d.ts +2 -14
- package/dist/static/seo.js +2 -25
- package/dist/submission-attribution.d.ts +73 -0
- package/dist/submission-attribution.js +221 -0
- package/dist/sync-core.d.ts +12 -1
- package/dist/sync-core.js +31 -13
- package/dist/task-queue/worker-status.d.ts +8 -0
- package/dist/task-queue/worker-status.js +17 -0
- package/dist/types.d.ts +31 -2
- package/dist/utils/content-serialize.d.ts +5 -2
- package/dist/utils/content-serialize.js +98 -24
- package/dist/utils/content-write-lock.d.ts +18 -7
- package/dist/utils/content-write-lock.js +18 -9
- package/dist/utils/debug.d.ts +8 -0
- package/dist/utils/debug.js +10 -2
- package/dist/utils/git.d.ts +32 -0
- package/dist/utils/git.js +42 -0
- package/dist/utils/occ-json-write.js +10 -2
- package/dist/utils/provision-log.d.ts +25 -0
- package/dist/utils/provision-log.js +49 -0
- package/dist/utils/provisioning-lock.d.ts +35 -5
- package/dist/utils/provisioning-lock.js +73 -12
- package/dist/utils/request-timing.d.ts +25 -0
- package/dist/utils/request-timing.js +101 -0
- package/dist/utils/sanitize-href.d.ts +8 -22
- package/dist/utils/sanitize-href.js +11 -28
- package/dist/utils/url-prefix.d.ts +30 -0
- package/dist/utils/url-prefix.js +61 -0
- package/dist/utils/yaml-source-splice.d.ts +58 -0
- package/dist/utils/yaml-source-splice.js +515 -0
- package/dist/validation/entry-validator.js +9 -3
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/worker/canopy-state.d.ts +45 -0
- package/dist/worker/canopy-state.js +75 -0
- package/dist/worker/cms-worker.d.ts +8 -3
- package/dist/worker/cms-worker.js +38 -2
- package/dist/worker/git-sync.d.ts +30 -12
- package/dist/worker/git-sync.js +253 -58
- package/dist/worker/history-rewrite.d.ts +1 -1
- package/dist/worker/history-rewrite.js +1 -1
- package/dist/worker/provisioned-workspace.d.ts +35 -0
- package/dist/worker/provisioned-workspace.js +50 -0
- package/dist/worker/rebase.d.ts +1 -1
- package/dist/worker/rebase.js +95 -23
- package/dist/worker/remote-git-maintenance.d.ts +3 -0
- package/dist/worker/remote-git-maintenance.js +11 -0
- package/dist/worker/sparse-cone.d.ts +20 -0
- package/dist/worker/sparse-cone.js +132 -0
- package/dist/worker/task-runner.js +99 -14
- package/dist/worker/worker-context.d.ts +6 -1
- package/package.json +8 -2
|
@@ -24,9 +24,10 @@ export type PermissionSet = Readonly<Record<string, PermissionLevel>>;
|
|
|
24
24
|
* - `metadata: read` — implied by any repository permission; declared so
|
|
25
25
|
* this object states the whole surface, not just the non-automatic part.
|
|
26
26
|
* Nothing else: no `issues`, `administration`, `actions`, or organisation
|
|
27
|
-
* permissions. No `workflows` either
|
|
28
|
-
*
|
|
29
|
-
* .
|
|
27
|
+
* permissions. No `workflows` either: GitHub refuses only workflow content it
|
|
28
|
+
* does not already hold, so rebasing onto a base that changed a workflow is
|
|
29
|
+
* accepted. Content that is new to GitHub fails the push task with the file
|
|
30
|
+
* named (`throwIfWorkflowRefusal` in worker/task-runner.ts).
|
|
30
31
|
*/
|
|
31
32
|
export declare const CANOPY_APP_PERMISSIONS: PermissionSet;
|
|
32
33
|
/**
|
|
@@ -22,9 +22,10 @@ const PERMISSION_LEVELS = ['read', 'write', 'admin'];
|
|
|
22
22
|
* - `metadata: read` — implied by any repository permission; declared so
|
|
23
23
|
* this object states the whole surface, not just the non-automatic part.
|
|
24
24
|
* Nothing else: no `issues`, `administration`, `actions`, or organisation
|
|
25
|
-
* permissions. No `workflows` either
|
|
26
|
-
*
|
|
27
|
-
* .
|
|
25
|
+
* permissions. No `workflows` either: GitHub refuses only workflow content it
|
|
26
|
+
* does not already hold, so rebasing onto a base that changed a workflow is
|
|
27
|
+
* accepted. Content that is new to GitHub fails the push task with the file
|
|
28
|
+
* named (`throwIfWorkflowRefusal` in worker/task-runner.ts).
|
|
28
29
|
*/
|
|
29
30
|
export const CANOPY_APP_PERMISSIONS = {
|
|
30
31
|
contents: 'write',
|
package/dist/cli/init.js
CHANGED
|
@@ -115,7 +115,8 @@ var init_field = __esm({
|
|
|
115
115
|
});
|
|
116
116
|
objectFieldSchema = fieldBaseSchema.extend({
|
|
117
117
|
type: z.literal("object"),
|
|
118
|
-
fields: z.array(z.lazy(() => fieldHolder[0])).min(1)
|
|
118
|
+
fields: z.array(z.lazy(() => fieldHolder[0])).min(1),
|
|
119
|
+
itemTitleField: z.string().min(1).optional()
|
|
119
120
|
});
|
|
120
121
|
inlineGroupFieldSchema = z.object({
|
|
121
122
|
type: z.literal("group"),
|
|
@@ -191,7 +192,7 @@ function isImplicitlyOffOrigin(url) {
|
|
|
191
192
|
return false;
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
|
-
function isHttpUrlOrSameOriginPath(value
|
|
195
|
+
function isHttpUrlOrSameOriginPath(value) {
|
|
195
196
|
if (value === "")
|
|
196
197
|
return false;
|
|
197
198
|
for (let index = 0; index < value.length; index++) {
|
|
@@ -215,9 +216,8 @@ function isHttpUrlOrSameOriginPath(value, opts = {}) {
|
|
|
215
216
|
return false;
|
|
216
217
|
}
|
|
217
218
|
}
|
|
218
|
-
if (isImplicitlyOffOrigin(value))
|
|
219
|
-
return
|
|
220
|
-
}
|
|
219
|
+
if (isImplicitlyOffOrigin(value))
|
|
220
|
+
return false;
|
|
221
221
|
return value.startsWith("/") && value[1] !== "/";
|
|
222
222
|
}
|
|
223
223
|
var SENTINEL_BASE, DOT_SEGMENT;
|
|
@@ -231,7 +231,7 @@ var init_sanitize_href = __esm({
|
|
|
231
231
|
|
|
232
232
|
// dist/config/schemas/url.js
|
|
233
233
|
import { z as z3 } from "zod";
|
|
234
|
-
var uploadTargetUrlSchema,
|
|
234
|
+
var uploadTargetUrlSchema, previewPrefixSchema;
|
|
235
235
|
var init_url = __esm({
|
|
236
236
|
"dist/config/schemas/url.js"() {
|
|
237
237
|
"use strict";
|
|
@@ -239,8 +239,8 @@ var init_url = __esm({
|
|
|
239
239
|
uploadTargetUrlSchema = z3.string().trim().refine((value) => isHttpUrlOrSameOriginPath(value), {
|
|
240
240
|
message: 'must be an absolute http(s) URL or a site-relative path beginning with a single "/", with no query or fragment'
|
|
241
241
|
});
|
|
242
|
-
|
|
243
|
-
message: 'must be an absolute http(s) URL
|
|
242
|
+
previewPrefixSchema = z3.string().trim().refine((value) => isHttpUrlOrSameOriginPath(value), {
|
|
243
|
+
message: 'editor.previewPrefix must be an absolute http(s) URL or a site-relative path beginning with a single "/", with no query or fragment'
|
|
244
244
|
});
|
|
245
245
|
}
|
|
246
246
|
});
|
|
@@ -256,7 +256,6 @@ var init_media = __esm({
|
|
|
256
256
|
mediaSchema = z4.discriminatedUnion("adapter", [
|
|
257
257
|
z4.object({
|
|
258
258
|
adapter: z4.literal("local"),
|
|
259
|
-
publicBaseUrl: assetMountUrlSchema.optional(),
|
|
260
259
|
/** Root directory for local asset storage. Defaults to the caller's dev-assets dir. */
|
|
261
260
|
directory: relativePathSchema.optional()
|
|
262
261
|
}).strict(),
|
|
@@ -264,7 +263,6 @@ var init_media = __esm({
|
|
|
264
263
|
adapter: z4.literal("s3"),
|
|
265
264
|
bucket: z4.string().min(1),
|
|
266
265
|
region: z4.string().min(1),
|
|
267
|
-
publicBaseUrl: assetMountUrlSchema.optional(),
|
|
268
266
|
/**
|
|
269
267
|
* Where the browser POSTs a presigned direct upload. Absolute http(s) URL or a
|
|
270
268
|
* site-relative path; defaults to the S3 REST endpoint the AWS SDK returns.
|
|
@@ -274,18 +272,17 @@ var init_media = __esm({
|
|
|
274
272
|
* signature is unaffected — a presigned POST's string-to-sign is the base64 policy
|
|
275
273
|
* alone, so the host never enters it (pinned by store-s3.test.ts).
|
|
276
274
|
*
|
|
277
|
-
* NOT a prefix
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
275
|
+
* NOT a prefix: nothing is joined onto this value; it replaces the POST target outright
|
|
276
|
+
* and is passed through byte-for-byte. Do not route it through `joinUrlPrefix` "for
|
|
277
|
+
* consistency" — that would strip the trailing slash and silently stop a CDN path
|
|
278
|
+
* pattern like `/asset-upload/*` from matching.
|
|
281
279
|
*/
|
|
282
280
|
uploadUrl: uploadTargetUrlSchema.optional(),
|
|
283
281
|
/** Max upload size in bytes for presigned direct uploads. Defaults to 50 MiB. */
|
|
284
282
|
maxUploadBytes: z4.number().int().positive().optional()
|
|
285
283
|
}).strict(),
|
|
286
284
|
z4.object({
|
|
287
|
-
adapter: z4.literal("lfs")
|
|
288
|
-
publicBaseUrl: assetMountUrlSchema.optional()
|
|
285
|
+
adapter: z4.literal("lfs")
|
|
289
286
|
}).strict()
|
|
290
287
|
]);
|
|
291
288
|
}
|
|
@@ -299,6 +296,7 @@ var init_config = __esm({
|
|
|
299
296
|
"use strict";
|
|
300
297
|
init_collection();
|
|
301
298
|
init_media();
|
|
299
|
+
init_url();
|
|
302
300
|
defaultBranchAccessSchema = z5.enum(["allow", "deny"]).default("deny");
|
|
303
301
|
defaultPathAccessLevelSchema = z5.enum(["allow", "deny"]);
|
|
304
302
|
defaultPathAccessLevelsSchema = z5.object({
|
|
@@ -329,7 +327,8 @@ var init_config = __esm({
|
|
|
329
327
|
title: z5.string().optional(),
|
|
330
328
|
subtitle: z5.string().optional(),
|
|
331
329
|
theme: z5.unknown().optional(),
|
|
332
|
-
previewBase: z5.record(z5.string()).optional(),
|
|
330
|
+
previewBase: z5.record(z5.union([z5.string(), z5.literal(false)])).optional(),
|
|
331
|
+
previewPrefix: previewPrefixSchema.optional(),
|
|
333
332
|
// UI handler functions (runtime only, don't serialize)
|
|
334
333
|
onAccountClick: z5.function().returns(z5.void()).optional(),
|
|
335
334
|
onLogoutClick: z5.function().returns(z5.void()).optional(),
|
|
@@ -357,6 +356,9 @@ var init_config = __esm({
|
|
|
357
356
|
defaultRemoteUrl: defaultRemoteUrlSchema.optional(),
|
|
358
357
|
gitBotAuthorName: gitBotAuthorNameSchema,
|
|
359
358
|
gitBotAuthorEmail: gitBotAuthorEmailSchema,
|
|
359
|
+
// Unset reads as on for Edited-by and off for Co-authored-by (services.ts submitBranch).
|
|
360
|
+
gitEditedByTrailers: z5.boolean().optional(),
|
|
361
|
+
gitCoAuthoredByTrailers: z5.boolean().optional(),
|
|
360
362
|
githubTokenEnvVar: githubTokenEnvVarSchema.optional(),
|
|
361
363
|
// Required by design (follow-up to SEC-C1): a prod deploy that omits `mode` must fail
|
|
362
364
|
// validation loudly rather than silently running header-trusting dev auth semantics.
|
|
@@ -368,7 +370,6 @@ var init_config = __esm({
|
|
|
368
370
|
// Default false/unset — the standard AWS Lambda+worker topology must leave this unset.
|
|
369
371
|
allowNetworkRemoteInProd: z5.boolean().optional(),
|
|
370
372
|
settingsBranch: z5.string().optional(),
|
|
371
|
-
autoCreateSettingsPR: z5.boolean().optional(),
|
|
372
373
|
// `.optional()`, NOT bare `deploymentNameSchema`: its own `.default('prod')` would make
|
|
373
374
|
// `parse(undefined)` resolve to 'prod' instead of staying `undefined`, collapsing the
|
|
374
375
|
// env > config > modeDefault precedence chain `resolveDeploymentName`
|
|
@@ -384,7 +385,7 @@ var init_config = __esm({
|
|
|
384
385
|
validateEntry: z5.custom().optional(),
|
|
385
386
|
dev: devConfigSchema.optional()
|
|
386
387
|
}).strict();
|
|
387
|
-
DEFAULT_PROD_WORKSPACE = "/mnt/efs
|
|
388
|
+
DEFAULT_PROD_WORKSPACE = "/mnt/efs";
|
|
388
389
|
}
|
|
389
390
|
});
|
|
390
391
|
|
|
@@ -889,6 +890,10 @@ var init_debug = __esm({
|
|
|
889
890
|
throw new Error(errorMsg);
|
|
890
891
|
}
|
|
891
892
|
}
|
|
893
|
+
/**
|
|
894
|
+
* Keyed by label alone, so two overlapping timers with one label overwrite each other;
|
|
895
|
+
* anything that can run concurrently uses {@link timed}.
|
|
896
|
+
*/
|
|
892
897
|
time(label) {
|
|
893
898
|
this.timers.set(label, Date.now());
|
|
894
899
|
}
|
|
@@ -903,12 +908,16 @@ var init_debug = __esm({
|
|
|
903
908
|
this.debug(category, `${label} completed`, { durationMs: duration });
|
|
904
909
|
return duration;
|
|
905
910
|
}
|
|
911
|
+
/**
|
|
912
|
+
* Log `<label> completed {durationMs}` once `fn` settles. The start time is local to the
|
|
913
|
+
* call, so concurrent spans with the same label on one logger never overwrite each other.
|
|
914
|
+
*/
|
|
906
915
|
async timed(category, label, fn) {
|
|
907
|
-
|
|
916
|
+
const start = Date.now();
|
|
908
917
|
try {
|
|
909
918
|
return await fn();
|
|
910
919
|
} finally {
|
|
911
|
-
this.
|
|
920
|
+
this.debug(category, `${label} completed`, { durationMs: Date.now() - start });
|
|
912
921
|
}
|
|
913
922
|
}
|
|
914
923
|
};
|
|
@@ -1525,9 +1534,6 @@ var ProdStrategy = class extends ProdClientSafeStrategy {
|
|
|
1525
1534
|
throw new Error("gitBotAuthorName and gitBotAuthorEmail are required in prod mode");
|
|
1526
1535
|
}
|
|
1527
1536
|
}
|
|
1528
|
-
shouldCreateSettingsPR(config) {
|
|
1529
|
-
return config.autoCreateSettingsPR ?? true;
|
|
1530
|
-
}
|
|
1531
1537
|
};
|
|
1532
1538
|
var DevStrategy = class extends DevClientSafeStrategy {
|
|
1533
1539
|
getWorkspaceRoot(sourceRoot) {
|
|
@@ -1574,9 +1580,6 @@ var DevStrategy = class extends DevClientSafeStrategy {
|
|
|
1574
1580
|
}
|
|
1575
1581
|
validateConfig(_config) {
|
|
1576
1582
|
}
|
|
1577
|
-
shouldCreateSettingsPR(_config) {
|
|
1578
|
-
return false;
|
|
1579
|
-
}
|
|
1580
1583
|
};
|
|
1581
1584
|
var strategyCache = /* @__PURE__ */ new Map();
|
|
1582
1585
|
function operatingStrategy(mode) {
|
package/dist/cli/migrate.js
CHANGED
|
@@ -21,8 +21,9 @@ import { parseSlug } from '../paths/index.js';
|
|
|
21
21
|
import { filePathExists } from '../utils/fs.js';
|
|
22
22
|
import { loadCollectionMetaFiles } from '../schema/index.js';
|
|
23
23
|
import { getErrorMessage } from '../utils/error.js';
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
24
|
+
import { ContentWriteLockBusyError } from '../utils/content-write-lock.js';
|
|
25
|
+
import { OccWriteConflictError } from '../utils/occ-json-write.js';
|
|
26
|
+
import { withBranchSchemaLock } from '../schema/schema-store.js';
|
|
26
27
|
import { BranchMetadataFileManager } from '../branch-metadata.js';
|
|
27
28
|
import { invalidateBranchContentCaches } from '../content-index-generation.js';
|
|
28
29
|
const MIGRATE_FORMATS = ['md', 'mdx', 'json', 'yaml'];
|
|
@@ -245,18 +246,21 @@ export async function migrate(options) {
|
|
|
245
246
|
};
|
|
246
247
|
if (isBranchClone) {
|
|
247
248
|
// projectDir IS the branch root in this case (see the invariant note
|
|
248
|
-
// above)
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
// serializes against it instead of silently interleaving writes.
|
|
252
|
-
const lockPath = path.join(projectDir, '.canopy-meta', 'schema');
|
|
249
|
+
// above). The renames rewrite the working tree the worker rebases, so this
|
|
250
|
+
// takes the same locks SchemaOps does for its own schema mutations: the
|
|
251
|
+
// content-write lock, then the schema surrogate.
|
|
253
252
|
try {
|
|
254
|
-
await
|
|
253
|
+
await withBranchSchemaLock(projectDir, applyOps);
|
|
255
254
|
}
|
|
256
255
|
catch (err) {
|
|
257
256
|
if (err instanceof OccWriteConflictError) {
|
|
258
257
|
throw new MigrateError('Another process is modifying the schema, try again.');
|
|
259
258
|
}
|
|
259
|
+
if (err instanceof ContentWriteLockBusyError) {
|
|
260
|
+
throw new MigrateError(err.outcome === 'unknown'
|
|
261
|
+
? 'The branch was being synced while migrate ran, so it may be partly applied. Check its state before running migrate again.'
|
|
262
|
+
: err.message);
|
|
263
|
+
}
|
|
260
264
|
throw err;
|
|
261
265
|
}
|
|
262
266
|
}
|
package/dist/cli/sync.js
CHANGED
|
@@ -17,8 +17,10 @@ import path from 'node:path';
|
|
|
17
17
|
import { simpleGit } from 'simple-git';
|
|
18
18
|
import * as p from '@clack/prompts';
|
|
19
19
|
import { filePathExists } from '../utils/fs.js';
|
|
20
|
+
import { isCanopyInternalPath, stageAllExceptCanopyState } from '../utils/git.js';
|
|
20
21
|
import { assertWithinDir, copyDir, listFilesRecursive, pushContentToWorkspace, safeReplaceDir, SYNC_BASE_TAG, } from '../sync-core.js';
|
|
21
22
|
import { invalidateBranchContentCaches } from '../content-index-generation.js';
|
|
23
|
+
import { ContentWriteLockBusyError, withContentWriteLock } from '../utils/content-write-lock.js';
|
|
22
24
|
import { ensureGitExcludePattern } from '../git-manager.js';
|
|
23
25
|
import { operatingStrategy } from '../operating-mode/index.js';
|
|
24
26
|
/**
|
|
@@ -32,6 +34,42 @@ class SyncError extends Error {
|
|
|
32
34
|
this.name = 'SyncError';
|
|
33
35
|
}
|
|
34
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* [SYNC-C1] Every sync step that rewrites a branch workspace (content replace, checkout, merge,
|
|
39
|
+
* merge abort) runs under the workspace's content-write lock, which the dev server's saves and
|
|
40
|
+
* the worker's rebase also take. Contention becomes a `SyncError`, so the CLI exits non-zero.
|
|
41
|
+
*/
|
|
42
|
+
function lockBusyAsSyncError(err, branchName) {
|
|
43
|
+
if (!(err instanceof ContentWriteLockBusyError))
|
|
44
|
+
return err;
|
|
45
|
+
return new SyncError(err.outcome === 'not-run'
|
|
46
|
+
? `Branch workspace "${branchName}" is busy (the worker is syncing it, or an editor save is in flight); nothing was changed. Try again in a moment.`
|
|
47
|
+
: `Branch workspace "${branchName}" was being synced during this run, so it may be partly updated. Check its state before running sync again.`);
|
|
48
|
+
}
|
|
49
|
+
async function withWorkspaceLock(branchPath, branchName, fn) {
|
|
50
|
+
try {
|
|
51
|
+
return await withContentWriteLock(branchPath, fn);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
throw lockBusyAsSyncError(err, branchName);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* `git merge --abort` in a workspace left mid-merge, re-checking under the lock that it still is.
|
|
59
|
+
* Returns whether a merge was aborted.
|
|
60
|
+
*/
|
|
61
|
+
async function abortWorkspaceMerge(branchPath, branchName) {
|
|
62
|
+
return withWorkspaceLock(branchPath, branchName, async () => {
|
|
63
|
+
const wsGit = simpleGit({ baseDir: branchPath });
|
|
64
|
+
if ((await wsGit.status()).conflicted.length === 0)
|
|
65
|
+
return false;
|
|
66
|
+
await wsGit.merge(['--abort']);
|
|
67
|
+
// The abort rewrote the clone's working tree — tell ContentStore ID
|
|
68
|
+
// indexes (the dev server is a separate process; on-disk marker).
|
|
69
|
+
await invalidateBranchContentCaches(branchPath);
|
|
70
|
+
return true;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
35
73
|
/** Detect the current git branch name from the working tree. */
|
|
36
74
|
async function detectCurrentBranch(projectDir) {
|
|
37
75
|
const git = simpleGit({ baseDir: projectDir });
|
|
@@ -140,22 +178,21 @@ async function syncPush(options) {
|
|
|
140
178
|
initialValue: false,
|
|
141
179
|
});
|
|
142
180
|
if (!p.isCancel(shouldAbort) && shouldAbort) {
|
|
143
|
-
await
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
await invalidateBranchContentCaches(branchPath);
|
|
147
|
-
p.log.success('Merge aborted. Workspace restored to pre-merge state.');
|
|
181
|
+
if (await abortWorkspaceMerge(branchPath, branchName)) {
|
|
182
|
+
p.log.success('Merge aborted. Workspace restored to pre-merge state.');
|
|
183
|
+
}
|
|
148
184
|
}
|
|
149
185
|
}
|
|
150
186
|
return { fileCount: 0 };
|
|
151
187
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
188
|
+
const editorChanges = status.files.filter((f) => !isCanopyInternalPath(f.path));
|
|
189
|
+
if (editorChanges.length > 0 && !options.force) {
|
|
190
|
+
p.log.warn(`Branch workspace has ${editorChanges.length} uncommitted change(s) that will be committed to history then overwritten:`);
|
|
191
|
+
for (const file of editorChanges.slice(0, 10)) {
|
|
155
192
|
p.log.warn(` ${file.path}`);
|
|
156
193
|
}
|
|
157
|
-
if (
|
|
158
|
-
p.log.warn(` ... and ${
|
|
194
|
+
if (editorChanges.length > 10) {
|
|
195
|
+
p.log.warn(` ... and ${editorChanges.length - 10} more`);
|
|
159
196
|
}
|
|
160
197
|
const confirm = await p.confirm({
|
|
161
198
|
message: 'Continue? Editor changes will be preserved in git history.',
|
|
@@ -166,20 +203,26 @@ async function syncPush(options) {
|
|
|
166
203
|
return { fileCount: 0 };
|
|
167
204
|
}
|
|
168
205
|
}
|
|
169
|
-
// Auto-commit uncommitted workspace changes to preserve in history
|
|
170
|
-
if (status.files.length > 0) {
|
|
171
|
-
await wsGit.add('-A');
|
|
172
|
-
await wsGit.commit('sync: save editor state before push');
|
|
173
|
-
p.log.info('Committed editor changes to history before push');
|
|
174
|
-
}
|
|
175
206
|
p.log.step(`Pushing content to branch workspace: ${branchName}`);
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
207
|
+
// Commit any editor changes (re-read under the lock, so a save landing after
|
|
208
|
+
// the listing above is preserved too), copy working-tree content → workspace
|
|
209
|
+
// content dir, commit, and tag the sync base.
|
|
210
|
+
let fileCount;
|
|
211
|
+
try {
|
|
212
|
+
const result = await pushContentToWorkspace({
|
|
213
|
+
srcContentDir,
|
|
214
|
+
branchPath,
|
|
215
|
+
contentRoot,
|
|
216
|
+
baseTag: SYNC_BASE_TAG,
|
|
217
|
+
saveEditorStateMessage: 'sync: save editor state before push',
|
|
218
|
+
});
|
|
219
|
+
fileCount = result.fileCount;
|
|
220
|
+
if (result.savedEditorState)
|
|
221
|
+
p.log.info('Committed editor changes to history before push');
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
throw lockBusyAsSyncError(err, branchName);
|
|
225
|
+
}
|
|
183
226
|
if (fileCount === 0) {
|
|
184
227
|
p.log.info('Content is already up to date — nothing to push');
|
|
185
228
|
}
|
|
@@ -321,16 +364,23 @@ async function syncBoth(options) {
|
|
|
321
364
|
initialValue: false,
|
|
322
365
|
});
|
|
323
366
|
if (!p.isCancel(shouldAbort) && shouldAbort) {
|
|
324
|
-
await
|
|
325
|
-
|
|
326
|
-
|
|
367
|
+
if (await abortWorkspaceMerge(branchPath, branchName)) {
|
|
368
|
+
p.log.success('Merge aborted. Workspace restored to pre-merge state.');
|
|
369
|
+
}
|
|
327
370
|
}
|
|
328
371
|
}
|
|
329
372
|
return { pushed: 0, pulled: 0 };
|
|
330
373
|
}
|
|
374
|
+
return withWorkspaceLock(branchPath, branchName, () => mergeIntoWorkspace(options, { branchName, branchPath, srcContentDir, contentRoot }));
|
|
375
|
+
}
|
|
376
|
+
/** The locked body of {@link syncBoth}: everything that rewrites the workspace. */
|
|
377
|
+
async function mergeIntoWorkspace(options, ws) {
|
|
378
|
+
const { branchName, branchPath, srcContentDir, contentRoot } = ws;
|
|
379
|
+
const wsGit = simpleGit({ baseDir: branchPath });
|
|
380
|
+
const status = await wsGit.status();
|
|
331
381
|
// Auto-commit uncommitted workspace changes (preserves editor work for the merge)
|
|
332
|
-
if (status.files.
|
|
333
|
-
await wsGit
|
|
382
|
+
if (status.files.some((f) => !isCanopyInternalPath(f.path))) {
|
|
383
|
+
await stageAllExceptCanopyState(wsGit);
|
|
334
384
|
await wsGit.commit('sync: save editor state before merge');
|
|
335
385
|
p.log.info('Committed editor changes before merge');
|
|
336
386
|
}
|
|
@@ -365,9 +415,9 @@ async function syncBoth(options) {
|
|
|
365
415
|
await wsGit.raw(['branch', '-D', incomingBranch]).catch(() => { });
|
|
366
416
|
throw err;
|
|
367
417
|
}
|
|
368
|
-
await wsGit
|
|
369
|
-
const
|
|
370
|
-
if (
|
|
418
|
+
await stageAllExceptCanopyState(wsGit);
|
|
419
|
+
const incomingFiles = (await wsGit.status()).files.filter((f) => !isCanopyInternalPath(f.path));
|
|
420
|
+
if (incomingFiles.length === 0) {
|
|
371
421
|
await wsGit.checkout(currentBranch);
|
|
372
422
|
await wsGit.raw(['branch', '-D', incomingBranch]);
|
|
373
423
|
p.log.info('No working-tree changes to merge — pulling editor changes only');
|
|
@@ -410,7 +460,7 @@ async function syncBoth(options) {
|
|
|
410
460
|
await wsGit.tag(['-f', SYNC_BASE_TAG]);
|
|
411
461
|
p.log.success('Merged working-tree changes with editor changes');
|
|
412
462
|
const pullResult = await syncPull({ ...options, branch: branchName, force: true });
|
|
413
|
-
return { pushed:
|
|
463
|
+
return { pushed: incomingFiles.length, pulled: pullResult.fileCount };
|
|
414
464
|
}
|
|
415
465
|
finally {
|
|
416
466
|
await invalidateBranchContentCaches(branchPath);
|
|
@@ -428,14 +478,10 @@ async function syncAbort(options) {
|
|
|
428
478
|
return;
|
|
429
479
|
const branchPath = path.join(branchesDir, branchName);
|
|
430
480
|
assertWithinDir(branchPath, branchesDir, '--branch');
|
|
431
|
-
|
|
432
|
-
const status = await wsGit.status();
|
|
433
|
-
if (status.conflicted.length === 0) {
|
|
481
|
+
if (!(await abortWorkspaceMerge(branchPath, branchName))) {
|
|
434
482
|
p.log.info(`Branch workspace "${branchName}" is not in a merge state — nothing to abort.`);
|
|
435
483
|
return;
|
|
436
484
|
}
|
|
437
|
-
await wsGit.merge(['--abort']);
|
|
438
|
-
await invalidateBranchContentCaches(branchPath);
|
|
439
485
|
p.log.success(`Merge aborted in branch workspace "${branchName}". Workspace restored to pre-merge state.`);
|
|
440
486
|
}
|
|
441
487
|
/**
|
|
@@ -73,5 +73,13 @@ COPY --from=builder /app/public ./public
|
|
|
73
73
|
# Lambda's filesystem is read-only outside /tmp. Next may write to .next/cache
|
|
74
74
|
# at runtime; symlink it to /tmp so those writes succeed instead of failing (EROFS).
|
|
75
75
|
RUN rm -rf .next/cache && ln -s /tmp .next/cache
|
|
76
|
+
# The CMS reports this in System health. A build arg, not a Lambda environment
|
|
77
|
+
# variable: a Lambda variable names the infrastructure's commit and would hide
|
|
78
|
+
# exactly the image/infrastructure skew this exists to reveal. Declared after
|
|
79
|
+
# every build layer, so with a warm layer cache a new revision re-runs only the
|
|
80
|
+
# metadata steps from here down.
|
|
81
|
+
ARG CANOPY_SOURCE_SHA=
|
|
82
|
+
ENV CANOPY_SOURCE_SHA=$CANOPY_SOURCE_SHA
|
|
83
|
+
LABEL org.opencontainers.image.revision=$CANOPY_SOURCE_SHA
|
|
76
84
|
ENV PORT=8080 AWS_LWA_PORT=8080 HOSTNAME=0.0.0.0 NODE_ENV=production
|
|
77
85
|
CMD ["node", "server.js"]
|
|
@@ -126,4 +126,8 @@ new CmsStack(app, '{{STACK_NAME}}', {
|
|
|
126
126
|
// point your own existing distribution at it.
|
|
127
127
|
domainName: process.env.CMS_DOMAIN_NAME || undefined,
|
|
128
128
|
hostedZoneDomain: process.env.CMS_HOSTED_ZONE_DOMAIN || undefined,
|
|
129
|
+
|
|
130
|
+
// Optional, and NOT `required()`: the commit the CMS image is built from,
|
|
131
|
+
// shown in System health. Unset, System health reports it as "not set".
|
|
132
|
+
sourceRevision: process.env.CANOPY_SOURCE_SHA || undefined,
|
|
129
133
|
})
|
|
@@ -77,6 +77,8 @@ export interface CmsStackProps extends StackProps {
|
|
|
77
77
|
domainName?: string
|
|
78
78
|
/** Optional Route53 hosted zone domain, e.g. 'example.org'. */
|
|
79
79
|
hostedZoneDomain?: string
|
|
80
|
+
/** Optional. Commit the CMS image is built from; shown in System health. */
|
|
81
|
+
sourceRevision?: string
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
export class CmsStack extends Stack {
|
|
@@ -128,6 +130,10 @@ export class CmsStack extends Stack {
|
|
|
128
130
|
// auth. The image's own `next build` stays in dev mode either way --
|
|
129
131
|
// see Dockerfile.cms.
|
|
130
132
|
NEXT_PUBLIC_CANOPY_MODE: 'prod',
|
|
133
|
+
// CDK hashes build args into the asset, so every new commit rebuilds
|
|
134
|
+
// the image, even one changing only the dockerignored infrastructure/
|
|
135
|
+
// -- that is what keeps the revision the CMS reports honest.
|
|
136
|
+
...(props.sourceRevision ? { CANOPY_SOURCE_SHA: props.sourceRevision } : {}),
|
|
131
137
|
},
|
|
132
138
|
}),
|
|
133
139
|
// The one place the CMS image's CPU architecture is decided. CDK derives
|
|
@@ -186,22 +192,21 @@ export class CmsStack extends Stack {
|
|
|
186
192
|
},
|
|
187
193
|
|
|
188
194
|
memorySize: 2048,
|
|
189
|
-
|
|
195
|
+
// A ceiling, free while idle. The editor's static chunks count against it
|
|
196
|
+
// until CloudFront caches them, and a cold editor load requests them
|
|
197
|
+
// together, so synth warns below 20. See the prop's doc comment.
|
|
198
|
+
reservedConcurrency: 50,
|
|
190
199
|
})
|
|
191
200
|
|
|
192
|
-
// Media support (uploads
|
|
201
|
+
// Media support (uploads and image derivatives). To enable it:
|
|
193
202
|
//
|
|
194
203
|
// 1. add `AssetSupport` to the `canopycms-cdk` import at the top;
|
|
195
204
|
// 2. uncomment the block below, moving it ABOVE `cmsService` (it has to
|
|
196
205
|
// exist before you can pass its bucket);
|
|
197
206
|
// 3. pass `assetBucket: assetSupport.bucket` to CanopyCmsService;
|
|
198
207
|
// 4. pass `assetSupport` to CanopyCmsDistribution below - it attaches
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
// patterns in order, so the general pattern would otherwise
|
|
202
|
-
// swallow the transform one). `cdk synth` fails loudly if a
|
|
203
|
-
// hand-written `additionalBehaviors` ever gets that order wrong
|
|
204
|
-
// instead.
|
|
208
|
+
// `/assets/t/*` before `/assets/*`, the order CloudFront needs, and
|
|
209
|
+
// `cdk synth` fails if a hand-written `additionalBehaviors` does not.
|
|
205
210
|
//
|
|
206
211
|
// `editorOrigins` is the S3 CORS allowlist for the editor's presigned
|
|
207
212
|
// uploads, so it must list the origin the editor is served from. Include
|
|
@@ -211,11 +216,17 @@ export class CmsStack extends Stack {
|
|
|
211
216
|
// CloudFront edge instead); with neither, a construct-created bucket
|
|
212
217
|
// refuses to synth.
|
|
213
218
|
//
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
219
|
+
// `/assets/*` and `/assets/t/*` serve only what is in the bucket and
|
|
220
|
+
// compute nothing: an image derivative no one wrote is a 403. Write every
|
|
221
|
+
// derivative a site build references before releasing that build, with
|
|
222
|
+
// `canopycms collect-asset-refs <outDir>` after the build and then
|
|
223
|
+
// `canopycms materialize-assets --refs <outDir>/canopy-asset-refs.json`.
|
|
224
|
+
// To compute missing derivatives on request instead, pass
|
|
225
|
+
// `lazyPublicTransforms: true`; that deploys a transform Lambda, so inside
|
|
226
|
+
// this monorepo run `pnpm --filter canopycms-cdk run build:lambda` first
|
|
227
|
+
// (the published package ships it built).
|
|
217
228
|
//
|
|
218
|
-
// See the
|
|
229
|
+
// See "Media: the public image path" in docs/deploying-to-aws.md.
|
|
219
230
|
//
|
|
220
231
|
// const assetSupport = new AssetSupport(this, 'Assets', {
|
|
221
232
|
// editorOrigins: [`https://${props.domainName}`],
|
|
@@ -241,4 +241,6 @@ jobs:
|
|
|
241
241
|
CANOPYCMS_DEPLOYMENT_NAME: ${{ vars.CANOPYCMS_DEPLOYMENT_NAME }}
|
|
242
242
|
CMS_DOMAIN_NAME: ${{ vars.CMS_DOMAIN_NAME }}
|
|
243
243
|
CMS_HOSTED_ZONE_DOMAIN: ${{ vars.CMS_HOSTED_ZONE_DOMAIN }}
|
|
244
|
+
# The commit the CMS image is built from, reported in System health.
|
|
245
|
+
CANOPY_SOURCE_SHA: ${{ github.sha }}
|
|
244
246
|
run: npx cdk deploy {{STACK_NAME}} --require-approval never
|
package/dist/client.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type { CustomFieldRenderers, CustomFieldRenderProps } from './editor/Form
|
|
|
3
3
|
export * from './editor/EditorPanes.js';
|
|
4
4
|
export * from './editor/EntryNavigator.js';
|
|
5
5
|
export * from './editor/Editor.js';
|
|
6
|
-
export
|
|
6
|
+
export { PreviewFrame } from './editor/PreviewFrame.js';
|
|
7
7
|
export * from './editor/canopy-path.js';
|
|
8
8
|
export * from './editor/theme.js';
|
|
9
9
|
export * from './editor/editor-config.js';
|
package/dist/client.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export * from './editor/EditorPanes.js';
|
|
3
3
|
export * from './editor/EntryNavigator.js';
|
|
4
4
|
export * from './editor/Editor.js';
|
|
5
|
-
export
|
|
5
|
+
export { PreviewFrame } from './editor/PreviewFrame.js';
|
|
6
6
|
export * from './editor/canopy-path.js';
|
|
7
7
|
export * from './editor/theme.js';
|
|
8
8
|
export * from './editor/editor-config.js';
|
package/dist/config/helpers.js
CHANGED
|
@@ -33,7 +33,7 @@ export function defineCanopyConfig(config) {
|
|
|
33
33
|
server: validated,
|
|
34
34
|
// Client config helper - extracts safe subset and merges overrides
|
|
35
35
|
client: (clientOverrides) => {
|
|
36
|
-
const { defaultBaseBranch, defaultActiveBranch, contentRoot, editor, mode, entryLinkUrl,
|
|
36
|
+
const { defaultBaseBranch, defaultActiveBranch, contentRoot, editor, mode, entryLinkUrl, basePath, } = validated;
|
|
37
37
|
// flatSchema is loaded dynamically by the editor via API (from .collection.json files)
|
|
38
38
|
const clientConfig = {
|
|
39
39
|
defaultBaseBranch,
|
|
@@ -42,7 +42,6 @@ export function defineCanopyConfig(config) {
|
|
|
42
42
|
editor,
|
|
43
43
|
mode,
|
|
44
44
|
entryLinkUrl,
|
|
45
|
-
assetBaseUrl: media?.publicBaseUrl,
|
|
46
45
|
basePath,
|
|
47
46
|
flatSchema: [],
|
|
48
47
|
};
|