canopycms 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/plugin.d.ts +8 -0
- package/dist/auth/plugin.d.ts.map +1 -1
- package/dist/build-mode.d.ts +15 -5
- package/dist/build-mode.d.ts.map +1 -1
- package/dist/build-mode.js +18 -8
- package/dist/build-mode.js.map +1 -1
- package/dist/cli/init.d.ts +2 -2
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +37 -36
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/template-files/ai-config.ts.template +21 -0
- package/dist/cli/template-files/ai-route.ts.template +10 -0
- package/dist/cli/template-files/canopy.ts.template +24 -0
- package/dist/cli/templates.d.ts +5 -1
- package/dist/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +9 -2
- package/dist/cli/templates.js.map +1 -1
- package/dist/config/schemas/config.d.ts +4 -0
- package/dist/config/schemas/config.d.ts.map +1 -1
- package/dist/config/schemas/config.js +2 -0
- package/dist/config/schemas/config.js.map +1 -1
- package/dist/config/types.d.ts +5 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/content-reader.js +2 -2
- package/dist/content-reader.js.map +1 -1
- package/dist/context.js +5 -5
- package/dist/context.js.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.d.ts.map +1 -1
- package/dist/operating-mode/client-unsafe-strategy.js +15 -18
- package/dist/operating-mode/client-unsafe-strategy.js.map +1 -1
- package/dist/operating-mode/types.d.ts +8 -0
- package/dist/operating-mode/types.d.ts.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/package.json +5 -4
- package/src/cli/init.ts +43 -38
- package/dist/__integration__/fixtures/content-seeds.d.ts +0 -43
- package/dist/__integration__/fixtures/content-seeds.d.ts.map +0 -1
- package/dist/__integration__/fixtures/content-seeds.js +0 -99
- package/dist/__integration__/fixtures/content-seeds.js.map +0 -1
- package/dist/__integration__/fixtures/schemas.d.ts +0 -12
- package/dist/__integration__/fixtures/schemas.d.ts.map +0 -1
- package/dist/__integration__/fixtures/schemas.js +0 -65
- package/dist/__integration__/fixtures/schemas.js.map +0 -1
- package/dist/__integration__/test-utils/api-client.d.ts +0 -123
- package/dist/__integration__/test-utils/api-client.d.ts.map +0 -1
- package/dist/__integration__/test-utils/api-client.js +0 -118
- package/dist/__integration__/test-utils/api-client.js.map +0 -1
- package/dist/__integration__/test-utils/multi-user.d.ts +0 -25
- package/dist/__integration__/test-utils/multi-user.d.ts.map +0 -1
- package/dist/__integration__/test-utils/multi-user.js +0 -105
- package/dist/__integration__/test-utils/multi-user.js.map +0 -1
- package/dist/__integration__/test-utils/test-workspace.d.ts +0 -25
- package/dist/__integration__/test-utils/test-workspace.d.ts.map +0 -1
- package/dist/__integration__/test-utils/test-workspace.js +0 -102
- package/dist/__integration__/test-utils/test-workspace.js.map +0 -1
- package/dist/editor/BranchManager.stories.d.ts +0 -8
- package/dist/editor/BranchManager.stories.d.ts.map +0 -1
- package/dist/editor/BranchManager.stories.js +0 -74
- package/dist/editor/BranchManager.stories.js.map +0 -1
- package/dist/editor/CanopyEditor.stories.d.ts +0 -7
- package/dist/editor/CanopyEditor.stories.d.ts.map +0 -1
- package/dist/editor/CanopyEditor.stories.js +0 -99
- package/dist/editor/CanopyEditor.stories.js.map +0 -1
- package/dist/editor/CommentsPanel.stories.d.ts +0 -10
- package/dist/editor/CommentsPanel.stories.d.ts.map +0 -1
- package/dist/editor/CommentsPanel.stories.js +0 -175
- package/dist/editor/CommentsPanel.stories.js.map +0 -1
- package/dist/editor/Editor.stories.d.ts +0 -7
- package/dist/editor/Editor.stories.d.ts.map +0 -1
- package/dist/editor/Editor.stories.js +0 -95
- package/dist/editor/Editor.stories.js.map +0 -1
- package/dist/editor/EditorPanes.stories.d.ts +0 -7
- package/dist/editor/EditorPanes.stories.d.ts.map +0 -1
- package/dist/editor/EditorPanes.stories.js +0 -116
- package/dist/editor/EditorPanes.stories.js.map +0 -1
- package/dist/editor/EntryNavigator.stories.d.ts +0 -8
- package/dist/editor/EntryNavigator.stories.d.ts.map +0 -1
- package/dist/editor/EntryNavigator.stories.js +0 -42
- package/dist/editor/EntryNavigator.stories.js.map +0 -1
- package/dist/editor/FormRenderer.stories.d.ts +0 -7
- package/dist/editor/FormRenderer.stories.d.ts.map +0 -1
- package/dist/editor/FormRenderer.stories.js +0 -115
- package/dist/editor/FormRenderer.stories.js.map +0 -1
- package/dist/editor/GroupManager.stories.d.ts +0 -19
- package/dist/editor/GroupManager.stories.d.ts.map +0 -1
- package/dist/editor/GroupManager.stories.js +0 -265
- package/dist/editor/GroupManager.stories.js.map +0 -1
- package/dist/editor/PermissionManager.stories.d.ts +0 -20
- package/dist/editor/PermissionManager.stories.d.ts.map +0 -1
- package/dist/editor/PermissionManager.stories.js +0 -506
- package/dist/editor/PermissionManager.stories.js.map +0 -1
- package/dist/editor/comments/FieldWrapper.stories.d.ts +0 -10
- package/dist/editor/comments/FieldWrapper.stories.d.ts.map +0 -1
- package/dist/editor/comments/FieldWrapper.stories.js +0 -173
- package/dist/editor/comments/FieldWrapper.stories.js.map +0 -1
- package/dist/editor/fields/BlockField.stories.d.ts +0 -7
- package/dist/editor/fields/BlockField.stories.d.ts.map +0 -1
- package/dist/editor/fields/BlockField.stories.js +0 -50
- package/dist/editor/fields/BlockField.stories.js.map +0 -1
- package/dist/editor/fields/fields.stories.d.ts +0 -8
- package/dist/editor/fields/fields.stories.d.ts.map +0 -1
- package/dist/editor/fields/fields.stories.js +0 -34
- package/dist/editor/fields/fields.stories.js.map +0 -1
- package/dist/test-utils/api-test-helpers.d.ts +0 -238
- package/dist/test-utils/api-test-helpers.d.ts.map +0 -1
- package/dist/test-utils/api-test-helpers.js +0 -347
- package/dist/test-utils/api-test-helpers.js.map +0 -1
- package/dist/test-utils/console-spy.d.ts +0 -56
- package/dist/test-utils/console-spy.d.ts.map +0 -1
- package/dist/test-utils/console-spy.js +0 -81
- package/dist/test-utils/console-spy.js.map +0 -1
- package/dist/test-utils/git-helpers.d.ts +0 -21
- package/dist/test-utils/git-helpers.d.ts.map +0 -1
- package/dist/test-utils/git-helpers.js +0 -23
- package/dist/test-utils/git-helpers.js.map +0 -1
- package/dist/test-utils/index.d.ts +0 -5
- package/dist/test-utils/index.d.ts.map +0 -1
- package/dist/test-utils/index.js +0 -4
- package/dist/test-utils/index.js.map +0 -1
- package/src/__integration__/errors/invalid-content.test.ts +0 -238
- package/src/__integration__/errors/permission-denied.test.ts +0 -220
- package/src/__integration__/fixtures/content-seeds.ts +0 -105
- package/src/__integration__/fixtures/schemas.ts +0 -67
- package/src/__integration__/initialization/prod-sim-init.test.ts +0 -139
- package/src/__integration__/permissions/path-permissions.test.ts +0 -314
- package/src/__integration__/permissions/role-permissions.test.ts +0 -354
- package/src/__integration__/permissions/settings-branch-isolation.test.ts +0 -317
- package/src/__integration__/settings/groups-api.test.ts +0 -403
- package/src/__integration__/test-utils/api-client.ts +0 -167
- package/src/__integration__/test-utils/multi-user.ts +0 -129
- package/src/__integration__/test-utils/test-workspace.ts +0 -130
- package/src/__integration__/user/user-context.test.ts +0 -174
- package/src/__integration__/validation/input-validation.test.ts +0 -166
- package/src/__integration__/workflows/api-editing-workflow.test.ts +0 -244
- package/src/__integration__/workflows/conflict-resolution.test.ts +0 -259
- package/src/__integration__/workflows/editing-workflow.test.ts +0 -205
- package/src/__integration__/workflows/review-workflow.test.ts +0 -260
- package/src/ai/__tests__/build.integration.test.ts +0 -224
- package/src/ai/__tests__/generate.integration.test.ts +0 -495
- package/src/ai/__tests__/handler.integration.test.ts +0 -212
- package/src/ai/__tests__/json-to-markdown.test.ts +0 -553
- package/src/ai/generate.ts +0 -410
- package/src/ai/handler.ts +0 -123
- package/src/ai/index.ts +0 -26
- package/src/ai/json-to-markdown.ts +0 -424
- package/src/ai/resolve-branch.ts +0 -34
- package/src/ai/types.ts +0 -160
- package/src/api/AGENTS.md +0 -81
- package/src/api/__test__/mock-client.ts +0 -404
- package/src/api/assets.test.ts +0 -140
- package/src/api/assets.ts +0 -154
- package/src/api/branch-merge.test.ts +0 -163
- package/src/api/branch-merge.ts +0 -113
- package/src/api/branch-review.test.ts +0 -297
- package/src/api/branch-review.ts +0 -136
- package/src/api/branch-status.test.ts +0 -85
- package/src/api/branch-status.ts +0 -153
- package/src/api/branch-withdraw.test.ts +0 -146
- package/src/api/branch-withdraw.ts +0 -81
- package/src/api/branch-workflow.integration.test.ts +0 -578
- package/src/api/branch.test.ts +0 -620
- package/src/api/branch.ts +0 -492
- package/src/api/client.test.ts +0 -349
- package/src/api/client.ts +0 -506
- package/src/api/comments.test.ts +0 -285
- package/src/api/comments.ts +0 -210
- package/src/api/content.test.ts +0 -345
- package/src/api/content.ts +0 -454
- package/src/api/entries.test.ts +0 -1339
- package/src/api/entries.ts +0 -650
- package/src/api/github-sync.ts +0 -144
- package/src/api/groups.test.ts +0 -1013
- package/src/api/groups.ts +0 -375
- package/src/api/guards.test.ts +0 -533
- package/src/api/guards.ts +0 -271
- package/src/api/index.ts +0 -87
- package/src/api/permissions.test.ts +0 -766
- package/src/api/permissions.ts +0 -334
- package/src/api/reference-options.ts +0 -118
- package/src/api/resolve-references.ts +0 -107
- package/src/api/route-builder.ts +0 -289
- package/src/api/schema.test.ts +0 -840
- package/src/api/schema.ts +0 -936
- package/src/api/security.test.ts +0 -233
- package/src/api/settings-helpers.ts +0 -84
- package/src/api/types.ts +0 -40
- package/src/api/user.test.ts +0 -127
- package/src/api/user.ts +0 -42
- package/src/api/validators.test.ts +0 -275
- package/src/api/validators.ts +0 -176
- package/src/asset-store.test.ts +0 -37
- package/src/asset-store.ts +0 -110
- package/src/auth/cache.ts +0 -7
- package/src/auth/caching-auth-plugin.test.ts +0 -154
- package/src/auth/caching-auth-plugin.ts +0 -109
- package/src/auth/context-helpers.ts +0 -75
- package/src/auth/file-based-auth-cache.test.ts +0 -257
- package/src/auth/file-based-auth-cache.ts +0 -279
- package/src/auth/index.ts +0 -12
- package/src/auth/plugin.ts +0 -51
- package/src/auth/types.ts +0 -38
- package/src/authorization/__tests__/branch.test.ts +0 -260
- package/src/authorization/__tests__/content.test.ts +0 -142
- package/src/authorization/__tests__/path.test.ts +0 -133
- package/src/authorization/__tests__/permissions-loader.test.ts +0 -200
- package/src/authorization/branch.ts +0 -94
- package/src/authorization/content.ts +0 -93
- package/src/authorization/groups/index.ts +0 -11
- package/src/authorization/groups/loader.ts +0 -127
- package/src/authorization/groups/schema.ts +0 -48
- package/src/authorization/helpers.ts +0 -48
- package/src/authorization/index.ts +0 -84
- package/src/authorization/path.ts +0 -112
- package/src/authorization/permissions/index.ts +0 -11
- package/src/authorization/permissions/loader.ts +0 -116
- package/src/authorization/permissions/schema.ts +0 -66
- package/src/authorization/test-utils.ts +0 -15
- package/src/authorization/types.ts +0 -66
- package/src/authorization/validation.test.ts +0 -100
- package/src/authorization/validation.ts +0 -62
- package/src/branch-metadata.test.ts +0 -168
- package/src/branch-metadata.ts +0 -166
- package/src/branch-registry.test.ts +0 -248
- package/src/branch-registry.ts +0 -152
- package/src/branch-schema-cache.test.ts +0 -275
- package/src/branch-schema-cache.ts +0 -189
- package/src/branch-workspace.test.ts +0 -183
- package/src/branch-workspace.ts +0 -124
- package/src/build/generate-ai-content.ts +0 -78
- package/src/build/index.ts +0 -8
- package/src/build-mode.ts +0 -27
- package/src/cli/generate-ai-content.ts +0 -100
- package/src/cli/init.test.ts +0 -240
- package/src/cli/templates/canopy.ts.template +0 -55
- package/src/cli/templates.ts +0 -47
- package/src/client.ts +0 -12
- package/src/comment-store.test.ts +0 -442
- package/src/comment-store.ts +0 -301
- package/src/config/__tests__/config.test.ts +0 -513
- package/src/config/flatten.ts +0 -174
- package/src/config/helpers.ts +0 -167
- package/src/config/index.ts +0 -86
- package/src/config/schemas/collection.ts +0 -67
- package/src/config/schemas/config.ts +0 -77
- package/src/config/schemas/field.ts +0 -108
- package/src/config/schemas/media.ts +0 -27
- package/src/config/schemas/permissions.ts +0 -21
- package/src/config/types.ts +0 -321
- package/src/config/validation.ts +0 -70
- package/src/config-test.ts +0 -65
- package/src/config.ts +0 -11
- package/src/content-id-index.test.ts +0 -512
- package/src/content-id-index.ts +0 -479
- package/src/content-reader.test.ts +0 -478
- package/src/content-reader.ts +0 -214
- package/src/content-store.test.ts +0 -1126
- package/src/content-store.ts +0 -793
- package/src/context.ts +0 -111
- package/src/editor/BranchManager.stories.tsx +0 -80
- package/src/editor/BranchManager.test.tsx +0 -324
- package/src/editor/BranchManager.tsx +0 -461
- package/src/editor/CanopyEditor.stories.tsx +0 -128
- package/src/editor/CanopyEditor.test.tsx +0 -81
- package/src/editor/CanopyEditor.tsx +0 -73
- package/src/editor/CanopyEditorPage.test.tsx +0 -59
- package/src/editor/CanopyEditorPage.tsx +0 -25
- package/src/editor/CommentsPanel.stories.tsx +0 -184
- package/src/editor/CommentsPanel.tsx +0 -338
- package/src/editor/Editor.integration.test.tsx +0 -227
- package/src/editor/Editor.stories.tsx +0 -119
- package/src/editor/Editor.tsx +0 -1221
- package/src/editor/EditorPanes.stories.tsx +0 -256
- package/src/editor/EditorPanes.test.tsx +0 -77
- package/src/editor/EditorPanes.tsx +0 -180
- package/src/editor/EntryNavigator.stories.tsx +0 -65
- package/src/editor/EntryNavigator.test.tsx +0 -598
- package/src/editor/EntryNavigator.tsx +0 -665
- package/src/editor/FormRenderer.stories.tsx +0 -212
- package/src/editor/FormRenderer.test.tsx +0 -194
- package/src/editor/FormRenderer.tsx +0 -432
- package/src/editor/GroupManager.stories.tsx +0 -301
- package/src/editor/GroupManager.test.tsx +0 -682
- package/src/editor/GroupManager.tsx +0 -9
- package/src/editor/PermissionManager.stories.tsx +0 -539
- package/src/editor/PermissionManager.test.tsx +0 -864
- package/src/editor/PermissionManager.tsx +0 -12
- package/src/editor/canopy-path.test.ts +0 -23
- package/src/editor/canopy-path.ts +0 -52
- package/src/editor/client-reference-resolver.ts +0 -118
- package/src/editor/comments/BranchComments.tsx +0 -93
- package/src/editor/comments/EntryComments.tsx +0 -94
- package/src/editor/comments/FieldWrapper.stories.tsx +0 -210
- package/src/editor/comments/FieldWrapper.tsx +0 -129
- package/src/editor/comments/InlineCommentThread.test.tsx +0 -384
- package/src/editor/comments/InlineCommentThread.tsx +0 -246
- package/src/editor/comments/ThreadCarousel.test.tsx +0 -393
- package/src/editor/comments/ThreadCarousel.tsx +0 -525
- package/src/editor/components/ConfirmDeleteModal.tsx +0 -49
- package/src/editor/components/EditorContext.tsx +0 -49
- package/src/editor/components/EditorFooter.tsx +0 -47
- package/src/editor/components/EditorHeader.tsx +0 -492
- package/src/editor/components/EditorSidebar.tsx +0 -193
- package/src/editor/components/EntryCreateModal.tsx +0 -193
- package/src/editor/components/RenameEntryModal.tsx +0 -152
- package/src/editor/components/UserBadge.test.tsx +0 -274
- package/src/editor/components/UserBadge.tsx +0 -240
- package/src/editor/components/index.ts +0 -6
- package/src/editor/context/ApiClientContext.tsx +0 -56
- package/src/editor/context/EditorStateContext.tsx +0 -221
- package/src/editor/context/index.ts +0 -40
- package/src/editor/editor-config.test.ts +0 -385
- package/src/editor/editor-config.ts +0 -94
- package/src/editor/editor-utils.test.ts +0 -772
- package/src/editor/editor-utils.ts +0 -303
- package/src/editor/env.ts +0 -4
- package/src/editor/fields/BlockField.stories.tsx +0 -79
- package/src/editor/fields/BlockField.tsx +0 -267
- package/src/editor/fields/CodeField.tsx +0 -41
- package/src/editor/fields/MarkdownField.tsx +0 -205
- package/src/editor/fields/ObjectField.tsx +0 -71
- package/src/editor/fields/ReferenceField.tsx +0 -138
- package/src/editor/fields/SelectField.tsx +0 -76
- package/src/editor/fields/TextField.tsx +0 -35
- package/src/editor/fields/ToggleField.tsx +0 -37
- package/src/editor/fields/fields.stories.tsx +0 -40
- package/src/editor/group-manager/ExternalGroupsTab.tsx +0 -114
- package/src/editor/group-manager/GroupCard.tsx +0 -102
- package/src/editor/group-manager/GroupForm.tsx +0 -66
- package/src/editor/group-manager/InternalGroupsTab.tsx +0 -147
- package/src/editor/group-manager/MemberList.tsx +0 -184
- package/src/editor/group-manager/hooks/useExternalGroupSearch.ts +0 -63
- package/src/editor/group-manager/hooks/useGroupState.ts +0 -134
- package/src/editor/group-manager/hooks/useUserSearch.ts +0 -84
- package/src/editor/group-manager/index.tsx +0 -210
- package/src/editor/group-manager/types.ts +0 -28
- package/src/editor/hooks/README.md +0 -26
- package/src/editor/hooks/__test__/test-utils.tsx +0 -183
- package/src/editor/hooks/index.ts +0 -23
- package/src/editor/hooks/useBranchActions.test.tsx +0 -267
- package/src/editor/hooks/useBranchActions.tsx +0 -121
- package/src/editor/hooks/useBranchManager.test.tsx +0 -391
- package/src/editor/hooks/useBranchManager.tsx +0 -326
- package/src/editor/hooks/useCommentSystem.test.ts +0 -615
- package/src/editor/hooks/useCommentSystem.ts +0 -347
- package/src/editor/hooks/useDraftManager.test.ts +0 -375
- package/src/editor/hooks/useDraftManager.ts +0 -259
- package/src/editor/hooks/useEditorLayout.test.ts +0 -147
- package/src/editor/hooks/useEditorLayout.ts +0 -67
- package/src/editor/hooks/useEntryManager.test.ts +0 -588
- package/src/editor/hooks/useEntryManager.ts +0 -387
- package/src/editor/hooks/useGroupManager.test.ts +0 -277
- package/src/editor/hooks/useGroupManager.ts +0 -139
- package/src/editor/hooks/usePermissionManager.test.ts +0 -211
- package/src/editor/hooks/usePermissionManager.ts +0 -113
- package/src/editor/hooks/useReferenceResolution.ts +0 -248
- package/src/editor/hooks/useSchemaManager.test.ts +0 -370
- package/src/editor/hooks/useSchemaManager.ts +0 -310
- package/src/editor/hooks/useUserContext.tsx +0 -57
- package/src/editor/hooks/useUserMetadata.test.ts +0 -191
- package/src/editor/hooks/useUserMetadata.ts +0 -71
- package/src/editor/permission-manager/GroupSelector.tsx +0 -73
- package/src/editor/permission-manager/PermissionEditor.tsx +0 -321
- package/src/editor/permission-manager/PermissionLevelBadge.tsx +0 -53
- package/src/editor/permission-manager/PermissionTree.tsx +0 -237
- package/src/editor/permission-manager/UserSelector.tsx +0 -95
- package/src/editor/permission-manager/constants.tsx +0 -18
- package/src/editor/permission-manager/hooks/useGroupsAndUsers.ts +0 -153
- package/src/editor/permission-manager/hooks/usePermissionTree.ts +0 -200
- package/src/editor/permission-manager/index.tsx +0 -294
- package/src/editor/permission-manager/types.ts +0 -58
- package/src/editor/permission-manager/utils.ts +0 -179
- package/src/editor/preview-bridge.test.tsx +0 -50
- package/src/editor/preview-bridge.tsx +0 -294
- package/src/editor/schema-editor/CollectionEditor.test.tsx +0 -238
- package/src/editor/schema-editor/CollectionEditor.tsx +0 -520
- package/src/editor/schema-editor/EntryTypeEditor.test.tsx +0 -215
- package/src/editor/schema-editor/EntryTypeEditor.tsx +0 -367
- package/src/editor/schema-editor/index.ts +0 -19
- package/src/editor/setup-test-dom.ts +0 -10
- package/src/editor/test-setup.ts +0 -33
- package/src/editor/theme.tsx +0 -119
- package/src/editor/utils/env.ts +0 -39
- package/src/entry-schema-registry.test.ts +0 -281
- package/src/entry-schema-registry.ts +0 -121
- package/src/entry-schema.ts +0 -84
- package/src/git-manager.test.ts +0 -552
- package/src/git-manager.ts +0 -667
- package/src/github-service.test.ts +0 -312
- package/src/github-service.ts +0 -295
- package/src/http/handler.test.ts +0 -275
- package/src/http/handler.ts +0 -280
- package/src/http/index.ts +0 -11
- package/src/http/router.ts +0 -164
- package/src/http/types.ts +0 -44
- package/src/id.test.ts +0 -48
- package/src/id.ts +0 -22
- package/src/index.ts +0 -26
- package/src/operating-mode/__tests__/strategies.test.ts +0 -511
- package/src/operating-mode/client-safe-strategy.ts +0 -184
- package/src/operating-mode/client-unsafe-strategy.ts +0 -303
- package/src/operating-mode/client.ts +0 -13
- package/src/operating-mode/index.ts +0 -34
- package/src/operating-mode/types.ts +0 -186
- package/src/paths/__tests__/branch.test.ts +0 -53
- package/src/paths/__tests__/normalize.test.ts +0 -141
- package/src/paths/__tests__/resolve.test.ts +0 -207
- package/src/paths/__tests__/validation.test.ts +0 -61
- package/src/paths/branch.ts +0 -115
- package/src/paths/index.ts +0 -73
- package/src/paths/normalize-server.ts +0 -40
- package/src/paths/normalize.ts +0 -107
- package/src/paths/resolve.ts +0 -61
- package/src/paths/test-utils.ts +0 -37
- package/src/paths/types.ts +0 -68
- package/src/paths/validation.test.ts +0 -480
- package/src/paths/validation.ts +0 -391
- package/src/reference-resolver.test.ts +0 -107
- package/src/reference-resolver.ts +0 -157
- package/src/schema/index.ts +0 -29
- package/src/schema/meta-loader.ts +0 -366
- package/src/schema/resolver.ts +0 -83
- package/src/schema/schema-store-types.ts +0 -56
- package/src/schema/schema-store.test.ts +0 -816
- package/src/schema/schema-store.ts +0 -795
- package/src/schema/types.ts +0 -33
- package/src/schema-meta-loader.test.ts +0 -447
- package/src/server.ts +0 -15
- package/src/services.test.ts +0 -559
- package/src/services.ts +0 -373
- package/src/settings-branch-utils.ts +0 -53
- package/src/settings-workspace.ts +0 -156
- package/src/task-queue/README.md +0 -144
- package/src/task-queue/index.ts +0 -14
- package/src/task-queue/task-queue.test.ts +0 -524
- package/src/task-queue/task-queue.ts +0 -514
- package/src/task-queue/types.ts +0 -41
- package/src/test-utils/api-test-helpers.ts +0 -445
- package/src/test-utils/console-spy.test.ts +0 -14
- package/src/test-utils/console-spy.ts +0 -125
- package/src/test-utils/git-helpers.ts +0 -31
- package/src/test-utils/index.ts +0 -4
- package/src/types.ts +0 -54
- package/src/user.ts +0 -118
- package/src/utils/debug.test.ts +0 -114
- package/src/utils/debug.ts +0 -127
- package/src/utils/error.test.ts +0 -92
- package/src/utils/error.ts +0 -83
- package/src/utils/format.ts +0 -12
- package/src/validation/__tests__/field-traversal.test.ts +0 -263
- package/src/validation/deletion-checker.ts +0 -234
- package/src/validation/field-traversal.ts +0 -146
- package/src/validation/reference-validator.ts +0 -168
- package/src/worker/cms-worker-rebase.test.ts +0 -473
- package/src/worker/cms-worker.ts +0 -777
- package/src/worker/integration.test.ts +0 -289
- package/src/worker/task-queue-config.ts +0 -25
- package/src/worker/task-queue.test.ts +0 -452
- package/src/worker/task-queue.ts +0 -58
- /package/{src/cli/templates → dist/cli/template-files}/Dockerfile.cms.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/canopycms.config.ts.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/deploy-cms.yml.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/edit-page.tsx.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/route.ts.template +0 -0
- /package/{src/cli/templates → dist/cli/template-files}/schemas.ts.template +0 -0
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for invalid content errors.
|
|
3
|
-
* Tests schema validation, malformed data, and security (path traversal).
|
|
4
|
-
* Tests go through the HTTP API layer.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
8
|
-
|
|
9
|
-
import { createTestWorkspace, type TestWorkspace } from '../test-utils/test-workspace'
|
|
10
|
-
import { createMockAuthPlugin } from '../test-utils/multi-user'
|
|
11
|
-
import { createApiClient } from '../test-utils/api-client'
|
|
12
|
-
import { BLOG_SCHEMA } from '../fixtures/schemas'
|
|
13
|
-
import type { ApiResponse } from '../../api/types'
|
|
14
|
-
|
|
15
|
-
describe('Invalid Content Errors', () => {
|
|
16
|
-
let workspace: TestWorkspace
|
|
17
|
-
let editorClient: Awaited<ReturnType<typeof createApiClient>>
|
|
18
|
-
|
|
19
|
-
beforeEach(async () => {
|
|
20
|
-
workspace = await createTestWorkspace({
|
|
21
|
-
schema: BLOG_SCHEMA,
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
editorClient = await createApiClient({
|
|
25
|
-
config: workspace.config,
|
|
26
|
-
authPlugin: createMockAuthPlugin('editor'),
|
|
27
|
-
schema: BLOG_SCHEMA,
|
|
28
|
-
})
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
afterEach(async () => {
|
|
32
|
-
await workspace.cleanup()
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('returns 400 for missing required fields', async () => {
|
|
36
|
-
// Create branch
|
|
37
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
38
|
-
branch: 'feature/validation-test',
|
|
39
|
-
title: 'Validation Test',
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
// Try to write content missing required fields
|
|
43
|
-
await editorClient.put('/api/canopycms/feature-validation-test/content/posts/invalid-post', {
|
|
44
|
-
format: 'mdx',
|
|
45
|
-
data: {
|
|
46
|
-
// Missing required fields: title, author, date
|
|
47
|
-
tags: ['test'],
|
|
48
|
-
},
|
|
49
|
-
body: 'Some content',
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// TODO: Once schema validation is enforced, this should be 400
|
|
53
|
-
// For now, ContentStore may accept any data shape
|
|
54
|
-
// expect(response.status).toBe(400)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('returns 400 for invalid collection name', async () => {
|
|
58
|
-
// Create branch
|
|
59
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
60
|
-
branch: 'feature/invalid-collection',
|
|
61
|
-
title: 'Invalid Collection',
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
// Try to write to non-existent collection
|
|
65
|
-
const response = await editorClient.put(
|
|
66
|
-
'/api/canopycms/feature-invalid-collection/content/nonexistent/test',
|
|
67
|
-
{
|
|
68
|
-
format: 'mdx',
|
|
69
|
-
data: {
|
|
70
|
-
title: 'Test',
|
|
71
|
-
},
|
|
72
|
-
body: 'Content',
|
|
73
|
-
},
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
// Should fail with 400 or 404
|
|
77
|
-
expect(response.status).toBeGreaterThanOrEqual(400)
|
|
78
|
-
expect(response.ok).toBe(false)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('returns 400 for malformed JSON data', async () => {
|
|
82
|
-
// Create branch
|
|
83
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
84
|
-
branch: 'feature/malformed-test',
|
|
85
|
-
title: 'Malformed Test',
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
// Try to write with invalid data structure
|
|
89
|
-
await editorClient.put('/api/canopycms/feature-malformed-test/content/posts/malformed', {
|
|
90
|
-
format: 'json',
|
|
91
|
-
data: 'not an object', // Invalid: should be object, not string
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
// TODO: Once validation is enforced, this should be 400
|
|
95
|
-
// expect(response.status).toBe(400)
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('prevents path traversal attacks in slug', async () => {
|
|
99
|
-
// Create branch
|
|
100
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
101
|
-
branch: 'feature/security-test',
|
|
102
|
-
title: 'Security Test',
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// Try path traversal in slug
|
|
106
|
-
const response = await editorClient.put(
|
|
107
|
-
'/api/canopycms/feature-security-test/content/posts/../../etc/passwd',
|
|
108
|
-
{
|
|
109
|
-
collection: 'posts',
|
|
110
|
-
slug: '../../etc/passwd',
|
|
111
|
-
format: 'mdx',
|
|
112
|
-
data: {
|
|
113
|
-
title: 'Malicious',
|
|
114
|
-
},
|
|
115
|
-
body: 'Should not write',
|
|
116
|
-
},
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
// Should fail (either 400 or 403)
|
|
120
|
-
expect(response.status).toBeGreaterThanOrEqual(400)
|
|
121
|
-
expect(response.ok).toBe(false)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('prevents path traversal attacks in collection', async () => {
|
|
125
|
-
// Create branch
|
|
126
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
127
|
-
branch: 'feature/security-test-2',
|
|
128
|
-
title: 'Security Test 2',
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
// Try path traversal in collection
|
|
132
|
-
const response = await editorClient.put(
|
|
133
|
-
'/api/canopycms/feature-security-test-2/content/../../../etc/test',
|
|
134
|
-
{
|
|
135
|
-
collection: '../../../etc',
|
|
136
|
-
slug: 'test',
|
|
137
|
-
format: 'mdx',
|
|
138
|
-
data: {
|
|
139
|
-
title: 'Malicious',
|
|
140
|
-
},
|
|
141
|
-
body: 'Should not write',
|
|
142
|
-
},
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
// Should fail
|
|
146
|
-
expect(response.status).toBeGreaterThanOrEqual(400)
|
|
147
|
-
expect(response.ok).toBe(false)
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
it('returns 400 for missing required body fields', async () => {
|
|
151
|
-
// Create branch
|
|
152
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
153
|
-
branch: 'feature/missing-fields',
|
|
154
|
-
title: 'Missing Fields',
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
// Try to write without format field (required in body)
|
|
158
|
-
const response = await editorClient.put(
|
|
159
|
-
'/api/canopycms/feature-missing-fields/content/posts/test',
|
|
160
|
-
{
|
|
161
|
-
// Missing: format (required field)
|
|
162
|
-
data: { title: 'Test' },
|
|
163
|
-
body: 'Content',
|
|
164
|
-
},
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
expect(response.status).toBe(400)
|
|
168
|
-
expect(response.ok).toBe(false)
|
|
169
|
-
const error = await response.json<ApiResponse>()
|
|
170
|
-
expect(error.error).toContain('format')
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
it('returns 400 for invalid format type', async () => {
|
|
174
|
-
// Create branch
|
|
175
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
176
|
-
branch: 'feature/invalid-format',
|
|
177
|
-
title: 'Invalid Format',
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
// Try to write with invalid format
|
|
181
|
-
await editorClient.put('/api/canopycms/feature-invalid-format/content/posts/test', {
|
|
182
|
-
format: 'invalid-format', // Not a valid ContentFormat
|
|
183
|
-
data: { title: 'Test' },
|
|
184
|
-
body: 'Content',
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
// TODO: Once format validation is enforced, this should be 400
|
|
188
|
-
// expect(response.status).toBe(400)
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
it('handles write errors gracefully', async () => {
|
|
192
|
-
// Create branch
|
|
193
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
194
|
-
branch: 'feature/write-error',
|
|
195
|
-
title: 'Write Error Test',
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
// Try to write with empty slug (might cause issues)
|
|
199
|
-
const response = await editorClient.put('/api/canopycms/feature-write-error/content/posts/', {
|
|
200
|
-
collection: 'posts',
|
|
201
|
-
slug: '',
|
|
202
|
-
format: 'mdx',
|
|
203
|
-
data: { title: 'Test' },
|
|
204
|
-
body: 'Content',
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
// Should either succeed (if empty slug is valid) or fail gracefully
|
|
208
|
-
if (!response.ok) {
|
|
209
|
-
expect(response.status).toBeGreaterThanOrEqual(400)
|
|
210
|
-
const error = await response.json<ApiResponse>()
|
|
211
|
-
expect(error.error).toBeDefined()
|
|
212
|
-
}
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('validates data types for schema fields', async () => {
|
|
216
|
-
// Create branch
|
|
217
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
218
|
-
branch: 'feature/type-validation',
|
|
219
|
-
title: 'Type Validation',
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
// Try to write with wrong data types
|
|
223
|
-
await editorClient.put('/api/canopycms/feature-type-validation/content/posts/test', {
|
|
224
|
-
format: 'mdx',
|
|
225
|
-
data: {
|
|
226
|
-
title: 'Test',
|
|
227
|
-
author: 'Author',
|
|
228
|
-
date: 12345, // Should be string, not number
|
|
229
|
-
tags: 'not-an-array', // Should be array, not string
|
|
230
|
-
},
|
|
231
|
-
body: 'Content',
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
// TODO: Once type validation is enforced, this should be 400
|
|
235
|
-
// For now, ContentStore may accept any data
|
|
236
|
-
// expect(response.status).toBe(400)
|
|
237
|
-
})
|
|
238
|
-
})
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for permission denied scenarios.
|
|
3
|
-
* Tests proper error messages and status codes for unauthorized access.
|
|
4
|
-
* Tests go through the HTTP API layer.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
8
|
-
|
|
9
|
-
import { createTestWorkspace, type TestWorkspace } from '../test-utils/test-workspace'
|
|
10
|
-
import { createMockAuthPlugin } from '../test-utils/multi-user'
|
|
11
|
-
import { createApiClient } from '../test-utils/api-client'
|
|
12
|
-
import { BLOG_SCHEMA } from '../fixtures/schemas'
|
|
13
|
-
import type { ApiResponse } from '../../api/types'
|
|
14
|
-
|
|
15
|
-
describe('Permission Denied Errors', () => {
|
|
16
|
-
let workspace: TestWorkspace
|
|
17
|
-
let adminClient: Awaited<ReturnType<typeof createApiClient>>
|
|
18
|
-
let editorClient: Awaited<ReturnType<typeof createApiClient>>
|
|
19
|
-
let reviewerClient: Awaited<ReturnType<typeof createApiClient>>
|
|
20
|
-
|
|
21
|
-
beforeEach(async () => {
|
|
22
|
-
workspace = await createTestWorkspace({
|
|
23
|
-
schema: BLOG_SCHEMA,
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
adminClient = await createApiClient({
|
|
27
|
-
config: workspace.config,
|
|
28
|
-
authPlugin: createMockAuthPlugin('admin'),
|
|
29
|
-
schema: BLOG_SCHEMA,
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
editorClient = await createApiClient({
|
|
33
|
-
config: workspace.config,
|
|
34
|
-
authPlugin: createMockAuthPlugin('editor'),
|
|
35
|
-
schema: BLOG_SCHEMA,
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
reviewerClient = await createApiClient({
|
|
39
|
-
config: workspace.config,
|
|
40
|
-
authPlugin: createMockAuthPlugin('reviewer'),
|
|
41
|
-
schema: BLOG_SCHEMA,
|
|
42
|
-
})
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
afterEach(async () => {
|
|
46
|
-
await workspace.cleanup()
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('returns 403 when editor tries to access restricted branch', async () => {
|
|
50
|
-
// Admin creates a restricted branch
|
|
51
|
-
await adminClient.post('/api/canopycms/branches', {
|
|
52
|
-
branch: 'admin-only',
|
|
53
|
-
title: 'Admin Only Branch',
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
await adminClient.patch('/api/canopycms/admin-only/access', {
|
|
57
|
-
allowedUsers: ['test-admin'],
|
|
58
|
-
allowedGroups: [],
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
// Editor tries to access
|
|
62
|
-
const response = await editorClient.get('/api/canopycms/admin-only/status')
|
|
63
|
-
|
|
64
|
-
expect(response.status).toBe(403)
|
|
65
|
-
expect(response.ok).toBe(false)
|
|
66
|
-
const error = await response.json<ApiResponse>()
|
|
67
|
-
expect(error.error).toBeDefined()
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('returns 403 when editor tries to access restricted content path', async () => {
|
|
71
|
-
// Admin creates branch with path restrictions
|
|
72
|
-
await adminClient.post('/api/canopycms/branches', {
|
|
73
|
-
branch: 'restricted-paths',
|
|
74
|
-
title: 'Restricted Paths',
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
// Write content as admin
|
|
78
|
-
await adminClient.put('/api/canopycms/restricted-paths/content/posts/admin-post', {
|
|
79
|
-
format: 'mdx',
|
|
80
|
-
data: {
|
|
81
|
-
title: 'Admin Post',
|
|
82
|
-
author: 'Admin',
|
|
83
|
-
date: '2024-01-01',
|
|
84
|
-
tags: ['admin'],
|
|
85
|
-
},
|
|
86
|
-
body: 'Admin only content',
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
// TODO: Once path-level access control is enforced in API, test:
|
|
90
|
-
// - Editor tries to read restricted path (should be 403)
|
|
91
|
-
// - Editor tries to write to restricted path (should be 403)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it('returns 403 when non-reviewer tries to approve', async () => {
|
|
95
|
-
// Editor creates and submits branch
|
|
96
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
97
|
-
branch: 'feature/approval-test',
|
|
98
|
-
title: 'Approval Test',
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
await editorClient.post('/api/canopycms/feature-approval-test/submit', {
|
|
102
|
-
message: 'Ready for review',
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// Editor (not a reviewer) tries to approve
|
|
106
|
-
const response = await editorClient.post('/api/canopycms/feature-approval-test/approve', {
|
|
107
|
-
message: 'Trying to approve',
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
expect(response.status).toBe(403)
|
|
111
|
-
expect(response.ok).toBe(false)
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
it('returns 403 when non-admin tries to delete branch they did not create', async () => {
|
|
115
|
-
// Admin creates a branch
|
|
116
|
-
await adminClient.post('/api/canopycms/branches', {
|
|
117
|
-
branch: 'feature/delete-test',
|
|
118
|
-
title: 'Delete Test',
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
// Editor tries to delete (not their branch, not admin) - should fail
|
|
122
|
-
const editorDeleteResponse = await editorClient.delete('/api/canopycms/feature-delete-test')
|
|
123
|
-
|
|
124
|
-
expect(editorDeleteResponse.status).toBe(403)
|
|
125
|
-
expect(editorDeleteResponse.ok).toBe(false)
|
|
126
|
-
|
|
127
|
-
// Reviewer tries to delete (not their branch, not admin) - should also fail
|
|
128
|
-
const reviewerDeleteResponse = await reviewerClient.delete('/api/canopycms/feature-delete-test')
|
|
129
|
-
|
|
130
|
-
expect(reviewerDeleteResponse.status).toBe(403)
|
|
131
|
-
expect(reviewerDeleteResponse.ok).toBe(false)
|
|
132
|
-
|
|
133
|
-
// Admin can delete (they are the creator and also admin)
|
|
134
|
-
const adminDeleteResponse = await adminClient.delete('/api/canopycms/feature-delete-test')
|
|
135
|
-
|
|
136
|
-
expect(adminDeleteResponse.status).toBe(200)
|
|
137
|
-
expect(adminDeleteResponse.ok).toBe(true)
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
it('returns 403 when editor tries to modify branch access control on branch they did not create', async () => {
|
|
141
|
-
// Admin creates a branch
|
|
142
|
-
await adminClient.post('/api/canopycms/branches', {
|
|
143
|
-
branch: 'feature/access-test',
|
|
144
|
-
title: 'Access Test',
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
// Editor tries to modify access control (not their branch, not admin) - should fail
|
|
148
|
-
const response = await editorClient.patch('/api/canopycms/feature-access-test/access', {
|
|
149
|
-
allowedUsers: ['test-editor'],
|
|
150
|
-
allowedGroups: [],
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
expect(response.status).toBe(403)
|
|
154
|
-
expect(response.ok).toBe(false)
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
it('returns proper error message for permission denied', async () => {
|
|
158
|
-
// Admin creates restricted branch
|
|
159
|
-
await adminClient.post('/api/canopycms/branches', {
|
|
160
|
-
branch: 'restricted',
|
|
161
|
-
title: 'Restricted',
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
await adminClient.patch('/api/canopycms/restricted/access', {
|
|
165
|
-
allowedUsers: ['test-admin'],
|
|
166
|
-
allowedGroups: [],
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
// Editor tries to access
|
|
170
|
-
const response = await editorClient.get('/api/canopycms/restricted/status')
|
|
171
|
-
|
|
172
|
-
expect(response.status).toBe(403)
|
|
173
|
-
const error = await response.json<ApiResponse>()
|
|
174
|
-
expect(error.error).toBeTruthy()
|
|
175
|
-
expect(typeof error.error).toBe('string')
|
|
176
|
-
// Error message should be informative
|
|
177
|
-
expect(error.error!.length).toBeGreaterThan(0)
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it('returns 403 when reviewer tries to edit content', async () => {
|
|
181
|
-
// Editor creates branch with content
|
|
182
|
-
await editorClient.post('/api/canopycms/branches', {
|
|
183
|
-
branch: 'feature/reviewer-test',
|
|
184
|
-
title: 'Reviewer Test',
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
await editorClient.put('/api/canopycms/feature-reviewer-test/content/posts/test-post', {
|
|
188
|
-
format: 'mdx',
|
|
189
|
-
data: {
|
|
190
|
-
title: 'Test Post',
|
|
191
|
-
author: 'Editor',
|
|
192
|
-
date: '2024-01-01',
|
|
193
|
-
tags: ['test'],
|
|
194
|
-
},
|
|
195
|
-
body: 'Original content',
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
// Reviewer can read (view access)
|
|
199
|
-
const readResponse = await reviewerClient.get(
|
|
200
|
-
'/api/canopycms/feature-reviewer-test/content/posts/test-post',
|
|
201
|
-
)
|
|
202
|
-
expect(readResponse.status).toBe(200)
|
|
203
|
-
|
|
204
|
-
// Reviewer tries to edit (should fail - reviewers have read-only access)
|
|
205
|
-
// TODO: Once role-based write restrictions are enforced, this should be 403
|
|
206
|
-
await reviewerClient.put('/api/canopycms/feature-reviewer-test/content/posts/test-post', {
|
|
207
|
-
format: 'mdx',
|
|
208
|
-
data: {
|
|
209
|
-
title: 'Modified by Reviewer',
|
|
210
|
-
author: 'Reviewer',
|
|
211
|
-
date: '2024-01-01',
|
|
212
|
-
tags: ['test'],
|
|
213
|
-
},
|
|
214
|
-
body: 'Modified content',
|
|
215
|
-
})
|
|
216
|
-
|
|
217
|
-
// This might succeed if defaultPathAccess is 'allow', but eventually should be 403
|
|
218
|
-
// expect(writeResponse.status).toBe(403)
|
|
219
|
-
})
|
|
220
|
-
})
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import type { ContentStore } from '../../content-store'
|
|
2
|
-
import { unsafeAsLogicalPath, unsafeAsEntrySlug } from '../../paths/test-utils'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Sample blog posts for seeding test content
|
|
6
|
-
*/
|
|
7
|
-
export const SAMPLE_POSTS = [
|
|
8
|
-
{
|
|
9
|
-
slug: 'hello-world',
|
|
10
|
-
data: {
|
|
11
|
-
title: 'Hello World',
|
|
12
|
-
author: 'Test Author',
|
|
13
|
-
date: '2024-01-01T00:00:00Z',
|
|
14
|
-
tags: ['intro', 'test'],
|
|
15
|
-
body: 'Welcome to the test blog! This is the first post.',
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
slug: 'second-post',
|
|
20
|
-
data: {
|
|
21
|
-
title: 'Second Post',
|
|
22
|
-
author: 'Test Author',
|
|
23
|
-
date: '2024-01-02T00:00:00Z',
|
|
24
|
-
tags: ['test'],
|
|
25
|
-
body: 'This is the second post for testing purposes.',
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
slug: 'draft-post',
|
|
30
|
-
data: {
|
|
31
|
-
title: 'Draft Post',
|
|
32
|
-
author: 'Test Author',
|
|
33
|
-
date: '2024-01-03T00:00:00Z',
|
|
34
|
-
tags: ['draft'],
|
|
35
|
-
body: "This is a draft post that hasn't been published yet.",
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Sample about page content
|
|
42
|
-
*/
|
|
43
|
-
export const SAMPLE_ABOUT = {
|
|
44
|
-
title: 'About Us',
|
|
45
|
-
bio: 'This is a test about page for integration testing.',
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Sample products for e-commerce schema
|
|
50
|
-
*/
|
|
51
|
-
export const SAMPLE_PRODUCTS = [
|
|
52
|
-
{
|
|
53
|
-
slug: 'product-1',
|
|
54
|
-
data: {
|
|
55
|
-
name: 'Test Product 1',
|
|
56
|
-
price: 29.99,
|
|
57
|
-
description: 'A great test product',
|
|
58
|
-
inStock: true,
|
|
59
|
-
images: ['product1.jpg'],
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
slug: 'product-2',
|
|
64
|
-
data: {
|
|
65
|
-
name: 'Test Product 2',
|
|
66
|
-
price: 49.99,
|
|
67
|
-
description: 'Another test product',
|
|
68
|
-
inStock: false,
|
|
69
|
-
images: ['product2.jpg', 'product2-alt.jpg'],
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
]
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Seed blog content into a ContentStore
|
|
76
|
-
*/
|
|
77
|
-
export async function seedBlogContent(store: ContentStore): Promise<void> {
|
|
78
|
-
// Seed posts
|
|
79
|
-
for (const post of SAMPLE_POSTS) {
|
|
80
|
-
await store.write(unsafeAsLogicalPath('content/posts'), unsafeAsEntrySlug(post.slug), {
|
|
81
|
-
format: 'mdx',
|
|
82
|
-
data: post.data,
|
|
83
|
-
body: post.data.body as string,
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Seed about page
|
|
88
|
-
await store.write(unsafeAsLogicalPath('content/about.md'), '', {
|
|
89
|
-
format: 'mdx',
|
|
90
|
-
data: SAMPLE_ABOUT,
|
|
91
|
-
body: SAMPLE_ABOUT.bio as string,
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Seed e-commerce content into a ContentStore
|
|
97
|
-
*/
|
|
98
|
-
export async function seedEcommerceContent(store: ContentStore): Promise<void> {
|
|
99
|
-
for (const product of SAMPLE_PRODUCTS) {
|
|
100
|
-
await store.write(unsafeAsLogicalPath('content/products'), unsafeAsEntrySlug(product.slug), {
|
|
101
|
-
format: 'json',
|
|
102
|
-
data: product.data,
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { RootCollectionConfig } from '../../config'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Blog schema for testing content workflows
|
|
5
|
-
* Contains posts collection
|
|
6
|
-
*/
|
|
7
|
-
export const BLOG_SCHEMA: RootCollectionConfig = {
|
|
8
|
-
collections: [
|
|
9
|
-
{
|
|
10
|
-
name: 'posts',
|
|
11
|
-
path: 'posts',
|
|
12
|
-
entries: [
|
|
13
|
-
{
|
|
14
|
-
name: 'post',
|
|
15
|
-
format: 'mdx',
|
|
16
|
-
schema: [
|
|
17
|
-
{ name: 'title', type: 'string', required: true },
|
|
18
|
-
{ name: 'author', type: 'string' },
|
|
19
|
-
{ name: 'date', type: 'datetime' },
|
|
20
|
-
{ name: 'tags', type: 'string', list: true },
|
|
21
|
-
{ name: 'body', type: 'markdown', required: true },
|
|
22
|
-
],
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* E-commerce schema for testing complex permission scenarios
|
|
31
|
-
* Contains products and categories
|
|
32
|
-
*/
|
|
33
|
-
export const ECOMMERCE_SCHEMA: RootCollectionConfig = {
|
|
34
|
-
collections: [
|
|
35
|
-
{
|
|
36
|
-
name: 'products',
|
|
37
|
-
path: 'products',
|
|
38
|
-
entries: [
|
|
39
|
-
{
|
|
40
|
-
name: 'product',
|
|
41
|
-
format: 'json',
|
|
42
|
-
schema: [
|
|
43
|
-
{ name: 'name', type: 'string', required: true },
|
|
44
|
-
{ name: 'price', type: 'number', required: true },
|
|
45
|
-
{ name: 'description', type: 'markdown' },
|
|
46
|
-
{ name: 'inStock', type: 'boolean' },
|
|
47
|
-
{ name: 'images', type: 'string', list: true },
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'categories',
|
|
54
|
-
path: 'categories',
|
|
55
|
-
entries: [
|
|
56
|
-
{
|
|
57
|
-
name: 'category',
|
|
58
|
-
format: 'json',
|
|
59
|
-
schema: [
|
|
60
|
-
{ name: 'name', type: 'string', required: true },
|
|
61
|
-
{ name: 'description', type: 'string' },
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
}
|