canopycms 0.0.0 → 0.0.1
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/package.json +2 -3
- 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/Dockerfile.cms.template +0 -19
- package/src/cli/templates/canopy.ts.template +0 -55
- package/src/cli/templates/canopycms.config.ts.template +0 -11
- package/src/cli/templates/deploy-cms.yml.template +0 -27
- package/src/cli/templates/edit-page.tsx.template +0 -32
- package/src/cli/templates/route.ts.template +0 -12
- package/src/cli/templates/schemas.ts.template +0 -16
- 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/api/security.test.ts
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Security tests for API endpoints.
|
|
3
|
-
*
|
|
4
|
-
* Verifies:
|
|
5
|
-
* - Branch access checks are enforced on all endpoints that accept a branch parameter
|
|
6
|
-
* - Double-encoded path traversal attempts are rejected
|
|
7
|
-
* - Invalid branch names are rejected by Zod validation
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
11
|
-
import type { ApiRequest } from './types'
|
|
12
|
-
import type { FlatSchemaItem } from '../config'
|
|
13
|
-
import type { ContentId, LogicalPath } from '../paths/types'
|
|
14
|
-
import { unsafeAsBranchName, unsafeAsLogicalPath } from '../paths/test-utils'
|
|
15
|
-
import { createMockApiContext, createMockBranchContext, createMockUser } from '../test-utils'
|
|
16
|
-
|
|
17
|
-
// Mock SchemaOps for schema tests
|
|
18
|
-
vi.mock('../schema/schema-store', async (importOriginal) => {
|
|
19
|
-
const actual = await importOriginal<typeof import('../schema/schema-store')>()
|
|
20
|
-
return {
|
|
21
|
-
...actual,
|
|
22
|
-
SchemaOps: vi.fn().mockImplementation(() => ({
|
|
23
|
-
createCollection: vi.fn(),
|
|
24
|
-
updateCollection: vi.fn(),
|
|
25
|
-
deleteCollection: vi.fn(),
|
|
26
|
-
addEntryType: vi.fn(),
|
|
27
|
-
updateEntryType: vi.fn(),
|
|
28
|
-
removeEntryType: vi.fn(),
|
|
29
|
-
updateOrder: vi.fn(),
|
|
30
|
-
isCollectionEmpty: vi.fn(),
|
|
31
|
-
countEntriesUsingType: vi.fn(),
|
|
32
|
-
readCollectionMeta: vi.fn(),
|
|
33
|
-
})),
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
// Mock ContentStore for reference tests
|
|
38
|
-
vi.mock('../content-store', () => ({
|
|
39
|
-
ContentStore: vi.fn().mockImplementation(() => ({
|
|
40
|
-
idIndex: vi.fn().mockResolvedValue({}),
|
|
41
|
-
read: vi.fn().mockResolvedValue({ data: { title: 'Test' } }),
|
|
42
|
-
})),
|
|
43
|
-
ContentStoreError: class ContentStoreError extends Error {},
|
|
44
|
-
}))
|
|
45
|
-
|
|
46
|
-
// Mock ReferenceResolver
|
|
47
|
-
vi.mock('../reference-resolver', () => ({
|
|
48
|
-
ReferenceResolver: vi.fn().mockImplementation(() => ({
|
|
49
|
-
loadReferenceOptions: vi.fn().mockResolvedValue([]),
|
|
50
|
-
resolve: vi.fn().mockResolvedValue({ exists: true, collection: 'posts', slug: 'hello' }),
|
|
51
|
-
})),
|
|
52
|
-
}))
|
|
53
|
-
|
|
54
|
-
import { REFERENCE_OPTIONS_ROUTES } from './reference-options'
|
|
55
|
-
import { RESOLVE_REFERENCES_ROUTES } from './resolve-references'
|
|
56
|
-
import { getSchema, getCollection } from './schema'
|
|
57
|
-
|
|
58
|
-
describe('Security: Branch access checks', () => {
|
|
59
|
-
const mockFlatSchema: FlatSchemaItem[] = [
|
|
60
|
-
{
|
|
61
|
-
type: 'collection',
|
|
62
|
-
logicalPath: 'posts' as LogicalPath,
|
|
63
|
-
name: 'posts',
|
|
64
|
-
label: 'Posts',
|
|
65
|
-
contentId: 'a1b2c3d4e5f6' as ContentId,
|
|
66
|
-
entries: [{ name: 'post', format: 'json', schema: [], schemaRef: 'postSchema' }],
|
|
67
|
-
},
|
|
68
|
-
]
|
|
69
|
-
|
|
70
|
-
const branchContext = createMockBranchContext({
|
|
71
|
-
branchName: 'secret-branch',
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
describe('reference-options endpoint', () => {
|
|
75
|
-
it('returns 403 when user lacks branch access', async () => {
|
|
76
|
-
const ctx = createMockApiContext({
|
|
77
|
-
branchContext: { ...branchContext, flatSchema: mockFlatSchema },
|
|
78
|
-
allowBranchAccess: false,
|
|
79
|
-
})
|
|
80
|
-
const req = {
|
|
81
|
-
user: createMockUser(),
|
|
82
|
-
query: { collections: 'posts' },
|
|
83
|
-
} as unknown as ApiRequest
|
|
84
|
-
|
|
85
|
-
const result = await REFERENCE_OPTIONS_ROUTES.get.handler(ctx, req, {
|
|
86
|
-
branch: unsafeAsBranchName('secret-branch'),
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
expect(result.ok).toBe(false)
|
|
90
|
-
expect(result.status).toBe(403)
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('returns 200 when user has branch access', async () => {
|
|
94
|
-
const ctx = createMockApiContext({
|
|
95
|
-
branchContext: { ...branchContext, flatSchema: mockFlatSchema },
|
|
96
|
-
allowBranchAccess: true,
|
|
97
|
-
})
|
|
98
|
-
const req = {
|
|
99
|
-
user: createMockUser(),
|
|
100
|
-
query: { collections: 'posts', displayField: 'title' },
|
|
101
|
-
} as unknown as ApiRequest
|
|
102
|
-
|
|
103
|
-
const result = await REFERENCE_OPTIONS_ROUTES.get.handler(ctx, req, {
|
|
104
|
-
branch: unsafeAsBranchName('secret-branch'),
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
expect(result.ok).toBe(true)
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
describe('resolve-references endpoint', () => {
|
|
112
|
-
it('returns 403 when user lacks branch access', async () => {
|
|
113
|
-
const ctx = createMockApiContext({
|
|
114
|
-
branchContext: { ...branchContext, flatSchema: mockFlatSchema },
|
|
115
|
-
allowBranchAccess: false,
|
|
116
|
-
})
|
|
117
|
-
const req = { user: createMockUser() } as unknown as ApiRequest
|
|
118
|
-
|
|
119
|
-
const result = await RESOLVE_REFERENCES_ROUTES.post.handler(
|
|
120
|
-
ctx,
|
|
121
|
-
req,
|
|
122
|
-
{ branch: unsafeAsBranchName('secret-branch') },
|
|
123
|
-
{ ids: ['a1b2c3d4e5f6' as ContentId] },
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
expect(result.ok).toBe(false)
|
|
127
|
-
expect(result.status).toBe(403)
|
|
128
|
-
})
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
describe('getSchema endpoint', () => {
|
|
132
|
-
it('returns 403 when user lacks branch access', async () => {
|
|
133
|
-
const ctx = createMockApiContext({
|
|
134
|
-
branchContext: { ...branchContext, flatSchema: mockFlatSchema },
|
|
135
|
-
allowBranchAccess: false,
|
|
136
|
-
services: {
|
|
137
|
-
entrySchemaRegistry: { postSchema: [{ name: 'title', type: 'string' }] },
|
|
138
|
-
},
|
|
139
|
-
})
|
|
140
|
-
const req = { user: createMockUser() } as unknown as ApiRequest
|
|
141
|
-
|
|
142
|
-
const result = await getSchema.handler(ctx, req, {
|
|
143
|
-
branch: unsafeAsBranchName('secret-branch'),
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
expect(result.ok).toBe(false)
|
|
147
|
-
expect(result.status).toBe(403)
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
describe('getCollection endpoint', () => {
|
|
152
|
-
it('returns 403 when user lacks branch access', async () => {
|
|
153
|
-
const ctx = createMockApiContext({
|
|
154
|
-
branchContext: { ...branchContext, flatSchema: mockFlatSchema },
|
|
155
|
-
allowBranchAccess: false,
|
|
156
|
-
})
|
|
157
|
-
const req = { user: createMockUser() } as unknown as ApiRequest
|
|
158
|
-
|
|
159
|
-
const result = await getCollection.handler(ctx, req, {
|
|
160
|
-
branch: unsafeAsBranchName('secret-branch'),
|
|
161
|
-
collectionPath: unsafeAsLogicalPath('posts'),
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
expect(result.ok).toBe(false)
|
|
165
|
-
expect(result.status).toBe(403)
|
|
166
|
-
})
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('Security: flatSchema null safety', () => {
|
|
171
|
-
it('returns 500 when flatSchema is not loaded', async () => {
|
|
172
|
-
const ctx = createMockApiContext({
|
|
173
|
-
branchContext: createMockBranchContext({ branchName: 'test' }),
|
|
174
|
-
allowBranchAccess: true,
|
|
175
|
-
services: {
|
|
176
|
-
entrySchemaRegistry: {},
|
|
177
|
-
},
|
|
178
|
-
})
|
|
179
|
-
// branchContext has no flatSchema property
|
|
180
|
-
const req = { user: createMockUser() } as unknown as ApiRequest
|
|
181
|
-
|
|
182
|
-
const result = await getSchema.handler(ctx, req, {
|
|
183
|
-
branch: unsafeAsBranchName('test'),
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
expect(result.ok).toBe(false)
|
|
187
|
-
expect(result.status).toBe(500)
|
|
188
|
-
expect(result.error).toContain('Schema not loaded')
|
|
189
|
-
})
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
describe('Security: Branch name validation', () => {
|
|
193
|
-
it('branchNameSchema rejects traversal attempts', async () => {
|
|
194
|
-
const { branchNameSchema } = await import('./validators')
|
|
195
|
-
|
|
196
|
-
const traversalAttempts = [
|
|
197
|
-
'../etc/passwd',
|
|
198
|
-
'branch/../escape',
|
|
199
|
-
'branch/...',
|
|
200
|
-
'branch@{evil}',
|
|
201
|
-
'branch name with spaces',
|
|
202
|
-
]
|
|
203
|
-
|
|
204
|
-
for (const name of traversalAttempts) {
|
|
205
|
-
const result = branchNameSchema.safeParse(name)
|
|
206
|
-
expect(result.success, `Expected "${name}" to be rejected`).toBe(false)
|
|
207
|
-
}
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
it('branchNameSchema accepts valid branch names', async () => {
|
|
211
|
-
const { branchNameSchema } = await import('./validators')
|
|
212
|
-
|
|
213
|
-
const validNames = ['main', 'feature/test', 'fix-123', 'release/v1.0']
|
|
214
|
-
|
|
215
|
-
for (const name of validNames) {
|
|
216
|
-
const result = branchNameSchema.safeParse(name)
|
|
217
|
-
expect(result.success, `Expected "${name}" to be accepted`).toBe(true)
|
|
218
|
-
}
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
describe('Security: Double URL decoding protection', () => {
|
|
223
|
-
it('logicalPathSchema rejects traversal sequences', async () => {
|
|
224
|
-
const { logicalPathSchema } = await import('./validators')
|
|
225
|
-
|
|
226
|
-
const attacks = ['../etc/passwd', 'content/../../../etc/passwd', 'content/..%2F..%2Fetc']
|
|
227
|
-
|
|
228
|
-
for (const path of attacks) {
|
|
229
|
-
const result = logicalPathSchema.safeParse(path)
|
|
230
|
-
expect(result.success, `Expected "${path}" to be rejected`).toBe(false)
|
|
231
|
-
}
|
|
232
|
-
})
|
|
233
|
-
})
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import type { ApiContext } from './types'
|
|
2
|
-
import type { OperatingMode } from '../operating-mode'
|
|
3
|
-
import { operatingStrategy } from '../operating-mode'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Get the appropriate root path for settings (permissions/groups).
|
|
7
|
-
* In dev mode, returns the main branch root (.canopy-dev/settings/).
|
|
8
|
-
* In prod/prod-sim modes, returns the settings root (settings/).
|
|
9
|
-
*/
|
|
10
|
-
export async function getSettingsBranchContext(
|
|
11
|
-
ctx: ApiContext,
|
|
12
|
-
): Promise<
|
|
13
|
-
| { context: { branchRoot: string }; mode: OperatingMode; branchName: string }
|
|
14
|
-
| { error: string; status: number }
|
|
15
|
-
> {
|
|
16
|
-
const mode = ctx.services.config.mode
|
|
17
|
-
const strategy = operatingStrategy(mode)
|
|
18
|
-
|
|
19
|
-
// Determine which branch name to use (for git operations)
|
|
20
|
-
const branchName = strategy.getSettingsBranchName({
|
|
21
|
-
settingsBranch: ctx.services.config.settingsBranch,
|
|
22
|
-
defaultBaseBranch: ctx.services.config.defaultBaseBranch,
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
// For modes with separate settings branch, use settings root
|
|
26
|
-
if (strategy.usesSeparateSettingsBranch()) {
|
|
27
|
-
// Get settings root and ensure workspace exists
|
|
28
|
-
const settingsRoot = await ctx.services.getSettingsBranchRoot()
|
|
29
|
-
return {
|
|
30
|
-
context: { branchRoot: settingsRoot },
|
|
31
|
-
mode,
|
|
32
|
-
branchName,
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// For dev mode, settings are stored in .canopy-dev/settings/
|
|
37
|
-
// We need to pass the workspace root, not a branch root
|
|
38
|
-
const workspaceRoot = ctx.services.config.sourceRoot ?? process.cwd()
|
|
39
|
-
return {
|
|
40
|
-
context: { branchRoot: workspaceRoot },
|
|
41
|
-
mode,
|
|
42
|
-
branchName,
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Commit and push settings changes based on the mode.
|
|
48
|
-
* In dev mode, does nothing (no git operations).
|
|
49
|
-
* In prod mode, uses commitToSettingsBranch.
|
|
50
|
-
* In prod-sim mode, uses regular commitFiles.
|
|
51
|
-
*/
|
|
52
|
-
export async function commitSettings(
|
|
53
|
-
ctx: ApiContext,
|
|
54
|
-
options: {
|
|
55
|
-
context: { branchRoot: string }
|
|
56
|
-
branchRoot: string
|
|
57
|
-
fileName: string
|
|
58
|
-
message: string
|
|
59
|
-
mode: OperatingMode
|
|
60
|
-
},
|
|
61
|
-
): Promise<void> {
|
|
62
|
-
const strategy = operatingStrategy(options.mode)
|
|
63
|
-
|
|
64
|
-
// No git operations if mode doesn't support commits
|
|
65
|
-
if (!strategy.shouldCommit()) {
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// For modes that use separate settings branch, commit to settings branch
|
|
70
|
-
if (strategy.usesSeparateSettingsBranch()) {
|
|
71
|
-
const result = await ctx.services.commitToSettingsBranch({
|
|
72
|
-
branchRoot: options.branchRoot,
|
|
73
|
-
files: options.fileName,
|
|
74
|
-
message: options.message,
|
|
75
|
-
createPR: strategy.shouldCreateSettingsPR({
|
|
76
|
-
autoCreateSettingsPR: ctx.services.config.autoCreateSettingsPR,
|
|
77
|
-
}),
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
if (!result.pushed) {
|
|
81
|
-
console.warn(`${options.message} committed but not pushed:`, result.error)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
package/src/api/types.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { BranchContext } from '../types'
|
|
2
|
-
import type { AuthPlugin } from '../auth/plugin'
|
|
3
|
-
import type { CanopyServices } from '../services'
|
|
4
|
-
import type { CanopyUser } from '../user'
|
|
5
|
-
import type { AssetStore } from '../asset-store'
|
|
6
|
-
|
|
7
|
-
export interface ApiContext {
|
|
8
|
-
services: CanopyServices
|
|
9
|
-
assetStore?: AssetStore
|
|
10
|
-
/**
|
|
11
|
-
* Load a branch context for the requested branch name.
|
|
12
|
-
* Can be backed by BranchRegistry + BranchMetadataFileManager.
|
|
13
|
-
*
|
|
14
|
-
* @param branchName - Name of the branch to load
|
|
15
|
-
* @param options - Optional configuration
|
|
16
|
-
* @param options.loadSchema - If true, loads per-branch schema into context.flatSchema
|
|
17
|
-
*/
|
|
18
|
-
getBranchContext: (
|
|
19
|
-
branchName: string,
|
|
20
|
-
options?: { loadSchema?: boolean },
|
|
21
|
-
) => Promise<BranchContext | null>
|
|
22
|
-
/**
|
|
23
|
-
* Auth plugin for user/group search (optional)
|
|
24
|
-
*/
|
|
25
|
-
authPlugin?: AuthPlugin
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface ApiRequest<TBody = unknown> {
|
|
29
|
-
branch?: string
|
|
30
|
-
body?: TBody
|
|
31
|
-
query?: Record<string, string | string[] | undefined>
|
|
32
|
-
user: CanopyUser
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface ApiResponse<TData = unknown> {
|
|
36
|
-
ok: boolean
|
|
37
|
-
status: number
|
|
38
|
-
data?: TData
|
|
39
|
-
error?: string
|
|
40
|
-
}
|
package/src/api/user.test.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
|
-
import type { ApiContext, ApiRequest } from './types'
|
|
3
|
-
import type { CanopyUserId, CanopyGroupId } from '../types'
|
|
4
|
-
import { USER_ROUTES } from './user'
|
|
5
|
-
|
|
6
|
-
// Extract handler for testing
|
|
7
|
-
const getUserInfo = USER_ROUTES.whoami.handler
|
|
8
|
-
|
|
9
|
-
describe('user API', () => {
|
|
10
|
-
let mockContext: ApiContext
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
mockContext = {
|
|
14
|
-
services: {
|
|
15
|
-
config: {
|
|
16
|
-
defaultBaseBranch: 'main',
|
|
17
|
-
mode: 'dev',
|
|
18
|
-
},
|
|
19
|
-
checkBranchAccess: vi.fn(),
|
|
20
|
-
checkContentAccess: vi.fn(),
|
|
21
|
-
bootstrapAdminIds: new Set<string>(),
|
|
22
|
-
registry: undefined as any,
|
|
23
|
-
commitFiles: vi.fn(),
|
|
24
|
-
submitBranch: vi.fn(),
|
|
25
|
-
},
|
|
26
|
-
getBranchContext: vi.fn(),
|
|
27
|
-
} as unknown as ApiContext
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
describe('whoami', () => {
|
|
31
|
-
it('should return user info for authenticated user without groups', async () => {
|
|
32
|
-
const req: ApiRequest<undefined> = {
|
|
33
|
-
user: {
|
|
34
|
-
type: 'authenticated',
|
|
35
|
-
userId: 'user-1' as CanopyUserId,
|
|
36
|
-
groups: [],
|
|
37
|
-
},
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const result = await getUserInfo(mockContext, req)
|
|
41
|
-
|
|
42
|
-
expect(result.ok).toBe(true)
|
|
43
|
-
expect(result.status).toBe(200)
|
|
44
|
-
expect(result.data).toEqual({
|
|
45
|
-
userId: 'user-1',
|
|
46
|
-
groups: [],
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('should return user info with multiple groups', async () => {
|
|
51
|
-
const req: ApiRequest<undefined> = {
|
|
52
|
-
user: {
|
|
53
|
-
type: 'authenticated',
|
|
54
|
-
userId: 'admin-user' as CanopyUserId,
|
|
55
|
-
groups: [
|
|
56
|
-
'admins' as CanopyGroupId,
|
|
57
|
-
'reviewers' as CanopyGroupId,
|
|
58
|
-
'editors' as CanopyGroupId,
|
|
59
|
-
],
|
|
60
|
-
},
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const result = await getUserInfo(mockContext, req)
|
|
64
|
-
|
|
65
|
-
expect(result.ok).toBe(true)
|
|
66
|
-
expect(result.status).toBe(200)
|
|
67
|
-
expect(result.data).toEqual({
|
|
68
|
-
userId: 'admin-user',
|
|
69
|
-
groups: ['admins', 'reviewers', 'editors'],
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('should return user info with single group', async () => {
|
|
74
|
-
const req: ApiRequest<undefined> = {
|
|
75
|
-
user: {
|
|
76
|
-
type: 'authenticated',
|
|
77
|
-
userId: 'reviewer-user' as CanopyUserId,
|
|
78
|
-
groups: ['reviewers' as CanopyGroupId],
|
|
79
|
-
},
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const result = await getUserInfo(mockContext, req)
|
|
83
|
-
|
|
84
|
-
expect(result.ok).toBe(true)
|
|
85
|
-
expect(result.status).toBe(200)
|
|
86
|
-
expect(result.data).toEqual({
|
|
87
|
-
userId: 'reviewer-user',
|
|
88
|
-
groups: ['reviewers'],
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('should preserve exact user ID from request', async () => {
|
|
93
|
-
const req: ApiRequest<undefined> = {
|
|
94
|
-
user: {
|
|
95
|
-
type: 'authenticated',
|
|
96
|
-
userId: 'user-with-special-chars-123' as CanopyUserId,
|
|
97
|
-
groups: [],
|
|
98
|
-
},
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const result = await getUserInfo(mockContext, req)
|
|
102
|
-
|
|
103
|
-
expect(result.ok).toBe(true)
|
|
104
|
-
expect(result.status).toBe(200)
|
|
105
|
-
expect(result.data?.userId).toBe('user-with-special-chars-123')
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('should return response with correct response type structure', async () => {
|
|
109
|
-
const req: ApiRequest<undefined> = {
|
|
110
|
-
user: {
|
|
111
|
-
type: 'authenticated',
|
|
112
|
-
userId: 'test-user' as CanopyUserId,
|
|
113
|
-
groups: ['test-group' as CanopyGroupId],
|
|
114
|
-
},
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const result = await getUserInfo(mockContext, req)
|
|
118
|
-
|
|
119
|
-
// Verify ApiResponse structure
|
|
120
|
-
expect(result).toHaveProperty('ok')
|
|
121
|
-
expect(result).toHaveProperty('status')
|
|
122
|
-
expect(result).toHaveProperty('data')
|
|
123
|
-
expect(result.ok).toBe(true)
|
|
124
|
-
expect(result.status).toBe(200)
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
})
|
package/src/api/user.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { defineEndpoint } from './route-builder'
|
|
2
|
-
import type { ApiContext, ApiRequest, ApiResponse } from './types'
|
|
3
|
-
|
|
4
|
-
export type UserInfoResponse = ApiResponse<{
|
|
5
|
-
userId: string
|
|
6
|
-
groups: string[]
|
|
7
|
-
}>
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Get current user info
|
|
11
|
-
* This is a PUBLIC endpoint - no special permissions required
|
|
12
|
-
*/
|
|
13
|
-
const getUserInfoHandler = async (ctx: ApiContext, req: ApiRequest): Promise<UserInfoResponse> => {
|
|
14
|
-
// Every authenticated request has req.user populated by the auth middleware
|
|
15
|
-
return {
|
|
16
|
-
ok: true,
|
|
17
|
-
status: 200,
|
|
18
|
-
data: {
|
|
19
|
-
userId: req.user.userId,
|
|
20
|
-
groups: req.user.groups as string[],
|
|
21
|
-
},
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Get current user information
|
|
27
|
-
* GET /whoami
|
|
28
|
-
*/
|
|
29
|
-
const getUserInfo = defineEndpoint({
|
|
30
|
-
namespace: 'user',
|
|
31
|
-
name: 'whoami',
|
|
32
|
-
method: 'GET',
|
|
33
|
-
path: '/whoami',
|
|
34
|
-
responseType: 'UserInfoResponse',
|
|
35
|
-
response: {} as UserInfoResponse,
|
|
36
|
-
defaultMockData: { userId: 'mock-user', groups: [] },
|
|
37
|
-
handler: getUserInfoHandler,
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
export const USER_ROUTES = {
|
|
41
|
-
whoami: getUserInfo,
|
|
42
|
-
} as const
|