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,452 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
2
|
-
import fs from 'node:fs/promises'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import os from 'node:os'
|
|
5
|
-
import {
|
|
6
|
-
enqueueTask,
|
|
7
|
-
dequeueTask,
|
|
8
|
-
completeTask,
|
|
9
|
-
failTask,
|
|
10
|
-
retryTask,
|
|
11
|
-
getTaskResult,
|
|
12
|
-
recoverOrphanedTasks,
|
|
13
|
-
cleanupOldTasks,
|
|
14
|
-
} from './task-queue'
|
|
15
|
-
|
|
16
|
-
describe('Task Queue', () => {
|
|
17
|
-
let tmpDir: string
|
|
18
|
-
|
|
19
|
-
beforeEach(async () => {
|
|
20
|
-
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'canopy-taskq-test-'))
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
afterEach(async () => {
|
|
24
|
-
await fs.rm(tmpDir, { recursive: true, force: true })
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe('enqueueTask', () => {
|
|
28
|
-
it('creates a pending task file', async () => {
|
|
29
|
-
const id = await enqueueTask(tmpDir, {
|
|
30
|
-
action: 'push-and-create-pr',
|
|
31
|
-
payload: { branch: 'feature-1', title: 'New feature' },
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
expect(id).toBeTruthy()
|
|
35
|
-
|
|
36
|
-
const filePath = path.join(tmpDir, 'pending', `${id}.json`)
|
|
37
|
-
const content = JSON.parse(await fs.readFile(filePath, 'utf-8'))
|
|
38
|
-
expect(content.id).toBe(id)
|
|
39
|
-
expect(content.action).toBe('push-and-create-pr')
|
|
40
|
-
expect(content.payload.branch).toBe('feature-1')
|
|
41
|
-
expect(content.status).toBe('pending')
|
|
42
|
-
expect(content.createdAt).toBeTruthy()
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('creates unique IDs for multiple tasks', async () => {
|
|
46
|
-
const id1 = await enqueueTask(tmpDir, {
|
|
47
|
-
action: 'push-branch',
|
|
48
|
-
payload: {},
|
|
49
|
-
})
|
|
50
|
-
const id2 = await enqueueTask(tmpDir, {
|
|
51
|
-
action: 'push-branch',
|
|
52
|
-
payload: {},
|
|
53
|
-
})
|
|
54
|
-
expect(id1).not.toBe(id2)
|
|
55
|
-
})
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
describe('dequeueTask', () => {
|
|
59
|
-
it('returns the oldest pending task', async () => {
|
|
60
|
-
const id1 = await enqueueTask(tmpDir, {
|
|
61
|
-
action: 'push-branch',
|
|
62
|
-
payload: { n: 1 },
|
|
63
|
-
})
|
|
64
|
-
await new Promise((r) => setTimeout(r, 5)) // Ensure different createdAt timestamp
|
|
65
|
-
await enqueueTask(tmpDir, { action: 'push-branch', payload: { n: 2 } })
|
|
66
|
-
|
|
67
|
-
const task = await dequeueTask(tmpDir)
|
|
68
|
-
expect(task).not.toBeNull()
|
|
69
|
-
expect(task!.id).toBe(id1)
|
|
70
|
-
expect(task!.status).toBe('processing')
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('moves task from pending to processing', async () => {
|
|
74
|
-
const id = await enqueueTask(tmpDir, {
|
|
75
|
-
action: 'push-branch',
|
|
76
|
-
payload: {},
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
await dequeueTask(tmpDir)
|
|
80
|
-
|
|
81
|
-
// Should not be in pending
|
|
82
|
-
await expect(fs.stat(path.join(tmpDir, 'pending', `${id}.json`))).rejects.toThrow()
|
|
83
|
-
// Should be in processing
|
|
84
|
-
const stat = await fs.stat(path.join(tmpDir, 'processing', `${id}.json`))
|
|
85
|
-
expect(stat.isFile()).toBe(true)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('returns null when no pending tasks', async () => {
|
|
89
|
-
const task = await dequeueTask(tmpDir)
|
|
90
|
-
expect(task).toBeNull()
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('returns null when pending directory does not exist', async () => {
|
|
94
|
-
const task = await dequeueTask(path.join(tmpDir, 'nonexistent'))
|
|
95
|
-
expect(task).toBeNull()
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
describe('completeTask', () => {
|
|
100
|
-
it('moves task from processing to completed with result', async () => {
|
|
101
|
-
const id = await enqueueTask(tmpDir, {
|
|
102
|
-
action: 'push-and-create-pr',
|
|
103
|
-
payload: { branch: 'feat' },
|
|
104
|
-
})
|
|
105
|
-
await dequeueTask(tmpDir)
|
|
106
|
-
|
|
107
|
-
await completeTask(tmpDir, id, {
|
|
108
|
-
prUrl: 'https://github.com/pr/1',
|
|
109
|
-
prNumber: 1,
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// Should be in completed
|
|
113
|
-
const filePath = path.join(tmpDir, 'completed', `${id}.json`)
|
|
114
|
-
const content = JSON.parse(await fs.readFile(filePath, 'utf-8'))
|
|
115
|
-
expect(content.status).toBe('completed')
|
|
116
|
-
expect(content.result.prUrl).toBe('https://github.com/pr/1')
|
|
117
|
-
expect(content.completedAt).toBeTruthy()
|
|
118
|
-
|
|
119
|
-
// Should not be in processing
|
|
120
|
-
await expect(fs.stat(path.join(tmpDir, 'processing', `${id}.json`))).rejects.toThrow()
|
|
121
|
-
})
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
describe('failTask', () => {
|
|
125
|
-
it('moves task from processing to failed with error', async () => {
|
|
126
|
-
const id = await enqueueTask(tmpDir, {
|
|
127
|
-
action: 'push-and-create-pr',
|
|
128
|
-
payload: {},
|
|
129
|
-
})
|
|
130
|
-
await dequeueTask(tmpDir)
|
|
131
|
-
|
|
132
|
-
await failTask(tmpDir, id, 'GitHub API rate limited')
|
|
133
|
-
|
|
134
|
-
const filePath = path.join(tmpDir, 'failed', `${id}.json`)
|
|
135
|
-
const content = JSON.parse(await fs.readFile(filePath, 'utf-8'))
|
|
136
|
-
expect(content.status).toBe('failed')
|
|
137
|
-
expect(content.error).toBe('GitHub API rate limited')
|
|
138
|
-
expect(content.completedAt).toBeTruthy()
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
describe('getTaskResult', () => {
|
|
143
|
-
it('finds completed task', async () => {
|
|
144
|
-
const id = await enqueueTask(tmpDir, {
|
|
145
|
-
action: 'push-branch',
|
|
146
|
-
payload: {},
|
|
147
|
-
})
|
|
148
|
-
await dequeueTask(tmpDir)
|
|
149
|
-
await completeTask(tmpDir, id, { pushed: true })
|
|
150
|
-
|
|
151
|
-
const result = await getTaskResult(tmpDir, id)
|
|
152
|
-
expect(result).not.toBeNull()
|
|
153
|
-
expect(result!.status).toBe('completed')
|
|
154
|
-
expect(result!.result).toEqual({ pushed: true })
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
it('finds failed task', async () => {
|
|
158
|
-
const id = await enqueueTask(tmpDir, {
|
|
159
|
-
action: 'push-branch',
|
|
160
|
-
payload: {},
|
|
161
|
-
})
|
|
162
|
-
await dequeueTask(tmpDir)
|
|
163
|
-
await failTask(tmpDir, id, 'error')
|
|
164
|
-
|
|
165
|
-
const result = await getTaskResult(tmpDir, id)
|
|
166
|
-
expect(result!.status).toBe('failed')
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
it('finds pending task', async () => {
|
|
170
|
-
const id = await enqueueTask(tmpDir, {
|
|
171
|
-
action: 'push-branch',
|
|
172
|
-
payload: {},
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
const result = await getTaskResult(tmpDir, id)
|
|
176
|
-
expect(result!.status).toBe('pending')
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('finds processing task', async () => {
|
|
180
|
-
const id = await enqueueTask(tmpDir, {
|
|
181
|
-
action: 'push-branch',
|
|
182
|
-
payload: {},
|
|
183
|
-
})
|
|
184
|
-
await dequeueTask(tmpDir)
|
|
185
|
-
|
|
186
|
-
const result = await getTaskResult(tmpDir, id)
|
|
187
|
-
expect(result!.status).toBe('processing')
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('returns null for unknown task', async () => {
|
|
191
|
-
const result = await getTaskResult(tmpDir, 'nonexistent-id')
|
|
192
|
-
expect(result).toBeNull()
|
|
193
|
-
})
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
describe('full lifecycle', () => {
|
|
197
|
-
it('enqueue → dequeue → complete', async () => {
|
|
198
|
-
const id = await enqueueTask(tmpDir, {
|
|
199
|
-
action: 'push-and-create-pr',
|
|
200
|
-
payload: { branch: 'feature', title: 'New PR' },
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
const task = await dequeueTask(tmpDir)
|
|
204
|
-
expect(task!.id).toBe(id)
|
|
205
|
-
expect(task!.action).toBe('push-and-create-pr')
|
|
206
|
-
|
|
207
|
-
await completeTask(tmpDir, id, { prUrl: 'https://github.com/pr/42' })
|
|
208
|
-
|
|
209
|
-
const result = await getTaskResult(tmpDir, id)
|
|
210
|
-
expect(result!.status).toBe('completed')
|
|
211
|
-
expect(result!.result!.prUrl).toBe('https://github.com/pr/42')
|
|
212
|
-
|
|
213
|
-
// Queue should be empty
|
|
214
|
-
const next = await dequeueTask(tmpDir)
|
|
215
|
-
expect(next).toBeNull()
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
it('enqueue → dequeue → fail', async () => {
|
|
219
|
-
const id = await enqueueTask(tmpDir, {
|
|
220
|
-
action: 'push-branch',
|
|
221
|
-
payload: { branch: 'broken' },
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
await dequeueTask(tmpDir)
|
|
225
|
-
await failTask(tmpDir, id, 'Remote rejected push')
|
|
226
|
-
|
|
227
|
-
const result = await getTaskResult(tmpDir, id)
|
|
228
|
-
expect(result!.status).toBe('failed')
|
|
229
|
-
expect(result!.error).toBe('Remote rejected push')
|
|
230
|
-
})
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
describe('retryTask', () => {
|
|
234
|
-
it('moves task back to pending with incremented retryCount', async () => {
|
|
235
|
-
const id = await enqueueTask(tmpDir, {
|
|
236
|
-
action: 'push-branch',
|
|
237
|
-
payload: { branch: 'retry-me' },
|
|
238
|
-
})
|
|
239
|
-
await dequeueTask(tmpDir)
|
|
240
|
-
|
|
241
|
-
await retryTask(tmpDir, id, 'Transient error')
|
|
242
|
-
|
|
243
|
-
// Should be back in pending
|
|
244
|
-
const filePath = path.join(tmpDir, 'pending', `${id}.json`)
|
|
245
|
-
const content = JSON.parse(await fs.readFile(filePath, 'utf-8'))
|
|
246
|
-
expect(content.status).toBe('pending')
|
|
247
|
-
expect(content.retryCount).toBe(1)
|
|
248
|
-
expect(content.retryAfter).toBeTruthy()
|
|
249
|
-
expect(content.error).toBe('Transient error')
|
|
250
|
-
|
|
251
|
-
// Should not be in processing
|
|
252
|
-
await expect(fs.stat(path.join(tmpDir, 'processing', `${id}.json`))).rejects.toThrow()
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
it('sets retryAfter with exponential backoff', async () => {
|
|
256
|
-
const id = await enqueueTask(tmpDir, {
|
|
257
|
-
action: 'push-branch',
|
|
258
|
-
payload: {},
|
|
259
|
-
})
|
|
260
|
-
await dequeueTask(tmpDir)
|
|
261
|
-
|
|
262
|
-
const beforeRetry = Date.now()
|
|
263
|
-
await retryTask(tmpDir, id, 'error')
|
|
264
|
-
|
|
265
|
-
const content = JSON.parse(
|
|
266
|
-
await fs.readFile(path.join(tmpDir, 'pending', `${id}.json`), 'utf-8'),
|
|
267
|
-
)
|
|
268
|
-
const retryAfterMs = new Date(content.retryAfter).getTime()
|
|
269
|
-
// First retry backoff is 5000ms
|
|
270
|
-
expect(retryAfterMs).toBeGreaterThanOrEqual(beforeRetry + 4000)
|
|
271
|
-
expect(retryAfterMs).toBeLessThanOrEqual(beforeRetry + 10000)
|
|
272
|
-
})
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
describe('dequeueTask with retryAfter', () => {
|
|
276
|
-
it('skips tasks whose retryAfter is in the future', async () => {
|
|
277
|
-
const id = await enqueueTask(tmpDir, {
|
|
278
|
-
action: 'push-branch',
|
|
279
|
-
payload: {},
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
// Manually set a retryAfter in the future
|
|
283
|
-
const filePath = path.join(tmpDir, 'pending', `${id}.json`)
|
|
284
|
-
const content = JSON.parse(await fs.readFile(filePath, 'utf-8'))
|
|
285
|
-
content.retryAfter = new Date(Date.now() + 60_000).toISOString()
|
|
286
|
-
await fs.writeFile(filePath, JSON.stringify(content), 'utf-8')
|
|
287
|
-
|
|
288
|
-
const task = await dequeueTask(tmpDir)
|
|
289
|
-
expect(task).toBeNull()
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
it('dequeues tasks whose retryAfter is in the past', async () => {
|
|
293
|
-
const id = await enqueueTask(tmpDir, {
|
|
294
|
-
action: 'push-branch',
|
|
295
|
-
payload: {},
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
// Set retryAfter to the past
|
|
299
|
-
const filePath = path.join(tmpDir, 'pending', `${id}.json`)
|
|
300
|
-
const content = JSON.parse(await fs.readFile(filePath, 'utf-8'))
|
|
301
|
-
content.retryAfter = new Date(Date.now() - 1000).toISOString()
|
|
302
|
-
await fs.writeFile(filePath, JSON.stringify(content), 'utf-8')
|
|
303
|
-
|
|
304
|
-
const task = await dequeueTask(tmpDir)
|
|
305
|
-
expect(task).not.toBeNull()
|
|
306
|
-
expect(task!.id).toBe(id)
|
|
307
|
-
})
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
describe('dedup detection', () => {
|
|
311
|
-
it('skips dequeue if task already exists in completed', async () => {
|
|
312
|
-
const id = await enqueueTask(tmpDir, {
|
|
313
|
-
action: 'push-branch',
|
|
314
|
-
payload: {},
|
|
315
|
-
})
|
|
316
|
-
|
|
317
|
-
// Simulate crash scenario: task in both pending and completed
|
|
318
|
-
await fs.mkdir(path.join(tmpDir, 'completed'), { recursive: true })
|
|
319
|
-
const completedContent = {
|
|
320
|
-
id,
|
|
321
|
-
action: 'push-branch',
|
|
322
|
-
payload: {},
|
|
323
|
-
status: 'completed',
|
|
324
|
-
}
|
|
325
|
-
await fs.writeFile(
|
|
326
|
-
path.join(tmpDir, 'completed', `${id}.json`),
|
|
327
|
-
JSON.stringify(completedContent),
|
|
328
|
-
'utf-8',
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
const task = await dequeueTask(tmpDir)
|
|
332
|
-
expect(task).toBeNull()
|
|
333
|
-
|
|
334
|
-
// Pending copy should have been cleaned up
|
|
335
|
-
await expect(fs.stat(path.join(tmpDir, 'pending', `${id}.json`))).rejects.toThrow()
|
|
336
|
-
})
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
describe('recoverOrphanedTasks', () => {
|
|
340
|
-
it('moves stale tasks from processing back to pending', async () => {
|
|
341
|
-
const id = await enqueueTask(tmpDir, {
|
|
342
|
-
action: 'push-branch',
|
|
343
|
-
payload: {},
|
|
344
|
-
})
|
|
345
|
-
await dequeueTask(tmpDir)
|
|
346
|
-
|
|
347
|
-
// Small delay to ensure file mtime is in the past
|
|
348
|
-
await new Promise((r) => setTimeout(r, 10))
|
|
349
|
-
// Recover with maxAge of 0 (treat everything as stale)
|
|
350
|
-
const recovered = await recoverOrphanedTasks(tmpDir, 0)
|
|
351
|
-
expect(recovered).toBe(1)
|
|
352
|
-
|
|
353
|
-
// Should be back in pending
|
|
354
|
-
const filePath = path.join(tmpDir, 'pending', `${id}.json`)
|
|
355
|
-
const content = JSON.parse(await fs.readFile(filePath, 'utf-8'))
|
|
356
|
-
expect(content.status).toBe('pending')
|
|
357
|
-
})
|
|
358
|
-
|
|
359
|
-
it('skips recovery if task already in completed (dedup)', async () => {
|
|
360
|
-
const id = await enqueueTask(tmpDir, {
|
|
361
|
-
action: 'push-branch',
|
|
362
|
-
payload: {},
|
|
363
|
-
})
|
|
364
|
-
await dequeueTask(tmpDir)
|
|
365
|
-
|
|
366
|
-
// Simulate: task also in completed (crash between write and unlink)
|
|
367
|
-
await fs.mkdir(path.join(tmpDir, 'completed'), { recursive: true })
|
|
368
|
-
await fs.writeFile(
|
|
369
|
-
path.join(tmpDir, 'completed', `${id}.json`),
|
|
370
|
-
JSON.stringify({ id, status: 'completed' }),
|
|
371
|
-
'utf-8',
|
|
372
|
-
)
|
|
373
|
-
|
|
374
|
-
// Small delay to ensure file mtime is in the past
|
|
375
|
-
await new Promise((r) => setTimeout(r, 10))
|
|
376
|
-
const recovered = await recoverOrphanedTasks(tmpDir, 0)
|
|
377
|
-
expect(recovered).toBe(0)
|
|
378
|
-
|
|
379
|
-
// Processing copy should be cleaned up
|
|
380
|
-
await expect(fs.stat(path.join(tmpDir, 'processing', `${id}.json`))).rejects.toThrow()
|
|
381
|
-
})
|
|
382
|
-
})
|
|
383
|
-
|
|
384
|
-
describe('corrupt file handling', () => {
|
|
385
|
-
it('moves corrupt files to corrupt/ and continues processing', async () => {
|
|
386
|
-
// Write a corrupt file
|
|
387
|
-
await fs.mkdir(path.join(tmpDir, 'pending'), { recursive: true })
|
|
388
|
-
await fs.writeFile(
|
|
389
|
-
path.join(tmpDir, 'pending', 'bad-task.json'),
|
|
390
|
-
'not valid json {{{{',
|
|
391
|
-
'utf-8',
|
|
392
|
-
)
|
|
393
|
-
|
|
394
|
-
// Also enqueue a valid task
|
|
395
|
-
const validId = await enqueueTask(tmpDir, {
|
|
396
|
-
action: 'push-branch',
|
|
397
|
-
payload: {},
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
const task = await dequeueTask(tmpDir)
|
|
401
|
-
expect(task).not.toBeNull()
|
|
402
|
-
expect(task!.id).toBe(validId)
|
|
403
|
-
|
|
404
|
-
// Corrupt file should be in corrupt/
|
|
405
|
-
const corruptFile = path.join(tmpDir, 'corrupt', 'bad-task.json')
|
|
406
|
-
await expect(fs.stat(corruptFile)).resolves.toBeTruthy()
|
|
407
|
-
})
|
|
408
|
-
})
|
|
409
|
-
|
|
410
|
-
describe('cleanupOldTasks', () => {
|
|
411
|
-
it('removes old completed and failed tasks', async () => {
|
|
412
|
-
const id1 = await enqueueTask(tmpDir, {
|
|
413
|
-
action: 'push-branch',
|
|
414
|
-
payload: {},
|
|
415
|
-
})
|
|
416
|
-
await new Promise((r) => setTimeout(r, 5))
|
|
417
|
-
const id2 = await enqueueTask(tmpDir, {
|
|
418
|
-
action: 'push-branch',
|
|
419
|
-
payload: {},
|
|
420
|
-
})
|
|
421
|
-
await dequeueTask(tmpDir)
|
|
422
|
-
await completeTask(tmpDir, id1, {})
|
|
423
|
-
await dequeueTask(tmpDir)
|
|
424
|
-
await failTask(tmpDir, id2, 'error')
|
|
425
|
-
|
|
426
|
-
// Small delay to ensure file mtimes are in the past
|
|
427
|
-
await new Promise((r) => setTimeout(r, 10))
|
|
428
|
-
// Clean with maxAge of 0 (treat everything as old)
|
|
429
|
-
const cleaned = await cleanupOldTasks(tmpDir, 0)
|
|
430
|
-
expect(cleaned).toBe(2)
|
|
431
|
-
|
|
432
|
-
await expect(fs.stat(path.join(tmpDir, 'completed', `${id1}.json`))).rejects.toThrow()
|
|
433
|
-
await expect(fs.stat(path.join(tmpDir, 'failed', `${id2}.json`))).rejects.toThrow()
|
|
434
|
-
})
|
|
435
|
-
|
|
436
|
-
it('keeps recent tasks', async () => {
|
|
437
|
-
const id = await enqueueTask(tmpDir, {
|
|
438
|
-
action: 'push-branch',
|
|
439
|
-
payload: {},
|
|
440
|
-
})
|
|
441
|
-
await dequeueTask(tmpDir)
|
|
442
|
-
await completeTask(tmpDir, id, {})
|
|
443
|
-
|
|
444
|
-
// Clean with 1 hour max age — recent tasks should remain
|
|
445
|
-
const cleaned = await cleanupOldTasks(tmpDir, 60 * 60_000)
|
|
446
|
-
expect(cleaned).toBe(0)
|
|
447
|
-
|
|
448
|
-
const filePath = path.join(tmpDir, 'completed', `${id}.json`)
|
|
449
|
-
await expect(fs.stat(filePath)).resolves.toBeTruthy()
|
|
450
|
-
})
|
|
451
|
-
})
|
|
452
|
-
})
|
package/src/worker/task-queue.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CanopyCMS task queue — re-exports from the generic task-queue module
|
|
3
|
-
* with CMS-specific action types and a WorkerTask alias.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { createDebugLogger } from '../utils/debug'
|
|
7
|
-
import type { Task, TaskQueueLogger } from '../task-queue'
|
|
8
|
-
|
|
9
|
-
// ============================================================================
|
|
10
|
-
// CMS-specific types
|
|
11
|
-
// ============================================================================
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Actions the EC2 worker can execute on behalf of Lambda.
|
|
15
|
-
*/
|
|
16
|
-
export type TaskAction =
|
|
17
|
-
| 'push-and-create-pr'
|
|
18
|
-
| 'push-and-update-pr'
|
|
19
|
-
| 'push-and-create-or-update-pr'
|
|
20
|
-
| 'convert-to-draft'
|
|
21
|
-
| 'close-pr'
|
|
22
|
-
| 'delete-remote-branch'
|
|
23
|
-
| 'push-branch'
|
|
24
|
-
|
|
25
|
-
/** A task with a CMS-specific action. */
|
|
26
|
-
export type WorkerTask = Task & { action: TaskAction }
|
|
27
|
-
|
|
28
|
-
// ============================================================================
|
|
29
|
-
// Shared logger instance for CMS task queue operations
|
|
30
|
-
// ============================================================================
|
|
31
|
-
|
|
32
|
-
const debugLogger = createDebugLogger({ prefix: 'TaskQueue' })
|
|
33
|
-
|
|
34
|
-
export const cmsTaskQueueLogger: TaskQueueLogger = {
|
|
35
|
-
debug(message: string, data?: Record<string, unknown>) {
|
|
36
|
-
debugLogger.debug('task', message, data)
|
|
37
|
-
},
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// ============================================================================
|
|
41
|
-
// Re-exports from generic task-queue module
|
|
42
|
-
// ============================================================================
|
|
43
|
-
|
|
44
|
-
export {
|
|
45
|
-
enqueueTask,
|
|
46
|
-
dequeueTask,
|
|
47
|
-
completeTask,
|
|
48
|
-
failTask,
|
|
49
|
-
retryTask,
|
|
50
|
-
recoverOrphanedTasks,
|
|
51
|
-
cleanupOldTasks,
|
|
52
|
-
getTask,
|
|
53
|
-
getTask as getTaskResult, // backward-compatible alias
|
|
54
|
-
listTasks,
|
|
55
|
-
getQueueStats,
|
|
56
|
-
} from '../task-queue'
|
|
57
|
-
|
|
58
|
-
export type { Task, TaskStatus, QueueStats, TaskQueueLogger } from '../task-queue'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|