@krantho/api 0.0.0-stage → 1.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/LICENSE +21 -0
- package/dist/active-locales.d.ts +11 -0
- package/dist/active-locales.d.ts.map +1 -0
- package/dist/active-locales.js +31 -0
- package/dist/active-locales.js.map +1 -0
- package/dist/assistant/access.d.ts +25 -0
- package/dist/assistant/access.d.ts.map +1 -0
- package/dist/assistant/access.js +35 -0
- package/dist/assistant/access.js.map +1 -0
- package/dist/assistant/agent-loop.d.ts +31 -0
- package/dist/assistant/agent-loop.d.ts.map +1 -0
- package/dist/assistant/agent-loop.js +183 -0
- package/dist/assistant/agent-loop.js.map +1 -0
- package/dist/assistant/call-handler.d.ts +15 -0
- package/dist/assistant/call-handler.d.ts.map +1 -0
- package/dist/assistant/call-handler.js +24 -0
- package/dist/assistant/call-handler.js.map +1 -0
- package/dist/assistant/chat-handler.d.ts +8 -0
- package/dist/assistant/chat-handler.d.ts.map +1 -0
- package/dist/assistant/chat-handler.js +79 -0
- package/dist/assistant/chat-handler.js.map +1 -0
- package/dist/assistant/chat-request.d.ts +16 -0
- package/dist/assistant/chat-request.d.ts.map +1 -0
- package/dist/assistant/chat-request.js +59 -0
- package/dist/assistant/chat-request.js.map +1 -0
- package/dist/assistant/confirm-handler.d.ts +3 -0
- package/dist/assistant/confirm-handler.d.ts.map +1 -0
- package/dist/assistant/confirm-handler.js +39 -0
- package/dist/assistant/confirm-handler.js.map +1 -0
- package/dist/assistant/document-change.d.ts +22 -0
- package/dist/assistant/document-change.d.ts.map +1 -0
- package/dist/assistant/document-change.js +74 -0
- package/dist/assistant/document-change.js.map +1 -0
- package/dist/assistant/document-lock.d.ts +12 -0
- package/dist/assistant/document-lock.d.ts.map +1 -0
- package/dist/assistant/document-lock.js +14 -0
- package/dist/assistant/document-lock.js.map +1 -0
- package/dist/assistant/execute-action.d.ts +19 -0
- package/dist/assistant/execute-action.d.ts.map +1 -0
- package/dist/assistant/execute-action.js +167 -0
- package/dist/assistant/execute-action.js.map +1 -0
- package/dist/assistant/pending-action.d.ts +86 -0
- package/dist/assistant/pending-action.d.ts.map +1 -0
- package/dist/assistant/pending-action.js +104 -0
- package/dist/assistant/pending-action.js.map +1 -0
- package/dist/assistant/protocol.d.ts +120 -0
- package/dist/assistant/protocol.d.ts.map +1 -0
- package/dist/assistant/protocol.js +2 -0
- package/dist/assistant/protocol.js.map +1 -0
- package/dist/assistant/routes.d.ts +4 -0
- package/dist/assistant/routes.d.ts.map +1 -0
- package/dist/assistant/routes.js +10 -0
- package/dist/assistant/routes.js.map +1 -0
- package/dist/assistant/sse-stream.d.ts +15 -0
- package/dist/assistant/sse-stream.d.ts.map +1 -0
- package/dist/assistant/sse-stream.js +61 -0
- package/dist/assistant/sse-stream.js.map +1 -0
- package/dist/assistant/status-handler.d.ts +8 -0
- package/dist/assistant/status-handler.d.ts.map +1 -0
- package/dist/assistant/status-handler.js +39 -0
- package/dist/assistant/status-handler.js.map +1 -0
- package/dist/assistant/system-prompt.d.ts +18 -0
- package/dist/assistant/system-prompt.d.ts.map +1 -0
- package/dist/assistant/system-prompt.js +48 -0
- package/dist/assistant/system-prompt.js.map +1 -0
- package/dist/assistant/tool-registry.d.ts +19 -0
- package/dist/assistant/tool-registry.d.ts.map +1 -0
- package/dist/assistant/tool-registry.js +69 -0
- package/dist/assistant/tool-registry.js.map +1 -0
- package/dist/assistant/tools/action-tools.d.ts +4 -0
- package/dist/assistant/tools/action-tools.d.ts.map +1 -0
- package/dist/assistant/tools/action-tools.js +132 -0
- package/dist/assistant/tools/action-tools.js.map +1 -0
- package/dist/assistant/tools/aeo-tools.d.ts +4 -0
- package/dist/assistant/tools/aeo-tools.d.ts.map +1 -0
- package/dist/assistant/tools/aeo-tools.js +162 -0
- package/dist/assistant/tools/aeo-tools.js.map +1 -0
- package/dist/assistant/tools/define-tool.d.ts +55 -0
- package/dist/assistant/tools/define-tool.d.ts.map +1 -0
- package/dist/assistant/tools/define-tool.js +5 -0
- package/dist/assistant/tools/define-tool.js.map +1 -0
- package/dist/assistant/tools/draft-tools.d.ts +7 -0
- package/dist/assistant/tools/draft-tools.d.ts.map +1 -0
- package/dist/assistant/tools/draft-tools.js +105 -0
- package/dist/assistant/tools/draft-tools.js.map +1 -0
- package/dist/assistant/tools/draft-write.d.ts +49 -0
- package/dist/assistant/tools/draft-write.d.ts.map +1 -0
- package/dist/assistant/tools/draft-write.js +122 -0
- package/dist/assistant/tools/draft-write.js.map +1 -0
- package/dist/assistant/tools/faq-fit.d.ts +32 -0
- package/dist/assistant/tools/faq-fit.d.ts.map +1 -0
- package/dist/assistant/tools/faq-fit.js +96 -0
- package/dist/assistant/tools/faq-fit.js.map +1 -0
- package/dist/assistant/tools/read-tools.d.ts +13 -0
- package/dist/assistant/tools/read-tools.d.ts.map +1 -0
- package/dist/assistant/tools/read-tools.js +242 -0
- package/dist/assistant/tools/read-tools.js.map +1 -0
- package/dist/assistant/tools/seo-tools.d.ts +4 -0
- package/dist/assistant/tools/seo-tools.d.ts.map +1 -0
- package/dist/assistant/tools/seo-tools.js +152 -0
- package/dist/assistant/tools/seo-tools.js.map +1 -0
- package/dist/assistant/tools/support.d.ts +35 -0
- package/dist/assistant/tools/support.d.ts.map +1 -0
- package/dist/assistant/tools/support.js +63 -0
- package/dist/assistant/tools/support.js.map +1 -0
- package/dist/assistant/untrusted.d.ts +15 -0
- package/dist/assistant/untrusted.d.ts.map +1 -0
- package/dist/assistant/untrusted.js +27 -0
- package/dist/assistant/untrusted.js.map +1 -0
- package/dist/assistant/write-policy.d.ts +20 -0
- package/dist/assistant/write-policy.d.ts.map +1 -0
- package/dist/assistant/write-policy.js +32 -0
- package/dist/assistant/write-policy.js.map +1 -0
- package/dist/auth-tokens.d.ts +31 -0
- package/dist/auth-tokens.d.ts.map +1 -0
- package/dist/auth-tokens.js +35 -0
- package/dist/auth-tokens.js.map +1 -0
- package/dist/content-change.d.ts +16 -0
- package/dist/content-change.d.ts.map +1 -0
- package/dist/content-change.js +34 -0
- package/dist/content-change.js.map +1 -0
- package/dist/content-locks.d.ts +27 -0
- package/dist/content-locks.d.ts.map +1 -0
- package/dist/content-locks.js +40 -0
- package/dist/content-locks.js.map +1 -0
- package/dist/cookies.d.ts +19 -0
- package/dist/cookies.d.ts.map +1 -0
- package/dist/cookies.js +52 -0
- package/dist/cookies.js.map +1 -0
- package/dist/create-api-handlers.d.ts +128 -0
- package/dist/create-api-handlers.d.ts.map +1 -0
- package/dist/create-api-handlers.js +384 -0
- package/dist/create-api-handlers.js.map +1 -0
- package/dist/document-actions.d.ts +25 -0
- package/dist/document-actions.d.ts.map +1 -0
- package/dist/document-actions.js +157 -0
- package/dist/document-actions.js.map +1 -0
- package/dist/document-seo.d.ts +15 -0
- package/dist/document-seo.d.ts.map +1 -0
- package/dist/document-seo.js +41 -0
- package/dist/document-seo.js.map +1 -0
- package/dist/group-by-collection.d.ts +6 -0
- package/dist/group-by-collection.d.ts.map +1 -0
- package/dist/group-by-collection.js +11 -0
- package/dist/group-by-collection.js.map +1 -0
- package/dist/handlers/apply-metadata-defaults.d.ts +4 -0
- package/dist/handlers/apply-metadata-defaults.d.ts.map +1 -0
- package/dist/handlers/apply-metadata-defaults.js +108 -0
- package/dist/handlers/apply-metadata-defaults.js.map +1 -0
- package/dist/handlers/auth-callback.d.ts +4 -0
- package/dist/handlers/auth-callback.d.ts.map +1 -0
- package/dist/handlers/auth-callback.js +217 -0
- package/dist/handlers/auth-callback.js.map +1 -0
- package/dist/handlers/auth-capabilities.d.ts +4 -0
- package/dist/handlers/auth-capabilities.d.ts.map +1 -0
- package/dist/handlers/auth-capabilities.js +19 -0
- package/dist/handlers/auth-capabilities.js.map +1 -0
- package/dist/handlers/auth-login.d.ts +4 -0
- package/dist/handlers/auth-login.d.ts.map +1 -0
- package/dist/handlers/auth-login.js +60 -0
- package/dist/handlers/auth-login.js.map +1 -0
- package/dist/handlers/auth-logout.d.ts +4 -0
- package/dist/handlers/auth-logout.d.ts.map +1 -0
- package/dist/handlers/auth-logout.js +40 -0
- package/dist/handlers/auth-logout.js.map +1 -0
- package/dist/handlers/auth-me.d.ts +4 -0
- package/dist/handlers/auth-me.d.ts.map +1 -0
- package/dist/handlers/auth-me.js +54 -0
- package/dist/handlers/auth-me.js.map +1 -0
- package/dist/handlers/auth-oidc-login.d.ts +4 -0
- package/dist/handlers/auth-oidc-login.d.ts.map +1 -0
- package/dist/handlers/auth-oidc-login.js +51 -0
- package/dist/handlers/auth-oidc-login.js.map +1 -0
- package/dist/handlers/auth-refresh.d.ts +15 -0
- package/dist/handlers/auth-refresh.d.ts.map +1 -0
- package/dist/handlers/auth-refresh.js +82 -0
- package/dist/handlers/auth-refresh.js.map +1 -0
- package/dist/handlers/bulk-delete.d.ts +8 -0
- package/dist/handlers/bulk-delete.d.ts.map +1 -0
- package/dist/handlers/bulk-delete.js +72 -0
- package/dist/handlers/bulk-delete.js.map +1 -0
- package/dist/handlers/bulk-publish.d.ts +8 -0
- package/dist/handlers/bulk-publish.d.ts.map +1 -0
- package/dist/handlers/bulk-publish.js +48 -0
- package/dist/handlers/bulk-publish.js.map +1 -0
- package/dist/handlers/capabilities.d.ts +4 -0
- package/dist/handlers/capabilities.d.ts.map +1 -0
- package/dist/handlers/capabilities.js +44 -0
- package/dist/handlers/capabilities.js.map +1 -0
- package/dist/handlers/content-changes.d.ts +28 -0
- package/dist/handlers/content-changes.d.ts.map +1 -0
- package/dist/handlers/content-changes.js +160 -0
- package/dist/handlers/content-changes.js.map +1 -0
- package/dist/handlers/content-lock.d.ts +13 -0
- package/dist/handlers/content-lock.d.ts.map +1 -0
- package/dist/handlers/content-lock.js +109 -0
- package/dist/handlers/content-lock.js.map +1 -0
- package/dist/handlers/content-tree.d.ts +11 -0
- package/dist/handlers/content-tree.d.ts.map +1 -0
- package/dist/handlers/content-tree.js +28 -0
- package/dist/handlers/content-tree.js.map +1 -0
- package/dist/handlers/create-content.d.ts +4 -0
- package/dist/handlers/create-content.d.ts.map +1 -0
- package/dist/handlers/create-content.js +49 -0
- package/dist/handlers/create-content.js.map +1 -0
- package/dist/handlers/delete-content.d.ts +4 -0
- package/dist/handlers/delete-content.d.ts.map +1 -0
- package/dist/handlers/delete-content.js +17 -0
- package/dist/handlers/delete-content.js.map +1 -0
- package/dist/handlers/delete-runtime-field.d.ts +4 -0
- package/dist/handlers/delete-runtime-field.d.ts.map +1 -0
- package/dist/handlers/delete-runtime-field.js +43 -0
- package/dist/handlers/delete-runtime-field.js.map +1 -0
- package/dist/handlers/export-bundle.d.ts +13 -0
- package/dist/handlers/export-bundle.d.ts.map +1 -0
- package/dist/handlers/export-bundle.js +99 -0
- package/dist/handlers/export-bundle.js.map +1 -0
- package/dist/handlers/export-content.d.ts +7 -0
- package/dist/handlers/export-content.d.ts.map +1 -0
- package/dist/handlers/export-content.js +69 -0
- package/dist/handlers/export-content.js.map +1 -0
- package/dist/handlers/export-schema.d.ts +4 -0
- package/dist/handlers/export-schema.d.ts.map +1 -0
- package/dist/handlers/export-schema.js +13 -0
- package/dist/handlers/export-schema.js.map +1 -0
- package/dist/handlers/get-content.d.ts +4 -0
- package/dist/handlers/get-content.d.ts.map +1 -0
- package/dist/handlers/get-content.js +65 -0
- package/dist/handlers/get-content.js.map +1 -0
- package/dist/handlers/get-runtime-schema.d.ts +4 -0
- package/dist/handlers/get-runtime-schema.d.ts.map +1 -0
- package/dist/handlers/get-runtime-schema.js +17 -0
- package/dist/handlers/get-runtime-schema.js.map +1 -0
- package/dist/handlers/get-schema.d.ts +4 -0
- package/dist/handlers/get-schema.d.ts.map +1 -0
- package/dist/handlers/get-schema.js +87 -0
- package/dist/handlers/get-schema.js.map +1 -0
- package/dist/handlers/get-version.d.ts +4 -0
- package/dist/handlers/get-version.d.ts.map +1 -0
- package/dist/handlers/get-version.js +26 -0
- package/dist/handlers/get-version.js.map +1 -0
- package/dist/handlers/import-bundle.d.ts +4 -0
- package/dist/handlers/import-bundle.d.ts.map +1 -0
- package/dist/handlers/import-bundle.js +55 -0
- package/dist/handlers/import-bundle.js.map +1 -0
- package/dist/handlers/import-content.d.ts +4 -0
- package/dist/handlers/import-content.d.ts.map +1 -0
- package/dist/handlers/import-content.js +152 -0
- package/dist/handlers/import-content.js.map +1 -0
- package/dist/handlers/index.d.ts +87 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +87 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/list-collection.d.ts +8 -0
- package/dist/handlers/list-collection.d.ts.map +1 -0
- package/dist/handlers/list-collection.js +14 -0
- package/dist/handlers/list-collection.js.map +1 -0
- package/dist/handlers/list-collections.d.ts +4 -0
- package/dist/handlers/list-collections.d.ts.map +1 -0
- package/dist/handlers/list-collections.js +17 -0
- package/dist/handlers/list-collections.js.map +1 -0
- package/dist/handlers/list-content.d.ts +8 -0
- package/dist/handlers/list-content.d.ts.map +1 -0
- package/dist/handlers/list-content.js +22 -0
- package/dist/handlers/list-content.js.map +1 -0
- package/dist/handlers/list-query.d.ts +7 -0
- package/dist/handlers/list-query.d.ts.map +1 -0
- package/dist/handlers/list-query.js +36 -0
- package/dist/handlers/list-query.js.map +1 -0
- package/dist/handlers/list-versions.d.ts +4 -0
- package/dist/handlers/list-versions.d.ts.map +1 -0
- package/dist/handlers/list-versions.js +19 -0
- package/dist/handlers/list-versions.js.map +1 -0
- package/dist/handlers/llm-credential.d.ts +46 -0
- package/dist/handlers/llm-credential.d.ts.map +1 -0
- package/dist/handlers/llm-credential.js +68 -0
- package/dist/handlers/llm-credential.js.map +1 -0
- package/dist/handlers/llm-resolve.d.ts +45 -0
- package/dist/handlers/llm-resolve.d.ts.map +1 -0
- package/dist/handlers/llm-resolve.js +126 -0
- package/dist/handlers/llm-resolve.js.map +1 -0
- package/dist/handlers/llm-settings.d.ts +19 -0
- package/dist/handlers/llm-settings.d.ts.map +1 -0
- package/dist/handlers/llm-settings.js +209 -0
- package/dist/handlers/llm-settings.js.map +1 -0
- package/dist/handlers/media-bulk-delete.d.ts +4 -0
- package/dist/handlers/media-bulk-delete.d.ts.map +1 -0
- package/dist/handlers/media-bulk-delete.js +19 -0
- package/dist/handlers/media-bulk-delete.js.map +1 -0
- package/dist/handlers/media-bulk-update.d.ts +4 -0
- package/dist/handlers/media-bulk-update.d.ts.map +1 -0
- package/dist/handlers/media-bulk-update.js +25 -0
- package/dist/handlers/media-bulk-update.js.map +1 -0
- package/dist/handlers/media-delete.d.ts +4 -0
- package/dist/handlers/media-delete.d.ts.map +1 -0
- package/dist/handlers/media-delete.js +27 -0
- package/dist/handlers/media-delete.js.map +1 -0
- package/dist/handlers/media-duplicate.d.ts +4 -0
- package/dist/handlers/media-duplicate.d.ts.map +1 -0
- package/dist/handlers/media-duplicate.js +20 -0
- package/dist/handlers/media-duplicate.js.map +1 -0
- package/dist/handlers/media-folders.d.ts +12 -0
- package/dist/handlers/media-folders.d.ts.map +1 -0
- package/dist/handlers/media-folders.js +119 -0
- package/dist/handlers/media-folders.js.map +1 -0
- package/dist/handlers/media-get.d.ts +4 -0
- package/dist/handlers/media-get.d.ts.map +1 -0
- package/dist/handlers/media-get.js +16 -0
- package/dist/handlers/media-get.js.map +1 -0
- package/dist/handlers/media-image-info.d.ts +4 -0
- package/dist/handlers/media-image-info.d.ts.map +1 -0
- package/dist/handlers/media-image-info.js +32 -0
- package/dist/handlers/media-image-info.js.map +1 -0
- package/dist/handlers/media-image.d.ts +11 -0
- package/dist/handlers/media-image.d.ts.map +1 -0
- package/dist/handlers/media-image.js +116 -0
- package/dist/handlers/media-image.js.map +1 -0
- package/dist/handlers/media-info.d.ts +4 -0
- package/dist/handlers/media-info.d.ts.map +1 -0
- package/dist/handlers/media-info.js +18 -0
- package/dist/handlers/media-info.js.map +1 -0
- package/dist/handlers/media-list.d.ts +4 -0
- package/dist/handlers/media-list.d.ts.map +1 -0
- package/dist/handlers/media-list.js +14 -0
- package/dist/handlers/media-list.js.map +1 -0
- package/dist/handlers/media-register.d.ts +4 -0
- package/dist/handlers/media-register.d.ts.map +1 -0
- package/dist/handlers/media-register.js +57 -0
- package/dist/handlers/media-register.js.map +1 -0
- package/dist/handlers/media-replace.d.ts +9 -0
- package/dist/handlers/media-replace.d.ts.map +1 -0
- package/dist/handlers/media-replace.js +53 -0
- package/dist/handlers/media-replace.js.map +1 -0
- package/dist/handlers/media-tags.d.ts +4 -0
- package/dist/handlers/media-tags.d.ts.map +1 -0
- package/dist/handlers/media-tags.js +9 -0
- package/dist/handlers/media-tags.js.map +1 -0
- package/dist/handlers/media-update.d.ts +4 -0
- package/dist/handlers/media-update.d.ts.map +1 -0
- package/dist/handlers/media-update.js +64 -0
- package/dist/handlers/media-update.js.map +1 -0
- package/dist/handlers/media-upload.d.ts +4 -0
- package/dist/handlers/media-upload.d.ts.map +1 -0
- package/dist/handlers/media-upload.js +26 -0
- package/dist/handlers/media-upload.js.map +1 -0
- package/dist/handlers/media-usage.d.ts +9 -0
- package/dist/handlers/media-usage.d.ts.map +1 -0
- package/dist/handlers/media-usage.js +36 -0
- package/dist/handlers/media-usage.js.map +1 -0
- package/dist/handlers/migration-conflicts.d.ts +13 -0
- package/dist/handlers/migration-conflicts.d.ts.map +1 -0
- package/dist/handlers/migration-conflicts.js +55 -0
- package/dist/handlers/migration-conflicts.js.map +1 -0
- package/dist/handlers/migration-status.d.ts +4 -0
- package/dist/handlers/migration-status.d.ts.map +1 -0
- package/dist/handlers/migration-status.js +34 -0
- package/dist/handlers/migration-status.js.map +1 -0
- package/dist/handlers/publish-content.d.ts +9 -0
- package/dist/handlers/publish-content.d.ts.map +1 -0
- package/dist/handlers/publish-content.js +47 -0
- package/dist/handlers/publish-content.js.map +1 -0
- package/dist/handlers/publish-impact.d.ts +11 -0
- package/dist/handlers/publish-impact.d.ts.map +1 -0
- package/dist/handlers/publish-impact.js +44 -0
- package/dist/handlers/publish-impact.js.map +1 -0
- package/dist/handlers/resolve-page.d.ts +9 -0
- package/dist/handlers/resolve-page.d.ts.map +1 -0
- package/dist/handlers/resolve-page.js +105 -0
- package/dist/handlers/resolve-page.js.map +1 -0
- package/dist/handlers/restore-version.d.ts +4 -0
- package/dist/handlers/restore-version.d.ts.map +1 -0
- package/dist/handlers/restore-version.js +69 -0
- package/dist/handlers/restore-version.js.map +1 -0
- package/dist/handlers/runtime-metadata.d.ts +6 -0
- package/dist/handlers/runtime-metadata.d.ts.map +1 -0
- package/dist/handlers/runtime-metadata.js +82 -0
- package/dist/handlers/runtime-metadata.js.map +1 -0
- package/dist/handlers/save-runtime-field.d.ts +4 -0
- package/dist/handlers/save-runtime-field.d.ts.map +1 -0
- package/dist/handlers/save-runtime-field.js +108 -0
- package/dist/handlers/save-runtime-field.js.map +1 -0
- package/dist/handlers/search-content.d.ts +9 -0
- package/dist/handlers/search-content.d.ts.map +1 -0
- package/dist/handlers/search-content.js +40 -0
- package/dist/handlers/search-content.js.map +1 -0
- package/dist/handlers/seo-config.d.ts +16 -0
- package/dist/handlers/seo-config.d.ts.map +1 -0
- package/dist/handlers/seo-config.js +250 -0
- package/dist/handlers/seo-config.js.map +1 -0
- package/dist/handlers/seo-document.d.ts +24 -0
- package/dist/handlers/seo-document.d.ts.map +1 -0
- package/dist/handlers/seo-document.js +119 -0
- package/dist/handlers/seo-document.js.map +1 -0
- package/dist/handlers/seo-enrich-archetype.d.ts +71 -0
- package/dist/handlers/seo-enrich-archetype.d.ts.map +1 -0
- package/dist/handlers/seo-enrich-archetype.js +250 -0
- package/dist/handlers/seo-enrich-archetype.js.map +1 -0
- package/dist/handlers/seo-enrich-meta.d.ts +40 -0
- package/dist/handlers/seo-enrich-meta.d.ts.map +1 -0
- package/dist/handlers/seo-enrich-meta.js +121 -0
- package/dist/handlers/seo-enrich-meta.js.map +1 -0
- package/dist/handlers/seo-enrich-runner.d.ts +65 -0
- package/dist/handlers/seo-enrich-runner.d.ts.map +1 -0
- package/dist/handlers/seo-enrich-runner.js +192 -0
- package/dist/handlers/seo-enrich-runner.js.map +1 -0
- package/dist/handlers/seo-enrich.d.ts +10 -0
- package/dist/handlers/seo-enrich.d.ts.map +1 -0
- package/dist/handlers/seo-enrich.js +166 -0
- package/dist/handlers/seo-enrich.js.map +1 -0
- package/dist/handlers/seo-generate.d.ts +4 -0
- package/dist/handlers/seo-generate.d.ts.map +1 -0
- package/dist/handlers/seo-generate.js +31 -0
- package/dist/handlers/seo-generate.js.map +1 -0
- package/dist/handlers/seo-impact.d.ts +36 -0
- package/dist/handlers/seo-impact.d.ts.map +1 -0
- package/dist/handlers/seo-impact.js +137 -0
- package/dist/handlers/seo-impact.js.map +1 -0
- package/dist/handlers/seo-indexnow.d.ts +11 -0
- package/dist/handlers/seo-indexnow.d.ts.map +1 -0
- package/dist/handlers/seo-indexnow.js +15 -0
- package/dist/handlers/seo-indexnow.js.map +1 -0
- package/dist/handlers/seo-llms-txt.d.ts +26 -0
- package/dist/handlers/seo-llms-txt.d.ts.map +1 -0
- package/dist/handlers/seo-llms-txt.js +99 -0
- package/dist/handlers/seo-llms-txt.js.map +1 -0
- package/dist/handlers/seo-preview.d.ts +8 -0
- package/dist/handlers/seo-preview.d.ts.map +1 -0
- package/dist/handlers/seo-preview.js +49 -0
- package/dist/handlers/seo-preview.js.map +1 -0
- package/dist/handlers/seo-robots.d.ts +22 -0
- package/dist/handlers/seo-robots.d.ts.map +1 -0
- package/dist/handlers/seo-robots.js +48 -0
- package/dist/handlers/seo-robots.js.map +1 -0
- package/dist/handlers/seo-sitemap.d.ts +68 -0
- package/dist/handlers/seo-sitemap.d.ts.map +1 -0
- package/dist/handlers/seo-sitemap.js +178 -0
- package/dist/handlers/seo-sitemap.js.map +1 -0
- package/dist/handlers/seo-status.d.ts +4 -0
- package/dist/handlers/seo-status.d.ts.map +1 -0
- package/dist/handlers/seo-status.js +61 -0
- package/dist/handlers/seo-status.js.map +1 -0
- package/dist/handlers/seo-structured-data.d.ts +4 -0
- package/dist/handlers/seo-structured-data.d.ts.map +1 -0
- package/dist/handlers/seo-structured-data.js +18 -0
- package/dist/handlers/seo-structured-data.js.map +1 -0
- package/dist/handlers/site-config.d.ts +8 -0
- package/dist/handlers/site-config.d.ts.map +1 -0
- package/dist/handlers/site-config.js +26 -0
- package/dist/handlers/site-config.js.map +1 -0
- package/dist/handlers/site-preview.d.ts +10 -0
- package/dist/handlers/site-preview.d.ts.map +1 -0
- package/dist/handlers/site-preview.js +54 -0
- package/dist/handlers/site-preview.js.map +1 -0
- package/dist/handlers/site-settings.d.ts +17 -0
- package/dist/handlers/site-settings.d.ts.map +1 -0
- package/dist/handlers/site-settings.js +75 -0
- package/dist/handlers/site-settings.js.map +1 -0
- package/dist/handlers/snapshot-create.d.ts +4 -0
- package/dist/handlers/snapshot-create.d.ts.map +1 -0
- package/dist/handlers/snapshot-create.js +15 -0
- package/dist/handlers/snapshot-create.js.map +1 -0
- package/dist/handlers/snapshot-delete.d.ts +4 -0
- package/dist/handlers/snapshot-delete.d.ts.map +1 -0
- package/dist/handlers/snapshot-delete.js +21 -0
- package/dist/handlers/snapshot-delete.js.map +1 -0
- package/dist/handlers/snapshot-get.d.ts +4 -0
- package/dist/handlers/snapshot-get.d.ts.map +1 -0
- package/dist/handlers/snapshot-get.js +17 -0
- package/dist/handlers/snapshot-get.js.map +1 -0
- package/dist/handlers/snapshot-list.d.ts +4 -0
- package/dist/handlers/snapshot-list.d.ts.map +1 -0
- package/dist/handlers/snapshot-list.js +9 -0
- package/dist/handlers/snapshot-list.js.map +1 -0
- package/dist/handlers/snapshot-restore.d.ts +4 -0
- package/dist/handlers/snapshot-restore.d.ts.map +1 -0
- package/dist/handlers/snapshot-restore.js +27 -0
- package/dist/handlers/snapshot-restore.js.map +1 -0
- package/dist/handlers/translation-status.d.ts +9 -0
- package/dist/handlers/translation-status.d.ts.map +1 -0
- package/dist/handlers/translation-status.js +68 -0
- package/dist/handlers/translation-status.js.map +1 -0
- package/dist/handlers/update-content.d.ts +4 -0
- package/dist/handlers/update-content.d.ts.map +1 -0
- package/dist/handlers/update-content.js +66 -0
- package/dist/handlers/update-content.js.map +1 -0
- package/dist/handlers/user-create.d.ts +4 -0
- package/dist/handlers/user-create.d.ts.map +1 -0
- package/dist/handlers/user-create.js +38 -0
- package/dist/handlers/user-create.js.map +1 -0
- package/dist/handlers/user-delete.d.ts +4 -0
- package/dist/handlers/user-delete.d.ts.map +1 -0
- package/dist/handlers/user-delete.js +25 -0
- package/dist/handlers/user-delete.js.map +1 -0
- package/dist/handlers/user-get.d.ts +4 -0
- package/dist/handlers/user-get.d.ts.map +1 -0
- package/dist/handlers/user-get.js +22 -0
- package/dist/handlers/user-get.js.map +1 -0
- package/dist/handlers/user-list.d.ts +4 -0
- package/dist/handlers/user-list.d.ts.map +1 -0
- package/dist/handlers/user-list.js +28 -0
- package/dist/handlers/user-list.js.map +1 -0
- package/dist/handlers/user-permissions.d.ts +6 -0
- package/dist/handlers/user-permissions.d.ts.map +1 -0
- package/dist/handlers/user-permissions.js +42 -0
- package/dist/handlers/user-permissions.js.map +1 -0
- package/dist/handlers/user-update.d.ts +4 -0
- package/dist/handlers/user-update.d.ts.map +1 -0
- package/dist/handlers/user-update.js +54 -0
- package/dist/handlers/user-update.js.map +1 -0
- package/dist/handlers/validate-all.d.ts +4 -0
- package/dist/handlers/validate-all.d.ts.map +1 -0
- package/dist/handlers/validate-all.js +14 -0
- package/dist/handlers/validate-all.js.map +1 -0
- package/dist/handlers/version-retention.d.ts +6 -0
- package/dist/handlers/version-retention.d.ts.map +1 -0
- package/dist/handlers/version-retention.js +40 -0
- package/dist/handlers/version-retention.js.map +1 -0
- package/dist/handlers/webhook-deliveries.d.ts +4 -0
- package/dist/handlers/webhook-deliveries.d.ts.map +1 -0
- package/dist/handlers/webhook-deliveries.js +24 -0
- package/dist/handlers/webhook-deliveries.js.map +1 -0
- package/dist/handlers/webhook-retry.d.ts +11 -0
- package/dist/handlers/webhook-retry.d.ts.map +1 -0
- package/dist/handlers/webhook-retry.js +69 -0
- package/dist/handlers/webhook-retry.js.map +1 -0
- package/dist/head.d.ts +9 -0
- package/dist/head.d.ts.map +1 -0
- package/dist/head.js +28 -0
- package/dist/head.js.map +1 -0
- package/dist/hooks.d.ts +34 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +19 -0
- package/dist/hooks.js.map +1 -0
- package/dist/image-cache.d.ts +47 -0
- package/dist/image-cache.d.ts.map +1 -0
- package/dist/image-cache.js +112 -0
- package/dist/image-cache.js.map +1 -0
- package/dist/image-dimensions.d.ts +12 -0
- package/dist/image-dimensions.d.ts.map +1 -0
- package/dist/image-dimensions.js +129 -0
- package/dist/image-dimensions.js.map +1 -0
- package/dist/image-optimizer.d.ts +86 -0
- package/dist/image-optimizer.d.ts.map +1 -0
- package/dist/image-optimizer.js +206 -0
- package/dist/image-optimizer.js.map +1 -0
- package/dist/image-presets.d.ts +17 -0
- package/dist/image-presets.d.ts.map +1 -0
- package/dist/image-presets.js +50 -0
- package/dist/image-presets.js.map +1 -0
- package/dist/image-url.d.ts +26 -0
- package/dist/image-url.d.ts.map +1 -0
- package/dist/image-url.js +47 -0
- package/dist/image-url.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/jwt.d.ts +54 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +114 -0
- package/dist/jwt.js.map +1 -0
- package/dist/locale-fallback.d.ts +18 -0
- package/dist/locale-fallback.d.ts.map +1 -0
- package/dist/locale-fallback.js +42 -0
- package/dist/locale-fallback.js.map +1 -0
- package/dist/media-library.d.ts +46 -0
- package/dist/media-library.d.ts.map +1 -0
- package/dist/media-library.js +231 -0
- package/dist/media-library.js.map +1 -0
- package/dist/media-reference-updater.d.ts +24 -0
- package/dist/media-reference-updater.d.ts.map +1 -0
- package/dist/media-reference-updater.js +124 -0
- package/dist/media-reference-updater.js.map +1 -0
- package/dist/media-references.d.ts +14 -0
- package/dist/media-references.d.ts.map +1 -0
- package/dist/media-references.js +25 -0
- package/dist/media-references.js.map +1 -0
- package/dist/merged-schema.d.ts +10 -0
- package/dist/merged-schema.d.ts.map +1 -0
- package/dist/merged-schema.js +21 -0
- package/dist/merged-schema.js.map +1 -0
- package/dist/middleware/auth.d.ts +21 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +82 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/oidc-state.d.ts +42 -0
- package/dist/oidc-state.d.ts.map +1 -0
- package/dist/oidc-state.js +72 -0
- package/dist/oidc-state.js.map +1 -0
- package/dist/oidc.d.ts +83 -0
- package/dist/oidc.d.ts.map +1 -0
- package/dist/oidc.js +226 -0
- package/dist/oidc.js.map +1 -0
- package/dist/openapi.d.ts +13 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +133 -0
- package/dist/openapi.js.map +1 -0
- package/dist/permissions.d.ts +37 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +69 -0
- package/dist/permissions.js.map +1 -0
- package/dist/plugins.d.ts +64 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +73 -0
- package/dist/plugins.js.map +1 -0
- package/dist/preview-token.d.ts +13 -0
- package/dist/preview-token.d.ts.map +1 -0
- package/dist/preview-token.js +45 -0
- package/dist/preview-token.js.map +1 -0
- package/dist/public-cache.d.ts +8 -0
- package/dist/public-cache.d.ts.map +1 -0
- package/dist/public-cache.js +8 -0
- package/dist/public-cache.js.map +1 -0
- package/dist/reference-resolver.d.ts +21 -0
- package/dist/reference-resolver.d.ts.map +1 -0
- package/dist/reference-resolver.js +128 -0
- package/dist/reference-resolver.js.map +1 -0
- package/dist/return-to.d.ts +7 -0
- package/dist/return-to.d.ts.map +1 -0
- package/dist/return-to.js +15 -0
- package/dist/return-to.js.map +1 -0
- package/dist/router.d.ts +14 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +51 -0
- package/dist/router.js.map +1 -0
- package/dist/runtime-field-checks.d.ts +11 -0
- package/dist/runtime-field-checks.d.ts.map +1 -0
- package/dist/runtime-field-checks.js +72 -0
- package/dist/runtime-field-checks.js.map +1 -0
- package/dist/save-document.d.ts +71 -0
- package/dist/save-document.d.ts.map +1 -0
- package/dist/save-document.js +213 -0
- package/dist/save-document.js.map +1 -0
- package/dist/seo-compose.d.ts +50 -0
- package/dist/seo-compose.d.ts.map +1 -0
- package/dist/seo-compose.js +104 -0
- package/dist/seo-compose.js.map +1 -0
- package/dist/seo-config-snapshot.d.ts +10 -0
- package/dist/seo-config-snapshot.d.ts.map +1 -0
- package/dist/seo-config-snapshot.js +16 -0
- package/dist/seo-config-snapshot.js.map +1 -0
- package/dist/seo-loader.d.ts +10 -0
- package/dist/seo-loader.d.ts.map +1 -0
- package/dist/seo-loader.js +14 -0
- package/dist/seo-loader.js.map +1 -0
- package/dist/seo-site-findings.d.ts +27 -0
- package/dist/seo-site-findings.d.ts.map +1 -0
- package/dist/seo-site-findings.js +87 -0
- package/dist/seo-site-findings.js.map +1 -0
- package/dist/seo-subsystem.d.ts +28 -0
- package/dist/seo-subsystem.d.ts.map +1 -0
- package/dist/seo-subsystem.js +62 -0
- package/dist/seo-subsystem.js.map +1 -0
- package/dist/seo-validation.d.ts +20 -0
- package/dist/seo-validation.d.ts.map +1 -0
- package/dist/seo-validation.js +96 -0
- package/dist/seo-validation.js.map +1 -0
- package/dist/types.d.ts +126 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/validators.d.ts +107 -0
- package/dist/validators.d.ts.map +1 -0
- package/dist/validators.js +199 -0
- package/dist/validators.js.map +1 -0
- package/dist/webhooks.d.ts +29 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +123 -0
- package/dist/webhooks.js.map +1 -0
- package/dist/workload-identity.d.ts +23 -0
- package/dist/workload-identity.d.ts.map +1 -0
- package/dist/workload-identity.js +145 -0
- package/dist/workload-identity.js.map +1 -0
- package/package.json +51 -3
- package/README.md +0 -3
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { structuredComplete } from '@krantho/ai';
|
|
2
|
+
import { buildSeoFieldMap, documentSeoProperties } from '@krantho/seo-shared';
|
|
3
|
+
import { getActiveContract } from '../merged-schema.js';
|
|
4
|
+
import { saveDocument } from '../save-document.js';
|
|
5
|
+
export const DESCRIPTION_SCHEMA = {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: { description: { type: 'string' } },
|
|
8
|
+
required: ['description'],
|
|
9
|
+
};
|
|
10
|
+
export function buildMetaPrompt(siteName, language, text, limits) {
|
|
11
|
+
return `You are an SEO expert for ${siteName}.
|
|
12
|
+
|
|
13
|
+
Write a meta description based on the text below.
|
|
14
|
+
|
|
15
|
+
Requirements:
|
|
16
|
+
- Between ${limits.minChars} and ${limits.maxChars} characters including spaces, so it displays in full in search results
|
|
17
|
+
- Written in ${language}
|
|
18
|
+
- Natural language, no keyword-stuffing
|
|
19
|
+
- No quotation marks around the text
|
|
20
|
+
- Only the description itself, nothing else
|
|
21
|
+
- Focus on what the user can expect from the page
|
|
22
|
+
|
|
23
|
+
Text:
|
|
24
|
+
${text.slice(0, limits.contentCap)}`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Whether a document needs a generated meta description: a description in its
|
|
28
|
+
* SEO config or in its description field is never replaced unless `force`, and
|
|
29
|
+
* a document with too little text is skipped. The reason when it is skipped.
|
|
30
|
+
*/
|
|
31
|
+
export async function prepareMetaDescription(_target, content, _seoConfigAdapter, force) {
|
|
32
|
+
const description = documentSeoProperties(content.metadata)['description'];
|
|
33
|
+
if (typeof description === 'string' && description.length > 0 && !force) {
|
|
34
|
+
return { skip: `Authored description exists (${description.length} chars) — preserved` };
|
|
35
|
+
}
|
|
36
|
+
// Resolve which CMS field holds the description dynamically
|
|
37
|
+
const properties = content.contract?.fields['properties'];
|
|
38
|
+
const field = buildSeoFieldMap(Object.keys(properties && typeof properties === 'object' ? properties : content.fields)).description;
|
|
39
|
+
// Check existing CMS field
|
|
40
|
+
const existing = field ? content.fields[field] : undefined;
|
|
41
|
+
if (typeof existing === 'string' && existing.length > 0 && !force) {
|
|
42
|
+
return { skip: `Already has ${field} (${existing.length} chars)` };
|
|
43
|
+
}
|
|
44
|
+
const text = descriptionSourceText(content, field);
|
|
45
|
+
if (text.length < 20)
|
|
46
|
+
return { skip: 'Insufficient content' };
|
|
47
|
+
return { field, text };
|
|
48
|
+
}
|
|
49
|
+
/** Body text, or the document's string fields when the body is short */
|
|
50
|
+
function descriptionSourceText(content, descriptionField) {
|
|
51
|
+
const text = content.body?.trim() ?? '';
|
|
52
|
+
if (text.length >= 50)
|
|
53
|
+
return text;
|
|
54
|
+
const parts = [];
|
|
55
|
+
for (const [key, val] of Object.entries(content.fields)) {
|
|
56
|
+
if (key === 'status' || key === descriptionField)
|
|
57
|
+
continue;
|
|
58
|
+
if (typeof val === 'string' && val.length > 3)
|
|
59
|
+
parts.push(val);
|
|
60
|
+
}
|
|
61
|
+
return parts.join('. ');
|
|
62
|
+
}
|
|
63
|
+
/** Generate a meta description from `text`, cut to `limits.maxChars` */
|
|
64
|
+
export async function generateMetaDescription(text, llm, site, limits) {
|
|
65
|
+
const prompt = buildMetaPrompt(site.name, site.language, text, limits);
|
|
66
|
+
const result = await structuredComplete(llm, prompt, DESCRIPTION_SCHEMA, { maxTokens: limits.maxTokens });
|
|
67
|
+
// LLMs can't count characters reliably — hard truncate if too long
|
|
68
|
+
const desc = result.description.trim();
|
|
69
|
+
if (desc.length <= limits.maxChars)
|
|
70
|
+
return desc;
|
|
71
|
+
return `${desc.slice(0, limits.maxChars - 1).replace(/\s+\S*$/, '')}.`;
|
|
72
|
+
}
|
|
73
|
+
/** Enrich meta-description for a single item */
|
|
74
|
+
export async function enrichMetaDescription(item, content, llm, ctx, seoConfigAdapter, site, limits, force) {
|
|
75
|
+
const collection = ctx.contentConfig.collections.get(item.collection);
|
|
76
|
+
if (!collection)
|
|
77
|
+
throw new Error('Collection not found');
|
|
78
|
+
const contract = await getActiveContract(collection, ctx.adapter);
|
|
79
|
+
const source = await prepareMetaDescription(item, { ...content, contract }, seoConfigAdapter, force);
|
|
80
|
+
if ('skip' in source) {
|
|
81
|
+
item.status = 'skipped';
|
|
82
|
+
item.result = source.skip;
|
|
83
|
+
return 'skipped';
|
|
84
|
+
}
|
|
85
|
+
if (!source.field && !contract.metadata['sharing']) {
|
|
86
|
+
item.status = 'skipped';
|
|
87
|
+
item.result = 'No description property is declared by this document contract';
|
|
88
|
+
return 'skipped';
|
|
89
|
+
}
|
|
90
|
+
item.status = 'generating';
|
|
91
|
+
const desc = await generateMetaDescription(source.text, llm, site, limits);
|
|
92
|
+
const fields = { ...content.fields };
|
|
93
|
+
const metadata = structuredClone(content.metadata);
|
|
94
|
+
if (source.field)
|
|
95
|
+
fields[source.field] = desc;
|
|
96
|
+
else if (contract.metadata['sharing']) {
|
|
97
|
+
metadata['sharing'] = { ...metadata['sharing'], description: desc };
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
item.status = 'skipped';
|
|
101
|
+
item.result = 'No description property is declared by this document contract';
|
|
102
|
+
return 'skipped';
|
|
103
|
+
}
|
|
104
|
+
const saved = await saveDocument(ctx, {
|
|
105
|
+
collection: item.collection,
|
|
106
|
+
slug: item.slug,
|
|
107
|
+
locale: content.meta.locale,
|
|
108
|
+
fields,
|
|
109
|
+
metadata,
|
|
110
|
+
body: content.body,
|
|
111
|
+
isNew: false,
|
|
112
|
+
expectedVersion: content.meta.version,
|
|
113
|
+
changedBy: 'seo-enrichment',
|
|
114
|
+
});
|
|
115
|
+
if (!saved.ok)
|
|
116
|
+
throw new Error(String(saved.response.body.error ?? 'Document save failed'));
|
|
117
|
+
item.status = 'complete';
|
|
118
|
+
item.result = `${desc.length} chars: ${desc}`;
|
|
119
|
+
return 'generated';
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=seo-enrich-meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-enrich-meta.js","sourceRoot":"","sources":["../../src/handlers/seo-enrich-meta.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { LLMAdapter } from '@krantho/ai';
|
|
2
|
+
import { type GetTypePropertiesFn } from './seo-enrich-archetype.js';
|
|
3
|
+
/** In-memory job state (one job at a time) */
|
|
4
|
+
export interface EnrichJob {
|
|
5
|
+
id: string;
|
|
6
|
+
status: 'running' | 'complete' | 'error';
|
|
7
|
+
type: string;
|
|
8
|
+
/** Whether the run writes over values someone set */
|
|
9
|
+
force: boolean;
|
|
10
|
+
items: Array<{
|
|
11
|
+
collection: string;
|
|
12
|
+
slug: string;
|
|
13
|
+
locale?: string | undefined;
|
|
14
|
+
status: 'pending' | 'generating' | 'complete' | 'skipped' | 'error';
|
|
15
|
+
result?: string | undefined;
|
|
16
|
+
error?: string | undefined;
|
|
17
|
+
}>;
|
|
18
|
+
startedAt: number;
|
|
19
|
+
/** The run that works on the job; a run that finds another's token in the saved job stops */
|
|
20
|
+
runner?: string | undefined;
|
|
21
|
+
/** When the job last saved its progress: a running job that has not for a while has lost its runner */
|
|
22
|
+
updatedAt: number;
|
|
23
|
+
completedAt?: number | undefined;
|
|
24
|
+
summary?: {
|
|
25
|
+
generated: number;
|
|
26
|
+
skipped: number;
|
|
27
|
+
errors: number;
|
|
28
|
+
} | undefined;
|
|
29
|
+
/** What the provider reported for the job's completions; zero when it reports none */
|
|
30
|
+
usage: EnrichUsage;
|
|
31
|
+
}
|
|
32
|
+
/** Tokens the job's completions used, and the model that served the first of them */
|
|
33
|
+
export interface EnrichUsage {
|
|
34
|
+
inputTokens: number;
|
|
35
|
+
outputTokens: number;
|
|
36
|
+
model: string | null;
|
|
37
|
+
}
|
|
38
|
+
declare class JobStore {
|
|
39
|
+
private job;
|
|
40
|
+
get(): EnrichJob | null;
|
|
41
|
+
set(job: EnrichJob): void;
|
|
42
|
+
clear(): void;
|
|
43
|
+
}
|
|
44
|
+
export declare const jobStore: JobStore;
|
|
45
|
+
/** Whether a running job has stopped saving: its runner is lost */
|
|
46
|
+
export declare function isStale(job: EnrichJob): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The latest job from any instance. A job this instance is running is read from memory; for
|
|
49
|
+
* another, the saved copy is read, because consecutive requests may reach different instances.
|
|
50
|
+
*/
|
|
51
|
+
export declare function currentJob(ctx: ApiContext): Promise<EnrichJob | null>;
|
|
52
|
+
/** Save the job's first state, so any instance can answer for it from the start */
|
|
53
|
+
export declare function announceJob(ctx: ApiContext, job: EnrichJob): Promise<void>;
|
|
54
|
+
import type { ApiContext } from '../types.js';
|
|
55
|
+
/**
|
|
56
|
+
* Load `getTypeProperties` from the optional `@krantho/seo` package once per
|
|
57
|
+
* job. If the package isn't installed, return null — archetype enrichment will
|
|
58
|
+
* short-circuit to error for each item, but meta-description enrichment still
|
|
59
|
+
* runs independently.
|
|
60
|
+
*/
|
|
61
|
+
export declare function loadGetTypeProperties(): Promise<GetTypePropertiesFn | null>;
|
|
62
|
+
/** Background enrichment runner */
|
|
63
|
+
export declare function runEnrichment(job: EnrichJob, llm: LLMAdapter, ctx: ApiContext, type: string, force: boolean): Promise<void>;
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=seo-enrich-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-enrich-runner.d.ts","sourceRoot":"","sources":["../../src/handlers/seo-enrich-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAG/F,8CAA8C;AAC9C,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,OAAO,CAAA;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,qDAAqD;IACrD,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,EAAE,KAAK,CAAC;QACX,UAAU,EAAE,MAAM,CAAA;QAClB,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC3B,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAA;QACnE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAC3B,CAAC,CAAA;IACF,SAAS,EAAE,MAAM,CAAA;IACjB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,uGAAuG;IACvG,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,OAAO,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;IAC5E,sFAAsF;IACtF,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,qFAAqF;AACrF,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAWD,cAAM,QAAQ;IACZ,OAAO,CAAC,GAAG,CAAyB;IAEpC,GAAG,IAAI,SAAS,GAAG,IAAI;IAIvB,GAAG,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI;IAIzB,KAAK,IAAI,IAAI;CAGd;AAED,eAAO,MAAM,QAAQ,UAAiB,CAAA;AA+CtC,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAE/C;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAQ3E;AAED,mFAAmF;AACnF,wBAAsB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhF;AAID,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C;;;;;GAKG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAOjF;AAuED,mCAAmC;AACnC,wBAAsB,aAAa,CACjC,GAAG,EAAE,SAAS,EACd,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,IAAI,CAAC,CAmDf"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { canGetContent } from '@krantho/persistence';
|
|
2
|
+
import { enrichArchetypeProperties } from './seo-enrich-archetype.js';
|
|
3
|
+
import { enrichMetaDescription } from './seo-enrich-meta.js';
|
|
4
|
+
/** The site setting every instance reads the running job from */
|
|
5
|
+
const JOB_SETTING = 'seo.enrich.job';
|
|
6
|
+
/** How long a running job may go without saving before its runner counts as lost (a frozen or stopped function) */
|
|
7
|
+
const STALE_MS = 90_000;
|
|
8
|
+
/** How often a running job saves its progress */
|
|
9
|
+
const SAVE_EVERY_MS = 2_000;
|
|
10
|
+
class JobStore {
|
|
11
|
+
job = null;
|
|
12
|
+
get() {
|
|
13
|
+
return this.job;
|
|
14
|
+
}
|
|
15
|
+
set(job) {
|
|
16
|
+
this.job = job;
|
|
17
|
+
}
|
|
18
|
+
clear() {
|
|
19
|
+
this.job = null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export const jobStore = new JobStore();
|
|
23
|
+
/** Save the job where every instance can read it; failing to save never stops the job */
|
|
24
|
+
async function persistJob(ctx, job) {
|
|
25
|
+
job.updatedAt = Date.now();
|
|
26
|
+
try {
|
|
27
|
+
await ctx.siteSettingsAdapter?.setSetting(JOB_SETTING, JSON.stringify(job));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// The job goes on from this instance's memory
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const JOB_STATUSES = ['running', 'complete', 'error'];
|
|
34
|
+
/** Whether a saved value is a job: the fields the takeover and the status endpoint read */
|
|
35
|
+
function isJob(value) {
|
|
36
|
+
if (typeof value !== 'object' || value === null)
|
|
37
|
+
return false;
|
|
38
|
+
const job = value;
|
|
39
|
+
return (typeof job['id'] === 'string' &&
|
|
40
|
+
typeof job['type'] === 'string' &&
|
|
41
|
+
JOB_STATUSES.includes(job['status']) &&
|
|
42
|
+
typeof job['startedAt'] === 'number' &&
|
|
43
|
+
typeof job['updatedAt'] === 'number' &&
|
|
44
|
+
Array.isArray(job['items']) &&
|
|
45
|
+
typeof job['usage'] === 'object' &&
|
|
46
|
+
job['usage'] !== null);
|
|
47
|
+
}
|
|
48
|
+
/** The job another instance saved, when there is one */
|
|
49
|
+
async function storedJob(ctx) {
|
|
50
|
+
try {
|
|
51
|
+
const raw = await ctx.siteSettingsAdapter?.getSetting(JOB_SETTING);
|
|
52
|
+
const job = raw ? JSON.parse(raw) : null;
|
|
53
|
+
return isJob(job) ? job : null;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Whether another run has taken the job over: its token is in the saved job, not this run's */
|
|
60
|
+
async function takenOver(ctx, job, runner) {
|
|
61
|
+
const stored = await storedJob(ctx);
|
|
62
|
+
return stored?.id === job.id && stored.runner !== undefined && stored.runner !== runner;
|
|
63
|
+
}
|
|
64
|
+
/** Whether a running job has stopped saving: its runner is lost */
|
|
65
|
+
export function isStale(job) {
|
|
66
|
+
return job.status === 'running' && Date.now() - job.updatedAt > STALE_MS;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The latest job from any instance. A job this instance is running is read from memory; for
|
|
70
|
+
* another, the saved copy is read, because consecutive requests may reach different instances.
|
|
71
|
+
*/
|
|
72
|
+
export async function currentJob(ctx) {
|
|
73
|
+
const own = jobStore.get();
|
|
74
|
+
if (own?.status === 'running' && !isStale(own))
|
|
75
|
+
return own;
|
|
76
|
+
const stored = await storedJob(ctx);
|
|
77
|
+
if (!stored)
|
|
78
|
+
return own;
|
|
79
|
+
if (!own)
|
|
80
|
+
return stored;
|
|
81
|
+
if (own.id === stored.id)
|
|
82
|
+
return own.updatedAt >= stored.updatedAt ? own : stored;
|
|
83
|
+
return own.startedAt >= stored.startedAt ? own : stored;
|
|
84
|
+
}
|
|
85
|
+
/** Save the job's first state, so any instance can answer for it from the start */
|
|
86
|
+
export async function announceJob(ctx, job) {
|
|
87
|
+
jobStore.set(job);
|
|
88
|
+
await persistJob(ctx, job);
|
|
89
|
+
}
|
|
90
|
+
import { lockHolder } from '../content-locks.js';
|
|
91
|
+
import { loadSeoModule } from '../seo-loader.js';
|
|
92
|
+
/**
|
|
93
|
+
* Load `getTypeProperties` from the optional `@krantho/seo` package once per
|
|
94
|
+
* job. If the package isn't installed, return null — archetype enrichment will
|
|
95
|
+
* short-circuit to error for each item, but meta-description enrichment still
|
|
96
|
+
* runs independently.
|
|
97
|
+
*/
|
|
98
|
+
export async function loadGetTypeProperties() {
|
|
99
|
+
try {
|
|
100
|
+
const seo = await loadSeoModule();
|
|
101
|
+
return seo.getTypeProperties;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** The adapter, adding each completion's usage and model to the job's totals */
|
|
108
|
+
function metered(llm, job) {
|
|
109
|
+
return {
|
|
110
|
+
get supportsJsonSchema() {
|
|
111
|
+
return llm.supportsJsonSchema;
|
|
112
|
+
},
|
|
113
|
+
async complete(prompt, options) {
|
|
114
|
+
const result = await llm.complete(prompt, options);
|
|
115
|
+
job.usage.inputTokens += result.usage.inputTokens;
|
|
116
|
+
job.usage.outputTokens += result.usage.outputTokens;
|
|
117
|
+
job.usage.model ??= result.model || null;
|
|
118
|
+
return result;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/** Enrich a single item based on the job type; returns the result classification. */
|
|
123
|
+
async function enrichItem(item, content, deps) {
|
|
124
|
+
if (deps.type === 'meta-descriptions') {
|
|
125
|
+
return enrichMetaDescription(item, content, deps.llm, deps.ctx, deps.seoConfigAdapter, deps.ctx.config.site, deps.ctx.config.seo.enrichment.meta, deps.force);
|
|
126
|
+
}
|
|
127
|
+
if (deps.type === 'archetype') {
|
|
128
|
+
if (!deps.getTypeProperties) {
|
|
129
|
+
item.status = 'error';
|
|
130
|
+
item.error = '@krantho/seo not available';
|
|
131
|
+
return 'error';
|
|
132
|
+
}
|
|
133
|
+
return enrichArchetypeProperties(item, content, deps.llm, deps.seoConfigAdapter, deps.ctx.config.site, deps.ctx.config.seo.enrichment.archetype, deps.force, deps.getTypeProperties, deps.ctx);
|
|
134
|
+
}
|
|
135
|
+
item.status = 'skipped';
|
|
136
|
+
item.result = `Unsupported type: ${deps.type}`;
|
|
137
|
+
return 'skipped';
|
|
138
|
+
}
|
|
139
|
+
/** Background enrichment runner */
|
|
140
|
+
export async function runEnrichment(job, llm, ctx, type, force) {
|
|
141
|
+
const getTypeProperties = type === 'archetype' ? await loadGetTypeProperties() : null;
|
|
142
|
+
const deps = {
|
|
143
|
+
llm: metered(llm, job),
|
|
144
|
+
ctx,
|
|
145
|
+
seoConfigAdapter: ctx.seoConfigAdapter ?? null,
|
|
146
|
+
type,
|
|
147
|
+
force,
|
|
148
|
+
getTypeProperties,
|
|
149
|
+
};
|
|
150
|
+
// Taking the job over: the run before this one, if it is still alive, stops at its next item
|
|
151
|
+
const runner = crypto.randomUUID();
|
|
152
|
+
job.runner = runner;
|
|
153
|
+
await persistJob(ctx, job);
|
|
154
|
+
let saved = Date.now();
|
|
155
|
+
// A resumed job leaves the items it finished alone
|
|
156
|
+
for (const item of job.items) {
|
|
157
|
+
if (item.status !== 'pending' && item.status !== 'generating')
|
|
158
|
+
continue;
|
|
159
|
+
if (await takenOver(ctx, job, runner))
|
|
160
|
+
return;
|
|
161
|
+
if (Date.now() - saved >= SAVE_EVERY_MS) {
|
|
162
|
+
saved = Date.now();
|
|
163
|
+
await persistJob(ctx, job);
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
if (!canGetContent(ctx.adapter))
|
|
167
|
+
break;
|
|
168
|
+
const content = await ctx.adapter.getContent(item.collection, item.slug, item.locale);
|
|
169
|
+
if (!content) {
|
|
170
|
+
item.status = 'skipped';
|
|
171
|
+
item.result = 'Content not found';
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if ((await lockHolder(ctx, item)) !== null) {
|
|
175
|
+
item.status = 'skipped';
|
|
176
|
+
item.result = 'Being edited by another user';
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
await enrichItem(item, content, deps);
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
item.status = 'error';
|
|
183
|
+
item.error = err instanceof Error ? err.message : 'Unknown error';
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const count = (status) => job.items.filter((i) => i.status === status).length;
|
|
187
|
+
job.status = 'complete';
|
|
188
|
+
job.completedAt = Date.now();
|
|
189
|
+
job.summary = { generated: count('complete'), skipped: count('skipped'), errors: count('error') };
|
|
190
|
+
await persistJob(ctx, job);
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=seo-enrich-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-enrich-runner.js","sourceRoot":"","sources":["../../src/handlers/seo-enrich-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ApiHandler } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* POST /api/seo/enrich — enrich the documents of a scope (`all`, `collection`
|
|
4
|
+
* or `item`): a collection scope reads only that collection's documents, an
|
|
5
|
+
* item only that collection's document with the slug.
|
|
6
|
+
*/
|
|
7
|
+
export declare const seoEnrich: ApiHandler;
|
|
8
|
+
/** GET /api/seo/enrich/status — poll job progress, from whichever instance answers */
|
|
9
|
+
export declare const seoEnrichStatus: ApiHandler;
|
|
10
|
+
//# sourceMappingURL=seo-enrich.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-enrich.d.ts","sourceRoot":"","sources":["../../src/handlers/seo-enrich.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,UAAU,EAAe,MAAM,aAAa,CAAA;AA6FtE;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,UAoCvB,CAAA;AAkBD,sFAAsF;AACtF,eAAO,MAAM,eAAe,EAAE,UAgC7B,CAAA"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { canQuery } from '@krantho/persistence';
|
|
2
|
+
import { groupByCollection } from '../group-by-collection.js';
|
|
3
|
+
import { requireRole } from '../permissions.js';
|
|
4
|
+
import { validateRequestBody } from '../validators.js';
|
|
5
|
+
import { resolveAdapter } from './llm-resolve.js';
|
|
6
|
+
import { announceJob, currentJob, isStale, runEnrichment } from './seo-enrich-runner.js';
|
|
7
|
+
/**
|
|
8
|
+
* The scope a request asks for: `scope` when given, else inferred from what
|
|
9
|
+
* it names (a collection and a slug, a collection, or neither). A collection
|
|
10
|
+
* or item scope must name a configured collection, and an item its slug.
|
|
11
|
+
*/
|
|
12
|
+
function enrichScope(payload, ctx) {
|
|
13
|
+
const collection = typeof payload['collection'] === 'string' ? payload['collection'] : undefined;
|
|
14
|
+
const slug = typeof payload['slug'] === 'string' ? payload['slug'] : undefined;
|
|
15
|
+
const named = slug !== undefined ? 'item' : collection !== undefined ? 'collection' : 'all';
|
|
16
|
+
const scope = payload['scope'] ?? named;
|
|
17
|
+
if (scope === 'all')
|
|
18
|
+
return { scope };
|
|
19
|
+
if (scope !== 'collection' && scope !== 'item')
|
|
20
|
+
return 'scope is all, collection or item';
|
|
21
|
+
if (collection === undefined || !ctx.contentConfig.collections.has(collection)) {
|
|
22
|
+
return `scope ${scope} needs a configured collection`;
|
|
23
|
+
}
|
|
24
|
+
if (scope === 'collection')
|
|
25
|
+
return { scope, collection };
|
|
26
|
+
if (slug === undefined)
|
|
27
|
+
return 'scope item needs a slug';
|
|
28
|
+
return { scope, collection, slug };
|
|
29
|
+
}
|
|
30
|
+
/** The store when it can query, read and write content; null otherwise */
|
|
31
|
+
function enrichStore(adapter) {
|
|
32
|
+
const { getContent, writeContent } = adapter;
|
|
33
|
+
return canQuery(adapter) && getContent && writeContent ? adapter : null;
|
|
34
|
+
}
|
|
35
|
+
/** The documents a job enriches: every document of the scope's collections, one document for an item */
|
|
36
|
+
async function enrichItems(adapter, ctx, target) {
|
|
37
|
+
const names = target.scope === 'all' ? [...ctx.contentConfig.collections.keys()] : [target.collection];
|
|
38
|
+
const { items: metas } = await adapter.query({
|
|
39
|
+
state: 'current',
|
|
40
|
+
projection: 'meta',
|
|
41
|
+
collections: names,
|
|
42
|
+
});
|
|
43
|
+
const documents = groupByCollection(metas, names, (meta) => meta.collection);
|
|
44
|
+
const items = [];
|
|
45
|
+
for (const collection of names) {
|
|
46
|
+
for (const meta of documents.get(collection) ?? []) {
|
|
47
|
+
if (target.scope === 'item' && meta.slug !== target.slug)
|
|
48
|
+
continue;
|
|
49
|
+
items.push({ collection, slug: meta.slug, locale: meta.locale, status: 'pending' });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return items;
|
|
53
|
+
}
|
|
54
|
+
/** Start a job over the items in the background; the response names it */
|
|
55
|
+
async function startJob(ctx, llm, type, force, items) {
|
|
56
|
+
const job = {
|
|
57
|
+
id: `enrich-${Date.now()}`,
|
|
58
|
+
status: 'running',
|
|
59
|
+
type,
|
|
60
|
+
force,
|
|
61
|
+
items,
|
|
62
|
+
startedAt: Date.now(),
|
|
63
|
+
updatedAt: Date.now(),
|
|
64
|
+
usage: { inputTokens: 0, outputTokens: 0, model: null },
|
|
65
|
+
};
|
|
66
|
+
await announceJob(ctx, job);
|
|
67
|
+
const run = runEnrichment(job, llm, ctx, type, force);
|
|
68
|
+
ctx.waitUntil?.(run);
|
|
69
|
+
return job;
|
|
70
|
+
}
|
|
71
|
+
/** The refusal while another job runs, on any instance: one job at a time; a job that lost its runner does not count */
|
|
72
|
+
async function runningJob(ctx) {
|
|
73
|
+
const active = await currentJob(ctx);
|
|
74
|
+
if (active?.status !== 'running' || isStale(active))
|
|
75
|
+
return null;
|
|
76
|
+
return { status: 409, body: { error: 'An enrichment job is already running', jobId: active.id } };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* POST /api/seo/enrich — enrich the documents of a scope (`all`, `collection`
|
|
80
|
+
* or `item`): a collection scope reads only that collection's documents, an
|
|
81
|
+
* item only that collection's document with the slug.
|
|
82
|
+
*/
|
|
83
|
+
export const seoEnrich = async (req, ctx) => {
|
|
84
|
+
const denied = requireRole(ctx.auth, 'admin');
|
|
85
|
+
if (denied)
|
|
86
|
+
return denied;
|
|
87
|
+
const running = await runningJob(ctx);
|
|
88
|
+
if (running)
|
|
89
|
+
return running;
|
|
90
|
+
const bodyCheck = validateRequestBody(req.body);
|
|
91
|
+
if (!bodyCheck.isValid)
|
|
92
|
+
return bodyCheck.response;
|
|
93
|
+
const payload = bodyCheck.body;
|
|
94
|
+
const target = enrichScope(payload, ctx);
|
|
95
|
+
if (typeof target === 'string')
|
|
96
|
+
return { status: 400, body: { error: target } };
|
|
97
|
+
const type = payload['type'] ?? 'meta-descriptions';
|
|
98
|
+
const llm = await resolveAdapter(ctx).catch((err) => err instanceof Error ? err.message : 'Failed to create LLM adapter');
|
|
99
|
+
if (typeof llm === 'string')
|
|
100
|
+
return { status: 400, body: { error: llm } };
|
|
101
|
+
const store = enrichStore(ctx.adapter);
|
|
102
|
+
if (!store) {
|
|
103
|
+
return {
|
|
104
|
+
status: 501,
|
|
105
|
+
body: { error: 'Persistence adapter does not support content read/write' },
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const items = await enrichItems(store, ctx, target);
|
|
109
|
+
if (items.length === 0) {
|
|
110
|
+
return { status: 200, body: { jobId: null, message: 'No items to enrich' } };
|
|
111
|
+
}
|
|
112
|
+
const job = await startJob(ctx, llm, type, payload['force'] === true, items);
|
|
113
|
+
return {
|
|
114
|
+
status: 202,
|
|
115
|
+
body: { jobId: job.id, status: 'running', type, totalItems: items.length },
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* A job whose runner stopped (the function that ran it was frozen or ended) goes on from the
|
|
120
|
+
* pending items on this instance; the items it finished are not run again.
|
|
121
|
+
*/
|
|
122
|
+
async function resumeIfLost(job, ctx) {
|
|
123
|
+
if (!isStale(job))
|
|
124
|
+
return;
|
|
125
|
+
try {
|
|
126
|
+
const llm = await resolveAdapter(ctx);
|
|
127
|
+
await announceJob(ctx, job);
|
|
128
|
+
ctx.waitUntil?.(runEnrichment(job, llm, ctx, job.type, job.force));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Without a model, or when the job cannot be saved, it is reported as it stands: the next
|
|
132
|
+
// status request tries again
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** GET /api/seo/enrich/status — poll job progress, from whichever instance answers */
|
|
136
|
+
export const seoEnrichStatus = async (req, ctx) => {
|
|
137
|
+
const jobId = req.query['jobId'];
|
|
138
|
+
const current = await currentJob(ctx);
|
|
139
|
+
if (!current || (jobId && current.id !== jobId)) {
|
|
140
|
+
return { status: 404, body: { error: 'No active enrichment job' } };
|
|
141
|
+
}
|
|
142
|
+
await resumeIfLost(current, ctx);
|
|
143
|
+
const completed = current.items.filter((i) => i.status === 'complete').length;
|
|
144
|
+
const skipped = current.items.filter((i) => i.status === 'skipped').length;
|
|
145
|
+
const errors = current.items.filter((i) => i.status === 'error').length;
|
|
146
|
+
const generating = current.items.find((i) => i.status === 'generating');
|
|
147
|
+
return {
|
|
148
|
+
status: 200,
|
|
149
|
+
body: {
|
|
150
|
+
jobId: current.id,
|
|
151
|
+
status: current.status,
|
|
152
|
+
type: current.type,
|
|
153
|
+
progress: {
|
|
154
|
+
total: current.items.length,
|
|
155
|
+
completed,
|
|
156
|
+
skipped,
|
|
157
|
+
errors,
|
|
158
|
+
current: generating ? `${generating.collection}/${generating.slug}` : null,
|
|
159
|
+
},
|
|
160
|
+
items: current.items,
|
|
161
|
+
summary: current.summary,
|
|
162
|
+
usage: current.usage,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=seo-enrich.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-enrich.js","sourceRoot":"","sources":["../../src/handlers/seo-enrich.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-generate.d.ts","sourceRoot":"","sources":["../../src/handlers/seo-generate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAG7C,wFAAwF;AACxF,eAAO,MAAM,WAAW,EAAE,UA2BzB,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { requireRole } from '../permissions.js';
|
|
4
|
+
import { buildSitemapUrls, serializeSitemapXml } from './seo-sitemap.js';
|
|
5
|
+
/** POST /api/seo/generate — regenerate SEO files that can be built without CLI tools */
|
|
6
|
+
export const seoGenerate = async (_req, ctx) => {
|
|
7
|
+
const denied = requireRole(ctx.auth, 'editor');
|
|
8
|
+
if (denied)
|
|
9
|
+
return denied;
|
|
10
|
+
const basePath = ctx.config.paths.seoGeneratedDir;
|
|
11
|
+
await mkdir(basePath, { recursive: true });
|
|
12
|
+
const results = {};
|
|
13
|
+
// The same sitemap the site serves at /sitemap.xml
|
|
14
|
+
try {
|
|
15
|
+
const xml = serializeSitemapXml(await buildSitemapUrls(ctx));
|
|
16
|
+
await writeFile(join(basePath, 'sitemap.xml'), xml, 'utf-8');
|
|
17
|
+
results['sitemap'] = 'generated';
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
results['sitemap'] = 'failed';
|
|
21
|
+
}
|
|
22
|
+
// structured-data.json and faq-pages.json require @krantho/tools (CLI-only)
|
|
23
|
+
results['structured-data'] = 'requires CLI: pnpm run seo:generate';
|
|
24
|
+
results['faq-pages'] = 'requires CLI: pnpm run seo:generate';
|
|
25
|
+
results['llms-txt'] = 'requires CLI: pnpm run seo:generate';
|
|
26
|
+
return {
|
|
27
|
+
status: 200,
|
|
28
|
+
body: { results },
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=seo-generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-generate.js","sourceRoot":"","sources":["../../src/handlers/seo-generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAExE,wFAAwF;AACxF,MAAM,CAAC,MAAM,WAAW,GAAe,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IACzD,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IAC9C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAA;IAEzB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAA;IACjD,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE1C,MAAM,OAAO,GAA2B,EAAE,CAAA;IAE1C,mDAAmD;IACnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAA;QAC5D,MAAM,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;QAC5D,OAAO,CAAC,SAAS,CAAC,GAAG,WAAW,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAA;IAC/B,CAAC;IAED,4EAA4E;IAC5E,OAAO,CAAC,iBAAiB,CAAC,GAAG,qCAAqC,CAAA;IAClE,OAAO,CAAC,WAAW,CAAC,GAAG,qCAAqC,CAAA;IAC5D,OAAO,CAAC,UAAU,CAAC,GAAG,qCAAqC,CAAA;IAE3D,OAAO;QACL,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,EAAE,OAAO,EAAE;KAClB,CAAA;AACH,CAAC,CAAA"}
|