canopycms 0.1.0-int.115 → 0.1.0
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/CHANGELOG.md +267 -231
- package/README.md +0 -1
- package/dist/ai/references.js +3 -1
- package/dist/api/assets.js +2 -2
- package/dist/api/branch-merge.d.ts +1 -1
- package/dist/api/branch.js +1 -1
- package/dist/api/content.js +1 -1
- package/dist/api/entries-constants.d.ts +1 -1
- package/dist/api/entries-constants.js +1 -1
- package/dist/api/entries.d.ts +2 -2
- package/dist/api/permissions.d.ts +2 -2
- package/dist/api/types.d.ts +3 -2
- package/dist/cli/cli.js +16 -14
- package/dist/cli/generate-ai-content.js +7 -5
- package/dist/cli/init.js +4 -4
- package/dist/client.d.ts +0 -1
- package/dist/client.js +0 -1
- package/dist/config/schemas/config.d.ts +0 -5
- package/dist/config/schemas/config.js +0 -1
- package/dist/config/types.d.ts +0 -1
- package/dist/content-index-generation.d.ts +1 -1
- package/dist/content-index-generation.js +1 -1
- package/dist/content-listing.js +1 -1
- package/dist/content-reader.js +1 -1
- package/dist/content-store.d.ts +1 -1
- package/dist/content-store.js +1 -1
- package/dist/dev-content-watcher.d.ts +1 -1
- package/dist/dev-content-watcher.js +1 -1
- package/dist/editor/BranchManager.d.ts +2 -0
- package/dist/editor/BranchManager.js +5 -4
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +1 -2
- package/dist/editor/CommentsPanel.js +3 -6
- package/dist/editor/Editor.d.ts +0 -2
- package/dist/editor/Editor.js +329 -181
- package/dist/editor/EditorAuthGate.js +8 -3
- package/dist/editor/EntryNavigator.d.ts +10 -0
- package/dist/editor/EntryNavigator.js +51 -2
- package/dist/editor/FormHeader.js +1 -1
- package/dist/editor/PreviewFrame.d.ts +5 -1
- package/dist/editor/PreviewFrame.js +3 -2
- package/dist/editor/PreviewPane.d.ts +47 -0
- package/dist/editor/PreviewPane.js +147 -0
- package/dist/editor/PreviewToolbarTools.d.ts +22 -0
- package/dist/editor/PreviewToolbarTools.js +73 -0
- package/dist/editor/comments/form-comments.js +2 -1
- package/dist/editor/components/BranchLockBanner.d.ts +22 -0
- package/dist/editor/components/BranchLockBanner.js +39 -0
- package/dist/editor/components/BranchPill.d.ts +32 -0
- package/dist/editor/components/BranchPill.js +33 -0
- package/dist/editor/components/ConfirmDeleteModal.d.ts +3 -1
- package/dist/editor/components/ConfirmDeleteModal.js +3 -2
- package/dist/editor/components/EditorHeader.d.ts +50 -108
- package/dist/editor/components/EditorHeader.js +117 -138
- package/dist/editor/components/EditorRail.d.ts +49 -0
- package/dist/editor/components/EditorRail.js +65 -0
- package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
- package/dist/editor/components/EntryBreadcrumb.js +56 -0
- package/dist/editor/components/QuickOpenPalette.d.ts +1 -1
- package/dist/editor/components/QuickOpenPalette.js +3 -2
- package/dist/editor/components/RenameEntryModal.d.ts +3 -1
- package/dist/editor/components/RenameEntryModal.js +3 -2
- package/dist/editor/components/SaveAllResult.d.ts +25 -0
- package/dist/editor/components/SaveAllResult.js +86 -0
- package/dist/editor/components/SaveSplitButton.d.ts +30 -0
- package/dist/editor/components/SaveSplitButton.js +108 -0
- package/dist/editor/components/index.d.ts +2 -2
- package/dist/editor/components/index.js +2 -2
- package/dist/editor/context/EditorStateContext.d.ts +4 -4
- package/dist/editor/context/EditorStateContext.js +4 -4
- package/dist/editor/copy.d.ts +3 -0
- package/dist/editor/copy.js +3 -0
- package/dist/editor/editor-utils.d.ts +11 -6
- package/dist/editor/editor-utils.js +8 -17
- package/dist/editor/fields/MarkdownField.js +3 -0
- package/dist/editor/hooks/save-all.d.ts +68 -0
- package/dist/editor/hooks/save-all.js +61 -0
- package/dist/editor/hooks/useCommentSystem.d.ts +2 -0
- package/dist/editor/hooks/useCommentSystem.js +3 -0
- package/dist/editor/hooks/useDraftManager.d.ts +24 -1
- package/dist/editor/hooks/useDraftManager.js +297 -16
- package/dist/editor/hooks/useEditorLayout.d.ts +15 -11
- package/dist/editor/hooks/useEditorLayout.js +13 -25
- package/dist/editor/hooks/useEntryManager.d.ts +4 -0
- package/dist/editor/hooks/useEntryManager.js +30 -7
- package/dist/editor/media/MediaLibrary.d.ts +1 -1
- package/dist/editor/preview-path.d.ts +12 -0
- package/dist/editor/preview-path.js +45 -1
- package/dist/editor/preview-scale.d.ts +27 -0
- package/dist/editor/preview-scale.js +34 -0
- package/dist/editor/shell/ActivityRail.d.ts +37 -0
- package/dist/editor/shell/ActivityRail.js +91 -0
- package/dist/editor/shell/EditorShell.d.ts +17 -0
- package/dist/editor/shell/EditorShell.js +31 -0
- package/dist/editor/shell/PaneLayout.d.ts +28 -0
- package/dist/editor/shell/PaneLayout.js +116 -0
- package/dist/editor/shell/SidePanelHost.d.ts +35 -0
- package/dist/editor/shell/SidePanelHost.js +184 -0
- package/dist/editor/shell/TopBar.d.ts +12 -0
- package/dist/editor/shell/TopBar.js +14 -0
- package/dist/editor/shell/host-chrome.d.ts +16 -0
- package/dist/editor/shell/host-chrome.js +69 -0
- package/dist/editor/theme.js +18 -3
- package/dist/git-manager.d.ts +1 -1
- package/dist/git-manager.js +2 -2
- package/dist/operating-mode/types.d.ts +1 -1
- package/dist/resolve-canopy-user.d.ts +1 -1
- package/dist/resolve-canopy-user.js +1 -1
- package/dist/schema/resolver.d.ts +1 -1
- package/dist/schema/resolver.js +1 -1
- package/dist/schema/schema-store.d.ts +1 -1
- package/dist/schema/schema-store.js +2 -2
- package/dist/url-collision.js +3 -3
- package/dist/url-exclusivity-fixtures.d.ts +1 -1
- package/dist/url-exclusivity-fixtures.js +1 -1
- package/dist/utils/content-write-lock.d.ts +1 -1
- package/dist/utils/content-write-lock.js +1 -1
- package/dist/utils/debug.d.ts +1 -1
- package/dist/utils/debug.js +5 -3
- package/dist/utils/git.d.ts +4 -0
- package/dist/utils/git.js +27 -5
- package/dist/validation/block-structural-keys.d.ts +1 -1
- package/dist/validation/block-structural-keys.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/cms-worker.d.ts +1 -1
- package/dist/worker/cms-worker.js +2 -2
- package/dist/worker/github-auth.d.ts +1 -1
- package/dist/worker/github-auth.js +1 -1
- package/dist/worker/github-gateway-wire.d.ts +2 -1
- package/dist/worker/github-gateway-wire.js +7 -3
- package/dist/worker/github-gateway.js +1 -1
- package/dist/worker/github-mirror.d.ts +2 -2
- package/dist/worker/github-mirror.js +2 -2
- package/dist/worker/history-rewrite.d.ts +1 -1
- package/dist/worker/history-rewrite.js +1 -1
- package/dist/worker/self-checks.d.ts +1 -1
- package/dist/worker/shared-repo-git.js +1 -1
- package/package.json +5 -4
- package/dist/editor/EditorPanes.d.ts +0 -20
- package/dist/editor/EditorPanes.js +0 -124
- package/dist/editor/components/EditorFooter.d.ts +0 -11
- package/dist/editor/components/EditorFooter.js +0 -9
- package/dist/editor/components/EditorSidebar.d.ts +0 -70
- package/dist/editor/components/EditorSidebar.js +0 -50
package/CHANGELOG.md
CHANGED
|
@@ -5,38 +5,11 @@ packages release together, at one version.
|
|
|
5
5
|
|
|
6
6
|
## This build
|
|
7
7
|
|
|
8
|
-
Version `0.1.0
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- [toPlainText takes an entry body and keeps prose after a leading --- — behaviour change](#toplaintext-takes-an-entry-body-and-keeps-prose-after-a-leading------behaviour-change)
|
|
14
|
-
- [People without a name show "Name unavailable"](#people-without-a-name-show-name-unavailable)
|
|
15
|
-
- [Branch access lists stay with admins and reviewers — behaviour change](#branch-access-lists-stay-with-admins-and-reviewers--behaviour-change)
|
|
16
|
-
- [A branch lockdown outranks the branch's access list — security fix](#a-branch-lockdown-outranks-the-branchs-access-list--security-fix)
|
|
17
|
-
- [The base-branch conflict notice stays until the branch merges — behaviour change](#the-base-branch-conflict-notice-stays-until-the-branch-merges--behaviour-change)
|
|
18
|
-
- [The editor calls the content drawer "All content"](#the-editor-calls-the-content-drawer-all-content)
|
|
19
|
-
- [The Branches drawer shows one action per branch, and comments reply in place](#the-branches-drawer-shows-one-action-per-branch-and-comments-reply-in-place)
|
|
20
|
-
- [An object's Clear offers Undo, and refusals say why](#an-objects-clear-offers-undo-and-refusals-say-why)
|
|
21
|
-
- [The collection dialog says what saves at once](#the-collection-dialog-says-what-saves-at-once)
|
|
22
|
-
- [Comments and branches name their people for every editor — behaviour change on two APIs](#comments-and-branches-name-their-people-for-every-editor--behaviour-change-on-two-apis)
|
|
23
|
-
- [A date picker, a form header, and a toolbar that wraps](#a-date-picker-a-form-header-and-a-toolbar-that-wraps)
|
|
24
|
-
- [Editor colours reach 4.5:1 in light and dark mode](#editor-colours-reach-451-in-light-and-dark-mode)
|
|
25
|
-
- [Editor contrast, and blocked buttons stay focusable](#editor-contrast-and-blocked-buttons-stay-focusable)
|
|
26
|
-
- [Editor focus rings and checked controls reach 3:1 for any brand](#editor-focus-rings-and-checked-controls-reach-31-for-any-brand)
|
|
27
|
-
- [Editor requests time out instead of hanging](#editor-requests-time-out-instead-of-hanging)
|
|
28
|
-
- [Field editing: descriptions, list-card titles, and public/ images, continued](#field-editing-descriptions-list-card-titles-and-public-images-continued)
|
|
29
|
-
- [List items and blocks collapse, and reorder from one menu](#list-items-and-blocks-collapse-and-reorder-from-one-menu)
|
|
30
|
-
- ["Add entry" follows path permissions; admin panels and labels tidied](#add-entry-follows-path-permissions-admin-panels-and-labels-tidied)
|
|
31
|
-
- [Quick open, a navigator filter, title-first new entries, and media search](#quick-open-a-navigator-filter-title-first-new-entries-and-media-search)
|
|
32
|
-
- [A save never brings back a deleted or moved entry — behaviour change](#a-save-never-brings-back-a-deleted-or-moved-entry--behaviour-change)
|
|
33
|
-
- [Submit names unsaved entries; unanswered writes recover more](#submit-names-unsaved-entries-unanswered-writes-recover-more)
|
|
34
|
-
- [Unlabelled fields and block templates show their names as words](#unlabelled-fields-and-block-templates-show-their-names-as-words)
|
|
35
|
-
- [Stable releases follow the changes they carry, and ship their changelog](#stable-releases-follow-the-changes-they-carry-and-ship-their-changelog)
|
|
36
|
-
- [List items and blocks carry a \_key, and field comments follow it — behaviour change](#list-items-and-blocks-carry-a-_key-and-field-comments-follow-it--behaviour-change)
|
|
37
|
-
- [stampOnPublish dates a new entry at its first submit](#stamponpublish-dates-a-new-entry-at-its-first-submit)
|
|
38
|
-
|
|
39
|
-
If you upgraded from a build on another branch, compare the `<!-- changeset: … -->` slugs in your previous build's `CHANGELOG.md` (`npm pack canopycms@<old>` fetches it) with this one's: entries whose slug your old file lacks are new to you. Legacy entries above the changeset entries carry hand-written int labels.
|
|
8
|
+
Version `0.1.0`, built from [`39a755c`](https://github.com/safeinsights/canopycms/tree/39a755c116a52b6d16e0b09e9dde03c67a081754).
|
|
9
|
+
|
|
10
|
+
Its entries are [0.1.0](#010), under **Released**.
|
|
11
|
+
|
|
12
|
+
If you upgraded from a build on another branch, compare the `<!-- changeset: … -->` slugs in your previous build's `CHANGELOG.md` (`npm pack canopycms@<old>` fetches it) with this one's: entries whose slug your old file lacks are new to you.
|
|
40
13
|
|
|
41
14
|
## How to use this document
|
|
42
15
|
|
|
@@ -51,7 +24,7 @@ Each entry has up to three parts:
|
|
|
51
24
|
`node_modules/canopycms/CHANGELOG.md`, assembled for that build: its **This build** section lists
|
|
52
25
|
what is new since the previous int on the same branch, or on a stable release links its entries, and its links point at the commit the build
|
|
53
26
|
came from. The copy in the repository holds released history and the entries from before changesets;
|
|
54
|
-
every entry written since is a file in [`.changeset/`](https://github.com/safeinsights/canopycms/blob/
|
|
27
|
+
every entry written since is a file in [`.changeset/`](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/.changeset/README.md) until a stable release
|
|
55
28
|
moves it here.
|
|
56
29
|
|
|
57
30
|
**Find your starting point.** From a stable pin, start at the first version under **Released**
|
|
@@ -80,89 +53,16 @@ Nothing in this section is edited by hand: each entry is a `.changeset/` file, w
|
|
|
80
53
|
assembles here and labels with the first int that carries it, and a stable release moves the
|
|
81
54
|
entries under **Released**.
|
|
82
55
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
| 93 | Editing | [Field descriptions, list-card titles, `public/` images](#field-editing-descriptions-list-card-titles-and-public-images) (96, 103) | None |
|
|
94
|
-
| 93 | Branches | [Commits name editors; submit refuses an empty branch](#commits-name-their-editors-and-submit-refuses-a-branch-with-nothing-to-submit) (108, 110) | Scripts |
|
|
95
|
-
| 94 | Branches | [Reads never create a branch](#reads-never-create-a-requested-branch--security-fix-breaking-for-some-direct-createcontentreader-callers) | Direct callers |
|
|
96
|
-
| 94 | Preview | [Preview URLs: one prefix, `trailingSlash`, own page](#preview-urls-take-one-prefix-follow-trailingslash-and-load-each-entrys-own-page--breaking-env) (98) | Required |
|
|
97
|
-
| 94 | Preview | [`createPreviewPage`, `/preview` entries](#the-preview-route-and-preview-entries--breaking-imports) (95, 101, 103) | Required |
|
|
98
|
-
| 94 | Refs | [Restricted and missing references](#a-reference-resolves-to-its-target-a-restricted-stub-or-a-missing-stub--security-fix-breaking-types-and-build) (106) | Required |
|
|
99
|
-
| 94 | CDK | [`attachTo`, editor response headers](#canopycms-cdk-canopycmsserviceattachto-and-editor-response-headers--behaviour-change-if-you-frame-the-cms) | If hand-wired or framed |
|
|
100
|
-
| 94 | Ops | [System health shows the build](#system-health-shows-which-build-is-running) | Optional |
|
|
101
|
-
| 100 | Branches | [Crash-safe branch creation](#fast-crash-safe-branch-creation--behaviour-change-branch-clones-hold-only-the-content-root) | Upgrade together |
|
|
102
|
-
| 100 | Ops | [Prod workspace defaults to `/mnt/efs`](#the-prod-workspace-defaults-to-mntefs--behaviour-change-if-you-run-prod-without-canopycms_workspace_root) | Non-CDK prod |
|
|
103
|
-
| 100 | Assets | [`AssetSupport` serves from S3 only](#canopycms-cdk-assetsupport-serves-images-from-s3-only--breaking) | Required |
|
|
104
|
-
| 100 | Assets | [`collect-asset-refs`, `materialize-assets`](#collect-asset-refs-and-materialize-assets-store-a-builds-images-before-release) (104) | With S3-only |
|
|
105
|
-
| 100 | Assets | [Editor images via signed-in route](#the-editor-and-its-live-preview-load-images-through-the-signed-in-asset-route) | CSP, origin |
|
|
106
|
-
| 100 | Assets | [`assetUrl` applies crop](#asseturl-applies-an-image-values-crop--behaviour-change-for-cropped-images) | Scale `<img>` |
|
|
107
|
-
| 100 | Assets | [`media.publicBaseUrl` removed; wider limits](#mediapublicbaseurl-is-removed-and-image-limits-are-wider--breaking-config) | Delete key |
|
|
108
|
-
| 101 | Editing | [Saves rewrite only what changed](#a-save-rewrites-only-what-changed) (103) | None |
|
|
109
|
-
| 102 | Auth | [`unauthenticatedStatus: 419`](#unauthenticatedstatus-answer-signed-out-api-calls-with-419) | Basic-auth sites |
|
|
110
|
-
| 105 | Editing | [MDXEditor 4.3](#the-markdown-editor-runs-mdxeditor-43) | Direct deps |
|
|
111
|
-
| 106 | Refs | [AI content links references](#ai-content-links-a-reference-to-its-target--behaviour-change-for-ai-output-and-ai-config-callbacks) | AI config |
|
|
112
|
-
| 106 | Refs | [Deleting a referenced entry asks](#deleting-a-referenced-entry-asks-first--behaviour-change-on-the-delete-api) | Scripts |
|
|
113
|
-
| 107 | Schema | [Unknown schemas cost one entry type](#a-schema-the-running-code-lacks-costs-one-entry-type-and-holds-the-worker--behaviour-change) | Rare |
|
|
114
|
-
| 108 | MDX | [MDX that runs code is refused](#mdx-content-that-runs-code-is-refused-at-save--breaking-behaviour) (109, 110) | Required |
|
|
115
|
-
| 108 | Worker | [On-demand worker, drain; `spotMaxPrice` removed](#canopycms-cdk-the-worker-drains-before-replacement-and-runs-on-demand--breaking-props-spotmaxprice-is-removed-behaviour-and-cost-change) | If set |
|
|
116
|
-
| 109 | Worker | [Hardened worker instance](#canopycms-cdk-the-worker-instance-is-hardened--an-existing-stack-upgrades-in-two-deploys-behaviour-and-cost-change) | Two deploys |
|
|
117
|
-
| 109 | Worker | [Failed or stopped worker says why](#a-failed-or-stopped-worker-says-why--behaviour-change-on-the-not-ready-503-new-worker-apis) | Custom entrypoint |
|
|
118
|
-
| 109 | Worker | [CI worker roll; worker-down alarm](#canopycms-cdk-ci-can-roll-the-worker-with-a-parameter-and-alarm-when-it-stops-syncing--new-opt-in) | Optional |
|
|
119
|
-
| 109 | Preview | [Typed `fieldProps`](#preview-fieldprops-is-typed-with-server-safe-helpers--breaking-types-and-schemas) | Required |
|
|
120
|
-
| 110 | Worker | [Worker needs a state directory](#canopycms-cdk-the-worker-needs-a-state-directory--deploy-the-template-before-the-bundle) | Template first |
|
|
121
|
-
| 110 | Ops | [Prod detects an unset `defaultBaseBranch`](#prod-detects-an-unset-defaultbasebranch-instead-of-assuming-main--behaviour-change-startup-can-fail) | Base ≠ repo default |
|
|
122
|
-
| 111 | CDK | [Example workflow's triggers and checks](#the-aws-example-workflow-gains-the-templates-triggers-and-dependency-checks) | If copied by hand |
|
|
123
|
-
| 111 | Ops | [Duplicate-ID scan only on request](#get-adminbranch-health-scans-for-duplicate-content-ids-only-on-request--behaviour-change) | Admin-API scripts |
|
|
124
|
-
| 111 | Auth | [CMS image builds a prod editor; mismatch blocks](#the-cms-image-builds-a-prod-editor-and-a-mode-mismatch-blocks-the-editor--behaviour-change-a-hand-built-image-can-fail-its-build) | Hand-built images |
|
|
125
|
-
| 111 | Auth | [Auth plugins look users up in batches](#auth-plugins-look-users-up-in-batches) | Custom plugins |
|
|
126
|
-
| 112 | Worker | [Bundle states the template it needs](#canopycms-cdk-a-worker-bundle-states-the-template-it-needs--template-first-for-the-gate-only) | Template first |
|
|
127
|
-
| 112 | Worker | [Poisoned `remote.git` re-clones](#a-poisoned-remotegit-re-clones-itself) | None |
|
|
128
|
-
| 112 | Worker | [Nano worker boots reliably](#canopycms-cdk-a-t4gnano-worker-boots-reliably--behaviour-change-a-deploy-replaces-the-worker) | Deploy |
|
|
129
|
-
| 112 | Worker | [Worker never pushes base or default branch](#the-worker-never-pushes-the-base-or-default-branch--security-fix) (114) | Protect base on GitHub |
|
|
130
|
-
| 112 | Worker | [Worker log is root-owned](#canopycms-cdk-the-workers-log-is-root-owned--security-fix) | Deploy; hand-installed units |
|
|
131
|
-
| 113 | Worker | [Push logs say whether GitHub moved](#the-workers-push-logs-say-whether-github-moved) | None |
|
|
132
|
-
| 113 | Editing | [Unsaved ACL changes show; closing asks](#unsaved-group-and-permission-changes-show-and-closing-asks-first) | None |
|
|
133
|
-
| 113 | Worker | [Credential in a per-command git config](#the-worker-hands-git-its-github-credential-in-a-per-command-file--security-fix-dev-behaviour-change) | Dev: proxy or CA in env |
|
|
134
|
-
| 114 | Worker | [GitHub objects cross as bundles](#the-worker-moves-objects-between-github-and-remotegit-as-bundles) | None |
|
|
135
|
-
| 114 | AI | [`noindex` entries leave AI content](#ai-content-leaves-out-noindex-entries--behaviour-change-for-ai-output) | `exclude.noindex: false` |
|
|
136
|
-
| 114 | Worker | [Worker follows a rebased or deleted branch](#the-worker-follows-a-rebased-or-deleted-github-branch) | None |
|
|
137
|
-
| 114 | Worker | [Worker holds no secret (contract 2)](#canopycms-cdk-the-worker-holds-no-secret--security-fix-template-first-contract-2) | Template first |
|
|
138
|
-
| 115 | AI | [referenceLink decides where AI-export entry links point](#ai-content-can-withhold-or-redirect-a-link-to-an-entry-with-no-page) | Optional |
|
|
139
|
-
| 115 | AI | [toPlainText no longer strips front matter](#toplaintext-takes-an-entry-body-and-keeps-prose-after-a-leading------behaviour-change) | Whole-file callers split first |
|
|
140
|
-
| 115 | Auth | [Clerk users without a name no longer show their id](#people-without-a-name-show-name-unavailable) | None |
|
|
141
|
-
| 115 | Branches | [Non-privileged callers get only their own branch ACL entries](#branch-access-lists-stay-with-admins-and-reviewers--behaviour-change) | None |
|
|
142
|
-
| 115 | Branches | [managerOrAdminAllowed now refuses editors an access list names](#a-branch-lockdown-outranks-the-branchs-access-list--security-fix) | Optional |
|
|
143
|
-
| 115 | Branches | [Conflict notice persists until merge](#the-base-branch-conflict-notice-stays-until-the-branch-merges--behaviour-change) | None |
|
|
144
|
-
| 115 | Editing | [Breadcrumb root and file menu say "All content"](#the-editor-calls-the-content-drawer-all-content) | Editor UI tests |
|
|
145
|
-
| 115 | Editing | [Branches drawer and comment replies](#the-branches-drawer-shows-one-action-per-branch-and-comments-reply-in-place) | Editor UI tests |
|
|
146
|
-
| 115 | Editing | [Clear offers Undo; refusals and conflicts explain themselves](#an-objects-clear-offers-undo-and-refusals-say-why) | None |
|
|
147
|
-
| 115 | Editing | [Collection dialog says what saves at once](#the-collection-dialog-says-what-saves-at-once) | Editor UI tests |
|
|
148
|
-
| 115 | Editing | [Comments and branches name their people](#comments-and-branches-name-their-people-for-every-editor--behaviour-change-on-two-apis) | Direct API callers |
|
|
149
|
-
| 115 | Editing | [Date picker, form header, wrapping toolbar](#a-date-picker-a-form-header-and-a-toolbar-that-wraps) | Editor UI tests |
|
|
150
|
-
| 115 | Editing | [Editor colours reach contrast in both schemes](#editor-colours-reach-451-in-light-and-dark-mode) | Visual snapshot tests |
|
|
151
|
-
| 115 | Editing | [Editor contrast; blocked buttons stay focusable](#editor-contrast-and-blocked-buttons-stay-focusable) | Browser tests |
|
|
152
|
-
| 115 | Editing | [Focus ring, control borders, light badges, sentence-case badges](#editor-focus-rings-and-checked-controls-reach-31-for-any-brand) | Visual snapshot tests |
|
|
153
|
-
| 115 | Editing | [Editor requests time out](#editor-requests-time-out-instead-of-hanging) | Slow-API browser tests |
|
|
154
|
-
| 115 | Editing | [Field descriptions, list-card titles, `public/` images, continued](#field-editing-descriptions-list-card-titles-and-public-images-continued) | None |
|
|
155
|
-
| 115 | Editing | [List items and blocks collapse](#list-items-and-blocks-collapse-and-reorder-from-one-menu) | Editor UI tests |
|
|
156
|
-
| 115 | Editing | [Navigator hides "Add entry" where path permissions refuse it](#add-entry-follows-path-permissions-admin-panels-and-labels-tidied) | None |
|
|
157
|
-
| 115 | Editing | [Quick open, navigator filter, title-first entries, media search](#quick-open-a-navigator-filter-title-first-new-entries-and-media-search) | Editor UI tests |
|
|
158
|
-
| 115 | Editing | [Saving a deleted or moved entry is refused](#a-save-never-brings-back-a-deleted-or-moved-entry--behaviour-change) | None |
|
|
159
|
-
| 115 | Editing | [Submit warns about unsaved entries; unanswered writes keep input](#submit-names-unsaved-entries-unanswered-writes-recover-more) | None |
|
|
160
|
-
| 115 | Editing | [Unlabelled field names are humanised](#unlabelled-fields-and-block-templates-show-their-names-as-words) | Editor UI tests |
|
|
161
|
-
| 115 | Ops | [Stable versions follow changesets; CHANGELOG.md ships](#stable-releases-follow-the-changes-they-carry-and-ship-their-changelog) | None |
|
|
162
|
-
| 115 | Reading | [List items and blocks gain a persisted `_key`](#list-items-and-blocks-carry-a-_key-and-field-comments-follow-it--behaviour-change) | Rename fields named _key |
|
|
163
|
-
| 115 | Schema | [Date new entries at their first submit](#stamponpublish-dates-a-new-entry-at-its-first-submit) | Optional |
|
|
164
|
-
|
|
165
|
-
### Preview URLs take one prefix, follow `trailingSlash`, and load each entry's own page — **breaking (env)**
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Released
|
|
59
|
+
|
|
60
|
+
### 0.1.0
|
|
61
|
+
|
|
62
|
+
<!-- changeset: legacy-unreleased -->
|
|
63
|
+
<!-- changeset: nice-boxes-battle -->
|
|
64
|
+
|
|
65
|
+
#### Preview URLs take one prefix, follow `trailingSlash`, and load each entry's own page — **breaking (env)**
|
|
166
66
|
|
|
167
67
|
**What changed.**
|
|
168
68
|
|
|
@@ -182,7 +82,7 @@ served at `/` without an `index` slug needs `'content/<slug>': '/'`, or re-model
|
|
|
182
82
|
**Now deletable.** `previewBase` keys that only added a shared prefix or restate a root entry's own
|
|
183
83
|
URL.
|
|
184
84
|
|
|
185
|
-
|
|
85
|
+
#### The preview route and `/preview` entries — **breaking (imports)**
|
|
186
86
|
|
|
187
87
|
**What changed.**
|
|
188
88
|
|
|
@@ -208,7 +108,7 @@ URL.
|
|
|
208
108
|
2. For a branch preview: wrap views with `withCanopyPreview` in a `'use client'` module, add
|
|
209
109
|
`app/preview/[[...path]]/page.server.tsx`, set `editor.previewPrefix: '/preview'`, and serve that
|
|
210
110
|
route with `frame-ancestors 'self'`, not `X-Frame-Options: DENY` (see
|
|
211
|
-
[Live Preview](https://github.com/safeinsights/canopycms/blob/
|
|
111
|
+
[Live Preview](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#live-preview)).
|
|
212
112
|
3. A test reading view content from the route's server HTML must load the page in a browser.
|
|
213
113
|
Server output rendered during a preview request carries the signed-in asset prefix; keep it out
|
|
214
114
|
of cross-request caches (`unstable_cache`, module memos).
|
|
@@ -216,14 +116,14 @@ URL.
|
|
|
216
116
|
**Now deletable.** A hand-built branch-preview route, and CSS layer or specificity workarounds that
|
|
217
117
|
kept site styles ahead of Mantine's in the preview.
|
|
218
118
|
|
|
219
|
-
|
|
119
|
+
#### Preview `fieldProps` is typed, with server-safe helpers — **breaking (types and schemas)**
|
|
220
120
|
|
|
221
121
|
**What changed.** (int.109) `fieldProps` checks each path against the view's content type, and
|
|
222
122
|
`canopycms` exports `FieldProps`, `FieldAttrs`, `fieldAttrs` and `scopeFieldProps`, callable from
|
|
223
123
|
server components. A string path marks the form's spelling (`'a.0.b'` marks `a[0].b`), and an empty
|
|
224
124
|
path marks nothing. The editor counts and logs marks naming no field. `createEntrySchemaRegistry`
|
|
225
125
|
refuses a field name that is empty, all digits or contains `.`, `[` or `]`. See
|
|
226
|
-
[Live Preview](https://github.com/safeinsights/canopycms/blob/
|
|
126
|
+
[Live Preview](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#live-preview).
|
|
227
127
|
|
|
228
128
|
**To adopt.** Fix each path that stops compiling; the error lists valid ones. Rewrite computed paths
|
|
229
129
|
as literal segments, or type that component's prop as plain `FieldProps`. Pass `fieldProps` as
|
|
@@ -233,7 +133,7 @@ as literal segments, or type that component's prop as plain `FieldProps`. Pass `
|
|
|
233
133
|
`fieldProps` defaults; schema-walking tests for misspelled mark paths, once components are typed
|
|
234
134
|
(the editor flags another block template's field).
|
|
235
135
|
|
|
236
|
-
|
|
136
|
+
#### A reference resolves to its target, a restricted stub, or a missing stub — **security fix; breaking (types and build)**
|
|
237
137
|
|
|
238
138
|
**What changed.**
|
|
239
139
|
|
|
@@ -271,7 +171,7 @@ optional if it was required.
|
|
|
271
171
|
content-integrity test checking reference fields against entry ids, and top-level-only reference
|
|
272
172
|
fields kept for the preview's sake.
|
|
273
173
|
|
|
274
|
-
|
|
174
|
+
#### AI content links a reference to its target — **behaviour change for `/ai` output and AI config callbacks**
|
|
275
175
|
|
|
276
176
|
**What changed.** (int.106) A `reference` field renders as a link to its target, not the stored id:
|
|
277
177
|
a byline reading `**Author:** 5NVkkrB1MJUv` now links the name `Alice` to that entry's page, then to
|
|
@@ -293,7 +193,7 @@ matching: search your AI config for each reference field's name.
|
|
|
293
193
|
|
|
294
194
|
**Now deletable.** A `fieldTransforms` entry that looked up a reference id to print its title.
|
|
295
195
|
|
|
296
|
-
|
|
196
|
+
#### AI content leaves out `noindex` entries — **behaviour change for `/ai` output**
|
|
297
197
|
|
|
298
198
|
**What changed.** (int.114) AI content leaves out entries marked `noindex`, both from
|
|
299
199
|
`generate-ai-content` and from the `/ai` route, using the same predicate as the sitemap and robots
|
|
@@ -305,11 +205,11 @@ or a failed render) renders as its plain text, with no URL; any other form of th
|
|
|
305
205
|
fields are nested or renamed, pass the AI config's `seo` the same object you pass
|
|
306
206
|
`createNextCanopyContext({ seo })`, so the sitemap and AI content read the flag from the same
|
|
307
207
|
place. A field that links to a hidden section by plain URL needs a field transform; the README
|
|
308
|
-
shows [the recipe](https://github.com/safeinsights/canopycms/blob/
|
|
208
|
+
shows [the recipe](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#ai-content-configuration).
|
|
309
209
|
|
|
310
210
|
**Now deletable.** An `exclude.where` that re-read the `noindex` flag by hand.
|
|
311
211
|
|
|
312
|
-
|
|
212
|
+
#### Deleting a referenced entry asks first — **behaviour change on the delete API**
|
|
313
213
|
|
|
314
214
|
**What changed.** (int.106) Deleting an entry that other entries reference (by field or `entry:`
|
|
315
215
|
link) returns 409 with `data.referencedBy`: the referencing entries the user may read, and a
|
|
@@ -318,7 +218,7 @@ link) returns 409 with `data.referencedBy`: the referencing entries the user may
|
|
|
318
218
|
|
|
319
219
|
**To adopt.** Only scripts calling the delete endpoint: pass the flag or handle the 409.
|
|
320
220
|
|
|
321
|
-
|
|
221
|
+
#### `mdx` content that runs code is refused at save — **breaking (behaviour)**
|
|
322
222
|
|
|
323
223
|
**What changed.** (int.108) An `mdx` field or body refuses `{…}` expressions other than comments and
|
|
324
224
|
plain values, `import`/`export`, and tags, attributes and URL schemes outside a safe set; other
|
|
@@ -327,7 +227,7 @@ A `markdown` field with `renderAs: 'mdx'` is checked as MDX, and `mdxAllow` narr
|
|
|
327
227
|
field or site-wide. New: field options `renderAs`, `mdxAllow`; config key `mdxAllow`; type
|
|
328
228
|
`MdxAllowlist`. (int.110) A component prop allowance can be `'string'` (or
|
|
329
229
|
`{ type: 'string', maxLength }`): a quoted value only, never bare or `{…}`. See
|
|
330
|
-
[MDX content cannot run code](https://github.com/safeinsights/canopycms/blob/
|
|
230
|
+
[MDX content cannot run code](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#mdx-content-cannot-run-code).
|
|
331
231
|
|
|
332
232
|
**To adopt.** Set `renderAs: 'mdx'` on each `markdown` field your site compiles as MDX, and
|
|
333
233
|
`mdxAllow` to what your renderer takes. Set `executable: true` only on a field whose editors you
|
|
@@ -339,7 +239,7 @@ build lists it.
|
|
|
339
239
|
`javascript:` links in MDX or markdown rendered as MDX, and the path-prefix matching behind its
|
|
340
240
|
entry-type gate. Keep a rule checking that the body compiles.
|
|
341
241
|
|
|
342
|
-
|
|
242
|
+
#### A save rewrites only what changed
|
|
343
243
|
|
|
344
244
|
**What changed.**
|
|
345
245
|
|
|
@@ -359,7 +259,7 @@ entry-type gate. Keep a rule checking that the body compiles.
|
|
|
359
259
|
**Now deletable.** A formatter pass or `.prettierignore` entry over CMS-written content that only
|
|
360
260
|
undoes the editor's re-folding, restyling or date rewriting.
|
|
361
261
|
|
|
362
|
-
|
|
262
|
+
#### The markdown editor runs MDXEditor 4.3
|
|
363
263
|
|
|
364
264
|
**What changed.** (int.105) `@mdxeditor/editor` is `^4.3.2` (Lexical 0.48), up from `^3.52.4`.
|
|
365
265
|
Two-paragraph list items, multi-block quotes and code fences in any language edit in rich text.
|
|
@@ -367,7 +267,7 @@ Two-paragraph list items, multi-block quotes and code fences in any language edi
|
|
|
367
267
|
**To adopt.** Nothing, unless your app depends on `@mdxeditor/editor` or `lexical` directly: align
|
|
368
268
|
those versions so one copy loads.
|
|
369
269
|
|
|
370
|
-
|
|
270
|
+
#### Unsaved group and permission changes show, and closing asks first
|
|
371
271
|
|
|
372
272
|
**What changed.** (int.113) Manage Groups and Manage Permissions still save as one batch, but now
|
|
373
273
|
mark unsaved changes, keep the save bar in view, and ask before closing or leaving drops them. The
|
|
@@ -375,7 +275,7 @@ group dialog's buttons read "Add" and "Apply", since neither saves.
|
|
|
375
275
|
|
|
376
276
|
**To adopt.** Nothing.
|
|
377
277
|
|
|
378
|
-
|
|
278
|
+
#### Field editing: descriptions, list-card titles, and `public/` images
|
|
379
279
|
|
|
380
280
|
**What changed.**
|
|
381
281
|
|
|
@@ -393,7 +293,7 @@ image, upload a raster copy to the media library. For card titles:
|
|
|
393
293
|
|
|
394
294
|
**Now deletable.** Editor hints worked into a field's `label` because `description` never showed.
|
|
395
295
|
|
|
396
|
-
|
|
296
|
+
#### Content reads: listings take a `branch`, and reads report `slug` and `urlPath`
|
|
397
297
|
|
|
398
298
|
**What changed.**
|
|
399
299
|
|
|
@@ -406,7 +306,7 @@ branch.
|
|
|
406
306
|
|
|
407
307
|
**Now deletable.** Code parsing a slug or URL back out of `path` or `entry.path`.
|
|
408
308
|
|
|
409
|
-
|
|
309
|
+
#### Path-permission rules now take effect below the content root — **security fix; breaking for rules written with on-disk names**
|
|
410
310
|
|
|
411
311
|
**What changed.** (int.93) Rules match an entry's logical path (`content/blog/my-post`). Enforcement
|
|
412
312
|
checked the id-suffixed on-disk path, so collection and entry rules matched nothing; only a glob
|
|
@@ -419,7 +319,7 @@ extension in logical form (`content/blog/**`, `content/about`).
|
|
|
419
319
|
|
|
420
320
|
**Now deletable.** A content-root grant working around inert collection grants.
|
|
421
321
|
|
|
422
|
-
|
|
322
|
+
#### Reads never create a requested branch — **security fix; breaking for some direct `createContentReader` callers**
|
|
423
323
|
|
|
424
324
|
**What changed.** (int.94) A branch other than the active one must exist and be readable by the
|
|
425
325
|
user, or `read()`/`readByUrlPath()` treat it as not found; no workspace is created per `?branch=`
|
|
@@ -430,7 +330,7 @@ passes `allowCreateBranch: true`, never with a request's branch.
|
|
|
430
330
|
|
|
431
331
|
**Now deletable.** Checks that allow-list `?branch=` before it reaches `read()`.
|
|
432
332
|
|
|
433
|
-
|
|
333
|
+
#### Fast, crash-safe branch creation — **behaviour change: branch clones hold only the content root**
|
|
434
334
|
|
|
435
335
|
**What changed.** (int.100) A branch is built under a staging name and appears only when complete.
|
|
436
336
|
The worker repairs branch directories an interrupted create or delete left wedged, and owns
|
|
@@ -444,7 +344,7 @@ changed `contentRoot` reaches existing clones within a worker cycle of the API r
|
|
|
444
344
|
**Now deletable.** Manual EFS cleanup of provisioning locks or half-made branch directories, and
|
|
445
345
|
`remote.git` gc scripts.
|
|
446
346
|
|
|
447
|
-
|
|
347
|
+
#### `.canopy-meta/` must not be committed, and System health says so
|
|
448
348
|
|
|
449
349
|
**What changed.** (int.93) The schema cache lives in each branch clone's `.git/canopycms/`. Sync,
|
|
450
350
|
editor submits and `canopycms sync` ignore `.canopy-meta/`, and System health shows the base
|
|
@@ -458,13 +358,13 @@ repaired or re-created.
|
|
|
458
358
|
**Now deletable.** Any local step that resets or reformats `.canopy-meta/` files before a commit or
|
|
459
359
|
a format check.
|
|
460
360
|
|
|
461
|
-
|
|
361
|
+
#### Commits name their editors, and submit refuses a branch with nothing to submit
|
|
462
362
|
|
|
463
363
|
**What changed.**
|
|
464
364
|
|
|
465
365
|
- (int.93) Submit commits gain an `Edited-by: Name (id)` trailer; PR bodies gain a section that
|
|
466
366
|
re-submits replace, keeping human text. Options: `gitEditedByTrailers`, `gitCoAuthoredByTrailers`
|
|
467
|
-
([reference](https://github.com/safeinsights/canopycms/blob/
|
|
367
|
+
([reference](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#definecanopyconfig-options)).
|
|
468
368
|
- (int.110) Submit-commit trailers name every user who saved since the last submit commit, and
|
|
469
369
|
the PR-body section every user who edited the branch, not only the submitter; settings commits
|
|
470
370
|
(permissions, groups) carry the acting user's trailer.
|
|
@@ -473,7 +373,7 @@ a format check.
|
|
|
473
373
|
|
|
474
374
|
**To adopt.** Scripts calling submit: save a change first, or handle the 400.
|
|
475
375
|
|
|
476
|
-
|
|
376
|
+
#### Settings saves only push the settings branch — **breaking (config): `autoCreateSettingsPR` is removed**
|
|
477
377
|
|
|
478
378
|
**What changed.** (int.93) The orphan settings branch can never get a PR, so groups and permissions
|
|
479
379
|
saves only push the branch, and no failing PR task lands in System health.
|
|
@@ -482,20 +382,20 @@ saves only push the branch, and no failing PR task lands in System health.
|
|
|
482
382
|
|
|
483
383
|
**Now deletable.** Filters that hid the failed settings-PR tasks.
|
|
484
384
|
|
|
485
|
-
|
|
385
|
+
#### A schema the running code lacks costs one entry type, and holds the worker — **behaviour change**
|
|
486
386
|
|
|
487
387
|
**What changed.** (int.107) When synced content names an entry schema the running code lacks, only
|
|
488
388
|
that entry type goes unavailable: the editor says so, and its entries answer 503 with
|
|
489
389
|
`code: 'SCHEMA_UNAVAILABLE'`. Builds, static deploys and `generate-ai-content` still fail. The
|
|
490
390
|
worker holds the base branch for up to 30 minutes while that lasts; see
|
|
491
|
-
[New schemas wait for the editor deploy](https://github.com/safeinsights/canopycms/blob/
|
|
391
|
+
[New schemas wait for the editor deploy](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#new-schemas-wait-for-the-editor-deploy).
|
|
492
392
|
Public types gain optional `unavailable` on `EntryTypeConfig` and `FlatSchemaItem`, optional
|
|
493
393
|
`ApiResponse.code`, and a required `SchemaResolutionResult.issues`.
|
|
494
394
|
|
|
495
395
|
**To adopt.** Code that builds a `SchemaResolutionResult` adds `issues`. A custom worker entrypoint
|
|
496
396
|
can pass `schemaHoldMaxMs` to `CmsWorker`.
|
|
497
397
|
|
|
498
|
-
|
|
398
|
+
#### `canopycms-cdk`: the worker drains before replacement and runs on-demand — **breaking (props): `spotMaxPrice` is removed; behaviour and cost change**
|
|
499
399
|
|
|
500
400
|
**What changed.** (int.108) The worker is one on-demand `t4g.nano` by default (about $3 a month,
|
|
501
401
|
against spot's $1–2); a spot shortage could leave no worker: on a first deploy the editor's API answers 503 "CMS worker not
|
|
@@ -512,7 +412,7 @@ drain applies from the deploy after this one.
|
|
|
512
412
|
|
|
513
413
|
**Now deletable.** Any override stripping `InstanceMarketOptions` from the worker's launch template.
|
|
514
414
|
|
|
515
|
-
|
|
415
|
+
#### `canopycms-cdk`: the worker instance is hardened — **an existing stack upgrades in two deploys; behaviour and cost change**
|
|
516
416
|
|
|
517
417
|
**Upgrade an existing stack in two deploys:**
|
|
518
418
|
|
|
@@ -526,7 +426,7 @@ hang until the drain heartbeat lets termination continue. Its in-flight task is
|
|
|
526
426
|
new stack needs no steps.
|
|
527
427
|
|
|
528
428
|
**What changed.** (int.109) Detailed in
|
|
529
|
-
[The worker instance](https://github.com/safeinsights/canopycms/blob/
|
|
429
|
+
[The worker instance](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#the-worker-instance): IMDSv2 with a hop limit of 1; the
|
|
530
430
|
bundle is one file whose sha256 user data checks, readable as that one object; a file-system policy
|
|
531
431
|
refusing clients without TLS or IAM, replacing the worker's
|
|
532
432
|
`AmazonElasticFileSystemClientReadWriteAccess`; an encrypted gp3 root volume; a boot-time upgrade to
|
|
@@ -542,7 +442,7 @@ key, grant the Auto Scaling service-linked role on it. Pass `workerMaxInstanceLi
|
|
|
542
442
|
**Now deletable.** Any override adding `MetadataOptions`, an encrypted root volume or an EFS
|
|
543
443
|
`FileSystemPolicy`, or narrowing the worker role's asset-bucket grant.
|
|
544
444
|
|
|
545
|
-
|
|
445
|
+
#### `canopycms-cdk`: the worker needs a state directory — **deploy the template before the bundle**
|
|
546
446
|
|
|
547
447
|
**What changed.** (int.110) The worker's git keeps the GitHub credential in a private mirror
|
|
548
448
|
under the unit's `StateDirectory=`, and the worker does not start without it.
|
|
@@ -552,14 +452,14 @@ new template before CI rolls an int.110 or later bundle; a parameter-only change
|
|
|
552
452
|
the new unit, so the new bundle exits at start. A hand-installed unit needs
|
|
553
453
|
`StateDirectory=canopy-worker` under `[Service]`.
|
|
554
454
|
|
|
555
|
-
|
|
455
|
+
#### A poisoned `remote.git` re-clones itself
|
|
556
456
|
|
|
557
457
|
**What changed.** (int.112) A `remote.git` missing its base branch is re-cloned unless an unpushed ref would be
|
|
558
458
|
lost; the refusal names those refs. A tampered config still refuses and needs an operator.
|
|
559
459
|
|
|
560
460
|
**To adopt.** Nothing.
|
|
561
461
|
|
|
562
|
-
|
|
462
|
+
#### A failed or stopped worker says why — **behaviour change on the not-ready 503; new worker APIs**
|
|
563
463
|
|
|
564
464
|
**What changed.** (int.109) While the latest start's recorded failure stands, the prod not-ready 503
|
|
565
465
|
is `WORKER_FAILED`: no `Retry-After`, the failure named to admins, account ids masked.
|
|
@@ -571,7 +471,7 @@ failure and exits non-zero on `selfStopped`, with a code outside `RestartPrevent
|
|
|
571
471
|
|
|
572
472
|
**Now deletable.** A watchdog that restarts an idle worker process.
|
|
573
473
|
|
|
574
|
-
|
|
474
|
+
#### `canopycms-cdk`: CI can roll the worker with a parameter, and alarm when it stops syncing — **new, opt-in**
|
|
575
475
|
|
|
576
476
|
**What changed.** (int.109)
|
|
577
477
|
|
|
@@ -580,28 +480,28 @@ failure and exits non-zero on `selfStopped`, with a code outside `RestartPrevent
|
|
|
580
480
|
with its hash, as `worker/dist/index.js` and `index.js.sha256`. The default, `'asset'`, is
|
|
581
481
|
unchanged.
|
|
582
482
|
- `CanopyCmsService` alarms when the worker logs no git sync for 30 minutes. See
|
|
583
|
-
[Worker-down alarm](https://github.com/safeinsights/canopycms/blob/
|
|
483
|
+
[Worker-down alarm](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#worker-down-alarm).
|
|
584
484
|
|
|
585
485
|
**To adopt.** Optional. For parameter-only change sets, see
|
|
586
|
-
[Rolling the worker from CI](https://github.com/safeinsights/canopycms/blob/
|
|
486
|
+
[Rolling the worker from CI](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#rolling-the-worker-from-ci). For the alarm, pass
|
|
587
487
|
`alarmTopic`.
|
|
588
488
|
|
|
589
489
|
**Now deletable.** A manual `cdk deploy` after each canopycms bump whose only purpose is moving the
|
|
590
490
|
worker, and a hand-built alarm on the worker log group.
|
|
591
491
|
|
|
592
|
-
|
|
492
|
+
#### `canopycms-cdk`: a `t4g.nano` worker boots reliably — **behaviour change: a deploy replaces the worker**
|
|
593
493
|
|
|
594
494
|
**What changed.** (int.112) The boot's `dnf upgrade` could be OOM-killed on every retry. A 1 GiB
|
|
595
495
|
swap file now goes on first; an upgrade that still fails starts the worker unpatched and notifies
|
|
596
496
|
`alarmTopic` if set; a retried step names itself when it gives up. See
|
|
597
|
-
[The worker instance](https://github.com/safeinsights/canopycms/blob/
|
|
497
|
+
[The worker instance](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#the-worker-instance).
|
|
598
498
|
|
|
599
499
|
**To adopt.** Deploy, which replaces the worker instance. The bundle needs none of this, so it is
|
|
600
500
|
not Template first and the worker contract stays at 1.
|
|
601
501
|
|
|
602
502
|
**Now deletable.** An instance type above `t4g.nano` chosen only to get the boot through.
|
|
603
503
|
|
|
604
|
-
|
|
504
|
+
#### `canopycms-cdk`: the worker's log is root-owned — **security fix**
|
|
605
505
|
|
|
606
506
|
**What changed.** (int.112) `/var/log/canopy-worker` and `worker.log` are root-owned, and the unit
|
|
607
507
|
drops `LogsDirectory=`. systemd opens the log as root, following symlinks, before the sandbox
|
|
@@ -619,7 +519,7 @@ contract is unchanged. A hand-installed unit needs the same change:
|
|
|
619
519
|
|
|
620
520
|
**Now deletable.** Nothing.
|
|
621
521
|
|
|
622
|
-
|
|
522
|
+
#### The worker never pushes the base or default branch — **security fix**
|
|
623
523
|
|
|
624
524
|
**What changed.** (int.112) The worker refuses to push, plainly or replacing history, to the base
|
|
625
525
|
branch or GitHub's default branch, whatever a task asks, and fails the task permanently.
|
|
@@ -635,14 +535,14 @@ its bypass list. Set `CANOPYCMS_BASE_BRANCH` (the construct's `baseBranch`) expl
|
|
|
635
535
|
it, the gateway protects only GitHub's default branch and your list; the worker still refuses the
|
|
636
536
|
base it detected, warning when that base is neither.
|
|
637
537
|
|
|
638
|
-
|
|
538
|
+
#### The worker's push logs say whether GitHub moved
|
|
639
539
|
|
|
640
540
|
**What changed.** (int.113) `Pushed … to GitHub` is logged only when the branch moved, saying
|
|
641
541
|
where from; an unmoved branch logs at debug level. An unchanged settings branch is not pushed.
|
|
642
542
|
|
|
643
543
|
**To adopt.** Nothing.
|
|
644
544
|
|
|
645
|
-
|
|
545
|
+
#### The worker hands git its GitHub credential in a per-command file — **security fix; dev behaviour change**
|
|
646
546
|
|
|
647
547
|
**What changed.** (int.113) The token leaves git URLs: each GitHub fetch and push reads it from a
|
|
648
548
|
`0600` file named by `GIT_CONFIG_GLOBAL`, deleted afterwards. For those commands the file replaces
|
|
@@ -652,7 +552,7 @@ stops applying and no keychain credential is tried.
|
|
|
652
552
|
**To adopt.** Nothing in production. In dev, move a global-config proxy or CA to `HTTPS_PROXY` or
|
|
653
553
|
`GIT_SSL_CAINFO`.
|
|
654
554
|
|
|
655
|
-
|
|
555
|
+
#### The worker moves objects between GitHub and `remote.git` as bundles
|
|
656
556
|
|
|
657
557
|
**What changed.** (int.114) The worker moves objects between GitHub and
|
|
658
558
|
`remote.git` as git bundles. A new instance's first sync fetches the whole repository from GitHub,
|
|
@@ -660,9 +560,9 @@ and operations may reuse GitHub fetches under 30 seconds old.
|
|
|
660
560
|
|
|
661
561
|
**To adopt.** Nothing. Seeding `remote.git` stages a copy of the repository beside the gateway's
|
|
662
562
|
mirror, so the root volume needs room for two
|
|
663
|
-
([details](https://github.com/safeinsights/canopycms/blob/
|
|
563
|
+
([details](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#the-worker-instance)).
|
|
664
564
|
|
|
665
|
-
|
|
565
|
+
#### The worker follows a rebased or deleted GitHub branch
|
|
666
566
|
|
|
667
567
|
**What changed.** (int.114) When a branch is rebased and force-pushed on GitHub, or deleted there, the
|
|
668
568
|
worker now updates or deletes its own copy of it instead of warning about it on every sync. A rebased
|
|
@@ -671,7 +571,7 @@ health lists it with what to do.
|
|
|
671
571
|
|
|
672
572
|
**To adopt.** Nothing.
|
|
673
573
|
|
|
674
|
-
|
|
574
|
+
#### `canopycms-cdk`: a worker bundle states the template it needs — **template first for the gate only**
|
|
675
575
|
|
|
676
576
|
**What changed.** (int.112) The worker unit carries a contract version
|
|
677
577
|
(`Environment=CANOPYCMS_WORKER_CONTRACT=<n>`). Parameter mode outputs it as `WorkerContract`, and
|
|
@@ -682,13 +582,13 @@ changes the template too (the fallback bundle's key and hash), so only the contr
|
|
|
682
582
|
bundle-only roll is safe.
|
|
683
583
|
|
|
684
584
|
**To adopt.** Parameter mode: gate bundle-only rolls on the contract
|
|
685
|
-
([recipe](https://github.com/safeinsights/canopycms/blob/
|
|
585
|
+
([recipe](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#rolling-the-worker-from-ci)). The gate refuses a stack without the
|
|
686
586
|
`WorkerContract` output, so `cdk deploy` the template once, which adds it. A hand-installed unit
|
|
687
587
|
copies its `Environment=CANOPYCMS_WORKER_CONTRACT=` line from `worker/canopy-worker.service`.
|
|
688
588
|
|
|
689
589
|
**Now deletable.** Deciding from the template diff whether a bundle-only roll is safe.
|
|
690
590
|
|
|
691
|
-
|
|
591
|
+
#### `canopycms-cdk`: the worker holds no secret — **security fix; template first (contract 2)**
|
|
692
592
|
|
|
693
593
|
**What changed.** (int.114) The worker runs with no network and no secret. `canopy-github`, a gateway
|
|
694
594
|
service under its own user with no view of EFS, holds the GitHub credential and the Clerk key, and
|
|
@@ -699,10 +599,10 @@ units from the bundle's contract: 2 gets the split, an older bundle the single u
|
|
|
699
599
|
template, then roll the bundle; on an older template it stops with `template too old for this
|
|
700
600
|
bundle`. Inspect EFS only through `sudo /opt/canopy-worker/canopy-inspect <command>`, never from a root shell. A hand install
|
|
701
601
|
takes `worker/`'s three units and `gateway.env.example`
|
|
702
|
-
([steps](https://github.com/safeinsights/canopycms/blob/
|
|
703
|
-
[checklist](https://github.com/safeinsights/canopycms/blob/
|
|
602
|
+
([steps](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#installing-the-units-by-hand)). After the first deploy, run the
|
|
603
|
+
[checklist](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#first-deploy-checklist).
|
|
704
604
|
|
|
705
|
-
|
|
605
|
+
#### `canopycms-cdk`: `CanopyCmsService.attachTo`, and editor response headers — **behaviour change if you frame the CMS**
|
|
706
606
|
|
|
707
607
|
**What changed.** (int.94) `cmsService.attachTo(distribution, { viewerRequestFunction?, behaviorOverrides? })`
|
|
708
608
|
adds the editor's behaviors (`/edit`, `/edit/*`, `/api/canopycms/*`) to a distribution you already
|
|
@@ -711,7 +611,7 @@ response headers policy. `CanopyCmsDistribution` sends the same headers: `frame-
|
|
|
711
611
|
`X-Frame-Options: SAMEORIGIN`, `nosniff`, HSTS and `X-Robots-Tag: noindex`. Unless your app sends
|
|
712
612
|
its own framing headers, no other origin can frame the editor or any page the CMS domain serves. Every such page is
|
|
713
613
|
marked `noindex`. The editor's default preview is same-origin and unaffected. See
|
|
714
|
-
[Serving the editor from a distribution you already own](https://github.com/safeinsights/canopycms/blob/
|
|
614
|
+
[Serving the editor from a distribution you already own](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#serving-the-editor-from-a-distribution-you-already-own).
|
|
715
615
|
|
|
716
616
|
**To adopt.** If you wired the Function URL into your own distribution by hand, delete those
|
|
717
617
|
behaviors and call `attachTo`, passing your CMS build's `assetPrefix` as `editorAssetPrefix` and a
|
|
@@ -723,12 +623,12 @@ gate, and read the synth warning if your distribution has custom error responses
|
|
|
723
623
|
`x-forwarded-host` function made for them, and any response-headers policy added only to stop
|
|
724
624
|
framing.
|
|
725
625
|
|
|
726
|
-
|
|
626
|
+
#### `unauthenticatedStatus`: answer signed-out API calls with 419
|
|
727
627
|
|
|
728
628
|
**To adopt.** (int.102) Set `unauthenticatedStatus: 419` if your pages sit behind HTTP Basic auth on
|
|
729
629
|
the editor's origin; the editor still detects sign-out. Otherwise nothing.
|
|
730
630
|
|
|
731
|
-
|
|
631
|
+
#### Auth plugins look users up in batches
|
|
732
632
|
|
|
733
633
|
**What changed.** (int.111) `AuthPlugin` gains an optional `getUsersMetadata(userIds)`, and the
|
|
734
634
|
editor batches its user-badge lookups.
|
|
@@ -736,7 +636,7 @@ editor batches its user-badge lookups.
|
|
|
736
636
|
**To adopt.** Nothing. A custom auth plugin may implement it; otherwise the server falls back to
|
|
737
637
|
bounded single lookups.
|
|
738
638
|
|
|
739
|
-
|
|
639
|
+
#### The CMS image builds a prod editor, and a mode mismatch blocks the editor — **behaviour change: a hand-built image can fail its build**
|
|
740
640
|
|
|
741
641
|
**What changed.** (int.111) `Dockerfile.cms` defaults `NEXT_PUBLIC_CANOPY_MODE` to `prod`, not
|
|
742
642
|
`dev`, and fails its build on any value but `prod` or `dev`. An editor built for the other mode than its
|
|
@@ -745,7 +645,7 @@ server runs now gets a blocking screen naming that variable, not a sign-in that
|
|
|
745
645
|
**To adopt.** A hand-built image running a dev-mode server passes
|
|
746
646
|
`--build-arg NEXT_PUBLIC_CANOPY_MODE=dev`.
|
|
747
647
|
|
|
748
|
-
|
|
648
|
+
#### Prod detects an unset `defaultBaseBranch` instead of assuming `main` — **behaviour change: startup can fail**
|
|
749
649
|
|
|
750
650
|
**What changed.** (int.110) Unset, prod reads the base branch from the HEAD of the workspace's `remote.git`,
|
|
751
651
|
which the worker points at the branch it uses. Before the worker creates `remote.git`, requests
|
|
@@ -759,7 +659,7 @@ does not follow a later change of GitHub's default branch, so set it before a cu
|
|
|
759
659
|
|
|
760
660
|
**Now deletable.** A `defaultBaseBranch: 'main'` in a repository whose default branch is `main`.
|
|
761
661
|
|
|
762
|
-
|
|
662
|
+
#### The prod workspace defaults to `/mnt/efs` — **behaviour change if you run prod without `CANOPYCMS_WORKSPACE_ROOT`**
|
|
763
663
|
|
|
764
664
|
**What changed.** (int.100) With `CANOPYCMS_WORKSPACE_ROOT` unset, prod mode keeps its branches,
|
|
765
665
|
settings, task queue and auth cache under `/mnt/efs` instead of `/mnt/efs/workspace`
|
|
@@ -770,7 +670,7 @@ the worker, so CDK deployments are unaffected.
|
|
|
770
670
|
`/mnt/efs/workspace` to keep your existing workspace, or move that directory's contents up to
|
|
771
671
|
`/mnt/efs`.
|
|
772
672
|
|
|
773
|
-
|
|
673
|
+
#### System health shows which build is running
|
|
774
674
|
|
|
775
675
|
**What changed.** (int.94) System health gains a Build section (canopycms version, source revision,
|
|
776
676
|
worker version, media-storage state) and warns when API and worker versions differ.
|
|
@@ -783,7 +683,7 @@ worker version, media-storage state) and warns when API and worker versions diff
|
|
|
783
683
|
|
|
784
684
|
**Now deletable.** Hand-rolled version or commit stamping, or a build-info endpoint.
|
|
785
685
|
|
|
786
|
-
|
|
686
|
+
#### The AWS example workflow gains the template's triggers and dependency checks
|
|
787
687
|
|
|
788
688
|
**What changed.** (int.111) Like the one `init-deploy aws` writes, `examples/aws-deployment/deploy-cms.yml`
|
|
789
689
|
now deploys on `next.config.*`, `middleware.ts` and `public/**` changes, and checks `canopycms` and
|
|
@@ -791,7 +691,7 @@ now deploys on `next.config.*`, `middleware.ts` and `public/**` changes, and che
|
|
|
791
691
|
|
|
792
692
|
**To adopt.** If you copied it by hand, add those `paths:` and packages.
|
|
793
693
|
|
|
794
|
-
|
|
694
|
+
#### `GET /admin/branch-health` scans for duplicate content IDs only on request — **behaviour change**
|
|
795
695
|
|
|
796
696
|
**What changed.** (int.111) The duplicate-ID scan runs only with `?duplicates=1`, under a 20 s
|
|
797
697
|
budget. Each healthy entry then carries `duplicateIdScan` (`none`, `found` or `unknown`), replacing
|
|
@@ -799,7 +699,7 @@ budget. Each healthy entry then carries `duplicateIdScan` (`none`, `found` or `u
|
|
|
799
699
|
|
|
800
700
|
**To adopt.** Scripts reading `duplicateContentIds`: pass `duplicates=1`, read `duplicateIdScan`.
|
|
801
701
|
|
|
802
|
-
|
|
702
|
+
#### `canopycms-cdk`: `AssetSupport` serves images from S3 only — **breaking**
|
|
803
703
|
|
|
804
704
|
**What changed.** (int.100) `/assets/*` and `/assets/t/*` come from the bucket alone, with an
|
|
805
705
|
optional `replicaBucket` for 5xx failover. An unmaterialized URL is a 403; no transform Lambda or
|
|
@@ -816,7 +716,7 @@ opt-in and those props, and pass `replicaBucket` if you replicate `assets/`.
|
|
|
816
716
|
|
|
817
717
|
**Now deletable.** Your `assets/t/` expiry rule, before leaving lazy mode.
|
|
818
718
|
|
|
819
|
-
|
|
719
|
+
#### `collect-asset-refs` and `materialize-assets` store a build's images before release
|
|
820
720
|
|
|
821
721
|
**What changed.** (int.100) `canopycms collect-asset-refs <outDir>` writes the image keys a static
|
|
822
722
|
build references to `<outDir>/canopy-asset-refs.json`. `canopycms materialize-assets --refs <file>`
|
|
@@ -831,7 +731,7 @@ Run `materialize-assets` before the release is served, with the S3 grants the RE
|
|
|
831
731
|
|
|
832
732
|
**Now deletable.** A pre-release warm-up step that requests image URLs to get them transformed.
|
|
833
733
|
|
|
834
|
-
|
|
734
|
+
#### The editor and its live preview load images through the signed-in asset route
|
|
835
735
|
|
|
836
736
|
**What changed.** (int.100) The editor loads asset-store images from
|
|
837
737
|
`GET /api/canopycms/assets/raw/…` under your `basePath`, which transforms on demand and, on S3,
|
|
@@ -848,7 +748,7 @@ same-origin or set `lazyPublicTransforms: true`.
|
|
|
848
748
|
|
|
849
749
|
**Now deletable.** Code passing `assetBaseUrl` into the editor.
|
|
850
750
|
|
|
851
|
-
|
|
751
|
+
#### `assetUrl` applies an image value's crop — **behaviour change for cropped images**
|
|
852
752
|
|
|
853
753
|
**What changed.** (int.100) `assetUrl`/`assetSrcSet` apply an `image` value's `crop`; `opts.crop`
|
|
854
754
|
overrides.
|
|
@@ -857,7 +757,7 @@ overrides.
|
|
|
857
757
|
|
|
858
758
|
**Now deletable.** Copying `value.crop` into `opts.crop`.
|
|
859
759
|
|
|
860
|
-
|
|
760
|
+
#### `media.publicBaseUrl` is removed, and image limits are wider — **breaking (config)**
|
|
861
761
|
|
|
862
762
|
**What changed.** (int.100) Nothing read `media.publicBaseUrl`, and the strict `media` schema fails a
|
|
863
763
|
config that sets it. Uploads go up to 24 MP (6000×4000), up from 16.7 MP. Widths are any integer up
|
|
@@ -869,9 +769,7 @@ asset URLs.
|
|
|
869
769
|
|
|
870
770
|
**Now deletable.** Anything that only fed `publicBaseUrl`, and rounding widths to a multiple of 160.
|
|
871
771
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
### AI content can withhold or redirect a link to an entry with no page
|
|
772
|
+
#### AI content can withhold or redirect a link to an entry with no page
|
|
875
773
|
|
|
876
774
|
<!-- changeset: ai-reference-link-hook -->
|
|
877
775
|
|
|
@@ -889,12 +787,12 @@ one the exclusions leave out. A throw or any other return is logged and treated
|
|
|
889
787
|
**To adopt.** If your site's routes, sitemap or bylines decide that some entries have no page,
|
|
890
788
|
apply the same rule here, for example `referenceLink: (target, { body }) =>
|
|
891
789
|
!body?.trim() ? false : undefined` in `defineAIContentConfig` from `canopycms/ai`. See
|
|
892
|
-
[AI Content Configuration](https://github.com/safeinsights/canopycms/blob/
|
|
790
|
+
[AI Content Configuration](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#ai-content-configuration).
|
|
893
791
|
|
|
894
792
|
**Now deletable.** A `fieldTransforms` entry that re-renders a reference field only to drop or
|
|
895
793
|
change its link.
|
|
896
794
|
|
|
897
|
-
|
|
795
|
+
#### `toPlainText` takes an entry body and keeps prose after a leading `---` — **behaviour change**
|
|
898
796
|
|
|
899
797
|
<!-- changeset: to-plain-text-body-only -->
|
|
900
798
|
|
|
@@ -918,7 +816,7 @@ import { toPlainText } from 'canopycms/ai'
|
|
|
918
816
|
const text = toPlainText(matter(file, {}).content)
|
|
919
817
|
```
|
|
920
818
|
|
|
921
|
-
|
|
819
|
+
#### People without a name show "Name unavailable"
|
|
922
820
|
|
|
923
821
|
<!-- changeset: people-without-a-name-show-name-unavailable -->
|
|
924
822
|
|
|
@@ -926,7 +824,7 @@ _First in int.115._
|
|
|
926
824
|
|
|
927
825
|
**What changed.** The Clerk plugin no longer uses the Clerk user id as a user's name: a user with no full name or username has an empty name, and the editor shows "Name unavailable" wherever that person appears. Core and the editor also treat a blank name, or one equal to the user id, as no name: `/users/:userId`, `/users/batch` and the `users` lists on comments and branches return an empty `name` for that person. The users snapshot the worker writes follows the same rule.
|
|
928
826
|
|
|
929
|
-
|
|
827
|
+
#### Branch access lists stay with admins and reviewers — **behaviour change**
|
|
930
828
|
|
|
931
829
|
<!-- changeset: branch-access-list-withheld-from-non-privileged -->
|
|
932
830
|
|
|
@@ -938,7 +836,7 @@ access updates) sends a caller who is not an admin or reviewer only the `access.
|
|
|
938
836
|
`withheldAccess` field. A branch card's access list shows the people the viewer can name, then
|
|
939
837
|
"and N others", instead of a row of "Name unavailable" avatars.
|
|
940
838
|
|
|
941
|
-
|
|
839
|
+
#### A branch lockdown outranks the branch's access list — **security fix**
|
|
942
840
|
|
|
943
841
|
<!-- changeset: branch-lockdown-outranks-branch-acl -->
|
|
944
842
|
|
|
@@ -954,7 +852,7 @@ the editor's Submit and Withdraw controls follow the same rule.
|
|
|
954
852
|
branch: those editors lose access. To give it back, set `managerOrAdminAllowed` to `false` in
|
|
955
853
|
that branch's `branch.json`, and the access list decides again.
|
|
956
854
|
|
|
957
|
-
|
|
855
|
+
#### The base-branch conflict notice stays until the branch merges — **behaviour change**
|
|
958
856
|
|
|
959
857
|
<!-- changeset: conflict-notice-persists-until-merge -->
|
|
960
858
|
|
|
@@ -964,10 +862,10 @@ _First in int.115._
|
|
|
964
862
|
entry the base branch also changed, the "updated on the base branch" notice and the branch's
|
|
965
863
|
conflict count now stay until the branch merges, so a reviewer still sees which entries replaced a
|
|
966
864
|
base change. They used to clear on the next sync, about five minutes later. README's new [Drafts
|
|
967
|
-
and Unpublishing](https://github.com/safeinsights/canopycms/blob/
|
|
865
|
+
and Unpublishing](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#drafts-and-unpublishing) section covers long-lived branches and
|
|
968
866
|
unpublishing.
|
|
969
867
|
|
|
970
|
-
|
|
868
|
+
#### The editor calls the content drawer "All content"
|
|
971
869
|
|
|
972
870
|
<!-- changeset: all-content-label -->
|
|
973
871
|
|
|
@@ -977,7 +875,7 @@ _First in int.115._
|
|
|
977
875
|
|
|
978
876
|
**To adopt.** Nothing, unless your browser tests find either by the text "All entries".
|
|
979
877
|
|
|
980
|
-
|
|
878
|
+
#### The Branches drawer shows one action per branch, and comments reply in place
|
|
981
879
|
|
|
982
880
|
<!-- changeset: branches-drawer-and-comment-replies -->
|
|
983
881
|
|
|
@@ -991,7 +889,7 @@ form has a "Field comments" button, so tests that find buttons by `/comment/i` m
|
|
|
991
889
|
one; and the editor listens for Ctrl+Alt+M (⌘⌥M on macOS) on the whole document, taking it while a
|
|
992
890
|
form is open.
|
|
993
891
|
|
|
994
|
-
|
|
892
|
+
#### An object's Clear offers Undo, and refusals say why
|
|
995
893
|
|
|
996
894
|
<!-- changeset: clear-undo-and-clearer-refusals -->
|
|
997
895
|
|
|
@@ -1006,7 +904,7 @@ conflict in yellow; the API marks it with the new error code `SETTINGS_CHANGED`.
|
|
|
1006
904
|
`sanitizeHref` returns its fallback for `undefined` or `null`, which a live preview's draft can
|
|
1007
905
|
pass for a link field it doesn't hold yet, instead of throwing.
|
|
1008
906
|
|
|
1009
|
-
|
|
907
|
+
#### The collection dialog says what saves at once
|
|
1010
908
|
|
|
1011
909
|
<!-- changeset: collection-dialog-says-what-saves -->
|
|
1012
910
|
|
|
@@ -1019,7 +917,7 @@ inline instead of as toasts.
|
|
|
1019
917
|
|
|
1020
918
|
**To adopt.** Nothing, unless browser tests click the old buttons or wait for those toasts.
|
|
1021
919
|
|
|
1022
|
-
|
|
920
|
+
#### Comments and branches name their people for every editor — **behaviour change on two APIs**
|
|
1023
921
|
|
|
1024
922
|
<!-- changeset: comments-and-branches-name-their-people -->
|
|
1025
923
|
|
|
@@ -1032,7 +930,7 @@ Your auth plugin answers through the `/users/batch` cache; a failed lookup leave
|
|
|
1032
930
|
|
|
1033
931
|
**To adopt.** Nothing, unless you call either API yourself: read `data.users`.
|
|
1034
932
|
|
|
1035
|
-
|
|
933
|
+
#### A date picker, a form header, and a toolbar that wraps
|
|
1036
934
|
|
|
1037
935
|
<!-- changeset: date-picker-form-header-wrapping-toolbar -->
|
|
1038
936
|
|
|
@@ -1046,7 +944,7 @@ editor styles.
|
|
|
1046
944
|
|
|
1047
945
|
**To adopt.** Nothing. Browser tests that typed into a `datetime-local` input pick a date instead.
|
|
1048
946
|
|
|
1049
|
-
|
|
947
|
+
#### Editor colours reach 4.5:1 in light and dark mode
|
|
1050
948
|
|
|
1051
949
|
<!-- changeset: editor-colours-reach-contrast-in-both-schemes -->
|
|
1052
950
|
|
|
@@ -1068,7 +966,7 @@ defaults.
|
|
|
1068
966
|
**Now deletable.** Local overrides that darkened light buttons, badges, placeholders or input
|
|
1069
967
|
borders for contrast.
|
|
1070
968
|
|
|
1071
|
-
|
|
969
|
+
#### Editor contrast, and blocked buttons stay focusable
|
|
1072
970
|
|
|
1073
971
|
<!-- changeset: editor-contrast-and-focusable-blocked-buttons -->
|
|
1074
972
|
|
|
@@ -1087,7 +985,7 @@ old "Reload File" or "Discard File Draft" use the new labels.
|
|
|
1087
985
|
|
|
1088
986
|
**Now deletable.** Local overrides that darkened the same text or buttons.
|
|
1089
987
|
|
|
1090
|
-
|
|
988
|
+
#### Editor focus rings and checked controls reach 3:1 for any brand
|
|
1091
989
|
|
|
1092
990
|
<!-- changeset: editor-focus-ring-and-control-contrast -->
|
|
1093
991
|
|
|
@@ -1106,7 +1004,7 @@ their tint instead of the primary colour, and Markdown popups have a border in d
|
|
|
1106
1004
|
text, such as the System Health panel's "corrupt metadata", now "Corrupt metadata". A
|
|
1107
1005
|
`themeOverride` that sets `primaryShade` moves where the ring starts.
|
|
1108
1006
|
|
|
1109
|
-
|
|
1007
|
+
#### Editor requests time out instead of hanging
|
|
1110
1008
|
|
|
1111
1009
|
<!-- changeset: editor-requests-time-out -->
|
|
1112
1010
|
|
|
@@ -1122,7 +1020,7 @@ write in flight says why.
|
|
|
1122
1020
|
**To adopt.** Nothing, unless browser tests hold an API response for longer than a deadline to
|
|
1123
1021
|
observe a busy state; keep such holds under it.
|
|
1124
1022
|
|
|
1125
|
-
|
|
1023
|
+
#### Field editing: descriptions, list-card titles, and public/ images, continued
|
|
1126
1024
|
|
|
1127
1025
|
<!-- changeset: list-card-titles-and-block-descriptions -->
|
|
1128
1026
|
|
|
@@ -1135,7 +1033,7 @@ takes its title from its first non-blank `string` field, then "Item N" (or its `
|
|
|
1135
1033
|
"Team member N"). A block template's `description` now renders; see
|
|
1136
1034
|
[List items and blocks collapse](#list-items-and-blocks-collapse-and-reorder-from-one-menu).
|
|
1137
1035
|
|
|
1138
|
-
|
|
1036
|
+
#### List items and blocks collapse, and reorder from one menu
|
|
1139
1037
|
|
|
1140
1038
|
<!-- changeset: list-items-and-blocks-collapse -->
|
|
1141
1039
|
|
|
@@ -1152,7 +1050,7 @@ a second value) or "Add section".
|
|
|
1152
1050
|
|
|
1153
1051
|
**Now deletable.** Template labels that repeated the template's description.
|
|
1154
1052
|
|
|
1155
|
-
|
|
1053
|
+
#### "Add entry" follows path permissions; admin panels and labels tidied
|
|
1156
1054
|
|
|
1157
1055
|
<!-- changeset: navigator-add-follows-path-access-and-ux-batch2-rest -->
|
|
1158
1056
|
|
|
@@ -1167,7 +1065,7 @@ labels such as "All entries", "Manage permissions" and "Create group" are now in
|
|
|
1167
1065
|
Discarding an entry's changes toasts only for a read-only branch's hidden draft, where the form shows
|
|
1168
1066
|
no change.
|
|
1169
1067
|
|
|
1170
|
-
|
|
1068
|
+
#### Quick open, a navigator filter, title-first new entries, and media search
|
|
1171
1069
|
|
|
1172
1070
|
<!-- changeset: quick-open-navigator-filter-media-search -->
|
|
1173
1071
|
|
|
@@ -1183,7 +1081,7 @@ library searches, sorts and filters all its files, in a grid or a list.
|
|
|
1183
1081
|
**To adopt.** Nothing, unless browser tests add an entry by typing only a slug: fill in "Title"
|
|
1184
1082
|
too when the entry type has one.
|
|
1185
1083
|
|
|
1186
|
-
|
|
1084
|
+
#### A save never brings back a deleted or moved entry — **behaviour change**
|
|
1187
1085
|
|
|
1188
1086
|
<!-- changeset: save-never-recreates-deleted-entry -->
|
|
1189
1087
|
|
|
@@ -1196,7 +1094,7 @@ its new name with the changes still in the form, ready to save again. For a dele
|
|
|
1196
1094
|
the changes and offers "Save as new entry", a deliberate create. This also covers an editor's own
|
|
1197
1095
|
delete or rename that got no answer. Creating an entry is unchanged.
|
|
1198
1096
|
|
|
1199
|
-
|
|
1097
|
+
#### Submit names unsaved entries; unanswered writes recover more
|
|
1200
1098
|
|
|
1201
1099
|
<!-- changeset: submit-warns-unsaved-and-unanswered-writes-recover -->
|
|
1202
1100
|
|
|
@@ -1212,7 +1110,7 @@ out). The save-outcome toasts name their
|
|
|
1212
1110
|
entry. A lookup sent as a POST that times out says to try again. Removing a staged entry type
|
|
1213
1111
|
from a new collection goes at once, with Undo in the dialog.
|
|
1214
1112
|
|
|
1215
|
-
|
|
1113
|
+
#### Unlabelled fields and block templates show their names as words
|
|
1216
1114
|
|
|
1217
1115
|
<!-- changeset: unlabelled-fields-read-as-words -->
|
|
1218
1116
|
|
|
@@ -1225,7 +1123,7 @@ block picker and the Remove toast.
|
|
|
1225
1123
|
**To adopt.** Nothing, unless your browser tests find such a field by its raw name. Give it a
|
|
1226
1124
|
`label` to choose the words yourself.
|
|
1227
1125
|
|
|
1228
|
-
|
|
1126
|
+
#### Stable releases follow the changes they carry, and ship their changelog
|
|
1229
1127
|
|
|
1230
1128
|
<!-- changeset: stable-releases-from-changesets -->
|
|
1231
1129
|
|
|
@@ -1238,7 +1136,7 @@ as int builds already do.
|
|
|
1238
1136
|
|
|
1239
1137
|
**To adopt.** Nothing. With `0.1.0` and later, a `^0.1.0` range takes patches without action.
|
|
1240
1138
|
|
|
1241
|
-
|
|
1139
|
+
#### List items and blocks carry a `_key`, and field comments follow it — **behaviour change**
|
|
1242
1140
|
|
|
1243
1141
|
<!-- changeset: list-items-and-blocks-carry-keys -->
|
|
1244
1142
|
|
|
@@ -1261,7 +1159,7 @@ a `validateEntry` hook included, checks content against a strict schema, allow `
|
|
|
1261
1159
|
items and blocks. Don't spread a list item onto a DOM element (`<li {...item}>`), or it renders
|
|
1262
1160
|
a `_key` attribute. `_key` also suits React's `key` when rendering a list.
|
|
1263
1161
|
|
|
1264
|
-
|
|
1162
|
+
#### `stampOnPublish` dates a new entry at its first submit
|
|
1265
1163
|
|
|
1266
1164
|
<!-- changeset: datetime-stamp-on-publish -->
|
|
1267
1165
|
|
|
@@ -1276,13 +1174,151 @@ editor carries an unsaved draft of a stamped entry onto its stamped version.
|
|
|
1276
1174
|
The flag is refused off a top-level `datetime`, on `list: true`, and with `required: true`.
|
|
1277
1175
|
|
|
1278
1176
|
**To adopt.** Add `stampOnPublish: true` to the date field your site sorts or labels by, such as
|
|
1279
|
-
`{ name: 'publishedAt', type: 'datetime', stampOnPublish: true }`. See [Stamping a publication date](https://github.com/safeinsights/canopycms/blob/
|
|
1177
|
+
`{ name: 'publishedAt', type: 'datetime', stampOnPublish: true }`. See [Stamping a publication date](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#stamping-a-publication-date).
|
|
1280
1178
|
|
|
1281
1179
|
**Now deletable.** A build step or hook that writes a missing publication date into new entries.
|
|
1282
1180
|
|
|
1283
|
-
|
|
1181
|
+
#### A left activity rail and a docked content panel
|
|
1284
1182
|
|
|
1285
|
-
|
|
1183
|
+
<!-- changeset: editor-activity-rail -->
|
|
1184
|
+
|
|
1185
|
+
_First in 0.1.0._
|
|
1186
|
+
|
|
1187
|
+
**What changed.** A rail down the editor's left edge opens the content panel, quick open, the
|
|
1188
|
+
Branches and Comments drawers and the media library, with Settings and the account control at its
|
|
1189
|
+
foot. Comments open from the rail only, with the unresolved count on the button, and the media
|
|
1190
|
+
library has its own button instead of a Settings menu item. In a wide side-by-side window the
|
|
1191
|
+
content panel docks beside the preview and stays open as you move between entries. Its width and
|
|
1192
|
+
whether it is open survive a reload. Narrower than 1024px, or stacked, it lays over the form
|
|
1193
|
+
only, so the preview stays in view. Below 1024px the editor also starts stacked until you choose
|
|
1194
|
+
a layout. Notifications moved to the bottom-right corner, opposite the rail.
|
|
1195
|
+
|
|
1196
|
+
#### `editor.subtitle` removed; the tab names the open entry — **breaking (`editor.subtitle` removed)**
|
|
1197
|
+
|
|
1198
|
+
<!-- changeset: editor-subtitle-removed-tab-title -->
|
|
1199
|
+
|
|
1200
|
+
_First in 0.1.0._
|
|
1201
|
+
|
|
1202
|
+
**What changed.** `editor.subtitle` is no longer a config option, and `Editor` no longer takes
|
|
1203
|
+
`subtitle` or `siteSubtitle`: nothing has shown them since the top bar replaced the old header.
|
|
1204
|
+
While the editor is mounted, the browser tab reads "Entry label · Site title", or the site title
|
|
1205
|
+
with no entry open, and your page's own title comes back when it unmounts, unless a page navigated to has set its own.
|
|
1206
|
+
|
|
1207
|
+
**To adopt.** Delete `editor.subtitle` from your config; it was no longer shown.
|
|
1208
|
+
|
|
1209
|
+
#### The editor takes over the window — **breaking (`EditorPanes` export removed)**
|
|
1210
|
+
|
|
1211
|
+
<!-- changeset: editor-takes-over-the-window -->
|
|
1212
|
+
|
|
1213
|
+
_First in 0.1.0._
|
|
1214
|
+
|
|
1215
|
+
**What changed.** The editor renders as one full-window layer above your page, so a header or
|
|
1216
|
+
footer your root layout renders no longer pushes it down or makes the page scroll. While it is
|
|
1217
|
+
mounted, its sign-in and loading screens included, your layout's elements are hidden and out of
|
|
1218
|
+
the Tab order, and the page does not scroll; unmount restores them. The footer is gone: the version and an "About CanopyCMS" link are
|
|
1219
|
+
in the Settings menu. The two read-only banners sit in their own row under the header. The
|
|
1220
|
+
preview/form divider is now keyboard-resizable within the same 15–85% the split was always
|
|
1221
|
+
stored at, and `react-split-pane` is no longer a dependency.
|
|
1222
|
+
`EditorPanes`, `EditorPanesProps`, the `PaneLayout` type and the `SPLIT_PERCENT_*` and `DEFAULT_*_SPLIT_PERCENT` constants are
|
|
1223
|
+
no longer exported from `canopycms/client`. See
|
|
1224
|
+
[Your root layout](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#editor-customization).
|
|
1225
|
+
|
|
1226
|
+
**To adopt.** Nothing, unless you import `EditorPanes` or those constants: render `CanopyEditor`
|
|
1227
|
+
instead, which lays out its own panes. Hiding your site chrome on the editor route is now
|
|
1228
|
+
optional, but keeping analytics and global fetches out of it is still worthwhile.
|
|
1229
|
+
|
|
1230
|
+
**Now deletable.** A wrapper that drops the site header and footer on the editor route only to
|
|
1231
|
+
stop them shifting the editor.
|
|
1232
|
+
|
|
1233
|
+
#### The editor's top bar, with Save all — **behaviour change**
|
|
1234
|
+
|
|
1235
|
+
<!-- changeset: editor-top-bar-and-save-all -->
|
|
1236
|
+
|
|
1237
|
+
_First in 0.1.0._
|
|
1238
|
+
|
|
1239
|
+
**What changed.** The editor's header is a 48px top bar. Its breadcrumb's crumbs navigate: "All
|
|
1240
|
+
content" opens the content panel, and a collection crumb opens it on that collection. The open
|
|
1241
|
+
entry's crumb holds the entry menu, whose "Reload entry" is now "Refresh from server". A
|
|
1242
|
+
"Read-only" chip says why the entry or branch takes no edits. The branch pill shows the branch,
|
|
1243
|
+
its status and how many entries are unsaved, and its menu lists them; its "Reload all entries" is
|
|
1244
|
+
now "Refresh branch" and re-reads the entry list too. Beside Save, a caret offers "Save all", which
|
|
1245
|
+
saves every unsaved entry on the branch and names any it could not save, with the reason, keeping
|
|
1246
|
+
their changes. The site title and `editor.subtitle` no longer appear in the header; the rail's
|
|
1247
|
+
monogram carries the site title. Below 62em the breadcrumb takes its own row and the actions wrap, so no control is clipped. A content save refused because the
|
|
1248
|
+
branch is mid-rebase now carries `code: 'BRANCH_SYNCING'`.
|
|
1249
|
+
|
|
1250
|
+
**To adopt.** Nothing, unless your browser tests find the header by its old text: "Reload entry",
|
|
1251
|
+
"Reload all entries", "Recently modified", "No entry selected", or the file menu's "All content"
|
|
1252
|
+
item, which the breadcrumb's "All content" replaces.
|
|
1253
|
+
|
|
1254
|
+
#### Rename and delete from the entry menu; Save says "Saved" itself — **behaviour change**
|
|
1255
|
+
|
|
1256
|
+
<!-- changeset: entry-menu-rename-delete-inline-saved -->
|
|
1257
|
+
|
|
1258
|
+
_First in 0.1.0._
|
|
1259
|
+
|
|
1260
|
+
**What changed.** The open entry's menu, on its name in the top bar, offers "Rename…" and
|
|
1261
|
+
"Delete entry", through the same dialogs as the content panel's. On a locked branch both stay in
|
|
1262
|
+
the menu, blocked, with the reason; for an entry a path rule refuses they are hidden, as in the
|
|
1263
|
+
content panel. A Save reads "Saving…" on the button, then "Saved" for two seconds, announced to
|
|
1264
|
+
screen readers, instead of a green "Saved" toast; on a phone the button shows a spinner, then a
|
|
1265
|
+
check. Failures still show their toast or alert, and Save all its result. Save is the top bar's
|
|
1266
|
+
one filled button; "Submit for review" and "Withdraw from review" are tinted. From either menu,
|
|
1267
|
+
deleting the open entry leaves no entry open instead of opening the first, and renaming it keeps
|
|
1268
|
+
it open under its new name. The delete dialog names the entry.
|
|
1269
|
+
|
|
1270
|
+
**To adopt.** Nothing, unless your browser tests wait for a "Saved" toast after Save: wait for the
|
|
1271
|
+
save request's response, or for the Save button to read "Saved".
|
|
1272
|
+
|
|
1273
|
+
#### The preview has a toolbar with device widths, reload and the saved version
|
|
1274
|
+
|
|
1275
|
+
<!-- changeset: preview-toolbar -->
|
|
1276
|
+
|
|
1277
|
+
_First in 0.1.0._
|
|
1278
|
+
|
|
1279
|
+
**What changed.** A toolbar above the editor's preview shows the page's path on your site
|
|
1280
|
+
(without `editor.previewPrefix` or `?branch=`), which copies on click. Its width selector
|
|
1281
|
+
renders the page at Fit, Desktop (1280 px), Tablet (768 px) or Mobile (390 px): the iframe takes
|
|
1282
|
+
exactly that CSS width, so your site's own breakpoints apply, scaled down when the pane is
|
|
1283
|
+
narrower. The choice persists per browser. Reload reloads the preview, the same action as the
|
|
1284
|
+
"Live updates off" Retry. "Open saved version" opens the page's `?branch=` URL in a new tab,
|
|
1285
|
+
which shows the branch's last saved state, without unsaved edits. A preview error now sits
|
|
1286
|
+
between the toolbar and the page instead of over it, naming the field by its labels. A custom
|
|
1287
|
+
`renderPreview` gets no toolbar. `PreviewFrame` takes two new optional props, `iframeStyle` and
|
|
1288
|
+
`onReload`.
|
|
1289
|
+
|
|
1290
|
+
#### The preview toolbar holds the highlight toggle and maximizes the preview; the layout toggle moves to the rail
|
|
1291
|
+
|
|
1292
|
+
<!-- changeset: preview-toolbar-controls -->
|
|
1293
|
+
|
|
1294
|
+
_First in 0.1.0._
|
|
1295
|
+
|
|
1296
|
+
**What changed.** The highlight toggle moves from the strip at the editor's right edge into the
|
|
1297
|
+
preview toolbar, and the layout toggle into the rail, above Settings, so it works with any
|
|
1298
|
+
preview or none; the strip is gone. The layout button shows the current layout and switches to
|
|
1299
|
+
the other; while the preview is maximized it says to restore the preview first. Layout, preview
|
|
1300
|
+
width and highlights persist per browser. Maximize lays the preview over the preview and form
|
|
1301
|
+
area, without reloading it, and drafts keep reaching it. Restore brings the form back, and so
|
|
1302
|
+
does Esc unless focus is inside the page. Anything that needs the form restores it too: a click
|
|
1303
|
+
on a highlighted element, which scrolls to its field, opening the content panel over the form,
|
|
1304
|
+
or a save refused for field errors. Dragging the divider between preview and form shows the
|
|
1305
|
+
preview's width over it, and resizing the panes, by drag or key, switches the width to Fit.
|
|
1306
|
+
Admins with highlights on see an "N unmapped" chip when the page marks fields that don't exist
|
|
1307
|
+
in the entry. It explains what that means and points to the browser console, which names the
|
|
1308
|
+
nearest field of each. Editors see no such diagnostics. A custom `renderPreview`, and an entry
|
|
1309
|
+
with no preview page, get no toolbar.
|
|
1310
|
+
|
|
1311
|
+
#### Linear-time mount paths and push refusals, and a fixed message for non-Error gateway failures — **security fix**
|
|
1312
|
+
|
|
1313
|
+
<!-- changeset: codeql-release-alerts -->
|
|
1314
|
+
|
|
1315
|
+
_First in 0.1.0._
|
|
1316
|
+
|
|
1317
|
+
**What changed.** The AI export trims slashes from `AIContentConfig.mountPath`, and the worker
|
|
1318
|
+
and its GitHub gateway recognise GitHub's refusal of a workflow push, in time linear in their
|
|
1319
|
+
length; a long run of slashes or a repeated phrase took seconds before. When the gateway fails with
|
|
1320
|
+
a thrown value that is not an `Error`, the worker gets a fixed message and the gateway's log gets
|
|
1321
|
+
the value, scrubbed and capped, since it could hold a stack.
|
|
1286
1322
|
|
|
1287
1323
|
### 0.0.67
|
|
1288
1324
|
|
|
@@ -1296,7 +1332,7 @@ never ended. `canopycms-auth-clerk` skips it while the editor is mounted, and ex
|
|
|
1296
1332
|
**To adopt.** Nothing for the editor, if your edit page uses `useClerkAuthConfig()` or
|
|
1297
1333
|
`ClerkSignIn`. If your CMS build renders `<SignIn>`, `UserButton` or `OrganizationSwitcher` on your
|
|
1298
1334
|
own pages, mount the hook as in
|
|
1299
|
-
[Clerk components on your own pages](https://github.com/safeinsights/canopycms/blob/
|
|
1335
|
+
[Clerk components on your own pages](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/packages/canopycms-auth-clerk/README.md#clerk-components-on-your-own-pages).
|
|
1300
1336
|
Your own Server Actions in the CMS build still 403 behind OAC.
|
|
1301
1337
|
|
|
1302
1338
|
**Now deletable.** Any local patch of `window.__internal_onBeforeSetActive` (or 6.x's
|
|
@@ -1337,12 +1373,12 @@ fast naming the ARN, the field and the keys present, never a value.
|
|
|
1337
1373
|
**To adopt.** Nothing, unless one of those secrets holds a JSON document: then set the matching
|
|
1338
1374
|
prop. The scaffolded stack fills them from the repository _variables_
|
|
1339
1375
|
`CANOPY_GITHUB_TOKEN_SECRET_JSON_FIELD` and `CLERK_SECRET_KEY_SECRET_JSON_FIELD`
|
|
1340
|
-
([why the prefix](https://github.com/safeinsights/canopycms/blob/
|
|
1376
|
+
([why the prefix](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#repository-secrets-and-variables)); a stack scaffolded earlier
|
|
1341
1377
|
adds the props to `infrastructure/bin/app.ts` and `infrastructure/lib/cms-stack.ts` and the two `env`
|
|
1342
1378
|
lines to `.github/workflows/deploy-cms.yml`, or re-runs the generator and diffs. `cdk synth` refuses a `…JsonField` prop without its `…SecretArn`, and an ARN carrying the ECS `:KEY::` suffix
|
|
1343
1379
|
(also in `secretsArns`). Don't use CDK's `secretValueFromJson`: it resolves the plaintext into the deployed
|
|
1344
1380
|
resource's configuration, readable by anyone who can describe it. Only `CLERK_SECRET_KEY` goes through Secrets Manager; `CLERK_JWT_KEY` and the publishable
|
|
1345
|
-
key are public material ([Security Model](https://github.com/safeinsights/canopycms/blob/
|
|
1381
|
+
key are public material ([Security Model](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#security-model)).
|
|
1346
1382
|
|
|
1347
1383
|
**Now deletable.** A wrapper that fetches the secret, parses it and re-exports one field into the
|
|
1348
1384
|
worker's environment, such as a `jq` step in user data or a wrapper entrypoint around
|
|
@@ -1354,7 +1390,7 @@ worker's environment, such as a `jq` step in user data or a wrapper entrypoint a
|
|
|
1354
1390
|
`githubToken` is not deprecated and stays the documented default; `canopycms` neither depends on
|
|
1355
1391
|
nor imports `@octokit/auth-app`. Register one App per site, not one shared across repositories:
|
|
1356
1392
|
anyone holding an App's key can mint a token for any of its installations
|
|
1357
|
-
([why](https://github.com/safeinsights/canopycms/blob/
|
|
1393
|
+
([why](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/ARCHITECTURE.md#why-one-github-app-per-site-not-one-shared-across-an-organisation)).
|
|
1358
1394
|
|
|
1359
1395
|
**To adopt with `canopycms-cdk`** (existing stacks need no edit). `CanopyCmsServiceProps` takes
|
|
1360
1396
|
`githubAppId`, `githubAppInstallationId`, `githubAppPrivateKeySecretArn` and
|
|
@@ -1367,7 +1403,7 @@ anyone holding an App's key can mint a token for any of its installations
|
|
|
1367
1403
|
`verify` checks an existing installation's permissions: run it, since an App missing a
|
|
1368
1404
|
permission only shows up later, as `sync-failed`. `create` needs an interactive terminal and
|
|
1369
1405
|
never edits an existing JSON secret (create one and point the JSON-field prop at it)
|
|
1370
|
-
([details](https://github.com/safeinsights/canopycms/blob/
|
|
1406
|
+
([details](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#register-it-with-canopycms-init-github-app)).
|
|
1371
1407
|
2. Set the three props and **remove `githubTokenSecretArn`** (with its JSON field). A partial set
|
|
1372
1408
|
of the three is refused at synth, and so is an App alongside a token.
|
|
1373
1409
|
3. In the generated workflow, store them as `CANOPY_GITHUB_APP_ID`,
|
|
@@ -1378,7 +1414,7 @@ anyone holding an App's key can mint a token for any of its installations
|
|
|
1378
1414
|
|
|
1379
1415
|
The private key is ARN-only; passing the key itself is refused at synth. Its ARN joins the worker's
|
|
1380
1416
|
IAM policy automatically, so you need not add it to `secretsArns`. See
|
|
1381
|
-
[Authenticating as a GitHub App](https://github.com/safeinsights/canopycms/blob/
|
|
1417
|
+
[Authenticating as a GitHub App](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#authenticating-as-a-github-app).
|
|
1382
1418
|
|
|
1383
1419
|
```bash
|
|
1384
1420
|
canopycms init-github-app create -- \
|
|
@@ -1426,7 +1462,7 @@ downloads the `.pem` from the App's settings page.
|
|
|
1426
1462
|
|
|
1427
1463
|
**What changed.** The worker re-reads a Secrets Manager secret (the GitHub token or the Clerk secret
|
|
1428
1464
|
key) when the operation using it fails. Timings, costs and the store-before-revoke order are in
|
|
1429
|
-
[Rotating a secret](https://github.com/safeinsights/canopycms/blob/
|
|
1465
|
+
[Rotating a secret](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#rotating-a-secret).
|
|
1430
1466
|
|
|
1431
1467
|
**To adopt.** Nothing for credentials from `*_SECRET_ARN`, which is every scaffolded deployment. A
|
|
1432
1468
|
GitHub App private key is still read only at boot: store the new key, replace the instance, and
|
|
@@ -1480,12 +1516,12 @@ also check the bucket policy for its grant.
|
|
|
1480
1516
|
5. `withCanopy()` adds sharp's libvips to Next's file tracing (not for a static export) and, on
|
|
1481
1517
|
Next 16 and later, sets `turbopack: {}` when your config has neither `turbopack` nor your own
|
|
1482
1518
|
`webpack` and it can read your Next version. A webpack build still fails its image transforms
|
|
1483
|
-
([Dual Build Support](https://github.com/safeinsights/canopycms/blob/
|
|
1519
|
+
([Dual Build Support](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#dual-build-support)).
|
|
1484
1520
|
|
|
1485
1521
|
**Breaking:** a stack setting `platform` on `fromImageAsset` without `architecture` gets an arm64
|
|
1486
1522
|
function while `platform` still decides the image, so `Platform.LINUX_AMD64` builds an image the
|
|
1487
1523
|
function cannot run. A stack setting neither moves to arm64 with a matching image, built under QEMU
|
|
1488
|
-
on an x86 host ([Where the image is built](https://github.com/safeinsights/canopycms/blob/
|
|
1524
|
+
on an x86 host ([Where the image is built](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#where-the-image-is-built)).
|
|
1489
1525
|
|
|
1490
1526
|
**To adopt.**
|
|
1491
1527
|
|
|
@@ -1514,7 +1550,7 @@ reason; `platform` on `fromImageAsset`; and, with `withCanopy()`, a hand-written
|
|
|
1514
1550
|
|
|
1515
1551
|
**What changed.** `media.uploadUrl` (s3 adapter; an absolute http(s) URL or a site-relative path)
|
|
1516
1552
|
replaces the `url` that `beginUpload()` returns, leaving the presign's `fields` untouched, so
|
|
1517
|
-
uploads can be same-origin. See [Media Configuration](https://github.com/safeinsights/canopycms/blob/
|
|
1553
|
+
uploads can be same-origin. See [Media Configuration](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#media-configuration) for the
|
|
1518
1554
|
CloudFront behavior it expects.
|
|
1519
1555
|
|
|
1520
1556
|
**To adopt.** Optional. Set it from an environment variable: a site-relative value works only where
|
|
@@ -1539,7 +1575,7 @@ needs `lazyPublicTransforms: true`) let you pass a deterministically named role,
|
|
|
1539
1575
|
bucket's stack computes `arn:aws:iam::<account>:role/<name>` from literals instead of a
|
|
1540
1576
|
`Fn::GetStackOutput` reference only the CDK CLI resolves. The constructs re-attach
|
|
1541
1577
|
`AWSLambdaBasicExecutionRole` (and the VPC policy) that `lambda.Function` drops from a role you
|
|
1542
|
-
pass. See [Cross-account asset bucket](https://github.com/safeinsights/canopycms/blob/
|
|
1578
|
+
pass. See [Cross-account asset bucket](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#cross-account-asset-bucket).
|
|
1543
1579
|
|
|
1544
1580
|
**To adopt.** Optional:
|
|
1545
1581
|
|
|
@@ -1649,7 +1685,7 @@ public JWKS PEM, used only to verify signatures.
|
|
|
1649
1685
|
to variables (Settings → Secrets and variables → Actions → Variables); `bin/app.ts` refuses the
|
|
1650
1686
|
deploy at synth while it is unset. Check that `bin/app.ts` passes `CLERK_SECRET_KEY` as
|
|
1651
1687
|
`clerkSecretKeySecretArn` (read by the worker), never in the Lambda's `environment`, unless you keep
|
|
1652
|
-
`clerkMiddleware` ([Security Model](https://github.com/safeinsights/canopycms/blob/
|
|
1688
|
+
`clerkMiddleware` ([Security Model](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/docs/deploying-to-aws.md#security-model)).
|
|
1653
1689
|
|
|
1654
1690
|
#### `readByUrlPath` answers only where `listEntries` publishes — **breaking (routing)**
|
|
1655
1691
|
|
|
@@ -1748,7 +1784,7 @@ basePath: process.env.NEXT_PUBLIC_BASE_PATH,
|
|
|
1748
1784
|
Then pass `baseUrl` to `assetUrl` only if Next serves `/assets` (local adapter, `next dev`, S3 with
|
|
1749
1785
|
no distribution): `assetUrl(image, { width: 960, baseUrl: BASE_PATH })`. Assets on CloudFront via
|
|
1750
1786
|
`AssetSupport` stay at the distribution root; pass no `baseUrl` (mount table under "Where `/assets`
|
|
1751
|
-
is mounted" in [Media Configuration](https://github.com/safeinsights/canopycms/blob/
|
|
1787
|
+
is mounted" in [Media Configuration](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#media-configuration)). Two traps:
|
|
1752
1788
|
|
|
1753
1789
|
- Don't pass a deployment `basePath` to `contentStaticParams({ basePath })`; that option filters by
|
|
1754
1790
|
a nested route prefix and emits zero params, building green.
|
|
@@ -1907,7 +1943,7 @@ Under `exactOptionalPropertyTypes: true`, omit keys instead of assigning `undefi
|
|
|
1907
1943
|
`withTrailingSlash` and `isAbsoluteUrl` from `canopycms/server`; `defineSeoFieldGroup()` from
|
|
1908
1944
|
`canopycms`; `generateContentSitemap` and `entryToMetadata` from `canopycms-next`, bound on
|
|
1909
1945
|
`createNextCanopyContext`'s result. See
|
|
1910
|
-
[Sitemap and SEO Metadata](https://github.com/safeinsights/canopycms/blob/
|
|
1946
|
+
[Sitemap and SEO Metadata](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#sitemap-and-seo-metadata). Every routable entry type is in
|
|
1911
1947
|
the sitemap unless `exclude`d or `noindex`; one `noindex` predicate drives both robots metadata and
|
|
1912
1948
|
sitemap exclusion. `trailingSlash` is never inferred. `lastModified` defaults to `updatedAt`, a
|
|
1913
1949
|
filesystem mtime. An empty SEO field counts as unset. `siteUrl` must be absolute, colliding URLs are
|
|
@@ -1964,7 +2000,7 @@ underscore-prefixed files are skipped.
|
|
|
1964
2000
|
|
|
1965
2001
|
**What changed.** New scaffolds write `defaultBranchAccess: 'deny'` and
|
|
1966
2002
|
`defaultPathAccess: { read: 'allow' }`
|
|
1967
|
-
([Public read on server deployments](https://github.com/safeinsights/canopycms/blob/
|
|
2003
|
+
([Public read on server deployments](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#public-read-on-server-deployments)).
|
|
1968
2004
|
|
|
1969
2005
|
**To adopt.** An older scaffold's `defaultBranchAccess: 'allow'` is wider than recommended;
|
|
1970
2006
|
consider `'deny'`. If you deleted `defaultPathAccess: { read: 'allow' }`, anonymous visitors get no content until you
|
|
@@ -2017,7 +2053,7 @@ re-checked an entry's type (a `switch` on `meta.entryType` can merge them into o
|
|
|
2017
2053
|
**What changed.** `BlockComponentRegistry<Blocks>` (types only, from `canopycms`; `BlockValueOf<Blocks, 'hero'>`
|
|
2018
2054
|
gives one template's value type) requires exactly
|
|
2019
2055
|
one component per block template name when written as an object literal. See
|
|
2020
|
-
[Block Component Registries](https://github.com/safeinsights/canopycms/blob/
|
|
2056
|
+
[Block Component Registries](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#block-component-registries) and
|
|
2021
2057
|
`apps/example1/app/components/PostView.tsx`.
|
|
2022
2058
|
|
|
2023
2059
|
```ts
|
|
@@ -2039,7 +2075,7 @@ templates against the schema.
|
|
|
2039
2075
|
|
|
2040
2076
|
**What changed.** Spreading a `const` field array into several schemas, and nesting
|
|
2041
2077
|
`defineInlineFieldGroup()` inside a block template, are documented
|
|
2042
|
-
([Reusable Field Fragments](https://github.com/safeinsights/canopycms/blob/
|
|
2078
|
+
([Reusable Field Fragments](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#reusable-field-fragments)); `defineFieldFragment()` is an
|
|
2043
2079
|
identity helper for them.
|
|
2044
2080
|
|
|
2045
2081
|
```ts
|
|
@@ -2058,7 +2094,7 @@ field by composing from the same `const` field object.
|
|
|
2058
2094
|
A block template holding a `reference` field is a shared block; `read()`/`readByUrlPath()` resolve
|
|
2059
2095
|
it, and listings do with
|
|
2060
2096
|
[`resolveReferences`](#listings-resolve-references-and-a-resolved-reference-carries-urlpath-and-optionally-its-body-16--breaking-type-level)
|
|
2061
|
-
(0.0.64). See [Shared / Referenced Blocks](https://github.com/safeinsights/canopycms/blob/
|
|
2097
|
+
(0.0.64). See [Shared / Referenced Blocks](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#shared--referenced-blocks).
|
|
2062
2098
|
|
|
2063
2099
|
**Now deletable.** A second `read()` in page code to unwrap a shared block's reference.
|
|
2064
2100
|
|
|
@@ -2080,7 +2116,7 @@ Not retro-documented, apart from these:
|
|
|
2080
2116
|
|
|
2081
2117
|
#### The registry is keyed by entry-type name (0.0.42)
|
|
2082
2118
|
|
|
2083
|
-
**What changed.** `createEntrySchemaRegistry` keys are the entry-type names that `.collection.json` files name in `entry.schema`, and `EntryTypesFromRegistry` derives the typed entry-type map from them. Schema-variable keys (`{ postSchema }`) still work but derive nothing; [README's registry convention](https://github.com/safeinsights/canopycms/blob/
|
|
2119
|
+
**What changed.** `createEntrySchemaRegistry` keys are the entry-type names that `.collection.json` files name in `entry.schema`, and `EntryTypesFromRegistry` derives the typed entry-type map from them. Schema-variable keys (`{ postSchema }`) still work but derive nothing; [README's registry convention](https://github.com/safeinsights/canopycms/blob/39a755c116a52b6d16e0b09e9dde03c67a081754/README.md#convention-why-key-the-registry-by-entry-type-name) says when to keep them.
|
|
2084
2120
|
|
|
2085
2121
|
**To adopt.**
|
|
2086
2122
|
|