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
package/src/ai/generate.ts
DELETED
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core AI content generation engine.
|
|
3
|
-
*
|
|
4
|
-
* Shared by both the route handler (runtime) and build utility (static).
|
|
5
|
-
* Reads content from ContentStore, converts to markdown, and produces
|
|
6
|
-
* a manifest + file map.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import path from 'node:path'
|
|
10
|
-
|
|
11
|
-
import { minimatch } from 'minimatch'
|
|
12
|
-
|
|
13
|
-
import type { ContentStore, ContentDocument, MarkdownDocument } from '../content-store'
|
|
14
|
-
import type { FlatSchemaItem, EntryTypeConfig } from '../config'
|
|
15
|
-
import { extractEntryTypeFromFilename } from '../content-id-index'
|
|
16
|
-
import { getErrorMessage } from '../utils/error'
|
|
17
|
-
import { entryToMarkdown } from './json-to-markdown'
|
|
18
|
-
import type {
|
|
19
|
-
AIContentConfig,
|
|
20
|
-
AIEntry,
|
|
21
|
-
AIEntryMeta,
|
|
22
|
-
AIManifest,
|
|
23
|
-
AIManifestCollection,
|
|
24
|
-
AIManifestEntry,
|
|
25
|
-
AIManifestBundle,
|
|
26
|
-
} from './types'
|
|
27
|
-
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
// Public API
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
|
|
32
|
-
export interface GenerateOptions {
|
|
33
|
-
store: ContentStore
|
|
34
|
-
flatSchema: FlatSchemaItem[]
|
|
35
|
-
/** The content root name (e.g., 'content') */
|
|
36
|
-
contentRoot: string
|
|
37
|
-
config?: AIContentConfig
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface GenerateResult {
|
|
41
|
-
manifest: AIManifest
|
|
42
|
-
/** Map from clean path to markdown content (e.g., 'posts/all.md' → '...') */
|
|
43
|
-
files: Map<string, string>
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Generate all AI content from the content store.
|
|
48
|
-
*
|
|
49
|
-
* Walks the schema tree, reads entries, converts to markdown,
|
|
50
|
-
* and produces per-entry files, per-collection all.md files,
|
|
51
|
-
* bundle files, and a manifest.
|
|
52
|
-
*/
|
|
53
|
-
export async function generateAIContent(options: GenerateOptions): Promise<GenerateResult> {
|
|
54
|
-
const { store, flatSchema, contentRoot, config } = options
|
|
55
|
-
const files = new Map<string, string>()
|
|
56
|
-
|
|
57
|
-
// Build lookup maps from flat schema
|
|
58
|
-
const collections = flatSchema.filter(
|
|
59
|
-
(item): item is FlatSchemaItem & { type: 'collection' } => item.type === 'collection',
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
// Track all entries for bundle filtering
|
|
63
|
-
const allEntries: AIEntry[] = []
|
|
64
|
-
// Track manifest collections (tree structure)
|
|
65
|
-
const manifestCollections: AIManifestCollection[] = []
|
|
66
|
-
// Track root-level entries (entries in the content root, not in a subcollection)
|
|
67
|
-
const rootEntries: AIManifestEntry[] = []
|
|
68
|
-
|
|
69
|
-
// Process each collection
|
|
70
|
-
for (const collection of collections) {
|
|
71
|
-
// Skip the content root itself — we process its children
|
|
72
|
-
if (collection.logicalPath === contentRoot) continue
|
|
73
|
-
|
|
74
|
-
// Check exclusion
|
|
75
|
-
if (isCollectionExcluded(collection.logicalPath, contentRoot, config)) continue
|
|
76
|
-
|
|
77
|
-
// Only process top-level collections and direct subcollections here
|
|
78
|
-
// (subcollections are handled recursively via their parent)
|
|
79
|
-
if (collection.parentPath && collection.parentPath !== contentRoot) continue
|
|
80
|
-
|
|
81
|
-
const collectionResult = await processCollection(
|
|
82
|
-
store,
|
|
83
|
-
collection,
|
|
84
|
-
flatSchema,
|
|
85
|
-
contentRoot,
|
|
86
|
-
config,
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
allEntries.push(...collectionResult.entries)
|
|
90
|
-
for (const [filePath, content] of collectionResult.files) {
|
|
91
|
-
files.set(filePath, content)
|
|
92
|
-
}
|
|
93
|
-
manifestCollections.push(collectionResult.manifestCollection)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Process root-level entries (entries in content root, not in any subcollection)
|
|
97
|
-
const rootCollection = collections.find((c) => c.logicalPath === contentRoot)
|
|
98
|
-
if (rootCollection?.entries) {
|
|
99
|
-
const rootResult = await processRootEntries(store, rootCollection, contentRoot, config)
|
|
100
|
-
allEntries.push(...rootResult.entries)
|
|
101
|
-
for (const [filePath, content] of rootResult.files) {
|
|
102
|
-
files.set(filePath, content)
|
|
103
|
-
}
|
|
104
|
-
rootEntries.push(...rootResult.manifestEntries)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Process bundles
|
|
108
|
-
const manifestBundles: AIManifestBundle[] = []
|
|
109
|
-
if (config?.bundles) {
|
|
110
|
-
for (const bundle of config.bundles) {
|
|
111
|
-
// Validate bundle name to prevent path traversal
|
|
112
|
-
if (/[/\\]|\.\./.test(bundle.name)) {
|
|
113
|
-
throw new Error(`Invalid bundle name "${bundle.name}": must not contain slashes or ".."`)
|
|
114
|
-
}
|
|
115
|
-
const matchingEntries = allEntries.filter((entry) =>
|
|
116
|
-
matchesBundleFilter(entry, bundle.filter, contentRoot),
|
|
117
|
-
)
|
|
118
|
-
if (matchingEntries.length > 0) {
|
|
119
|
-
const bundleContent = matchingEntries
|
|
120
|
-
.map((e) => entryToMarkdown(e, config))
|
|
121
|
-
.join('\n---\n\n')
|
|
122
|
-
const bundlePath = `bundles/${bundle.name}.md`
|
|
123
|
-
files.set(bundlePath, bundleContent)
|
|
124
|
-
manifestBundles.push({
|
|
125
|
-
name: bundle.name,
|
|
126
|
-
description: bundle.description,
|
|
127
|
-
file: bundlePath,
|
|
128
|
-
entryCount: matchingEntries.length,
|
|
129
|
-
})
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Build manifest
|
|
135
|
-
const manifest: AIManifest = {
|
|
136
|
-
generated: new Date().toISOString(),
|
|
137
|
-
entries: rootEntries,
|
|
138
|
-
collections: manifestCollections,
|
|
139
|
-
bundles: manifestBundles,
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
files.set('manifest.json', JSON.stringify(manifest, null, 2))
|
|
143
|
-
|
|
144
|
-
return { manifest, files }
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
// Collection processing
|
|
149
|
-
// ---------------------------------------------------------------------------
|
|
150
|
-
|
|
151
|
-
interface CollectionProcessResult {
|
|
152
|
-
entries: AIEntry[]
|
|
153
|
-
files: Map<string, string>
|
|
154
|
-
manifestCollection: AIManifestCollection
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async function processCollection(
|
|
158
|
-
store: ContentStore,
|
|
159
|
-
collection: FlatSchemaItem & { type: 'collection' },
|
|
160
|
-
flatSchema: FlatSchemaItem[],
|
|
161
|
-
contentRoot: string,
|
|
162
|
-
config?: AIContentConfig,
|
|
163
|
-
): Promise<CollectionProcessResult> {
|
|
164
|
-
const files = new Map<string, string>()
|
|
165
|
-
const entries: AIEntry[] = []
|
|
166
|
-
const cleanPath = stripContentRoot(collection.logicalPath, contentRoot)
|
|
167
|
-
const manifestEntries: AIManifestEntry[] = []
|
|
168
|
-
|
|
169
|
-
// Read entries directly in this collection (not subcollections)
|
|
170
|
-
const listed = await store.listCollectionEntries(collection.logicalPath)
|
|
171
|
-
|
|
172
|
-
// Filter to only entries in this exact collection (not subcollections)
|
|
173
|
-
const directEntries = listed.filter((e) => e.collection === collection.logicalPath)
|
|
174
|
-
|
|
175
|
-
for (const listEntry of directEntries) {
|
|
176
|
-
const entryTypeName = extractEntryTypeFromFilename(path.basename(listEntry.relativePath))
|
|
177
|
-
if (!entryTypeName) continue
|
|
178
|
-
|
|
179
|
-
// Check entry type exclusion
|
|
180
|
-
if (config?.exclude?.entryTypes?.includes(entryTypeName)) continue
|
|
181
|
-
|
|
182
|
-
// Find the entry type config to get schema fields
|
|
183
|
-
const entryTypeConfig = findEntryType(collection, entryTypeName)
|
|
184
|
-
if (!entryTypeConfig) continue
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
const doc = await store.read(listEntry.collection, listEntry.slug, {
|
|
188
|
-
resolveReferences: false,
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
const aiEntry = docToAIEntry(doc, listEntry.slug, entryTypeName, entryTypeConfig, cleanPath)
|
|
192
|
-
|
|
193
|
-
// Check predicate exclusion
|
|
194
|
-
if (config?.exclude?.where?.(aiEntry)) continue
|
|
195
|
-
|
|
196
|
-
entries.push(aiEntry)
|
|
197
|
-
|
|
198
|
-
// Write individual entry file
|
|
199
|
-
const entryFilePath = `${cleanPath}/${listEntry.slug}.md`
|
|
200
|
-
const entryMarkdown = entryToMarkdown(aiEntry, config)
|
|
201
|
-
files.set(entryFilePath, entryMarkdown)
|
|
202
|
-
|
|
203
|
-
manifestEntries.push({
|
|
204
|
-
slug: listEntry.slug,
|
|
205
|
-
title: aiEntry.data.title ? String(aiEntry.data.title) : undefined,
|
|
206
|
-
file: entryFilePath,
|
|
207
|
-
})
|
|
208
|
-
} catch (err) {
|
|
209
|
-
console.warn(
|
|
210
|
-
`AI content: skipping entry "${listEntry.slug}" in ${collection.logicalPath}:`,
|
|
211
|
-
getErrorMessage(err),
|
|
212
|
-
)
|
|
213
|
-
continue
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Process subcollections
|
|
218
|
-
const subcollections = flatSchema.filter(
|
|
219
|
-
(item): item is FlatSchemaItem & { type: 'collection' } =>
|
|
220
|
-
item.type === 'collection' && item.parentPath === collection.logicalPath,
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
const manifestSubcollections: AIManifestCollection[] = []
|
|
224
|
-
for (const sub of subcollections) {
|
|
225
|
-
if (isCollectionExcluded(sub.logicalPath, contentRoot, config)) continue
|
|
226
|
-
|
|
227
|
-
const subResult = await processCollection(store, sub, flatSchema, contentRoot, config)
|
|
228
|
-
entries.push(...subResult.entries)
|
|
229
|
-
for (const [filePath, content] of subResult.files) {
|
|
230
|
-
files.set(filePath, content)
|
|
231
|
-
}
|
|
232
|
-
manifestSubcollections.push(subResult.manifestCollection)
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Write all.md for this collection (includes direct entries + subcollection entries)
|
|
236
|
-
if (entries.length > 0) {
|
|
237
|
-
const allContent = entries.map((e) => entryToMarkdown(e, config)).join('\n---\n\n')
|
|
238
|
-
const allPath = `${cleanPath}/all.md`
|
|
239
|
-
files.set(allPath, allContent)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const manifestCollection: AIManifestCollection = {
|
|
243
|
-
name: collection.name,
|
|
244
|
-
label: collection.label,
|
|
245
|
-
description: collection.description,
|
|
246
|
-
path: cleanPath,
|
|
247
|
-
allFile: entries.length > 0 ? `${cleanPath}/all.md` : undefined,
|
|
248
|
-
entryCount: entries.length,
|
|
249
|
-
entries: manifestEntries,
|
|
250
|
-
subcollections: manifestSubcollections.length > 0 ? manifestSubcollections : undefined,
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return { entries, files, manifestCollection }
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// ---------------------------------------------------------------------------
|
|
257
|
-
// Root entry processing
|
|
258
|
-
// ---------------------------------------------------------------------------
|
|
259
|
-
|
|
260
|
-
interface RootEntryResult {
|
|
261
|
-
entries: AIEntry[]
|
|
262
|
-
files: Map<string, string>
|
|
263
|
-
manifestEntries: AIManifestEntry[]
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
async function processRootEntries(
|
|
267
|
-
store: ContentStore,
|
|
268
|
-
rootCollection: FlatSchemaItem & { type: 'collection' },
|
|
269
|
-
contentRoot: string,
|
|
270
|
-
config?: AIContentConfig,
|
|
271
|
-
): Promise<RootEntryResult> {
|
|
272
|
-
const files = new Map<string, string>()
|
|
273
|
-
const entries: AIEntry[] = []
|
|
274
|
-
const manifestEntries: AIManifestEntry[] = []
|
|
275
|
-
|
|
276
|
-
const listed = await store.listCollectionEntries(rootCollection.logicalPath)
|
|
277
|
-
// Only direct entries in root (not in subcollections)
|
|
278
|
-
const directEntries = listed.filter((e) => e.collection === rootCollection.logicalPath)
|
|
279
|
-
|
|
280
|
-
for (const listEntry of directEntries) {
|
|
281
|
-
const entryTypeName = extractEntryTypeFromFilename(path.basename(listEntry.relativePath))
|
|
282
|
-
if (!entryTypeName) continue
|
|
283
|
-
|
|
284
|
-
if (config?.exclude?.entryTypes?.includes(entryTypeName)) continue
|
|
285
|
-
|
|
286
|
-
const entryTypeConfig = findEntryType(rootCollection, entryTypeName)
|
|
287
|
-
if (!entryTypeConfig) continue
|
|
288
|
-
|
|
289
|
-
try {
|
|
290
|
-
const doc = await store.read(listEntry.collection, listEntry.slug, {
|
|
291
|
-
resolveReferences: false,
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
const aiEntry = docToAIEntry(doc, listEntry.slug, entryTypeName, entryTypeConfig, '')
|
|
295
|
-
|
|
296
|
-
if (config?.exclude?.where?.(aiEntry)) continue
|
|
297
|
-
|
|
298
|
-
entries.push(aiEntry)
|
|
299
|
-
|
|
300
|
-
const entryFilePath = `${listEntry.slug}.md`
|
|
301
|
-
const entryMarkdown = entryToMarkdown(aiEntry, config)
|
|
302
|
-
files.set(entryFilePath, entryMarkdown)
|
|
303
|
-
|
|
304
|
-
manifestEntries.push({
|
|
305
|
-
slug: listEntry.slug,
|
|
306
|
-
title: aiEntry.data.title ? String(aiEntry.data.title) : undefined,
|
|
307
|
-
file: entryFilePath,
|
|
308
|
-
})
|
|
309
|
-
} catch (err) {
|
|
310
|
-
console.warn(`AI content: skipping root entry "${listEntry.slug}":`, getErrorMessage(err))
|
|
311
|
-
continue
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return { entries, files, manifestEntries }
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// ---------------------------------------------------------------------------
|
|
319
|
-
// Helpers
|
|
320
|
-
// ---------------------------------------------------------------------------
|
|
321
|
-
|
|
322
|
-
/** Strip contentRoot prefix from a logical path */
|
|
323
|
-
function stripContentRoot(logicalPath: string, contentRoot: string): string {
|
|
324
|
-
if (logicalPath.startsWith(contentRoot + '/')) {
|
|
325
|
-
return logicalPath.slice(contentRoot.length + 1)
|
|
326
|
-
}
|
|
327
|
-
return logicalPath
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/** Check if a collection is excluded by path */
|
|
331
|
-
function isCollectionExcluded(
|
|
332
|
-
logicalPath: string,
|
|
333
|
-
contentRoot: string,
|
|
334
|
-
config?: AIContentConfig,
|
|
335
|
-
): boolean {
|
|
336
|
-
if (!config?.exclude?.collections) return false
|
|
337
|
-
const cleanPath = stripContentRoot(logicalPath, contentRoot)
|
|
338
|
-
return config.exclude.collections.some(
|
|
339
|
-
(pattern) =>
|
|
340
|
-
// Match against clean path or full logical path
|
|
341
|
-
minimatch(cleanPath, pattern) || minimatch(logicalPath, pattern),
|
|
342
|
-
)
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/** Find an entry type config by name within a collection */
|
|
346
|
-
function findEntryType(
|
|
347
|
-
collection: FlatSchemaItem & { type: 'collection' },
|
|
348
|
-
entryTypeName: string,
|
|
349
|
-
): EntryTypeConfig | undefined {
|
|
350
|
-
return collection.entries?.find((e) => e.name === entryTypeName)
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/** Convert a ContentDocument to an AIEntry */
|
|
354
|
-
function docToAIEntry(
|
|
355
|
-
doc: ContentDocument,
|
|
356
|
-
slug: string,
|
|
357
|
-
entryTypeName: string,
|
|
358
|
-
entryTypeConfig: EntryTypeConfig,
|
|
359
|
-
cleanCollectionPath: string,
|
|
360
|
-
): AIEntry {
|
|
361
|
-
return {
|
|
362
|
-
slug,
|
|
363
|
-
collection: cleanCollectionPath,
|
|
364
|
-
collectionName: doc.collectionName,
|
|
365
|
-
entryType: entryTypeName,
|
|
366
|
-
format: doc.format,
|
|
367
|
-
data: doc.data,
|
|
368
|
-
body: doc.format !== 'json' ? (doc as MarkdownDocument).body : undefined,
|
|
369
|
-
fields: entryTypeConfig.schema,
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/** Check if an entry matches a bundle filter (filters are AND'd) */
|
|
374
|
-
function matchesBundleFilter(
|
|
375
|
-
entry: AIEntryMeta,
|
|
376
|
-
filter: NonNullable<AIContentConfig['bundles']>[number]['filter'],
|
|
377
|
-
contentRoot: string,
|
|
378
|
-
): boolean {
|
|
379
|
-
// Collections filter
|
|
380
|
-
if (filter.collections) {
|
|
381
|
-
const matches = filter.collections.some((pattern) => {
|
|
382
|
-
const cleanPattern = stripContentRoot(pattern, contentRoot)
|
|
383
|
-
return (
|
|
384
|
-
entry.collection === cleanPattern ||
|
|
385
|
-
entry.collection === pattern ||
|
|
386
|
-
entry.collection.startsWith(cleanPattern + '/')
|
|
387
|
-
)
|
|
388
|
-
})
|
|
389
|
-
if (!matches) return false
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// Entry types filter
|
|
393
|
-
if (filter.entryTypes) {
|
|
394
|
-
if (!filter.entryTypes.includes(entry.entryType)) return false
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Path glob filter
|
|
398
|
-
if (filter.paths) {
|
|
399
|
-
const entryPath = entry.collection ? `${entry.collection}/${entry.slug}` : entry.slug
|
|
400
|
-
const matches = filter.paths.some((pattern) => minimatch(entryPath, pattern))
|
|
401
|
-
if (!matches) return false
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Predicate filter
|
|
405
|
-
if (filter.where) {
|
|
406
|
-
if (!filter.where(entry)) return false
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return true
|
|
410
|
-
}
|
package/src/ai/handler.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Next.js route handler for AI content.
|
|
3
|
-
*
|
|
4
|
-
* Creates a lightweight, read-only handler that serves AI-ready markdown.
|
|
5
|
-
* Does NOT require authentication or the editor API — only needs ContentStore.
|
|
6
|
-
*
|
|
7
|
-
* Mount as a Next.js catch-all route:
|
|
8
|
-
* ```ts
|
|
9
|
-
* // app/ai/[...path]/route.ts
|
|
10
|
-
* export const GET = createAIContentHandler({ config, entrySchemaRegistry })
|
|
11
|
-
* ```
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { ContentStore } from '../content-store'
|
|
15
|
-
import { BranchSchemaCache } from '../branch-schema-cache'
|
|
16
|
-
import type { CanopyConfig, FlatSchemaItem } from '../config'
|
|
17
|
-
import type { EntrySchemaRegistry } from '../schema/types'
|
|
18
|
-
import { getErrorMessage } from '../utils/error'
|
|
19
|
-
import { generateAIContent, type GenerateResult } from './generate'
|
|
20
|
-
import { resolveBranchRoot } from './resolve-branch'
|
|
21
|
-
import type { AIContentConfig } from './types'
|
|
22
|
-
|
|
23
|
-
export interface AIContentHandlerOptions {
|
|
24
|
-
config: CanopyConfig
|
|
25
|
-
entrySchemaRegistry: EntrySchemaRegistry
|
|
26
|
-
aiConfig?: AIContentConfig
|
|
27
|
-
/** @internal Test-only: pre-resolved schema to bypass BranchSchemaCache */
|
|
28
|
-
_testFlatSchema?: FlatSchemaItem[]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Create a Next.js GET handler for serving AI content.
|
|
33
|
-
*
|
|
34
|
-
* Returns a function compatible with Next.js route handlers.
|
|
35
|
-
*
|
|
36
|
-
* Caching strategy:
|
|
37
|
-
* - Dev mode: regenerates on every request (picks up content changes immediately)
|
|
38
|
-
* - Prod/prod-sim: generates once per process lifetime (Lambda instances are recycled
|
|
39
|
-
* on deploy, so content changes via merge → deploy → new instance with fresh cache)
|
|
40
|
-
*/
|
|
41
|
-
export function createAIContentHandler(
|
|
42
|
-
options: AIContentHandlerOptions,
|
|
43
|
-
): (req: Request, ctx: { params: Promise<{ path: string[] }> }) => Promise<Response> {
|
|
44
|
-
const { config, entrySchemaRegistry, aiConfig, _testFlatSchema } = options
|
|
45
|
-
const schemaCache = new BranchSchemaCache(config.mode)
|
|
46
|
-
let cachedResult: GenerateResult | null = null
|
|
47
|
-
|
|
48
|
-
const generate = async (): Promise<GenerateResult> => {
|
|
49
|
-
// In dev mode, always regenerate (content changes without deploys)
|
|
50
|
-
if (config.mode === 'dev') {
|
|
51
|
-
if (!_testFlatSchema) {
|
|
52
|
-
await schemaCache.clearAll()
|
|
53
|
-
}
|
|
54
|
-
cachedResult = null
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (cachedResult) return cachedResult
|
|
58
|
-
|
|
59
|
-
// Resolve branch root
|
|
60
|
-
const branchRoot = await resolveBranchRoot(config)
|
|
61
|
-
const contentRootName = config.contentRoot || 'content'
|
|
62
|
-
|
|
63
|
-
// Load schema (use test override if provided)
|
|
64
|
-
const flatSchema =
|
|
65
|
-
_testFlatSchema ??
|
|
66
|
-
(await schemaCache.getSchema(branchRoot, entrySchemaRegistry, contentRootName)).flatSchema
|
|
67
|
-
|
|
68
|
-
// Create store and generate
|
|
69
|
-
const store = new ContentStore(branchRoot, flatSchema)
|
|
70
|
-
const result = await generateAIContent({
|
|
71
|
-
store,
|
|
72
|
-
flatSchema,
|
|
73
|
-
contentRoot: contentRootName,
|
|
74
|
-
config: aiConfig,
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
cachedResult = result
|
|
78
|
-
return result
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return async (_req: Request, ctx: { params: Promise<{ path: string[] }> }): Promise<Response> => {
|
|
82
|
-
try {
|
|
83
|
-
const { path: pathSegments } = await ctx.params
|
|
84
|
-
const result = await generate()
|
|
85
|
-
|
|
86
|
-
// Join path segments to get the file key
|
|
87
|
-
const requestPath = pathSegments.join('/')
|
|
88
|
-
|
|
89
|
-
// Check for manifest
|
|
90
|
-
if (requestPath === 'manifest.json') {
|
|
91
|
-
return new Response(result.files.get('manifest.json'), {
|
|
92
|
-
headers: {
|
|
93
|
-
'Content-Type': 'application/json; charset=utf-8',
|
|
94
|
-
'Cache-Control': config.mode === 'dev' ? 'no-cache' : 'public, max-age=60',
|
|
95
|
-
},
|
|
96
|
-
})
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Check for generated file
|
|
100
|
-
const content = result.files.get(requestPath)
|
|
101
|
-
if (content) {
|
|
102
|
-
return new Response(content, {
|
|
103
|
-
headers: {
|
|
104
|
-
'Content-Type': 'text/markdown; charset=utf-8',
|
|
105
|
-
'Cache-Control': config.mode === 'dev' ? 'no-cache' : 'public, max-age=60',
|
|
106
|
-
},
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return new Response(JSON.stringify({ error: 'Not found' }), {
|
|
111
|
-
status: 404,
|
|
112
|
-
headers: { 'Content-Type': 'application/json' },
|
|
113
|
-
})
|
|
114
|
-
} catch (error) {
|
|
115
|
-
// Log the real error server-side; don't leak internals to unauthenticated callers
|
|
116
|
-
console.error('AI content handler error:', getErrorMessage(error))
|
|
117
|
-
return new Response(JSON.stringify({ error: 'Internal server error' }), {
|
|
118
|
-
status: 500,
|
|
119
|
-
headers: { 'Content-Type': 'application/json' },
|
|
120
|
-
})
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
package/src/ai/index.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public exports for canopycms/ai entrypoint.
|
|
3
|
-
*
|
|
4
|
-
* Provides AI-ready content generation: config helpers,
|
|
5
|
-
* route handler for runtime serving, and content types.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export { defineAIContentConfig } from './types'
|
|
9
|
-
export { createAIContentHandler } from './handler'
|
|
10
|
-
export { generateAIContent } from './generate'
|
|
11
|
-
export type {
|
|
12
|
-
AIContentConfig,
|
|
13
|
-
ExcludeConfig,
|
|
14
|
-
BundleConfig,
|
|
15
|
-
BundleFilter,
|
|
16
|
-
FieldTransformFn,
|
|
17
|
-
FieldTransforms,
|
|
18
|
-
AIManifest,
|
|
19
|
-
AIManifestCollection,
|
|
20
|
-
AIManifestEntry,
|
|
21
|
-
AIManifestBundle,
|
|
22
|
-
AIEntry,
|
|
23
|
-
AIEntryMeta,
|
|
24
|
-
} from './types'
|
|
25
|
-
export type { AIContentHandlerOptions } from './handler'
|
|
26
|
-
export type { GenerateOptions, GenerateResult } from './generate'
|