@prenta/core 0.118.0
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/CHANGELOG.md +2974 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/a11y/index.d.ts +25 -0
- package/dist/a11y/index.d.ts.map +1 -0
- package/dist/a11y/index.js +91 -0
- package/dist/a11y/index.js.map +1 -0
- package/dist/actions.d.ts +130 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +1324 -0
- package/dist/actions.js.map +1 -0
- package/dist/ai/brand-voice-alignment.d.ts +17 -0
- package/dist/ai/brand-voice-alignment.d.ts.map +1 -0
- package/dist/ai/brand-voice-alignment.js +40 -0
- package/dist/ai/brand-voice-alignment.js.map +1 -0
- package/dist/ai/brand-voice-analyze.d.ts +71 -0
- package/dist/ai/brand-voice-analyze.d.ts.map +1 -0
- package/dist/ai/brand-voice-analyze.js +151 -0
- package/dist/ai/brand-voice-analyze.js.map +1 -0
- package/dist/ai/brand-voice-document.d.ts +56 -0
- package/dist/ai/brand-voice-document.d.ts.map +1 -0
- package/dist/ai/brand-voice-document.js +335 -0
- package/dist/ai/brand-voice-document.js.map +1 -0
- package/dist/ai/brand-voice-fix.d.ts +26 -0
- package/dist/ai/brand-voice-fix.d.ts.map +1 -0
- package/dist/ai/brand-voice-fix.js +97 -0
- package/dist/ai/brand-voice-fix.js.map +1 -0
- package/dist/ai/brand-voice-save.d.ts +11 -0
- package/dist/ai/brand-voice-save.d.ts.map +1 -0
- package/dist/ai/brand-voice-save.js +51 -0
- package/dist/ai/brand-voice-save.js.map +1 -0
- package/dist/ai/brand-voice-sources.d.ts +16 -0
- package/dist/ai/brand-voice-sources.d.ts.map +1 -0
- package/dist/ai/brand-voice-sources.js +106 -0
- package/dist/ai/brand-voice-sources.js.map +1 -0
- package/dist/ai/brand-voice-structured.d.ts +87 -0
- package/dist/ai/brand-voice-structured.d.ts.map +1 -0
- package/dist/ai/brand-voice-structured.js +438 -0
- package/dist/ai/brand-voice-structured.js.map +1 -0
- package/dist/ai/brand-voice.d.ts +40 -0
- package/dist/ai/brand-voice.d.ts.map +1 -0
- package/dist/ai/brand-voice.js +103 -0
- package/dist/ai/brand-voice.js.map +1 -0
- package/dist/ai/catalog.d.ts +35 -0
- package/dist/ai/catalog.d.ts.map +1 -0
- package/dist/ai/catalog.js +370 -0
- package/dist/ai/catalog.js.map +1 -0
- package/dist/ai/config-store.d.ts +55 -0
- package/dist/ai/config-store.d.ts.map +1 -0
- package/dist/ai/config-store.js +177 -0
- package/dist/ai/config-store.js.map +1 -0
- package/dist/ai/content-writing-generate.d.ts +19 -0
- package/dist/ai/content-writing-generate.d.ts.map +1 -0
- package/dist/ai/content-writing-generate.js +64 -0
- package/dist/ai/content-writing-generate.js.map +1 -0
- package/dist/ai/feature-defaults.d.ts +20 -0
- package/dist/ai/feature-defaults.d.ts.map +1 -0
- package/dist/ai/feature-defaults.js +104 -0
- package/dist/ai/feature-defaults.js.map +1 -0
- package/dist/ai/index.d.ts +24 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +24 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/models.d.ts +37 -0
- package/dist/ai/models.d.ts.map +1 -0
- package/dist/ai/models.js +126 -0
- package/dist/ai/models.js.map +1 -0
- package/dist/ai/providers/anthropic.d.ts +10 -0
- package/dist/ai/providers/anthropic.d.ts.map +1 -0
- package/dist/ai/providers/anthropic.js +63 -0
- package/dist/ai/providers/anthropic.js.map +1 -0
- package/dist/ai/providers/custom.d.ts +12 -0
- package/dist/ai/providers/custom.d.ts.map +1 -0
- package/dist/ai/providers/custom.js +76 -0
- package/dist/ai/providers/custom.js.map +1 -0
- package/dist/ai/providers/http.d.ts +66 -0
- package/dist/ai/providers/http.d.ts.map +1 -0
- package/dist/ai/providers/http.js +185 -0
- package/dist/ai/providers/http.js.map +1 -0
- package/dist/ai/providers/index.d.ts +18 -0
- package/dist/ai/providers/index.d.ts.map +1 -0
- package/dist/ai/providers/index.js +28 -0
- package/dist/ai/providers/index.js.map +1 -0
- package/dist/ai/providers/openai.d.ts +11 -0
- package/dist/ai/providers/openai.d.ts.map +1 -0
- package/dist/ai/providers/openai.js +44 -0
- package/dist/ai/providers/openai.js.map +1 -0
- package/dist/ai/providers/xai.d.ts +10 -0
- package/dist/ai/providers/xai.d.ts.map +1 -0
- package/dist/ai/providers/xai.js +38 -0
- package/dist/ai/providers/xai.js.map +1 -0
- package/dist/ai/resolve.d.ts +41 -0
- package/dist/ai/resolve.d.ts.map +1 -0
- package/dist/ai/resolve.js +143 -0
- package/dist/ai/resolve.js.map +1 -0
- package/dist/ai/runtime.d.ts +88 -0
- package/dist/ai/runtime.d.ts.map +1 -0
- package/dist/ai/runtime.js +192 -0
- package/dist/ai/runtime.js.map +1 -0
- package/dist/ai/sampling.d.ts +17 -0
- package/dist/ai/sampling.d.ts.map +1 -0
- package/dist/ai/sampling.js +51 -0
- package/dist/ai/sampling.js.map +1 -0
- package/dist/ai/types.d.ts +193 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +11 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/ai/usage.d.ts +18 -0
- package/dist/ai/usage.d.ts.map +1 -0
- package/dist/ai/usage.js +70 -0
- package/dist/ai/usage.js.map +1 -0
- package/dist/api/collection-introspection.d.ts +46 -0
- package/dist/api/collection-introspection.d.ts.map +1 -0
- package/dist/api/collection-introspection.js +82 -0
- package/dist/api/collection-introspection.js.map +1 -0
- package/dist/api/guarded-db.d.ts +14 -0
- package/dist/api/guarded-db.d.ts.map +1 -0
- package/dist/api/guarded-db.js +62 -0
- package/dist/api/guarded-db.js.map +1 -0
- package/dist/api/handler-factory.d.ts +7 -0
- package/dist/api/handler-factory.d.ts.map +1 -0
- package/dist/api/handler-factory.js +380 -0
- package/dist/api/handler-factory.js.map +1 -0
- package/dist/api/handlers.d.ts +8 -0
- package/dist/api/handlers.d.ts.map +1 -0
- package/dist/api/handlers.js +62 -0
- package/dist/api/handlers.js.map +1 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +8 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/openapi.d.ts +3 -0
- package/dist/api/openapi.d.ts.map +1 -0
- package/dist/api/openapi.js +539 -0
- package/dist/api/openapi.js.map +1 -0
- package/dist/api/route-helpers.d.ts +369 -0
- package/dist/api/route-helpers.d.ts.map +1 -0
- package/dist/api/route-helpers.js +1574 -0
- package/dist/api/route-helpers.js.map +1 -0
- package/dist/api/router.d.ts +21 -0
- package/dist/api/router.d.ts.map +1 -0
- package/dist/api/router.js +75 -0
- package/dist/api/router.js.map +1 -0
- package/dist/api/routes/ai-seo.d.ts +3 -0
- package/dist/api/routes/ai-seo.d.ts.map +1 -0
- package/dist/api/routes/ai-seo.js +482 -0
- package/dist/api/routes/ai-seo.js.map +1 -0
- package/dist/api/routes/ai-settings.d.ts +3 -0
- package/dist/api/routes/ai-settings.d.ts.map +1 -0
- package/dist/api/routes/ai-settings.js +1078 -0
- package/dist/api/routes/ai-settings.js.map +1 -0
- package/dist/api/routes/auth.d.ts +3 -0
- package/dist/api/routes/auth.d.ts.map +1 -0
- package/dist/api/routes/auth.js +877 -0
- package/dist/api/routes/auth.js.map +1 -0
- package/dist/api/routes/collab.d.ts +3 -0
- package/dist/api/routes/collab.d.ts.map +1 -0
- package/dist/api/routes/collab.js +426 -0
- package/dist/api/routes/collab.js.map +1 -0
- package/dist/api/routes/dashboard.d.ts +7 -0
- package/dist/api/routes/dashboard.d.ts.map +1 -0
- package/dist/api/routes/dashboard.js +540 -0
- package/dist/api/routes/dashboard.js.map +1 -0
- package/dist/api/routes/documents.d.ts +11 -0
- package/dist/api/routes/documents.d.ts.map +1 -0
- package/dist/api/routes/documents.js +340 -0
- package/dist/api/routes/documents.js.map +1 -0
- package/dist/api/routes/email-settings.d.ts +3 -0
- package/dist/api/routes/email-settings.d.ts.map +1 -0
- package/dist/api/routes/email-settings.js +248 -0
- package/dist/api/routes/email-settings.js.map +1 -0
- package/dist/api/routes/folders.d.ts +3 -0
- package/dist/api/routes/folders.d.ts.map +1 -0
- package/dist/api/routes/folders.js +195 -0
- package/dist/api/routes/folders.js.map +1 -0
- package/dist/api/routes/forms.d.ts +3 -0
- package/dist/api/routes/forms.d.ts.map +1 -0
- package/dist/api/routes/forms.js +776 -0
- package/dist/api/routes/forms.js.map +1 -0
- package/dist/api/routes/globals.d.ts +3 -0
- package/dist/api/routes/globals.d.ts.map +1 -0
- package/dist/api/routes/globals.js +157 -0
- package/dist/api/routes/globals.js.map +1 -0
- package/dist/api/routes/media.d.ts +3 -0
- package/dist/api/routes/media.d.ts.map +1 -0
- package/dist/api/routes/media.js +807 -0
- package/dist/api/routes/media.js.map +1 -0
- package/dist/api/routes/meta.d.ts +3 -0
- package/dist/api/routes/meta.d.ts.map +1 -0
- package/dist/api/routes/meta.js +97 -0
- package/dist/api/routes/meta.js.map +1 -0
- package/dist/api/routes/navigations.d.ts +7 -0
- package/dist/api/routes/navigations.d.ts.map +1 -0
- package/dist/api/routes/navigations.js +81 -0
- package/dist/api/routes/navigations.js.map +1 -0
- package/dist/api/routes/page-templates.d.ts +3 -0
- package/dist/api/routes/page-templates.d.ts.map +1 -0
- package/dist/api/routes/page-templates.js +265 -0
- package/dist/api/routes/page-templates.js.map +1 -0
- package/dist/api/routes/presence.d.ts +3 -0
- package/dist/api/routes/presence.d.ts.map +1 -0
- package/dist/api/routes/presence.js +35 -0
- package/dist/api/routes/presence.js.map +1 -0
- package/dist/api/routes/preview.d.ts +3 -0
- package/dist/api/routes/preview.d.ts.map +1 -0
- package/dist/api/routes/preview.js +111 -0
- package/dist/api/routes/preview.js.map +1 -0
- package/dist/api/routes/redirects.d.ts +3 -0
- package/dist/api/routes/redirects.d.ts.map +1 -0
- package/dist/api/routes/redirects.js +937 -0
- package/dist/api/routes/redirects.js.map +1 -0
- package/dist/api/routes/saved-sections.d.ts +3 -0
- package/dist/api/routes/saved-sections.d.ts.map +1 -0
- package/dist/api/routes/saved-sections.js +1071 -0
- package/dist/api/routes/saved-sections.js.map +1 -0
- package/dist/api/routes/scheduling.d.ts +3 -0
- package/dist/api/routes/scheduling.d.ts.map +1 -0
- package/dist/api/routes/scheduling.js +391 -0
- package/dist/api/routes/scheduling.js.map +1 -0
- package/dist/api/routes/sections.d.ts +3 -0
- package/dist/api/routes/sections.d.ts.map +1 -0
- package/dist/api/routes/sections.js +512 -0
- package/dist/api/routes/sections.js.map +1 -0
- package/dist/api/routes/security-center.d.ts +3 -0
- package/dist/api/routes/security-center.d.ts.map +1 -0
- package/dist/api/routes/security-center.js +71 -0
- package/dist/api/routes/security-center.js.map +1 -0
- package/dist/api/routes/seo-public.d.ts +14 -0
- package/dist/api/routes/seo-public.d.ts.map +1 -0
- package/dist/api/routes/seo-public.js +1366 -0
- package/dist/api/routes/seo-public.js.map +1 -0
- package/dist/api/routes/seo.d.ts +8 -0
- package/dist/api/routes/seo.d.ts.map +1 -0
- package/dist/api/routes/seo.js +2256 -0
- package/dist/api/routes/seo.js.map +1 -0
- package/dist/api/routes/system.d.ts +3 -0
- package/dist/api/routes/system.d.ts.map +1 -0
- package/dist/api/routes/system.js +353 -0
- package/dist/api/routes/system.js.map +1 -0
- package/dist/api/routes/url-resolution.d.ts +3 -0
- package/dist/api/routes/url-resolution.d.ts.map +1 -0
- package/dist/api/routes/url-resolution.js +522 -0
- package/dist/api/routes/url-resolution.js.map +1 -0
- package/dist/api/routes/users.d.ts +3 -0
- package/dist/api/routes/users.d.ts.map +1 -0
- package/dist/api/routes/users.js +1177 -0
- package/dist/api/routes/users.js.map +1 -0
- package/dist/api/routes/webhooks.d.ts +3 -0
- package/dist/api/routes/webhooks.d.ts.map +1 -0
- package/dist/api/routes/webhooks.js +422 -0
- package/dist/api/routes/webhooks.js.map +1 -0
- package/dist/appearance/color.d.ts +24 -0
- package/dist/appearance/color.d.ts.map +1 -0
- package/dist/appearance/color.js +90 -0
- package/dist/appearance/color.js.map +1 -0
- package/dist/appearance/favicon-icon.d.ts +12 -0
- package/dist/appearance/favicon-icon.d.ts.map +1 -0
- package/dist/appearance/favicon-icon.js +58 -0
- package/dist/appearance/favicon-icon.js.map +1 -0
- package/dist/appearance/favicon-paths.d.ts +6 -0
- package/dist/appearance/favicon-paths.d.ts.map +1 -0
- package/dist/appearance/favicon-paths.js +6 -0
- package/dist/appearance/favicon-paths.js.map +1 -0
- package/dist/appearance/index.d.ts +15 -0
- package/dist/appearance/index.d.ts.map +1 -0
- package/dist/appearance/index.js +7 -0
- package/dist/appearance/index.js.map +1 -0
- package/dist/appearance/logo-shape.d.ts +26 -0
- package/dist/appearance/logo-shape.d.ts.map +1 -0
- package/dist/appearance/logo-shape.js +62 -0
- package/dist/appearance/logo-shape.js.map +1 -0
- package/dist/appearance/resolve.d.ts +52 -0
- package/dist/appearance/resolve.d.ts.map +1 -0
- package/dist/appearance/resolve.js +219 -0
- package/dist/appearance/resolve.js.map +1 -0
- package/dist/appearance/theme-tokens.d.ts +49 -0
- package/dist/appearance/theme-tokens.d.ts.map +1 -0
- package/dist/appearance/theme-tokens.js +229 -0
- package/dist/appearance/theme-tokens.js.map +1 -0
- package/dist/appearance/types.d.ts +110 -0
- package/dist/appearance/types.d.ts.map +1 -0
- package/dist/appearance/types.js +16 -0
- package/dist/appearance/types.js.map +1 -0
- package/dist/astro-cache.d.ts +80 -0
- package/dist/astro-cache.d.ts.map +1 -0
- package/dist/astro-cache.js +108 -0
- package/dist/astro-cache.js.map +1 -0
- package/dist/astro-content.d.ts +81 -0
- package/dist/astro-content.d.ts.map +1 -0
- package/dist/astro-content.js +151 -0
- package/dist/astro-content.js.map +1 -0
- package/dist/astro-redirects.d.ts +38 -0
- package/dist/astro-redirects.d.ts.map +1 -0
- package/dist/astro-redirects.js +45 -0
- package/dist/astro-redirects.js.map +1 -0
- package/dist/astro-security.d.ts +34 -0
- package/dist/astro-security.d.ts.map +1 -0
- package/dist/astro-security.js +31 -0
- package/dist/astro-security.js.map +1 -0
- package/dist/astro-site.d.ts +69 -0
- package/dist/astro-site.d.ts.map +1 -0
- package/dist/astro-site.js +81 -0
- package/dist/astro-site.js.map +1 -0
- package/dist/auth/index.d.ts +17 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +12 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/invite-email.d.ts +12 -0
- package/dist/auth/invite-email.d.ts.map +1 -0
- package/dist/auth/invite-email.js +57 -0
- package/dist/auth/invite-email.js.map +1 -0
- package/dist/auth/invites.d.ts +72 -0
- package/dist/auth/invites.d.ts.map +1 -0
- package/dist/auth/invites.js +279 -0
- package/dist/auth/invites.js.map +1 -0
- package/dist/auth/mfa-pending.d.ts +24 -0
- package/dist/auth/mfa-pending.d.ts.map +1 -0
- package/dist/auth/mfa-pending.js +38 -0
- package/dist/auth/mfa-pending.js.map +1 -0
- package/dist/auth/oauth.d.ts +139 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +376 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/password.d.ts +57 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +150 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/auth/providers/github.d.ts +9 -0
- package/dist/auth/providers/github.d.ts.map +1 -0
- package/dist/auth/providers/github.js +10 -0
- package/dist/auth/providers/github.js.map +1 -0
- package/dist/auth/providers/google.d.ts +9 -0
- package/dist/auth/providers/google.d.ts.map +1 -0
- package/dist/auth/providers/google.js +10 -0
- package/dist/auth/providers/google.js.map +1 -0
- package/dist/auth/providers/microsoft.d.ts +9 -0
- package/dist/auth/providers/microsoft.d.ts.map +1 -0
- package/dist/auth/providers/microsoft.js +11 -0
- package/dist/auth/providers/microsoft.js.map +1 -0
- package/dist/auth/reset-email.d.ts +10 -0
- package/dist/auth/reset-email.d.ts.map +1 -0
- package/dist/auth/reset-email.js +30 -0
- package/dist/auth/reset-email.js.map +1 -0
- package/dist/auth/reset.d.ts +42 -0
- package/dist/auth/reset.d.ts.map +1 -0
- package/dist/auth/reset.js +142 -0
- package/dist/auth/reset.js.map +1 -0
- package/dist/auth/roles.d.ts +51 -0
- package/dist/auth/roles.d.ts.map +1 -0
- package/dist/auth/roles.js +159 -0
- package/dist/auth/roles.js.map +1 -0
- package/dist/auth/session.d.ts +38 -0
- package/dist/auth/session.d.ts.map +1 -0
- package/dist/auth/session.js +106 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/auth/team.d.ts +99 -0
- package/dist/auth/team.d.ts.map +1 -0
- package/dist/auth/team.js +327 -0
- package/dist/auth/team.js.map +1 -0
- package/dist/auth/totp.d.ts +31 -0
- package/dist/auth/totp.d.ts.map +1 -0
- package/dist/auth/totp.js +134 -0
- package/dist/auth/totp.js.map +1 -0
- package/dist/auth/user-admin.d.ts +119 -0
- package/dist/auth/user-admin.d.ts.map +1 -0
- package/dist/auth/user-admin.js +292 -0
- package/dist/auth/user-admin.js.map +1 -0
- package/dist/backup/index.d.ts +19 -0
- package/dist/backup/index.d.ts.map +1 -0
- package/dist/backup/index.js +24 -0
- package/dist/backup/index.js.map +1 -0
- package/dist/billing/stripe-meter.d.ts +22 -0
- package/dist/billing/stripe-meter.d.ts.map +1 -0
- package/dist/billing/stripe-meter.js +101 -0
- package/dist/billing/stripe-meter.js.map +1 -0
- package/dist/brand-voice/index.d.ts +7 -0
- package/dist/brand-voice/index.d.ts.map +1 -0
- package/dist/brand-voice/index.js +7 -0
- package/dist/brand-voice/index.js.map +1 -0
- package/dist/cache/http.d.ts +140 -0
- package/dist/cache/http.d.ts.map +1 -0
- package/dist/cache/http.js +213 -0
- package/dist/cache/http.js.map +1 -0
- package/dist/cache/index.d.ts +15 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +32 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/client.d.ts +51 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +59 -0
- package/dist/client.js.map +1 -0
- package/dist/codegen/index.d.ts +4 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +366 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/collections/index.d.ts +19 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/collections/index.js +30 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/presets.d.ts +90 -0
- package/dist/collections/presets.d.ts.map +1 -0
- package/dist/collections/presets.js +573 -0
- package/dist/collections/presets.js.map +1 -0
- package/dist/config/define.d.ts +8 -0
- package/dist/config/define.d.ts.map +1 -0
- package/dist/config/define.js +7 -0
- package/dist/config/define.js.map +1 -0
- package/dist/config/index.d.ts +31 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +196 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/runtime.d.ts +107 -0
- package/dist/config/runtime.d.ts.map +1 -0
- package/dist/config/runtime.js +77 -0
- package/dist/config/runtime.js.map +1 -0
- package/dist/config/types.d.ts +924 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/content/ai-api.d.ts +21 -0
- package/dist/content/ai-api.d.ts.map +1 -0
- package/dist/content/ai-api.js +25 -0
- package/dist/content/ai-api.js.map +1 -0
- package/dist/content/content-graph.d.ts +25 -0
- package/dist/content/content-graph.d.ts.map +1 -0
- package/dist/content/content-graph.js +40 -0
- package/dist/content/content-graph.js.map +1 -0
- package/dist/content/extract.d.ts +7 -0
- package/dist/content/extract.d.ts.map +1 -0
- package/dist/content/extract.js +33 -0
- package/dist/content/extract.js.map +1 -0
- package/dist/content/index.d.ts +9 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/index.js +6 -0
- package/dist/content/index.js.map +1 -0
- package/dist/content/slug.d.ts +40 -0
- package/dist/content/slug.d.ts.map +1 -0
- package/dist/content/slug.js +78 -0
- package/dist/content/slug.js.map +1 -0
- package/dist/content/structured-data.d.ts +163 -0
- package/dist/content/structured-data.d.ts.map +1 -0
- package/dist/content/structured-data.js +479 -0
- package/dist/content/structured-data.js.map +1 -0
- package/dist/content-health/cron.d.ts +68 -0
- package/dist/content-health/cron.d.ts.map +1 -0
- package/dist/content-health/cron.js +167 -0
- package/dist/content-health/cron.js.map +1 -0
- package/dist/content-health/scanner.d.ts +119 -0
- package/dist/content-health/scanner.d.ts.map +1 -0
- package/dist/content-health/scanner.js +257 -0
- package/dist/content-health/scanner.js.map +1 -0
- package/dist/cron/index.d.ts +90 -0
- package/dist/cron/index.d.ts.map +1 -0
- package/dist/cron/index.js +299 -0
- package/dist/cron/index.js.map +1 -0
- package/dist/db/adapters/mysql.d.ts +5 -0
- package/dist/db/adapters/mysql.d.ts.map +1 -0
- package/dist/db/adapters/mysql.js +26 -0
- package/dist/db/adapters/mysql.js.map +1 -0
- package/dist/db/adapters/postgres.d.ts +7 -0
- package/dist/db/adapters/postgres.d.ts.map +1 -0
- package/dist/db/adapters/postgres.js +25 -0
- package/dist/db/adapters/postgres.js.map +1 -0
- package/dist/db/adapters/sqlite.d.ts +5 -0
- package/dist/db/adapters/sqlite.d.ts.map +1 -0
- package/dist/db/adapters/sqlite.js +27 -0
- package/dist/db/adapters/sqlite.js.map +1 -0
- package/dist/db/client-types.d.ts +75 -0
- package/dist/db/client-types.d.ts.map +1 -0
- package/dist/db/client-types.js +2 -0
- package/dist/db/client-types.js.map +1 -0
- package/dist/db/create-adapter.d.ts +11 -0
- package/dist/db/create-adapter.d.ts.map +1 -0
- package/dist/db/create-adapter.js +43 -0
- package/dist/db/create-adapter.js.map +1 -0
- package/dist/db/find-in-batches.d.ts +12 -0
- package/dist/db/find-in-batches.d.ts.map +1 -0
- package/dist/db/find-in-batches.js +20 -0
- package/dist/db/find-in-batches.js.map +1 -0
- package/dist/db/index.d.ts +9 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +5 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/model-types.d.ts +602 -0
- package/dist/db/model-types.d.ts.map +1 -0
- package/dist/db/model-types.js +14 -0
- package/dist/db/model-types.js.map +1 -0
- package/dist/db.d.ts +20 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +35 -0
- package/dist/db.js.map +1 -0
- package/dist/diagnostics/api-metrics.d.ts +135 -0
- package/dist/diagnostics/api-metrics.d.ts.map +1 -0
- package/dist/diagnostics/api-metrics.js +376 -0
- package/dist/diagnostics/api-metrics.js.map +1 -0
- package/dist/diagnostics/env.d.ts +44 -0
- package/dist/diagnostics/env.d.ts.map +1 -0
- package/dist/diagnostics/env.js +354 -0
- package/dist/diagnostics/env.js.map +1 -0
- package/dist/diagnostics/logger.d.ts +38 -0
- package/dist/diagnostics/logger.d.ts.map +1 -0
- package/dist/diagnostics/logger.js +89 -0
- package/dist/diagnostics/logger.js.map +1 -0
- package/dist/diagnostics/sentry.d.ts +8 -0
- package/dist/diagnostics/sentry.d.ts.map +1 -0
- package/dist/diagnostics/sentry.js +54 -0
- package/dist/diagnostics/sentry.js.map +1 -0
- package/dist/email/resolve.d.ts +27 -0
- package/dist/email/resolve.d.ts.map +1 -0
- package/dist/email/resolve.js +68 -0
- package/dist/email/resolve.js.map +1 -0
- package/dist/email/sender.d.ts +71 -0
- package/dist/email/sender.d.ts.map +1 -0
- package/dist/email/sender.js +41 -0
- package/dist/email/sender.js.map +1 -0
- package/dist/email/settings-store.d.ts +116 -0
- package/dist/email/settings-store.d.ts.map +1 -0
- package/dist/email/settings-store.js +222 -0
- package/dist/email/settings-store.js.map +1 -0
- package/dist/fields/component-block.d.ts +23 -0
- package/dist/fields/component-block.d.ts.map +1 -0
- package/dist/fields/component-block.js +137 -0
- package/dist/fields/component-block.js.map +1 -0
- package/dist/fields/index.d.ts +19 -0
- package/dist/fields/index.d.ts.map +1 -0
- package/dist/fields/index.js +95 -0
- package/dist/fields/index.js.map +1 -0
- package/dist/fields/presets.d.ts +144 -0
- package/dist/fields/presets.d.ts.map +1 -0
- package/dist/fields/presets.js +350 -0
- package/dist/fields/presets.js.map +1 -0
- package/dist/fields/relations.d.ts +87 -0
- package/dist/fields/relations.d.ts.map +1 -0
- package/dist/fields/relations.js +231 -0
- package/dist/fields/relations.js.map +1 -0
- package/dist/forms/analytics.d.ts +62 -0
- package/dist/forms/analytics.d.ts.map +1 -0
- package/dist/forms/analytics.js +95 -0
- package/dist/forms/analytics.js.map +1 -0
- package/dist/forms/attribution.d.ts +175 -0
- package/dist/forms/attribution.d.ts.map +1 -0
- package/dist/forms/attribution.js +577 -0
- package/dist/forms/attribution.js.map +1 -0
- package/dist/forms/client-validation.d.ts +50 -0
- package/dist/forms/client-validation.d.ts.map +1 -0
- package/dist/forms/client-validation.js +215 -0
- package/dist/forms/client-validation.js.map +1 -0
- package/dist/forms/delivery.d.ts +89 -0
- package/dist/forms/delivery.d.ts.map +1 -0
- package/dist/forms/delivery.js +477 -0
- package/dist/forms/delivery.js.map +1 -0
- package/dist/forms/encryption.d.ts +20 -0
- package/dist/forms/encryption.d.ts.map +1 -0
- package/dist/forms/encryption.js +80 -0
- package/dist/forms/encryption.js.map +1 -0
- package/dist/forms/entries.d.ts +68 -0
- package/dist/forms/entries.d.ts.map +1 -0
- package/dist/forms/entries.js +557 -0
- package/dist/forms/entries.js.map +1 -0
- package/dist/forms/files.d.ts +38 -0
- package/dist/forms/files.d.ts.map +1 -0
- package/dist/forms/files.js +134 -0
- package/dist/forms/files.js.map +1 -0
- package/dist/forms/index.d.ts +21 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/index.js +20 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/notify.d.ts +80 -0
- package/dist/forms/notify.d.ts.map +1 -0
- package/dist/forms/notify.js +357 -0
- package/dist/forms/notify.js.map +1 -0
- package/dist/forms/prefetch.d.ts +17 -0
- package/dist/forms/prefetch.d.ts.map +1 -0
- package/dist/forms/prefetch.js +36 -0
- package/dist/forms/prefetch.js.map +1 -0
- package/dist/forms/public-html.d.ts +22 -0
- package/dist/forms/public-html.d.ts.map +1 -0
- package/dist/forms/public-html.js +145 -0
- package/dist/forms/public-html.js.map +1 -0
- package/dist/forms/service.d.ts +102 -0
- package/dist/forms/service.d.ts.map +1 -0
- package/dist/forms/service.js +625 -0
- package/dist/forms/service.js.map +1 -0
- package/dist/forms/spam.d.ts +33 -0
- package/dist/forms/spam.d.ts.map +1 -0
- package/dist/forms/spam.js +93 -0
- package/dist/forms/spam.js.map +1 -0
- package/dist/forms/submission.d.ts +132 -0
- package/dist/forms/submission.d.ts.map +1 -0
- package/dist/forms/submission.js +348 -0
- package/dist/forms/submission.js.map +1 -0
- package/dist/forms/types.d.ts +259 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/forms/types.js +20 -0
- package/dist/forms/types.js.map +1 -0
- package/dist/forms/validation.d.ts +19 -0
- package/dist/forms/validation.d.ts.map +1 -0
- package/dist/forms/validation.js +166 -0
- package/dist/forms/validation.js.map +1 -0
- package/dist/forms/webhooks.d.ts +60 -0
- package/dist/forms/webhooks.d.ts.map +1 -0
- package/dist/forms/webhooks.js +360 -0
- package/dist/forms/webhooks.js.map +1 -0
- package/dist/forms/webmcp.d.ts +36 -0
- package/dist/forms/webmcp.d.ts.map +1 -0
- package/dist/forms/webmcp.js +67 -0
- package/dist/forms/webmcp.js.map +1 -0
- package/dist/forms/xlsx.d.ts +10 -0
- package/dist/forms/xlsx.d.ts.map +1 -0
- package/dist/forms/xlsx.js +207 -0
- package/dist/forms/xlsx.js.map +1 -0
- package/dist/generated/browser.d.ts +220 -0
- package/dist/generated/browser.js +17 -0
- package/dist/generated/client.d.ts +239 -0
- package/dist/generated/client.js +34 -0
- package/dist/generated/commonInputTypes.d.ts +887 -0
- package/dist/generated/commonInputTypes.js +10 -0
- package/dist/generated/enums.d.ts +83 -0
- package/dist/generated/enums.js +81 -0
- package/dist/generated/internal/class.d.ts +517 -0
- package/dist/generated/internal/class.js +52 -0
- package/dist/generated/internal/prismaNamespace.d.ts +4184 -0
- package/dist/generated/internal/prismaNamespace.js +932 -0
- package/dist/generated/internal/prismaNamespaceBrowser.d.ts +968 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +903 -0
- package/dist/generated/models/AiCrawlerHit.d.ts +1115 -0
- package/dist/generated/models/AiCrawlerHit.js +1 -0
- package/dist/generated/models/ApiKey.d.ts +1388 -0
- package/dist/generated/models/ApiKey.js +1 -0
- package/dist/generated/models/ApiRequestMetric.d.ts +1229 -0
- package/dist/generated/models/ApiRequestMetric.js +1 -0
- package/dist/generated/models/AuditLog.d.ts +1062 -0
- package/dist/generated/models/AuditLog.js +1 -0
- package/dist/generated/models/BackupRecord.d.ts +1100 -0
- package/dist/generated/models/BackupRecord.js +1 -0
- package/dist/generated/models/ContentIssue.d.ts +1318 -0
- package/dist/generated/models/ContentIssue.js +1 -0
- package/dist/generated/models/ContentLock.d.ts +1295 -0
- package/dist/generated/models/ContentLock.js +1 -0
- package/dist/generated/models/ContentTemplate.d.ts +1254 -0
- package/dist/generated/models/ContentTemplate.js +1 -0
- package/dist/generated/models/Document.d.ts +3443 -0
- package/dist/generated/models/Document.js +1 -0
- package/dist/generated/models/Folder.d.ts +1689 -0
- package/dist/generated/models/Folder.js +1 -0
- package/dist/generated/models/FormDeliveryAttempt.d.ts +1705 -0
- package/dist/generated/models/FormDeliveryAttempt.js +1 -0
- package/dist/generated/models/FormSchemaVersion.d.ts +1105 -0
- package/dist/generated/models/FormSchemaVersion.js +1 -0
- package/dist/generated/models/FormSubmission.d.ts +2125 -0
- package/dist/generated/models/FormSubmission.js +1 -0
- package/dist/generated/models/FormSubmissionFile.d.ts +1438 -0
- package/dist/generated/models/FormSubmissionFile.js +1 -0
- package/dist/generated/models/FormWebhook.d.ts +1271 -0
- package/dist/generated/models/FormWebhook.js +1 -0
- package/dist/generated/models/InAppNotification.d.ts +1295 -0
- package/dist/generated/models/InAppNotification.js +1 -0
- package/dist/generated/models/Invite.d.ts +1240 -0
- package/dist/generated/models/Invite.js +1 -0
- package/dist/generated/models/Media.d.ts +2759 -0
- package/dist/generated/models/Media.js +1 -0
- package/dist/generated/models/MediaUsage.d.ts +1301 -0
- package/dist/generated/models/MediaUsage.js +1 -0
- package/dist/generated/models/OAuthAccount.d.ts +1300 -0
- package/dist/generated/models/OAuthAccount.js +1 -0
- package/dist/generated/models/PageTemplate.d.ts +1118 -0
- package/dist/generated/models/PageTemplate.js +1 -0
- package/dist/generated/models/PasswordResetToken.d.ts +1225 -0
- package/dist/generated/models/PasswordResetToken.js +1 -0
- package/dist/generated/models/Redirect.d.ts +1342 -0
- package/dist/generated/models/Redirect.js +1 -0
- package/dist/generated/models/Redirect404Hit.d.ts +1107 -0
- package/dist/generated/models/Redirect404Hit.js +1 -0
- package/dist/generated/models/RedirectSuggestion.d.ts +1185 -0
- package/dist/generated/models/RedirectSuggestion.js +1 -0
- package/dist/generated/models/SavedSection.d.ts +1156 -0
- package/dist/generated/models/SavedSection.js +1 -0
- package/dist/generated/models/ScriptTag.d.ts +1291 -0
- package/dist/generated/models/ScriptTag.js +1 -0
- package/dist/generated/models/SeoAuditRun.d.ts +1570 -0
- package/dist/generated/models/SeoAuditRun.js +1 -0
- package/dist/generated/models/SeoIssue.d.ts +1873 -0
- package/dist/generated/models/SeoIssue.js +1 -0
- package/dist/generated/models/Session.d.ts +1330 -0
- package/dist/generated/models/Session.js +1 -0
- package/dist/generated/models/Site.d.ts +1062 -0
- package/dist/generated/models/Site.js +1 -0
- package/dist/generated/models/User.d.ts +4344 -0
- package/dist/generated/models/User.js +1 -0
- package/dist/generated/models/Version.d.ts +1334 -0
- package/dist/generated/models/Version.js +1 -0
- package/dist/generated/models/WebhookDeliveryLog.d.ts +1479 -0
- package/dist/generated/models/WebhookDeliveryLog.js +1 -0
- package/dist/generated/models/WebhookEndpoint.d.ts +1331 -0
- package/dist/generated/models/WebhookEndpoint.js +1 -0
- package/dist/generated/models/WorkflowState.d.ts +1436 -0
- package/dist/generated/models/WorkflowState.js +1 -0
- package/dist/generated/models.d.ts +37 -0
- package/dist/generated/models.js +1 -0
- package/dist/graphql/index.d.ts +11 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +74 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/resolvers.d.ts +8 -0
- package/dist/graphql/resolvers.d.ts.map +1 -0
- package/dist/graphql/resolvers.js +89 -0
- package/dist/graphql/resolvers.js.map +1 -0
- package/dist/graphql/schema-builder.d.ts +3 -0
- package/dist/graphql/schema-builder.d.ts.map +1 -0
- package/dist/graphql/schema-builder.js +103 -0
- package/dist/graphql/schema-builder.js.map +1 -0
- package/dist/health/index.d.ts +27 -0
- package/dist/health/index.d.ts.map +1 -0
- package/dist/health/index.js +43 -0
- package/dist/health/index.js.map +1 -0
- package/dist/i18n/index.d.ts +22 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +37 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +125 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +132 -0
- package/dist/index.js.map +1 -0
- package/dist/media/content-hash.d.ts +3 -0
- package/dist/media/content-hash.d.ts.map +1 -0
- package/dist/media/content-hash.js +11 -0
- package/dist/media/content-hash.js.map +1 -0
- package/dist/media/denormalize.d.ts +23 -0
- package/dist/media/denormalize.d.ts.map +1 -0
- package/dist/media/denormalize.js +170 -0
- package/dist/media/denormalize.js.map +1 -0
- package/dist/media/index.d.ts +8 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/index.js +5 -0
- package/dist/media/index.js.map +1 -0
- package/dist/media/merge-document-media.d.ts +23 -0
- package/dist/media/merge-document-media.d.ts.map +1 -0
- package/dist/media/merge-document-media.js +146 -0
- package/dist/media/merge-document-media.js.map +1 -0
- package/dist/media/metadata-patch.d.ts +21 -0
- package/dist/media/metadata-patch.d.ts.map +1 -0
- package/dist/media/metadata-patch.js +37 -0
- package/dist/media/metadata-patch.js.map +1 -0
- package/dist/media/optimize.d.ts +61 -0
- package/dist/media/optimize.d.ts.map +1 -0
- package/dist/media/optimize.js +168 -0
- package/dist/media/optimize.js.map +1 -0
- package/dist/media/seo.d.ts +110 -0
- package/dist/media/seo.d.ts.map +1 -0
- package/dist/media/seo.js +263 -0
- package/dist/media/seo.js.map +1 -0
- package/dist/media/usage-sync.d.ts +37 -0
- package/dist/media/usage-sync.d.ts.map +1 -0
- package/dist/media/usage-sync.js +234 -0
- package/dist/media/usage-sync.js.map +1 -0
- package/dist/middleware.d.ts +17 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +159 -0
- package/dist/middleware.js.map +1 -0
- package/dist/multisite/index.d.ts +20 -0
- package/dist/multisite/index.d.ts.map +1 -0
- package/dist/multisite/index.js +26 -0
- package/dist/multisite/index.js.map +1 -0
- package/dist/navigation/unresolved-targets.d.ts +35 -0
- package/dist/navigation/unresolved-targets.d.ts.map +1 -0
- package/dist/navigation/unresolved-targets.js +109 -0
- package/dist/navigation/unresolved-targets.js.map +1 -0
- package/dist/next/preview.d.ts +10 -0
- package/dist/next/preview.d.ts.map +1 -0
- package/dist/next/preview.js +17 -0
- package/dist/next/preview.js.map +1 -0
- package/dist/next/script-tags.d.ts +15 -0
- package/dist/next/script-tags.d.ts.map +1 -0
- package/dist/next/script-tags.js +58 -0
- package/dist/next/script-tags.js.map +1 -0
- package/dist/next-site.d.ts +29 -0
- package/dist/next-site.d.ts.map +1 -0
- package/dist/next-site.js +60 -0
- package/dist/next-site.js.map +1 -0
- package/dist/next.d.ts +33 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +142 -0
- package/dist/next.js.map +1 -0
- package/dist/notifications/index.d.ts +20 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +22 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/page-builder/a11y-fix.d.ts +20 -0
- package/dist/page-builder/a11y-fix.d.ts.map +1 -0
- package/dist/page-builder/a11y-fix.js +182 -0
- package/dist/page-builder/a11y-fix.js.map +1 -0
- package/dist/page-builder/ai-pipeline.d.ts +43 -0
- package/dist/page-builder/ai-pipeline.d.ts.map +1 -0
- package/dist/page-builder/ai-pipeline.js +165 -0
- package/dist/page-builder/ai-pipeline.js.map +1 -0
- package/dist/page-builder/blocks.d.ts +27 -0
- package/dist/page-builder/blocks.d.ts.map +1 -0
- package/dist/page-builder/blocks.js +313 -0
- package/dist/page-builder/blocks.js.map +1 -0
- package/dist/page-builder/design-scorer.d.ts +27 -0
- package/dist/page-builder/design-scorer.d.ts.map +1 -0
- package/dist/page-builder/design-scorer.js +612 -0
- package/dist/page-builder/design-scorer.js.map +1 -0
- package/dist/page-builder/index.d.ts +18 -0
- package/dist/page-builder/index.d.ts.map +1 -0
- package/dist/page-builder/index.js +20 -0
- package/dist/page-builder/index.js.map +1 -0
- package/dist/page-builder/schema.d.ts +107 -0
- package/dist/page-builder/schema.d.ts.map +1 -0
- package/dist/page-builder/schema.js +90 -0
- package/dist/page-builder/schema.js.map +1 -0
- package/dist/page-builder/seo-analyzer.d.ts +61 -0
- package/dist/page-builder/seo-analyzer.d.ts.map +1 -0
- package/dist/page-builder/seo-analyzer.js +778 -0
- package/dist/page-builder/seo-analyzer.js.map +1 -0
- package/dist/page-builder/templates.d.ts +9 -0
- package/dist/page-builder/templates.d.ts.map +1 -0
- package/dist/page-builder/templates.js +742 -0
- package/dist/page-builder/templates.js.map +1 -0
- package/dist/page-builder/tree.d.ts +17 -0
- package/dist/page-builder/tree.d.ts.map +1 -0
- package/dist/page-builder/tree.js +160 -0
- package/dist/page-builder/tree.js.map +1 -0
- package/dist/page-builder/types.d.ts +112 -0
- package/dist/page-builder/types.d.ts.map +1 -0
- package/dist/page-builder/types.js +4 -0
- package/dist/page-builder/types.js.map +1 -0
- package/dist/page-builder/validate.d.ts +6 -0
- package/dist/page-builder/validate.d.ts.map +1 -0
- package/dist/page-builder/validate.js +87 -0
- package/dist/page-builder/validate.js.map +1 -0
- package/dist/plan/features.d.ts +17 -0
- package/dist/plan/features.d.ts.map +1 -0
- package/dist/plan/features.js +73 -0
- package/dist/plan/features.js.map +1 -0
- package/dist/posts/query.d.ts +50 -0
- package/dist/posts/query.d.ts.map +1 -0
- package/dist/posts/query.js +105 -0
- package/dist/posts/query.js.map +1 -0
- package/dist/presence/index.d.ts +24 -0
- package/dist/presence/index.d.ts.map +1 -0
- package/dist/presence/index.js +99 -0
- package/dist/presence/index.js.map +1 -0
- package/dist/preview/event-bus.d.ts +39 -0
- package/dist/preview/event-bus.d.ts.map +1 -0
- package/dist/preview/event-bus.js +73 -0
- package/dist/preview/event-bus.js.map +1 -0
- package/dist/preview/index.d.ts +36 -0
- package/dist/preview/index.d.ts.map +1 -0
- package/dist/preview/index.js +68 -0
- package/dist/preview/index.js.map +1 -0
- package/dist/preview/sse-stream.d.ts +47 -0
- package/dist/preview/sse-stream.d.ts.map +1 -0
- package/dist/preview/sse-stream.js +111 -0
- package/dist/preview/sse-stream.js.map +1 -0
- package/dist/privacy/index.d.ts +33 -0
- package/dist/privacy/index.d.ts.map +1 -0
- package/dist/privacy/index.js +15 -0
- package/dist/privacy/index.js.map +1 -0
- package/dist/public-redirects.d.ts +78 -0
- package/dist/public-redirects.d.ts.map +1 -0
- package/dist/public-redirects.js +187 -0
- package/dist/public-redirects.js.map +1 -0
- package/dist/public-security-headers.d.ts +27 -0
- package/dist/public-security-headers.d.ts.map +1 -0
- package/dist/public-security-headers.js +40 -0
- package/dist/public-security-headers.js.map +1 -0
- package/dist/publishing/publish-sync.d.ts +50 -0
- package/dist/publishing/publish-sync.d.ts.map +1 -0
- package/dist/publishing/publish-sync.js +124 -0
- package/dist/publishing/publish-sync.js.map +1 -0
- package/dist/purge/adapters.d.ts +60 -0
- package/dist/purge/adapters.d.ts.map +1 -0
- package/dist/purge/adapters.js +81 -0
- package/dist/purge/adapters.js.map +1 -0
- package/dist/purge/index.d.ts +12 -0
- package/dist/purge/index.d.ts.map +1 -0
- package/dist/purge/index.js +10 -0
- package/dist/purge/index.js.map +1 -0
- package/dist/purge/receiver.d.ts +95 -0
- package/dist/purge/receiver.d.ts.map +1 -0
- package/dist/purge/receiver.js +176 -0
- package/dist/purge/receiver.js.map +1 -0
- package/dist/realtime/comments.d.ts +217 -0
- package/dist/realtime/comments.d.ts.map +1 -0
- package/dist/realtime/comments.js +282 -0
- package/dist/realtime/comments.js.map +1 -0
- package/dist/realtime/gateway.d.ts +107 -0
- package/dist/realtime/gateway.d.ts.map +1 -0
- package/dist/realtime/gateway.js +215 -0
- package/dist/realtime/gateway.js.map +1 -0
- package/dist/realtime/index.d.ts +21 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +27 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/notification-bus.d.ts +60 -0
- package/dist/realtime/notification-bus.d.ts.map +1 -0
- package/dist/realtime/notification-bus.js +77 -0
- package/dist/realtime/notification-bus.js.map +1 -0
- package/dist/realtime/notification-stream.d.ts +50 -0
- package/dist/realtime/notification-stream.d.ts.map +1 -0
- package/dist/realtime/notification-stream.js +148 -0
- package/dist/realtime/notification-stream.js.map +1 -0
- package/dist/realtime/notifications.d.ts +201 -0
- package/dist/realtime/notifications.d.ts.map +1 -0
- package/dist/realtime/notifications.js +233 -0
- package/dist/realtime/notifications.js.map +1 -0
- package/dist/realtime/persistence.d.ts +72 -0
- package/dist/realtime/persistence.d.ts.map +1 -0
- package/dist/realtime/persistence.js +53 -0
- package/dist/realtime/persistence.js.map +1 -0
- package/dist/realtime/sse.d.ts +20 -0
- package/dist/realtime/sse.d.ts.map +1 -0
- package/dist/realtime/sse.js +31 -0
- package/dist/realtime/sse.js.map +1 -0
- package/dist/redirects/auto.d.ts +45 -0
- package/dist/redirects/auto.d.ts.map +1 -0
- package/dist/redirects/auto.js +60 -0
- package/dist/redirects/auto.js.map +1 -0
- package/dist/redirects/fix-link.d.ts +15 -0
- package/dist/redirects/fix-link.d.ts.map +1 -0
- package/dist/redirects/fix-link.js +66 -0
- package/dist/redirects/fix-link.js.map +1 -0
- package/dist/redirects/graph.d.ts +92 -0
- package/dist/redirects/graph.d.ts.map +1 -0
- package/dist/redirects/graph.js +176 -0
- package/dist/redirects/graph.js.map +1 -0
- package/dist/redirects/index.d.ts +17 -0
- package/dist/redirects/index.d.ts.map +1 -0
- package/dist/redirects/index.js +10 -0
- package/dist/redirects/index.js.map +1 -0
- package/dist/redirects/legitimacy.d.ts +23 -0
- package/dist/redirects/legitimacy.d.ts.map +1 -0
- package/dist/redirects/legitimacy.js +64 -0
- package/dist/redirects/legitimacy.js.map +1 -0
- package/dist/redirects/recovery.d.ts +92 -0
- package/dist/redirects/recovery.d.ts.map +1 -0
- package/dist/redirects/recovery.js +210 -0
- package/dist/redirects/recovery.js.map +1 -0
- package/dist/redirects/rerank.d.ts +24 -0
- package/dist/redirects/rerank.d.ts.map +1 -0
- package/dist/redirects/rerank.js +82 -0
- package/dist/redirects/rerank.js.map +1 -0
- package/dist/redirects/suggest.d.ts +23 -0
- package/dist/redirects/suggest.d.ts.map +1 -0
- package/dist/redirects/suggest.js +80 -0
- package/dist/redirects/suggest.js.map +1 -0
- package/dist/redirects/typo.d.ts +10 -0
- package/dist/redirects/typo.d.ts.map +1 -0
- package/dist/redirects/typo.js +51 -0
- package/dist/redirects/typo.js.map +1 -0
- package/dist/redirects/validate-destination.d.ts +13 -0
- package/dist/redirects/validate-destination.d.ts.map +1 -0
- package/dist/redirects/validate-destination.js +51 -0
- package/dist/redirects/validate-destination.js.map +1 -0
- package/dist/relationships/index.d.ts +13 -0
- package/dist/relationships/index.d.ts.map +1 -0
- package/dist/relationships/index.js +12 -0
- package/dist/relationships/index.js.map +1 -0
- package/dist/scheduling/index.d.ts +45 -0
- package/dist/scheduling/index.d.ts.map +1 -0
- package/dist/scheduling/index.js +141 -0
- package/dist/scheduling/index.js.map +1 -0
- package/dist/script-tags/index.d.ts +3 -0
- package/dist/script-tags/index.d.ts.map +1 -0
- package/dist/script-tags/index.js +3 -0
- package/dist/script-tags/index.js.map +1 -0
- package/dist/script-tags/invalidate.d.ts +3 -0
- package/dist/script-tags/invalidate.d.ts.map +1 -0
- package/dist/script-tags/invalidate.js +16 -0
- package/dist/script-tags/invalidate.js.map +1 -0
- package/dist/script-tags/resolve.d.ts +41 -0
- package/dist/script-tags/resolve.d.ts.map +1 -0
- package/dist/script-tags/resolve.js +130 -0
- package/dist/script-tags/resolve.js.map +1 -0
- package/dist/search/index.d.ts +25 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +189 -0
- package/dist/search/index.js.map +1 -0
- package/dist/sections/bridge.d.ts +8 -0
- package/dist/sections/bridge.d.ts.map +1 -0
- package/dist/sections/bridge.js +211 -0
- package/dist/sections/bridge.js.map +1 -0
- package/dist/sections/define.d.ts +21 -0
- package/dist/sections/define.d.ts.map +1 -0
- package/dist/sections/define.js +160 -0
- package/dist/sections/define.js.map +1 -0
- package/dist/sections/embed.d.ts +24 -0
- package/dist/sections/embed.d.ts.map +1 -0
- package/dist/sections/embed.js +78 -0
- package/dist/sections/embed.js.map +1 -0
- package/dist/sections/fields.d.ts +37 -0
- package/dist/sections/fields.d.ts.map +1 -0
- package/dist/sections/fields.js +50 -0
- package/dist/sections/fields.js.map +1 -0
- package/dist/sections/helpers.d.ts +149 -0
- package/dist/sections/helpers.d.ts.map +1 -0
- package/dist/sections/helpers.js +373 -0
- package/dist/sections/helpers.js.map +1 -0
- package/dist/sections/index.d.ts +22 -0
- package/dist/sections/index.d.ts.map +1 -0
- package/dist/sections/index.js +18 -0
- package/dist/sections/index.js.map +1 -0
- package/dist/sections/media-enrich.d.ts +45 -0
- package/dist/sections/media-enrich.d.ts.map +1 -0
- package/dist/sections/media-enrich.js +137 -0
- package/dist/sections/media-enrich.js.map +1 -0
- package/dist/sections/migrate.d.ts +42 -0
- package/dist/sections/migrate.d.ts.map +1 -0
- package/dist/sections/migrate.js +66 -0
- package/dist/sections/migrate.js.map +1 -0
- package/dist/sections/registry.d.ts +46 -0
- package/dist/sections/registry.d.ts.map +1 -0
- package/dist/sections/registry.js +598 -0
- package/dist/sections/registry.js.map +1 -0
- package/dist/sections/types.d.ts +192 -0
- package/dist/sections/types.d.ts.map +1 -0
- package/dist/sections/types.js +21 -0
- package/dist/sections/types.js.map +1 -0
- package/dist/sections/validate.d.ts +12 -0
- package/dist/sections/validate.d.ts.map +1 -0
- package/dist/sections/validate.js +186 -0
- package/dist/sections/validate.js.map +1 -0
- package/dist/sections/widget-embed.d.ts +45 -0
- package/dist/sections/widget-embed.d.ts.map +1 -0
- package/dist/sections/widget-embed.js +129 -0
- package/dist/sections/widget-embed.js.map +1 -0
- package/dist/security/access.d.ts +35 -0
- package/dist/security/access.d.ts.map +1 -0
- package/dist/security/access.js +133 -0
- package/dist/security/access.js.map +1 -0
- package/dist/security/anomaly-detection.d.ts +17 -0
- package/dist/security/anomaly-detection.d.ts.map +1 -0
- package/dist/security/anomaly-detection.js +39 -0
- package/dist/security/anomaly-detection.js.map +1 -0
- package/dist/security/api-key-enhanced.d.ts +68 -0
- package/dist/security/api-key-enhanced.d.ts.map +1 -0
- package/dist/security/api-key-enhanced.js +76 -0
- package/dist/security/api-key-enhanced.js.map +1 -0
- package/dist/security/audit.d.ts +46 -0
- package/dist/security/audit.d.ts.map +1 -0
- package/dist/security/audit.js +67 -0
- package/dist/security/audit.js.map +1 -0
- package/dist/security/breach-check.d.ts +3 -0
- package/dist/security/breach-check.d.ts.map +1 -0
- package/dist/security/breach-check.js +27 -0
- package/dist/security/breach-check.js.map +1 -0
- package/dist/security/captcha.d.ts +67 -0
- package/dist/security/captcha.d.ts.map +1 -0
- package/dist/security/captcha.js +186 -0
- package/dist/security/captcha.js.map +1 -0
- package/dist/security/center/gather.d.ts +20 -0
- package/dist/security/center/gather.d.ts.map +1 -0
- package/dist/security/center/gather.js +240 -0
- package/dist/security/center/gather.js.map +1 -0
- package/dist/security/center/index.d.ts +13 -0
- package/dist/security/center/index.d.ts.map +1 -0
- package/dist/security/center/index.js +4 -0
- package/dist/security/center/index.js.map +1 -0
- package/dist/security/center/settings.d.ts +48 -0
- package/dist/security/center/settings.d.ts.map +1 -0
- package/dist/security/center/settings.js +218 -0
- package/dist/security/center/settings.js.map +1 -0
- package/dist/security/center/status.d.ts +10 -0
- package/dist/security/center/status.d.ts.map +1 -0
- package/dist/security/center/status.js +249 -0
- package/dist/security/center/status.js.map +1 -0
- package/dist/security/center/summaries.d.ts +21 -0
- package/dist/security/center/summaries.d.ts.map +1 -0
- package/dist/security/center/summaries.js +65 -0
- package/dist/security/center/summaries.js.map +1 -0
- package/dist/security/center/types.d.ts +142 -0
- package/dist/security/center/types.d.ts.map +1 -0
- package/dist/security/center/types.js +12 -0
- package/dist/security/center/types.js.map +1 -0
- package/dist/security/client-ip.d.ts +23 -0
- package/dist/security/client-ip.d.ts.map +1 -0
- package/dist/security/client-ip.js +97 -0
- package/dist/security/client-ip.js.map +1 -0
- package/dist/security/cors.d.ts +11 -0
- package/dist/security/cors.d.ts.map +1 -0
- package/dist/security/cors.js +33 -0
- package/dist/security/cors.js.map +1 -0
- package/dist/security/csp-nonces.d.ts +5 -0
- package/dist/security/csp-nonces.d.ts.map +1 -0
- package/dist/security/csp-nonces.js +24 -0
- package/dist/security/csp-nonces.js.map +1 -0
- package/dist/security/csrf.d.ts +5 -0
- package/dist/security/csrf.d.ts.map +1 -0
- package/dist/security/csrf.js +20 -0
- package/dist/security/csrf.js.map +1 -0
- package/dist/security/encrypted-fields.d.ts +14 -0
- package/dist/security/encrypted-fields.d.ts.map +1 -0
- package/dist/security/encrypted-fields.js +94 -0
- package/dist/security/encrypted-fields.js.map +1 -0
- package/dist/security/headers.d.ts +11 -0
- package/dist/security/headers.d.ts.map +1 -0
- package/dist/security/headers.js +32 -0
- package/dist/security/headers.js.map +1 -0
- package/dist/security/index.d.ts +40 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +26 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/internal-keys.d.ts +15 -0
- package/dist/security/internal-keys.d.ts.map +1 -0
- package/dist/security/internal-keys.js +33 -0
- package/dist/security/internal-keys.js.map +1 -0
- package/dist/security/ip-allowlist.d.ts +15 -0
- package/dist/security/ip-allowlist.d.ts.map +1 -0
- package/dist/security/ip-allowlist.js +141 -0
- package/dist/security/ip-allowlist.js.map +1 -0
- package/dist/security/ip-canon.d.ts +71 -0
- package/dist/security/ip-canon.d.ts.map +1 -0
- package/dist/security/ip-canon.js +352 -0
- package/dist/security/ip-canon.js.map +1 -0
- package/dist/security/middleware.d.ts +20 -0
- package/dist/security/middleware.d.ts.map +1 -0
- package/dist/security/middleware.js +45 -0
- package/dist/security/middleware.js.map +1 -0
- package/dist/security/rate-limit-policy.d.ts +40 -0
- package/dist/security/rate-limit-policy.d.ts.map +1 -0
- package/dist/security/rate-limit-policy.js +57 -0
- package/dist/security/rate-limit-policy.js.map +1 -0
- package/dist/security/rate-limit.d.ts +55 -0
- package/dist/security/rate-limit.d.ts.map +1 -0
- package/dist/security/rate-limit.js +298 -0
- package/dist/security/rate-limit.js.map +1 -0
- package/dist/security/reauth.d.ts +16 -0
- package/dist/security/reauth.d.ts.map +1 -0
- package/dist/security/reauth.js +56 -0
- package/dist/security/reauth.js.map +1 -0
- package/dist/security/redact.d.ts +12 -0
- package/dist/security/redact.d.ts.map +1 -0
- package/dist/security/redact.js +44 -0
- package/dist/security/redact.js.map +1 -0
- package/dist/security/safe-fetch.d.ts +57 -0
- package/dist/security/safe-fetch.d.ts.map +1 -0
- package/dist/security/safe-fetch.js +71 -0
- package/dist/security/safe-fetch.js.map +1 -0
- package/dist/security/sanitize-document.d.ts +14 -0
- package/dist/security/sanitize-document.d.ts.map +1 -0
- package/dist/security/sanitize-document.js +117 -0
- package/dist/security/sanitize-document.js.map +1 -0
- package/dist/security/sanitize.d.ts +13 -0
- package/dist/security/sanitize.d.ts.map +1 -0
- package/dist/security/sanitize.js +64 -0
- package/dist/security/sanitize.js.map +1 -0
- package/dist/security/secret-storage.d.ts +22 -0
- package/dist/security/secret-storage.d.ts.map +1 -0
- package/dist/security/secret-storage.js +75 -0
- package/dist/security/secret-storage.js.map +1 -0
- package/dist/security/security-txt.d.ts +12 -0
- package/dist/security/security-txt.d.ts.map +1 -0
- package/dist/security/security-txt.js +19 -0
- package/dist/security/security-txt.js.map +1 -0
- package/dist/security/session-limits.d.ts +17 -0
- package/dist/security/session-limits.d.ts.map +1 -0
- package/dist/security/session-limits.js +14 -0
- package/dist/security/session-limits.js.map +1 -0
- package/dist/security/upload.d.ts +32 -0
- package/dist/security/upload.d.ts.map +1 -0
- package/dist/security/upload.js +129 -0
- package/dist/security/upload.js.map +1 -0
- package/dist/security/webhook.d.ts +30 -0
- package/dist/security/webhook.d.ts.map +1 -0
- package/dist/security/webhook.js +133 -0
- package/dist/security/webhook.js.map +1 -0
- package/dist/seo/ai-bots.d.ts +56 -0
- package/dist/seo/ai-bots.d.ts.map +1 -0
- package/dist/seo/ai-bots.js +125 -0
- package/dist/seo/ai-bots.js.map +1 -0
- package/dist/seo/ai-crawler-log.d.ts +14 -0
- package/dist/seo/ai-crawler-log.d.ts.map +1 -0
- package/dist/seo/ai-crawler-log.js +48 -0
- package/dist/seo/ai-crawler-log.js.map +1 -0
- package/dist/seo/alt-text.d.ts +39 -0
- package/dist/seo/alt-text.d.ts.map +1 -0
- package/dist/seo/alt-text.js +67 -0
- package/dist/seo/alt-text.js.map +1 -0
- package/dist/seo/analysis.d.ts +75 -0
- package/dist/seo/analysis.d.ts.map +1 -0
- package/dist/seo/analysis.js +641 -0
- package/dist/seo/analysis.js.map +1 -0
- package/dist/seo/audit-engine.d.ts +124 -0
- package/dist/seo/audit-engine.d.ts.map +1 -0
- package/dist/seo/audit-engine.js +534 -0
- package/dist/seo/audit-engine.js.map +1 -0
- package/dist/seo/audit-runner.d.ts +84 -0
- package/dist/seo/audit-runner.d.ts.map +1 -0
- package/dist/seo/audit-runner.js +372 -0
- package/dist/seo/audit-runner.js.map +1 -0
- package/dist/seo/audit-signals.d.ts +28 -0
- package/dist/seo/audit-signals.d.ts.map +1 -0
- package/dist/seo/audit-signals.js +133 -0
- package/dist/seo/audit-signals.js.map +1 -0
- package/dist/seo/config-store.d.ts +99 -0
- package/dist/seo/config-store.d.ts.map +1 -0
- package/dist/seo/config-store.js +194 -0
- package/dist/seo/config-store.js.map +1 -0
- package/dist/seo/confirm-broken-links.d.ts +48 -0
- package/dist/seo/confirm-broken-links.d.ts.map +1 -0
- package/dist/seo/confirm-broken-links.js +135 -0
- package/dist/seo/confirm-broken-links.js.map +1 -0
- package/dist/seo/content-markdown.d.ts +26 -0
- package/dist/seo/content-markdown.d.ts.map +1 -0
- package/dist/seo/content-markdown.js +235 -0
- package/dist/seo/content-markdown.js.map +1 -0
- package/dist/seo/document-content.d.ts +18 -0
- package/dist/seo/document-content.d.ts.map +1 -0
- package/dist/seo/document-content.js +80 -0
- package/dist/seo/document-content.js.map +1 -0
- package/dist/seo/document-path.d.ts +33 -0
- package/dist/seo/document-path.d.ts.map +1 -0
- package/dist/seo/document-path.js +44 -0
- package/dist/seo/document-path.js.map +1 -0
- package/dist/seo/feeds.d.ts +44 -0
- package/dist/seo/feeds.d.ts.map +1 -0
- package/dist/seo/feeds.js +95 -0
- package/dist/seo/feeds.js.map +1 -0
- package/dist/seo/fix-brief-export.d.ts +47 -0
- package/dist/seo/fix-brief-export.d.ts.map +1 -0
- package/dist/seo/fix-brief-export.js +224 -0
- package/dist/seo/fix-brief-export.js.map +1 -0
- package/dist/seo/index-status.d.ts +56 -0
- package/dist/seo/index-status.d.ts.map +1 -0
- package/dist/seo/index-status.js +193 -0
- package/dist/seo/index-status.js.map +1 -0
- package/dist/seo/index.d.ts +68 -0
- package/dist/seo/index.d.ts.map +1 -0
- package/dist/seo/index.js +36 -0
- package/dist/seo/index.js.map +1 -0
- package/dist/seo/issue-batch-briefs.d.ts +37 -0
- package/dist/seo/issue-batch-briefs.d.ts.map +1 -0
- package/dist/seo/issue-batch-briefs.js +85 -0
- package/dist/seo/issue-batch-briefs.js.map +1 -0
- package/dist/seo/issue-content-brief.d.ts +51 -0
- package/dist/seo/issue-content-brief.d.ts.map +1 -0
- package/dist/seo/issue-content-brief.js +267 -0
- package/dist/seo/issue-content-brief.js.map +1 -0
- package/dist/seo/issue-content-research.d.ts +51 -0
- package/dist/seo/issue-content-research.d.ts.map +1 -0
- package/dist/seo/issue-content-research.js +303 -0
- package/dist/seo/issue-content-research.js.map +1 -0
- package/dist/seo/issue-fix-ai.d.ts +39 -0
- package/dist/seo/issue-fix-ai.d.ts.map +1 -0
- package/dist/seo/issue-fix-ai.js +320 -0
- package/dist/seo/issue-fix-ai.js.map +1 -0
- package/dist/seo/issue-fix-redirect.d.ts +18 -0
- package/dist/seo/issue-fix-redirect.d.ts.map +1 -0
- package/dist/seo/issue-fix-redirect.js +153 -0
- package/dist/seo/issue-fix-redirect.js.map +1 -0
- package/dist/seo/issue-fix.d.ts +72 -0
- package/dist/seo/issue-fix.d.ts.map +1 -0
- package/dist/seo/issue-fix.js +266 -0
- package/dist/seo/issue-fix.js.map +1 -0
- package/dist/seo/link-graph.d.ts +54 -0
- package/dist/seo/link-graph.d.ts.map +1 -0
- package/dist/seo/link-graph.js +0 -0
- package/dist/seo/link-graph.js.map +1 -0
- package/dist/seo/link-probe.d.ts +49 -0
- package/dist/seo/link-probe.d.ts.map +1 -0
- package/dist/seo/link-probe.js +147 -0
- package/dist/seo/link-probe.js.map +1 -0
- package/dist/seo/llms-select.d.ts +34 -0
- package/dist/seo/llms-select.d.ts.map +1 -0
- package/dist/seo/llms-select.js +67 -0
- package/dist/seo/llms-select.js.map +1 -0
- package/dist/seo/llms-txt.d.ts +40 -0
- package/dist/seo/llms-txt.d.ts.map +1 -0
- package/dist/seo/llms-txt.js +177 -0
- package/dist/seo/llms-txt.js.map +1 -0
- package/dist/seo/meta-tags.d.ts +108 -0
- package/dist/seo/meta-tags.d.ts.map +1 -0
- package/dist/seo/meta-tags.js +353 -0
- package/dist/seo/meta-tags.js.map +1 -0
- package/dist/seo/migrate-meta.d.ts +23 -0
- package/dist/seo/migrate-meta.d.ts.map +1 -0
- package/dist/seo/migrate-meta.js +114 -0
- package/dist/seo/migrate-meta.js.map +1 -0
- package/dist/seo/migrate-schema.d.ts +28 -0
- package/dist/seo/migrate-schema.d.ts.map +1 -0
- package/dist/seo/migrate-schema.js +119 -0
- package/dist/seo/migrate-schema.js.map +1 -0
- package/dist/seo/page-meta.d.ts +179 -0
- package/dist/seo/page-meta.d.ts.map +1 -0
- package/dist/seo/page-meta.js +710 -0
- package/dist/seo/page-meta.js.map +1 -0
- package/dist/seo/public-site-url.d.ts +16 -0
- package/dist/seo/public-site-url.d.ts.map +1 -0
- package/dist/seo/public-site-url.js +39 -0
- package/dist/seo/public-site-url.js.map +1 -0
- package/dist/seo/resolve-path.d.ts +22 -0
- package/dist/seo/resolve-path.d.ts.map +1 -0
- package/dist/seo/resolve-path.js +53 -0
- package/dist/seo/resolve-path.js.map +1 -0
- package/dist/seo/rewrite-public-origin.d.ts +12 -0
- package/dist/seo/rewrite-public-origin.d.ts.map +1 -0
- package/dist/seo/rewrite-public-origin.js +17 -0
- package/dist/seo/rewrite-public-origin.js.map +1 -0
- package/dist/seo/robots.d.ts +45 -0
- package/dist/seo/robots.d.ts.map +1 -0
- package/dist/seo/robots.js +90 -0
- package/dist/seo/robots.js.map +1 -0
- package/dist/seo/schema-sync.d.ts +65 -0
- package/dist/seo/schema-sync.d.ts.map +1 -0
- package/dist/seo/schema-sync.js +163 -0
- package/dist/seo/schema-sync.js.map +1 -0
- package/dist/seo/score.d.ts +132 -0
- package/dist/seo/score.d.ts.map +1 -0
- package/dist/seo/score.js +216 -0
- package/dist/seo/score.js.map +1 -0
- package/dist/seo/serving-origin.d.ts +42 -0
- package/dist/seo/serving-origin.d.ts.map +1 -0
- package/dist/seo/serving-origin.js +83 -0
- package/dist/seo/serving-origin.js.map +1 -0
- package/dist/seo/site-identity.d.ts +60 -0
- package/dist/seo/site-identity.d.ts.map +1 -0
- package/dist/seo/site-identity.js +109 -0
- package/dist/seo/site-identity.js.map +1 -0
- package/dist/seo/sitemap-notify.d.ts +123 -0
- package/dist/seo/sitemap-notify.d.ts.map +1 -0
- package/dist/seo/sitemap-notify.js +270 -0
- package/dist/seo/sitemap-notify.js.map +1 -0
- package/dist/seo/sitemap-public.d.ts +43 -0
- package/dist/seo/sitemap-public.d.ts.map +1 -0
- package/dist/seo/sitemap-public.js +213 -0
- package/dist/seo/sitemap-public.js.map +1 -0
- package/dist/seo/title-templates.d.ts +80 -0
- package/dist/seo/title-templates.d.ts.map +1 -0
- package/dist/seo/title-templates.js +175 -0
- package/dist/seo/title-templates.js.map +1 -0
- package/dist/server-site.d.ts +55 -0
- package/dist/server-site.d.ts.map +1 -0
- package/dist/server-site.js +184 -0
- package/dist/server-site.js.map +1 -0
- package/dist/setup/index.d.ts +68 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +153 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/site.d.ts +178 -0
- package/dist/site.d.ts.map +1 -0
- package/dist/site.js +222 -0
- package/dist/site.js.map +1 -0
- package/dist/storage/auto-wire.d.ts +14 -0
- package/dist/storage/auto-wire.d.ts.map +1 -0
- package/dist/storage/auto-wire.js +60 -0
- package/dist/storage/auto-wire.js.map +1 -0
- package/dist/storage/index.d.ts +21 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +14 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/templates/index.d.ts +16 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +23 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/upgrade/changelog.d.ts +18 -0
- package/dist/upgrade/changelog.d.ts.map +1 -0
- package/dist/upgrade/changelog.js +60 -0
- package/dist/upgrade/changelog.js.map +1 -0
- package/dist/upgrade/index.d.ts +7 -0
- package/dist/upgrade/index.d.ts.map +1 -0
- package/dist/upgrade/index.js +4 -0
- package/dist/upgrade/index.js.map +1 -0
- package/dist/upgrade/upgrade-pr.d.ts +16 -0
- package/dist/upgrade/upgrade-pr.d.ts.map +1 -0
- package/dist/upgrade/upgrade-pr.js +128 -0
- package/dist/upgrade/upgrade-pr.js.map +1 -0
- package/dist/upgrade/version-check.d.ts +59 -0
- package/dist/upgrade/version-check.d.ts.map +1 -0
- package/dist/upgrade/version-check.js +142 -0
- package/dist/upgrade/version-check.js.map +1 -0
- package/dist/validation/publish.d.ts +53 -0
- package/dist/validation/publish.d.ts.map +1 -0
- package/dist/validation/publish.js +75 -0
- package/dist/validation/publish.js.map +1 -0
- package/dist/webhooks/index.d.ts +99 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +387 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/signing.d.ts +68 -0
- package/dist/webhooks/signing.d.ts.map +1 -0
- package/dist/webhooks/signing.js +98 -0
- package/dist/webhooks/signing.js.map +1 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +56 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflows/index.d.ts +30 -0
- package/dist/workflows/index.d.ts.map +1 -0
- package/dist/workflows/index.js +14 -0
- package/dist/workflows/index.js.map +1 -0
- package/package.json +250 -0
- package/prisma/migrations/0001_init/migration.sql +941 -0
- package/prisma/migrations/0002_media_usage_field_path/migration.sql +11 -0
- package/prisma/migrations/0003_ai_crawler_hits/migration.sql +21 -0
- package/prisma/migrations/0004_drop_search_vector/migration.sql +4 -0
- package/prisma/migrations/0005_script_tag_delivery_controls/migration.sql +8 -0
- package/prisma/migrations/0006_totp_last_step/migration.sql +4 -0
- package/prisma/migrations/0007_workflow_fk_drop_dead_enums/migration.sql +27 -0
- package/prisma/migrations/0008_form_delivery_attempts/migration.sql +29 -0
- package/prisma/migrations/0009_webhook_secret_rotation/migration.sql +6 -0
- package/prisma/migrations/0010_media_is_decorative/migration.sql +3 -0
- package/prisma/migrations/0011_media_content_hash/migration.sql +4 -0
- package/prisma/migrations/0012_rename_to_prenta/migration.sql +89 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +995 -0
- package/prisma/seed.ts +82 -0
- package/schema-fragments/cms-schema.prisma +526 -0
package/dist/actions.js
ADDED
|
@@ -0,0 +1,1324 @@
|
|
|
1
|
+
import { extractPlainText, hashContent } from './content/index.js';
|
|
2
|
+
import { applyFieldAccess } from './security/access.js';
|
|
3
|
+
import { sanitizeDocumentHtml, sanitizeLayoutTree } from './security/sanitize-document.js';
|
|
4
|
+
import { layoutTreeToSections } from './sections/bridge.js';
|
|
5
|
+
import { stripInternalDataKeys } from './security/internal-keys.js';
|
|
6
|
+
import { findInBatches } from './db/find-in-batches.js';
|
|
7
|
+
import { getPrentaConfig } from './config/runtime.js';
|
|
8
|
+
import { prepareContentStructuredData, syncSchemaTypeFields, applyStructuredDataFieldsToData, isPublicContentCollection, } from './seo/schema-sync.js';
|
|
9
|
+
import { validateRelations } from './fields/relations.js';
|
|
10
|
+
import { invalidationTagsForDocumentWrite, invalidationTagsForGlobalWrite } from './cache/http.js';
|
|
11
|
+
import { notifySitemapOnPublish } from './seo/sitemap-notify.js';
|
|
12
|
+
import { resolveDocumentUrl } from './seo/page-meta.js';
|
|
13
|
+
import { normalizeRedirectPath } from './redirects/graph.js';
|
|
14
|
+
import { planSlugChangeRedirects, isEmptyPlan } from './redirects/auto.js';
|
|
15
|
+
import { enforcePublishValidation } from './validation/publish.js';
|
|
16
|
+
import { getSeoOverrides, putSeoOverrides, resolveSeoModuleSettings, } from './seo/config-store.js';
|
|
17
|
+
import { createLogger } from './diagnostics/logger.js';
|
|
18
|
+
import { syncMediaUsageForDocument, clearMediaUsageForDocument } from './media/usage-sync.js';
|
|
19
|
+
import { denormalizeMediaFields } from './media/denormalize.js';
|
|
20
|
+
import { assertMediaFieldsHaveIdentity, mergeDocumentMediaFields, } from './media/merge-document-media.js';
|
|
21
|
+
const logger = createLogger('actions');
|
|
22
|
+
/**
|
|
23
|
+
* Widen a typed DB row to the `Record<string, unknown>` shape the public
|
|
24
|
+
* action results and plugin hooks use. Rows are plain objects; this is a
|
|
25
|
+
* type-level conversion only.
|
|
26
|
+
*/
|
|
27
|
+
function asDocRecord(doc) {
|
|
28
|
+
return doc;
|
|
29
|
+
}
|
|
30
|
+
function prisma(ctx) {
|
|
31
|
+
return ctx.db;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Fire-and-forget webhook dispatch. Errors are logged but never thrown — the
|
|
35
|
+
* caller is expected to have already committed the underlying database change.
|
|
36
|
+
*
|
|
37
|
+
* MUST be called AFTER the surrounding transaction commits — never inside a
|
|
38
|
+
* `db.$transaction` callback. A rolled-back transaction must not dispatch
|
|
39
|
+
* webhooks for a doc that no longer exists.
|
|
40
|
+
*/
|
|
41
|
+
async function fireWebhook(event, data) {
|
|
42
|
+
try {
|
|
43
|
+
const { dispatch } = await import('./webhooks/index.js');
|
|
44
|
+
await dispatch(event, data);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
48
|
+
logger.error('Webhook dispatch failed', {
|
|
49
|
+
event,
|
|
50
|
+
error: err instanceof Error ? err.message : String(err),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Run every registered plugin hook whose event matches `event` OR the
|
|
57
|
+
* collection-namespaced form `${event}:${collection}`. A throwing hook is
|
|
58
|
+
* logged and never aborts the caller.
|
|
59
|
+
*/
|
|
60
|
+
async function runMatchingHooks(event, collection, payload) {
|
|
61
|
+
const config = getPrentaConfig();
|
|
62
|
+
const hooks = (config?._pluginHooks ?? []);
|
|
63
|
+
const namespaced = collection ? `${event}:${collection}` : null;
|
|
64
|
+
for (const hook of hooks) {
|
|
65
|
+
if (!hook || (hook.event !== event && hook.event !== namespaced))
|
|
66
|
+
continue;
|
|
67
|
+
try {
|
|
68
|
+
await hook.handler(payload);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
logger.error('Plugin hook error', { event: hook.event, error: err });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function firePluginHooks(event, doc, ctx) {
|
|
76
|
+
try {
|
|
77
|
+
const collection = typeof doc.collection === 'string' ? doc.collection : null;
|
|
78
|
+
const payload = {
|
|
79
|
+
id: typeof doc.id === 'string' ? doc.id : '',
|
|
80
|
+
collection: collection ?? '',
|
|
81
|
+
slug: typeof doc.slug === 'string' ? doc.slug : null,
|
|
82
|
+
status: typeof doc.status === 'string' ? doc.status : null,
|
|
83
|
+
data: doc.data && typeof doc.data === 'object' ? doc.data : null,
|
|
84
|
+
};
|
|
85
|
+
await runMatchingHooks(event, collection, payload);
|
|
86
|
+
// A hook may have written AI-derived fields back onto the payload data
|
|
87
|
+
// (same object reference as the doc's data); persist those.
|
|
88
|
+
if (payload.data) {
|
|
89
|
+
const hasAiUpdates = payload.data._aiScore !== undefined || payload.data._embedding !== undefined;
|
|
90
|
+
if (hasAiUpdates && payload.id) {
|
|
91
|
+
const db = prisma(ctx);
|
|
92
|
+
await db.document
|
|
93
|
+
.update({ where: { id: payload.id }, data: { data: payload.data } })
|
|
94
|
+
.catch((err) => {
|
|
95
|
+
logger.error('Failed to persist plugin hook data', { error: err });
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
logger.error('Plugin hooks dispatch failed', { event, error: err });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Fire the `afterUpload` plugin hook after a successful media upload. Exposed
|
|
106
|
+
* for the media route (uploads don't go through the document write path). A
|
|
107
|
+
* failing hook is logged and never fails the upload.
|
|
108
|
+
*/
|
|
109
|
+
export async function firePluginUploadHook(payload) {
|
|
110
|
+
await runMatchingHooks('afterUpload', null, payload);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Dispatch `cache.onInvalidate` for the given tag set, swallowing any
|
|
114
|
+
* failure. Cache invalidation is best-effort — the underlying DB write
|
|
115
|
+
* has already committed, so a webhook revalidation failure must NOT
|
|
116
|
+
* surface to the caller (otherwise we'd appear to have failed a write
|
|
117
|
+
* that actually succeeded).
|
|
118
|
+
*/
|
|
119
|
+
async function fireCacheInvalidate(tags) {
|
|
120
|
+
const onInvalidate = getPrentaConfig()?.cache?.onInvalidate;
|
|
121
|
+
if (!onInvalidate || tags.length === 0)
|
|
122
|
+
return;
|
|
123
|
+
try {
|
|
124
|
+
await onInvalidate(tags);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
128
|
+
logger.error('cache.onInvalidate threw — cache may be stale until TTL', {
|
|
129
|
+
error: err instanceof Error ? err.message : String(err),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function flushEffects(effects, ctx) {
|
|
135
|
+
for (const effect of effects) {
|
|
136
|
+
if (effect.kind === 'webhook') {
|
|
137
|
+
await fireWebhook(effect.event, effect.payload);
|
|
138
|
+
}
|
|
139
|
+
else if (effect.kind === 'plugin-hook') {
|
|
140
|
+
await firePluginHooks(effect.event, effect.doc, ctx);
|
|
141
|
+
}
|
|
142
|
+
else if (effect.kind === 'cache-invalidate') {
|
|
143
|
+
await fireCacheInvalidate(effect.tags);
|
|
144
|
+
}
|
|
145
|
+
else if (effect.kind === 'auto-redirect') {
|
|
146
|
+
await fireAutoRedirect(ctx, effect.oldPath, effect.newPath);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
await fireSitemapNotify(ctx, effect.changed);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Persist the redirect mutations for a slug/path change. Reads the current
|
|
155
|
+
* rule set, plans loop-free 301s via {@link planSlugChangeRedirects}, and
|
|
156
|
+
* applies the plan in one transaction. Never throws — the content write has
|
|
157
|
+
* already committed, so a redirect failure must not surface to the caller.
|
|
158
|
+
*/
|
|
159
|
+
async function fireAutoRedirect(ctx, oldPath, newPath) {
|
|
160
|
+
try {
|
|
161
|
+
const db = prisma(ctx);
|
|
162
|
+
const rows = await findInBatches(({ take, cursor }) => db.redirect.findMany({
|
|
163
|
+
take,
|
|
164
|
+
...(cursor ? { skip: 1, cursor: { id: cursor } } : {}),
|
|
165
|
+
orderBy: { id: 'asc' },
|
|
166
|
+
select: { id: true, source: true, destination: true, enabled: true },
|
|
167
|
+
}));
|
|
168
|
+
const existing = rows.map((r) => ({
|
|
169
|
+
id: r.id,
|
|
170
|
+
from: r.source,
|
|
171
|
+
to: r.destination,
|
|
172
|
+
enabled: r.enabled,
|
|
173
|
+
}));
|
|
174
|
+
const plan = planSlugChangeRedirects({ oldPath, newPath, existing });
|
|
175
|
+
if (isEmptyPlan(plan))
|
|
176
|
+
return;
|
|
177
|
+
await db.$transaction(async (tx) => {
|
|
178
|
+
for (const id of plan.deleteIds) {
|
|
179
|
+
await tx.redirect.delete({ where: { id } });
|
|
180
|
+
}
|
|
181
|
+
for (const rp of plan.repoint) {
|
|
182
|
+
await tx.redirect.update({ where: { id: rp.id }, data: { destination: rp.destination } });
|
|
183
|
+
}
|
|
184
|
+
if (plan.upsert) {
|
|
185
|
+
await tx.redirect.upsert({
|
|
186
|
+
where: { source: plan.upsert.source },
|
|
187
|
+
create: {
|
|
188
|
+
source: plan.upsert.source,
|
|
189
|
+
destination: plan.upsert.destination,
|
|
190
|
+
statusCode: 301,
|
|
191
|
+
source_kind: 'slug-change',
|
|
192
|
+
createdById: ctx.userId || undefined,
|
|
193
|
+
},
|
|
194
|
+
update: {
|
|
195
|
+
destination: plan.upsert.destination,
|
|
196
|
+
statusCode: 301,
|
|
197
|
+
enabled: true,
|
|
198
|
+
source_kind: 'slug-change',
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
206
|
+
logger.error('auto-301 failed — old URL may 404 until a redirect is added manually', {
|
|
207
|
+
error: err instanceof Error ? err.message : String(err),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Sitemap cache tag — invalidated on any public-content change. */
|
|
213
|
+
const SITEMAP_CACHE_TAG = 'sitemap';
|
|
214
|
+
/**
|
|
215
|
+
* Roles permitted to publish content. AUTHOR (and lower) may save drafts but
|
|
216
|
+
* never transition a document into PUBLISHED — on either the create or the
|
|
217
|
+
* update path. Finer-grained control belongs in a dedicated publish endpoint
|
|
218
|
+
* with its own access check.
|
|
219
|
+
*/
|
|
220
|
+
const PUBLISH_ROLES = new Set(['ADMIN', 'EDITOR']);
|
|
221
|
+
/**
|
|
222
|
+
* The `DocumentStatus` enum values (must mirror prisma/schema.prisma). The
|
|
223
|
+
* document lifecycle column is overloaded with the data key `status`, but many
|
|
224
|
+
* collections legitimately use their OWN `status` field with non-lifecycle
|
|
225
|
+
* values — forms, for instance, store `status: 'draft' | 'active' | 'archived'`
|
|
226
|
+
* inside `data`. We must only hoist a `data.status` onto the document column
|
|
227
|
+
* when it is an actual lifecycle status; any other string is domain data and is
|
|
228
|
+
* left untouched in `data`. Without this guard, creating/updating such a
|
|
229
|
+
* document throws (invalid create status) or writes an invalid enum value.
|
|
230
|
+
*/
|
|
231
|
+
const DOCUMENT_STATUSES = new Set([
|
|
232
|
+
'DRAFT',
|
|
233
|
+
'PUBLISHED',
|
|
234
|
+
'ARCHIVED',
|
|
235
|
+
'SCHEDULED',
|
|
236
|
+
'SCHEDULED_UNPUBLISH',
|
|
237
|
+
]);
|
|
238
|
+
/**
|
|
239
|
+
* Read the requested document lifecycle status from a data payload, ignoring
|
|
240
|
+
* collection-defined `status` fields whose value is not a `DocumentStatus`.
|
|
241
|
+
*/
|
|
242
|
+
function readLifecycleStatus(data) {
|
|
243
|
+
const raw = typeof data.status === 'string' ? data.status : undefined;
|
|
244
|
+
return raw && DOCUMENT_STATUSES.has(raw) ? raw : undefined;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Best-effort sitemap regeneration + (production-gated) search-engine ping
|
|
248
|
+
* fired after public content changes. Reads the shared SEO module settings so
|
|
249
|
+
* the toggles in Settings > SEO / SEO Technical govern behaviour. Never throws
|
|
250
|
+
* — the content write has already committed.
|
|
251
|
+
*/
|
|
252
|
+
async function fireSitemapNotify(ctx, changed) {
|
|
253
|
+
try {
|
|
254
|
+
const overrides = await getSeoOverrides(ctx.db);
|
|
255
|
+
const settings = resolveSeoModuleSettings(overrides);
|
|
256
|
+
if (!settings.sitemapEnabled || !settings.autoRegenerateSitemapOnPublish)
|
|
257
|
+
return;
|
|
258
|
+
// Master switch: when the public site is opted out of indexing, refresh the
|
|
259
|
+
// (now-empty) sitemap cache but never ping search engines or submit to
|
|
260
|
+
// IndexNow — we must not solicit crawling of a site the operator deindexed.
|
|
261
|
+
if (settings.indexEntireSite === false) {
|
|
262
|
+
await fireCacheInvalidate([SITEMAP_CACHE_TAG]);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const cfg = getPrentaConfig();
|
|
266
|
+
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ??
|
|
267
|
+
cfg?.seo?.siteUrl ??
|
|
268
|
+
null;
|
|
269
|
+
// Resolve the specific changed URL for IndexNow (URL-based instant
|
|
270
|
+
// indexing). Uses the SAME resolver as the sitemap + canonical tag so the
|
|
271
|
+
// submitted URL is always the page's real, canonical address.
|
|
272
|
+
const indexNowKey = process.env.INDEXNOW_KEY?.trim() || null;
|
|
273
|
+
let changedUrls = [];
|
|
274
|
+
let indexNowKeyLocation = null;
|
|
275
|
+
if (siteUrl && indexNowKey && changed) {
|
|
276
|
+
const base = siteUrl.replace(/\/+$/, '');
|
|
277
|
+
indexNowKeyLocation = `${base}/api/cms/indexnow-key.txt`;
|
|
278
|
+
const collectionDef = cfg?.collections?.[changed.collection];
|
|
279
|
+
changedUrls = [
|
|
280
|
+
resolveDocumentUrl({
|
|
281
|
+
siteUrl: base,
|
|
282
|
+
urlPrefix: collectionDef?.urlPrefix,
|
|
283
|
+
slug: changed.slug,
|
|
284
|
+
data: changed.path ? { path: changed.path } : {},
|
|
285
|
+
}),
|
|
286
|
+
];
|
|
287
|
+
}
|
|
288
|
+
const result = await notifySitemapOnPublish({
|
|
289
|
+
settings,
|
|
290
|
+
siteUrl,
|
|
291
|
+
lastGeneratedAt: settings.sitemapLastGeneratedAt,
|
|
292
|
+
changedUrls,
|
|
293
|
+
indexNowKey,
|
|
294
|
+
indexNowKeyLocation,
|
|
295
|
+
});
|
|
296
|
+
// Cheap + un-debounced: refresh the sitemap cache on every change so the
|
|
297
|
+
// next request rebuilds with the latest public content.
|
|
298
|
+
if (result.invalidateCache) {
|
|
299
|
+
await fireCacheInvalidate([SITEMAP_CACHE_TAG]);
|
|
300
|
+
}
|
|
301
|
+
// Expensive + debounced: only persist the regeneration timestamp once per
|
|
302
|
+
// window so bursts of publishes don't hammer the single `__seo_config__`
|
|
303
|
+
// row. The Settings/Technical UI reads this for "last generated".
|
|
304
|
+
if (result.regenerated) {
|
|
305
|
+
const next = {
|
|
306
|
+
...(overrides ?? {}),
|
|
307
|
+
module: {
|
|
308
|
+
...(overrides?.module ?? {}),
|
|
309
|
+
sitemapLastGeneratedAt: new Date().toISOString(),
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
await putSeoOverrides(ctx.db, next, ctx.userId);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
317
|
+
logger.error('sitemap notify failed — sitemap may be stale until next write', {
|
|
318
|
+
error: err instanceof Error ? err.message : String(err),
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function getCollectionFields(collection) {
|
|
324
|
+
const config = getPrentaConfig()?.collections?.[collection];
|
|
325
|
+
return config?.fields ?? null;
|
|
326
|
+
}
|
|
327
|
+
async function checkCollectionAccess(collection, operation, ctx, doc) {
|
|
328
|
+
const collectionConfig = getPrentaConfig()?.collections?.[collection];
|
|
329
|
+
const accessFn = collectionConfig?.access?.[operation];
|
|
330
|
+
if (!accessFn)
|
|
331
|
+
return;
|
|
332
|
+
const user = ctx.userId ? { id: ctx.userId, role: ctx.role } : null;
|
|
333
|
+
const allowed = await accessFn({ user, doc });
|
|
334
|
+
if (!allowed) {
|
|
335
|
+
throw new Error(`Access denied: cannot ${operation} in collection "${collection}"`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Public wrapper around the internal per-collection access gate. Lets API
|
|
340
|
+
* handlers that don't go through the standard CRUD actions (e.g. the read-only
|
|
341
|
+
* SEO analysis endpoints) still enforce a collection's `access[operation]`
|
|
342
|
+
* rule. Throws `Access denied: …` when the rule rejects the user.
|
|
343
|
+
*/
|
|
344
|
+
export async function assertCollectionAccess(collection, operation, ctx, doc) {
|
|
345
|
+
await checkCollectionAccess(collection, operation, ctx, doc);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Sanitize every author-HTML sink in a document payload before storage:
|
|
349
|
+
* top-level + nested rich-text fields and the canonical `sections[]` rich-text
|
|
350
|
+
* slots (see {@link sanitizeDocumentHtml}). The page-builder `_layout` tree is
|
|
351
|
+
* sanitized separately at the call site because it is split into an envelope
|
|
352
|
+
* before this runs.
|
|
353
|
+
*/
|
|
354
|
+
function sanitizeDocumentData(data, collection) {
|
|
355
|
+
return sanitizeDocumentHtml(data, collection);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Canonicalize legacy SEO aliases so DocumentEdit (`focusKeyphrase`) and the
|
|
359
|
+
* SEO API (`focusKeyword`) share one stored key.
|
|
360
|
+
*/
|
|
361
|
+
function normalizeSeoFieldAliases(data) {
|
|
362
|
+
const next = { ...data };
|
|
363
|
+
const legacy = next.focusKeyphrase;
|
|
364
|
+
const canonical = next.focusKeyword;
|
|
365
|
+
if (typeof legacy === 'string' && legacy.trim()) {
|
|
366
|
+
if (typeof canonical !== 'string' || !canonical.trim()) {
|
|
367
|
+
next.focusKeyword = legacy.trim();
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if ('focusKeyphrase' in next)
|
|
371
|
+
delete next.focusKeyphrase;
|
|
372
|
+
return next;
|
|
373
|
+
}
|
|
374
|
+
async function computeTextFields(data) {
|
|
375
|
+
const serialized = JSON.stringify(data);
|
|
376
|
+
const plainText = extractPlainText(serialized);
|
|
377
|
+
const contentHash = await hashContent(serialized);
|
|
378
|
+
return { plainText, contentHash };
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Build a {@link RelationLookup} backed by the active Prisma client. The
|
|
382
|
+
* lookup batches by collection and filters out soft-deleted docs so a
|
|
383
|
+
* relation that points at a tombstoned record is treated as broken.
|
|
384
|
+
*
|
|
385
|
+
* Populated relation data is run through the same protections as a direct read
|
|
386
|
+
* (`stripInternalKeys` + field-level `access.read`) so `?populate` cannot be
|
|
387
|
+
* used to bypass field access or leak internal keys, and — with `publicOnly` —
|
|
388
|
+
* cannot disclose unpublished referenced documents to anonymous callers.
|
|
389
|
+
*
|
|
390
|
+
* Exported so the API layer (resolve, list, get) can reuse it without
|
|
391
|
+
* pulling in the entire actions module.
|
|
392
|
+
*/
|
|
393
|
+
export function buildRelationLookup(db, options = {}) {
|
|
394
|
+
const { publicOnly = false, viewer } = options;
|
|
395
|
+
return {
|
|
396
|
+
fetchByIds: async (collections, ids) => {
|
|
397
|
+
const result = new Map();
|
|
398
|
+
if (ids.length === 0 || collections.length === 0)
|
|
399
|
+
return result;
|
|
400
|
+
const rows = await db.document.findMany({
|
|
401
|
+
where: {
|
|
402
|
+
id: { in: ids },
|
|
403
|
+
collection: { in: collections },
|
|
404
|
+
deletedAt: null,
|
|
405
|
+
...(publicOnly ? { status: 'PUBLISHED' } : {}),
|
|
406
|
+
},
|
|
407
|
+
select: {
|
|
408
|
+
id: true,
|
|
409
|
+
collection: true,
|
|
410
|
+
title: true,
|
|
411
|
+
slug: true,
|
|
412
|
+
status: true,
|
|
413
|
+
data: true,
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
for (const row of rows) {
|
|
417
|
+
let data = row.data && typeof row.data === 'object' ? row.data : null;
|
|
418
|
+
if (data) {
|
|
419
|
+
// Mirror the protections getDocument applies to a document's own data:
|
|
420
|
+
// never expose internal `_`-keys, and apply the target collection's
|
|
421
|
+
// field-level read access for the requesting viewer.
|
|
422
|
+
data = stripInternalKeys(data);
|
|
423
|
+
const fields = getCollectionFields(row.collection);
|
|
424
|
+
if (fields) {
|
|
425
|
+
// null viewer = anonymous → field `access.read` rules strip
|
|
426
|
+
// restricted fields (mirrors the convention used elsewhere).
|
|
427
|
+
const accessUser = viewer?.id != null && viewer?.role != null
|
|
428
|
+
? { id: viewer.id, role: viewer.role }
|
|
429
|
+
: null;
|
|
430
|
+
data = await applyFieldAccess('read', fields, data, accessUser);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
result.set(row.id, {
|
|
434
|
+
id: row.id,
|
|
435
|
+
collection: row.collection,
|
|
436
|
+
title: row.title,
|
|
437
|
+
slug: row.slug,
|
|
438
|
+
status: row.status,
|
|
439
|
+
data,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
return result;
|
|
443
|
+
},
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* The public URL path tag(s) for a document write (#544). Returns the doc's
|
|
448
|
+
* current public path and, when `previous` is given and the path changed, its
|
|
449
|
+
* OLD path (so a slug rename refreshes the vacated URL). Only publicly-routed
|
|
450
|
+
* collections (page/post, or any with a URL prefix) produce path tags — other
|
|
451
|
+
* docs have no public page. Uses `resolveDocumentUrl` so the tag matches the
|
|
452
|
+
* read-side `prenta:path:<path>` exactly (locked by the path-tag-parity test).
|
|
453
|
+
*/
|
|
454
|
+
function publicPathTagsFor(collection, doc, previous) {
|
|
455
|
+
const def = getPrentaConfig()?.collections?.[collection];
|
|
456
|
+
const hasPrefix = !!(def?.urlPrefix ?? '').replace(/^\/+|\/+$/g, '');
|
|
457
|
+
if (def?.type !== 'page' && def?.type !== 'post' && !hasPrefix)
|
|
458
|
+
return [];
|
|
459
|
+
const paths = new Set();
|
|
460
|
+
paths.add(resolveDocumentUrl({
|
|
461
|
+
siteUrl: '',
|
|
462
|
+
urlPrefix: def?.urlPrefix,
|
|
463
|
+
slug: doc.slug ?? null,
|
|
464
|
+
data: doc.data ?? null,
|
|
465
|
+
}));
|
|
466
|
+
if (previous) {
|
|
467
|
+
paths.add(resolveDocumentUrl({
|
|
468
|
+
siteUrl: '',
|
|
469
|
+
urlPrefix: def?.urlPrefix,
|
|
470
|
+
slug: previous.slug ?? null,
|
|
471
|
+
data: previous.data ?? null,
|
|
472
|
+
}));
|
|
473
|
+
}
|
|
474
|
+
return [...paths];
|
|
475
|
+
}
|
|
476
|
+
/** Create a new document in a collection. */
|
|
477
|
+
export async function createDocument(collection, data, ctx) {
|
|
478
|
+
await checkCollectionAccess(collection, 'create', ctx);
|
|
479
|
+
const db = prisma(ctx);
|
|
480
|
+
const user = { id: ctx.userId, role: ctx.role };
|
|
481
|
+
// Strip top-level page builder envelope (`layout` / `pageSettings`) and
|
|
482
|
+
// merge it back into `data` as `_layout` / `_pageSettings` so the storage
|
|
483
|
+
// shape is single-sourced. Both wire shapes are accepted for backwards
|
|
484
|
+
// compatibility — top-level wins when both are present.
|
|
485
|
+
const { envelope, rest } = extractPageBuilderEnvelope(data);
|
|
486
|
+
const fields = getCollectionFields(collection);
|
|
487
|
+
const accessFiltered = fields ? await applyFieldAccess('write', fields, rest, user) : rest;
|
|
488
|
+
const sanitizedData = sanitizeDocumentData(accessFiltered, collection);
|
|
489
|
+
let filteredData = normalizeSeoFieldAliases(lowerPageBuilderEnvelope(sanitizedData, envelope));
|
|
490
|
+
// Honor a requested status on create so an agent/SDK can create-and-publish
|
|
491
|
+
// in one call. The lifecycle status is a top-level document column, NEVER a
|
|
492
|
+
// `data` key — read it first, then strip a lifecycle-valued `status` from
|
|
493
|
+
// `data` so it can't pollute the stored JSON. (Migration/import scripts that
|
|
494
|
+
// wrote `data.status` confused the admin UI.) Domain `status` fields whose
|
|
495
|
+
// value is not a lifecycle status — e.g. forms' draft/active/archived — are
|
|
496
|
+
// left untouched.
|
|
497
|
+
const requestedStatus = readLifecycleStatus(filteredData);
|
|
498
|
+
if (requestedStatus !== undefined) {
|
|
499
|
+
delete filteredData.status;
|
|
500
|
+
}
|
|
501
|
+
// Headless/MCP writes often store media as bare IDs. Expand to
|
|
502
|
+
// `{ id, url, alt, width, height }` so raw-data readers (blog listings,
|
|
503
|
+
// JSON-LD) match admin picker persistence.
|
|
504
|
+
if (fields) {
|
|
505
|
+
filteredData = await denormalizeMediaFields(db, fields, filteredData);
|
|
506
|
+
}
|
|
507
|
+
// Verify any relation fields point at real, non-deleted documents BEFORE
|
|
508
|
+
// we open the transaction. Doing this inside the txn would block the
|
|
509
|
+
// write while we run extra SELECTs, so we accept a tiny race here (a
|
|
510
|
+
// referenced doc could be deleted between validation and create) in
|
|
511
|
+
// exchange for a much shorter critical section.
|
|
512
|
+
if (fields) {
|
|
513
|
+
await validateRelations(fields, filteredData, buildRelationLookup(db));
|
|
514
|
+
}
|
|
515
|
+
const { plainText, contentHash } = await computeTextFields(filteredData);
|
|
516
|
+
// Only DRAFT and PUBLISHED are valid at create time — scheduling/archiving
|
|
517
|
+
// requires the dedicated fields the update path manages (scheduledAt, etc.),
|
|
518
|
+
// so route those through update.
|
|
519
|
+
if (requestedStatus && requestedStatus !== 'DRAFT' && requestedStatus !== 'PUBLISHED') {
|
|
520
|
+
throw new Error(`Cannot create a document with status "${requestedStatus}". Create it as DRAFT or PUBLISHED, then change status via update.`);
|
|
521
|
+
}
|
|
522
|
+
const publishingNow = requestedStatus === 'PUBLISHED';
|
|
523
|
+
if (publishingNow && !PUBLISH_ROLES.has(ctx.role)) {
|
|
524
|
+
throw new Error('Insufficient permissions to publish — only EDITOR or ADMIN may publish.');
|
|
525
|
+
}
|
|
526
|
+
const status = publishingNow ? 'PUBLISHED' : 'DRAFT';
|
|
527
|
+
// Publish gate: enforce hard content invariants server-side so the SDK/MCP/
|
|
528
|
+
// API can't publish a broken page past the admin's checks. Only fires for
|
|
529
|
+
// publicly-routed content (page/post collections) on a publish. Throws in
|
|
530
|
+
// `block` mode (the default).
|
|
531
|
+
if (publishingNow) {
|
|
532
|
+
enforcePublishValidation({
|
|
533
|
+
collectionDef: getPrentaConfig()?.collections?.[collection],
|
|
534
|
+
data: filteredData,
|
|
535
|
+
config: getPrentaConfig(),
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
const collectionDef = getPrentaConfig()?.collections?.[collection];
|
|
539
|
+
const { data: dataForStore } = prepareContentStructuredData(collection, filteredData, {
|
|
540
|
+
collectionDef,
|
|
541
|
+
});
|
|
542
|
+
const pendingEffects = [];
|
|
543
|
+
const doc = await db.$transaction(async (tx) => {
|
|
544
|
+
const created = await tx.document.create({
|
|
545
|
+
data: {
|
|
546
|
+
collection,
|
|
547
|
+
title: typeof dataForStore.title === 'string' ? dataForStore.title : null,
|
|
548
|
+
slug: typeof dataForStore.slug === 'string' ? dataForStore.slug : null,
|
|
549
|
+
data: dataForStore,
|
|
550
|
+
status,
|
|
551
|
+
locale: ctx.locale ?? null,
|
|
552
|
+
createdById: ctx.userId,
|
|
553
|
+
updatedById: ctx.userId,
|
|
554
|
+
publishedAt: publishingNow ? new Date() : null,
|
|
555
|
+
plainText,
|
|
556
|
+
contentHash,
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
if (publishingNow && collectionDef) {
|
|
560
|
+
const publishedPrep = prepareContentStructuredData(collection, dataForStore, {
|
|
561
|
+
collectionDef,
|
|
562
|
+
config: getPrentaConfig(),
|
|
563
|
+
publishing: true,
|
|
564
|
+
doc: {
|
|
565
|
+
id: created.id,
|
|
566
|
+
slug: created.slug,
|
|
567
|
+
publishedAt: created.publishedAt,
|
|
568
|
+
updatedAt: created.updatedAt,
|
|
569
|
+
},
|
|
570
|
+
});
|
|
571
|
+
if (publishedPrep.structuredData) {
|
|
572
|
+
await tx.document.update({
|
|
573
|
+
where: { id: created.id },
|
|
574
|
+
data: { structuredData: publishedPrep.structuredData },
|
|
575
|
+
});
|
|
576
|
+
created.structuredData = publishedPrep.structuredData;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
await tx.version.create({
|
|
580
|
+
data: {
|
|
581
|
+
documentId: created.id,
|
|
582
|
+
data: dataForStore,
|
|
583
|
+
changedById: ctx.userId,
|
|
584
|
+
changeType: 'CREATE',
|
|
585
|
+
},
|
|
586
|
+
});
|
|
587
|
+
await syncMediaUsageForDocument(tx, created.id, dataForStore);
|
|
588
|
+
pendingEffects.push({
|
|
589
|
+
kind: 'webhook',
|
|
590
|
+
event: 'document.created',
|
|
591
|
+
payload: {
|
|
592
|
+
id: created.id,
|
|
593
|
+
collection,
|
|
594
|
+
title: created.title,
|
|
595
|
+
slug: created.slug,
|
|
596
|
+
status: created.status,
|
|
597
|
+
},
|
|
598
|
+
});
|
|
599
|
+
// A document created directly as PUBLISHED also emits a publish event so
|
|
600
|
+
// downstream subscribers (and the sitemap) react the same as a draft→publish
|
|
601
|
+
// transition through update.
|
|
602
|
+
if (publishingNow) {
|
|
603
|
+
pendingEffects.push({
|
|
604
|
+
kind: 'webhook',
|
|
605
|
+
event: 'document.published',
|
|
606
|
+
payload: {
|
|
607
|
+
id: created.id,
|
|
608
|
+
collection,
|
|
609
|
+
title: created.title,
|
|
610
|
+
slug: created.slug,
|
|
611
|
+
status: created.status,
|
|
612
|
+
},
|
|
613
|
+
});
|
|
614
|
+
pendingEffects.push({
|
|
615
|
+
kind: 'sitemap-notify',
|
|
616
|
+
reason: 'publish',
|
|
617
|
+
changed: {
|
|
618
|
+
collection,
|
|
619
|
+
slug: created.slug,
|
|
620
|
+
path: created.data?.path ?? null,
|
|
621
|
+
},
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
pendingEffects.push({ kind: 'plugin-hook', event: 'afterCreate', doc: asDocRecord(created) });
|
|
625
|
+
pendingEffects.push({
|
|
626
|
+
kind: 'cache-invalidate',
|
|
627
|
+
tags: invalidationTagsForDocumentWrite(collection, created.id, publicPathTagsFor(collection, created)),
|
|
628
|
+
});
|
|
629
|
+
return created;
|
|
630
|
+
});
|
|
631
|
+
await flushEffects(pendingEffects, ctx);
|
|
632
|
+
return doc;
|
|
633
|
+
}
|
|
634
|
+
/** Update an existing document. Merges incoming data with existing to prevent field loss. */
|
|
635
|
+
export async function updateDocument(collection, id, data, ctx) {
|
|
636
|
+
await checkCollectionAccess(collection, 'update', ctx);
|
|
637
|
+
const db = prisma(ctx);
|
|
638
|
+
const user = { id: ctx.userId, role: ctx.role };
|
|
639
|
+
const existing = await db.document.findFirst({
|
|
640
|
+
where: { id, collection, deletedAt: null },
|
|
641
|
+
});
|
|
642
|
+
if (!existing) {
|
|
643
|
+
throw new Error(`Document "${id}" not found in collection "${collection}"`);
|
|
644
|
+
}
|
|
645
|
+
const existingData = existing.data && typeof existing.data === 'object'
|
|
646
|
+
? existing.data
|
|
647
|
+
: {};
|
|
648
|
+
// Strip top-level page builder envelope before merge so we don't end up
|
|
649
|
+
// with a duplicate `layout` user field shadowing `_layout`. See
|
|
650
|
+
// {@link extractPageBuilderEnvelope} for the wire-vs-storage explanation.
|
|
651
|
+
const { envelope, rest } = extractPageBuilderEnvelope(data);
|
|
652
|
+
// Field-access filter the *incoming patch* only, then merge onto existing
|
|
653
|
+
// data. Filtering the merged blob (old behavior) stripped undeclared SEO
|
|
654
|
+
// convention keys (`focusKeyword`, `schemaType`, `canonical`, …) that the
|
|
655
|
+
// SEO save path intentionally persists — so a post-editor save that omitted
|
|
656
|
+
// those keys wiped them (#671).
|
|
657
|
+
const fields = getCollectionFields(collection);
|
|
658
|
+
const filteredRest = fields ? await applyFieldAccess('write', fields, rest, user) : rest;
|
|
659
|
+
// Deep-merge media-typed objects so a partial `{ featuredImage: { alt } }`
|
|
660
|
+
// patch does not wipe `url` / `id` (#716). Other top-level keys stay shallow.
|
|
661
|
+
const mergedData = fields
|
|
662
|
+
? mergeDocumentMediaFields(fields, existingData, filteredRest)
|
|
663
|
+
: { ...existingData, ...filteredRest };
|
|
664
|
+
const sanitizedData = sanitizeDocumentData(mergedData, collection);
|
|
665
|
+
let filteredData = normalizeSeoFieldAliases(lowerPageBuilderEnvelope(sanitizedData, envelope));
|
|
666
|
+
// The lifecycle status is a top-level document column, NEVER a `data` key.
|
|
667
|
+
// Read it first, then strip a lifecycle-valued `status` from `data` so it
|
|
668
|
+
// can't pollute the stored JSON — and so an edit of a doc whose `data` was
|
|
669
|
+
// polluted by a migration/import script cleans it up. Domain `status` fields
|
|
670
|
+
// whose value is not a lifecycle status (e.g. forms' draft/active/archived)
|
|
671
|
+
// are left untouched.
|
|
672
|
+
const requestedStatus = readLifecycleStatus(filteredData);
|
|
673
|
+
if (requestedStatus !== undefined) {
|
|
674
|
+
delete filteredData.status;
|
|
675
|
+
}
|
|
676
|
+
// Reject media objects that still lack both id and url after merge — almost
|
|
677
|
+
// always a partial-update accident rather than an intentional write (#716).
|
|
678
|
+
if (fields) {
|
|
679
|
+
assertMediaFieldsHaveIdentity(fields, filteredData);
|
|
680
|
+
}
|
|
681
|
+
// Expand bare media IDs to denormalized `{ id, url, … }` (see createDocument).
|
|
682
|
+
if (fields) {
|
|
683
|
+
filteredData = await denormalizeMediaFields(db, fields, filteredData);
|
|
684
|
+
}
|
|
685
|
+
// Only re-validate relations whose value actually changed — most updates
|
|
686
|
+
// are partial (status flip, slug rename) and re-running every lookup on
|
|
687
|
+
// every save is wasteful. We compare the incoming `rest` against the
|
|
688
|
+
// existing data and only validate fields the caller touched.
|
|
689
|
+
if (fields) {
|
|
690
|
+
const touchedFields = {};
|
|
691
|
+
const touchedData = {};
|
|
692
|
+
for (const [key, def] of Object.entries(fields)) {
|
|
693
|
+
if (def.type !== 'relationship' && def.type !== 'array')
|
|
694
|
+
continue;
|
|
695
|
+
if (Object.prototype.hasOwnProperty.call(rest, key)) {
|
|
696
|
+
touchedFields[key] = def;
|
|
697
|
+
touchedData[key] = filteredData[key];
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
if (Object.keys(touchedFields).length > 0) {
|
|
701
|
+
await validateRelations(touchedFields, touchedData, buildRelationLookup(db));
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
const { plainText, contentHash } = await computeTextFields(filteredData);
|
|
705
|
+
// Only EDITOR+ can change status to PUBLISHED. Authors can save drafts but
|
|
706
|
+
// can never publish through the document update path. (Use a dedicated
|
|
707
|
+
// publish endpoint with its own access check for finer-grained control.)
|
|
708
|
+
let status = requestedStatus;
|
|
709
|
+
if (status === 'PUBLISHED' && existing.status !== 'PUBLISHED' && !PUBLISH_ROLES.has(ctx.role)) {
|
|
710
|
+
throw new Error('Insufficient permissions to publish — only EDITOR or ADMIN may publish.');
|
|
711
|
+
}
|
|
712
|
+
// Preserve the original publishedAt when the status was already PUBLISHED;
|
|
713
|
+
// only stamp publishedAt on the transition into PUBLISHED.
|
|
714
|
+
const isPublishingNow = status === 'PUBLISHED' && existing.status !== 'PUBLISHED';
|
|
715
|
+
// Publish gate: a document that will be published (newly or by staying
|
|
716
|
+
// published through this edit) must satisfy the hard content invariants.
|
|
717
|
+
// Enforced server-side so partial API edits can't leave a live page broken.
|
|
718
|
+
const willBePublished = (status ?? existing.status) === 'PUBLISHED';
|
|
719
|
+
if (willBePublished) {
|
|
720
|
+
enforcePublishValidation({
|
|
721
|
+
collectionDef: getPrentaConfig()?.collections?.[collection],
|
|
722
|
+
data: filteredData,
|
|
723
|
+
config: getPrentaConfig(),
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
const collectionDef = getPrentaConfig()?.collections?.[collection];
|
|
727
|
+
const existingStructured = existing.structuredData && typeof existing.structuredData === 'object'
|
|
728
|
+
? existing.structuredData
|
|
729
|
+
: null;
|
|
730
|
+
const seoPrep = prepareContentStructuredData(collection, filteredData, {
|
|
731
|
+
collectionDef,
|
|
732
|
+
existingStructuredData: existingStructured,
|
|
733
|
+
});
|
|
734
|
+
const dataForStore = seoPrep.data;
|
|
735
|
+
// Capture side-effects to fire AFTER the transaction commits so we never
|
|
736
|
+
// dispatch a webhook for a rolled-back write. Reuses the module-level
|
|
737
|
+
// `PendingEffect` type so newer effect kinds (e.g. cache-invalidate)
|
|
738
|
+
// are accepted here automatically.
|
|
739
|
+
const pendingEffects = [];
|
|
740
|
+
const updated = await db.$transaction(async (tx) => {
|
|
741
|
+
let structuredDataColumn;
|
|
742
|
+
if (willBePublished && collectionDef) {
|
|
743
|
+
const publishedPrep = prepareContentStructuredData(collection, dataForStore, {
|
|
744
|
+
collectionDef,
|
|
745
|
+
config: getPrentaConfig(),
|
|
746
|
+
existingStructuredData: existingStructured,
|
|
747
|
+
publishing: true,
|
|
748
|
+
doc: {
|
|
749
|
+
id,
|
|
750
|
+
slug: typeof dataForStore.slug === 'string' ? dataForStore.slug : existing.slug,
|
|
751
|
+
publishedAt: isPublishingNow ? new Date() : existing.publishedAt,
|
|
752
|
+
updatedAt: new Date(),
|
|
753
|
+
},
|
|
754
|
+
});
|
|
755
|
+
structuredDataColumn = publishedPrep.structuredData ?? undefined;
|
|
756
|
+
}
|
|
757
|
+
const result = await tx.document.update({
|
|
758
|
+
where: { id },
|
|
759
|
+
data: {
|
|
760
|
+
title: typeof dataForStore.title === 'string' ? dataForStore.title : undefined,
|
|
761
|
+
slug: typeof dataForStore.slug === 'string' ? dataForStore.slug : undefined,
|
|
762
|
+
data: dataForStore,
|
|
763
|
+
updatedById: ctx.userId,
|
|
764
|
+
plainText,
|
|
765
|
+
contentHash,
|
|
766
|
+
...(status ? { status } : {}),
|
|
767
|
+
...(isPublishingNow ? { publishedAt: new Date() } : {}),
|
|
768
|
+
...(structuredDataColumn ? { structuredData: structuredDataColumn } : {}),
|
|
769
|
+
},
|
|
770
|
+
});
|
|
771
|
+
await tx.version.create({
|
|
772
|
+
data: {
|
|
773
|
+
documentId: id,
|
|
774
|
+
data: dataForStore,
|
|
775
|
+
changedById: ctx.userId,
|
|
776
|
+
changeType: 'UPDATE',
|
|
777
|
+
},
|
|
778
|
+
});
|
|
779
|
+
await syncMediaUsageForDocument(tx, id, dataForStore);
|
|
780
|
+
// Publish lifecycle is a first-class webhook contract: entering PUBLISHED
|
|
781
|
+
// emits `document.published`, leaving it emits `document.unpublished`
|
|
782
|
+
// (purge receivers must evict the now-offline page from edge caches),
|
|
783
|
+
// everything else is `document.updated`.
|
|
784
|
+
const wasPublished = existing.status === 'PUBLISHED';
|
|
785
|
+
const isPublished = (status ?? existing.status) === 'PUBLISHED';
|
|
786
|
+
const webhookEvent = isPublishingNow
|
|
787
|
+
? 'document.published'
|
|
788
|
+
: wasPublished && !isPublished
|
|
789
|
+
? 'document.unpublished'
|
|
790
|
+
: 'document.updated';
|
|
791
|
+
pendingEffects.push({
|
|
792
|
+
kind: 'webhook',
|
|
793
|
+
event: webhookEvent,
|
|
794
|
+
payload: {
|
|
795
|
+
id,
|
|
796
|
+
collection,
|
|
797
|
+
title: result.title,
|
|
798
|
+
slug: result.slug,
|
|
799
|
+
status: status ?? existing.status,
|
|
800
|
+
},
|
|
801
|
+
});
|
|
802
|
+
pendingEffects.push({ kind: 'plugin-hook', event: 'afterUpdate', doc: asDocRecord(result) });
|
|
803
|
+
pendingEffects.push({
|
|
804
|
+
kind: 'cache-invalidate',
|
|
805
|
+
// Pass `existing` so a slug rename also busts the OLD public path (#544).
|
|
806
|
+
tags: invalidationTagsForDocumentWrite(collection, id, publicPathTagsFor(collection, result, existing)),
|
|
807
|
+
});
|
|
808
|
+
// Sitemap upkeep: a change is sitemap-relevant when the document enters,
|
|
809
|
+
// stays in, or leaves the PUBLISHED state. Pure DRAFT→DRAFT edits never
|
|
810
|
+
// touch the public sitemap, so don't enqueue (avoids needless pings).
|
|
811
|
+
const changedRef = {
|
|
812
|
+
collection,
|
|
813
|
+
slug: result.slug,
|
|
814
|
+
path: result.data?.path ?? null,
|
|
815
|
+
};
|
|
816
|
+
if (isPublishingNow) {
|
|
817
|
+
pendingEffects.push({ kind: 'sitemap-notify', reason: 'publish', changed: changedRef });
|
|
818
|
+
}
|
|
819
|
+
else if (wasPublished && !isPublished) {
|
|
820
|
+
pendingEffects.push({ kind: 'sitemap-notify', reason: 'unpublish', changed: changedRef });
|
|
821
|
+
}
|
|
822
|
+
else if (wasPublished && isPublished) {
|
|
823
|
+
pendingEffects.push({ kind: 'sitemap-notify', reason: 'update', changed: changedRef });
|
|
824
|
+
}
|
|
825
|
+
// Auto-301: when a document that was AND stays published changes its
|
|
826
|
+
// resolved URL, the old URL is already indexed/linked — keep it alive.
|
|
827
|
+
// Only on published→published; a draft's slug was never publicly reachable,
|
|
828
|
+
// and an unpublish leaves nothing to redirect to.
|
|
829
|
+
if (wasPublished && isPublished) {
|
|
830
|
+
const urlPrefix = getPrentaConfig()?.collections?.[collection]?.urlPrefix;
|
|
831
|
+
const oldPath = resolveDocumentUrl({
|
|
832
|
+
siteUrl: '',
|
|
833
|
+
urlPrefix,
|
|
834
|
+
slug: existing.slug,
|
|
835
|
+
data: existingData,
|
|
836
|
+
});
|
|
837
|
+
const newPath = resolveDocumentUrl({
|
|
838
|
+
siteUrl: '',
|
|
839
|
+
urlPrefix,
|
|
840
|
+
slug: result.slug,
|
|
841
|
+
data: result.data,
|
|
842
|
+
});
|
|
843
|
+
if (normalizeRedirectPath(oldPath) !== normalizeRedirectPath(newPath)) {
|
|
844
|
+
pendingEffects.push({ kind: 'auto-redirect', oldPath, newPath });
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return result;
|
|
848
|
+
});
|
|
849
|
+
await flushEffects(pendingEffects, ctx);
|
|
850
|
+
return updated;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Update SEO metadata on a document through the data layer.
|
|
854
|
+
*
|
|
855
|
+
* SEO fields (`canonical`, `og*`, `focusKeyword`, `structuredData`, `noindex`,
|
|
856
|
+
* …) are a cross-cutting convention that collections are not required to
|
|
857
|
+
* declare as fields. Unlike {@link updateDocument} this therefore does NOT run
|
|
858
|
+
* field-access stripping — that strips any key without a matching field
|
|
859
|
+
* definition and would silently drop these undeclared SEO keys. It still:
|
|
860
|
+
* - enforces the collection's `update` access rule (no cross-collection edits),
|
|
861
|
+
* - snapshots a `Version` row (audit trail),
|
|
862
|
+
* - recomputes `plainText`/`contentHash` (search index stays consistent),
|
|
863
|
+
* - fires the `afterUpdate` + cache-invalidate effects.
|
|
864
|
+
*
|
|
865
|
+
* `seoFields` MUST be pre-validated and length-bounded by the caller (the API
|
|
866
|
+
* layer enforces type + length); this function trusts the shapes it receives.
|
|
867
|
+
*/
|
|
868
|
+
export async function updateDocumentSeoFields(collection, id, seoFields, ctx) {
|
|
869
|
+
await checkCollectionAccess(collection, 'update', ctx);
|
|
870
|
+
const db = prisma(ctx);
|
|
871
|
+
const existing = await db.document.findFirst({
|
|
872
|
+
where: { id, collection, deletedAt: null },
|
|
873
|
+
});
|
|
874
|
+
if (!existing) {
|
|
875
|
+
throw new Error(`Document "${id}" not found in collection "${collection}"`);
|
|
876
|
+
}
|
|
877
|
+
const existingData = existing.data && typeof existing.data === 'object'
|
|
878
|
+
? existing.data
|
|
879
|
+
: {};
|
|
880
|
+
const collectionDef = getPrentaConfig()?.collections?.[collection];
|
|
881
|
+
const existingStructured = existing.structuredData && typeof existing.structuredData === 'object'
|
|
882
|
+
? existing.structuredData
|
|
883
|
+
: null;
|
|
884
|
+
let nextData = normalizeSeoFieldAliases({ ...existingData, ...seoFields });
|
|
885
|
+
if ('structuredDataType' in seoFields || 'schemaType' in seoFields) {
|
|
886
|
+
nextData = syncSchemaTypeFields(nextData);
|
|
887
|
+
}
|
|
888
|
+
if (isPublicContentCollection(collectionDef)) {
|
|
889
|
+
nextData = applyStructuredDataFieldsToData(collection, nextData, collectionDef, existingStructured);
|
|
890
|
+
}
|
|
891
|
+
const { plainText, contentHash } = await computeTextFields(nextData);
|
|
892
|
+
const pendingEffects = [];
|
|
893
|
+
const updated = await db.$transaction(async (tx) => {
|
|
894
|
+
const result = await tx.document.update({
|
|
895
|
+
where: { id },
|
|
896
|
+
data: { data: nextData, updatedById: ctx.userId, plainText, contentHash },
|
|
897
|
+
});
|
|
898
|
+
await tx.version.create({
|
|
899
|
+
data: {
|
|
900
|
+
documentId: id,
|
|
901
|
+
data: nextData,
|
|
902
|
+
changedById: ctx.userId,
|
|
903
|
+
changeType: 'UPDATE',
|
|
904
|
+
},
|
|
905
|
+
});
|
|
906
|
+
pendingEffects.push({ kind: 'plugin-hook', event: 'afterUpdate', doc: asDocRecord(result) });
|
|
907
|
+
pendingEffects.push({
|
|
908
|
+
kind: 'cache-invalidate',
|
|
909
|
+
tags: invalidationTagsForDocumentWrite(collection, id, publicPathTagsFor(collection, result)),
|
|
910
|
+
});
|
|
911
|
+
// SEO field edits (e.g. toggling `noindex`, changing canonical) change
|
|
912
|
+
// sitemap inclusion for already-public docs, so refresh the sitemap.
|
|
913
|
+
if (existing.status === 'PUBLISHED') {
|
|
914
|
+
pendingEffects.push({
|
|
915
|
+
kind: 'sitemap-notify',
|
|
916
|
+
reason: 'update',
|
|
917
|
+
changed: {
|
|
918
|
+
collection,
|
|
919
|
+
slug: result.slug,
|
|
920
|
+
path: result.data?.path ?? null,
|
|
921
|
+
},
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
return result;
|
|
925
|
+
});
|
|
926
|
+
await flushEffects(pendingEffects, ctx);
|
|
927
|
+
return updated;
|
|
928
|
+
}
|
|
929
|
+
/** Soft-delete a document. Creates a version snapshot before deletion. */
|
|
930
|
+
export async function deleteDocument(collection, id, ctx) {
|
|
931
|
+
await checkCollectionAccess(collection, 'delete', ctx);
|
|
932
|
+
const db = prisma(ctx);
|
|
933
|
+
const existing = await db.document.findFirst({
|
|
934
|
+
where: { id, collection, deletedAt: null },
|
|
935
|
+
});
|
|
936
|
+
if (!existing) {
|
|
937
|
+
throw new Error(`Document "${id}" not found in collection "${collection}"`);
|
|
938
|
+
}
|
|
939
|
+
await db.$transaction(async (tx) => {
|
|
940
|
+
await tx.version.create({
|
|
941
|
+
data: {
|
|
942
|
+
documentId: id,
|
|
943
|
+
data: existing.data ?? {},
|
|
944
|
+
changedById: ctx.userId,
|
|
945
|
+
changeType: 'DELETE',
|
|
946
|
+
},
|
|
947
|
+
});
|
|
948
|
+
// Free the slug so a new document can reuse this URL. The (collection, slug)
|
|
949
|
+
// unique index counts soft-deleted rows, so leaving the slug in place would
|
|
950
|
+
// permanently strand it: creating or renaming a live document onto the same
|
|
951
|
+
// slug throws a Prisma P2002 that surfaced as an opaque HTTP 500 (#560).
|
|
952
|
+
// Nulling drops this row out of the unique index (NULLs are distinct in
|
|
953
|
+
// Postgres); the pre-delete slug is still captured in `existing` for the
|
|
954
|
+
// effects below and preserved in the DELETE version snapshot above.
|
|
955
|
+
await tx.document.update({
|
|
956
|
+
where: { id },
|
|
957
|
+
data: { deletedAt: new Date(), slug: null },
|
|
958
|
+
});
|
|
959
|
+
await clearMediaUsageForDocument(tx, id);
|
|
960
|
+
});
|
|
961
|
+
const deleteEffects = [
|
|
962
|
+
{ kind: 'plugin-hook', event: 'afterDelete', doc: asDocRecord(existing) },
|
|
963
|
+
{
|
|
964
|
+
kind: 'webhook',
|
|
965
|
+
event: 'document.deleted',
|
|
966
|
+
payload: { id, collection, title: existing.title, slug: existing.slug },
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
kind: 'cache-invalidate',
|
|
970
|
+
tags: invalidationTagsForDocumentWrite(collection, id, publicPathTagsFor(collection, existing)),
|
|
971
|
+
},
|
|
972
|
+
];
|
|
973
|
+
// Removing public content changes the sitemap; drafts were never in it.
|
|
974
|
+
// Submitting the now-gone URL to IndexNow prompts a recrawl → 404 → deindex.
|
|
975
|
+
if (existing.status === 'PUBLISHED') {
|
|
976
|
+
deleteEffects.push({
|
|
977
|
+
kind: 'sitemap-notify',
|
|
978
|
+
reason: 'delete',
|
|
979
|
+
changed: {
|
|
980
|
+
collection,
|
|
981
|
+
slug: existing.slug,
|
|
982
|
+
path: existing.data?.path ?? null,
|
|
983
|
+
},
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
await flushEffects(deleteEffects, ctx);
|
|
987
|
+
}
|
|
988
|
+
function stripInternalKeys(data) {
|
|
989
|
+
return stripInternalDataKeys(data);
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Page Builder envelope: the admin UI sends `layout` and `pageSettings` at
|
|
993
|
+
* the top level of the document, but the database stores them inside
|
|
994
|
+
* `data._layout` and `data._pageSettings` so they don't collide with
|
|
995
|
+
* user-defined fields. These two helpers normalise between the wire shape
|
|
996
|
+
* and the storage shape so both forms are accepted on input and the wire
|
|
997
|
+
* shape is consistent on output.
|
|
998
|
+
*
|
|
999
|
+
* Wire shape:
|
|
1000
|
+
* { id, title, slug, status, data: {...}, layout?, pageSettings? }
|
|
1001
|
+
*
|
|
1002
|
+
* Storage shape:
|
|
1003
|
+
* data = { ...userFields, _layout?, _pageSettings? }
|
|
1004
|
+
*/
|
|
1005
|
+
function liftPageBuilderEnvelope(input) {
|
|
1006
|
+
if (!input.data || typeof input.data !== 'object')
|
|
1007
|
+
return input;
|
|
1008
|
+
const data = input.data;
|
|
1009
|
+
const out = { ...input };
|
|
1010
|
+
if (data._layout !== undefined) {
|
|
1011
|
+
out.layout = data._layout;
|
|
1012
|
+
}
|
|
1013
|
+
if (data._pageSettings !== undefined) {
|
|
1014
|
+
out.pageSettings = data._pageSettings;
|
|
1015
|
+
}
|
|
1016
|
+
return out;
|
|
1017
|
+
}
|
|
1018
|
+
function lowerPageBuilderEnvelope(data, envelope) {
|
|
1019
|
+
const out = { ...data };
|
|
1020
|
+
if (envelope.layout !== undefined) {
|
|
1021
|
+
// SECURITY: the page-builder tree carries author HTML in its rich-text
|
|
1022
|
+
// block bodies and is merged in AFTER field-level sanitization, so it must
|
|
1023
|
+
// be sanitized here too (see sanitize-document.ts).
|
|
1024
|
+
const sanitizedLayout = sanitizeLayoutTree(envelope.layout);
|
|
1025
|
+
out._layout = sanitizedLayout;
|
|
1026
|
+
// ADR 0002: the page builder's `_layout` tree is editor state, not a second
|
|
1027
|
+
// public contract. Compile it to the canonical `sections[]` on save so every
|
|
1028
|
+
// reader (SDK, MCP, search, content-graph, /resolve) sees one contract —
|
|
1029
|
+
// instead of deriving it lazily on each /resolve read. The page is then
|
|
1030
|
+
// "builder-owned": these derived sections are overwritten on the next builder
|
|
1031
|
+
// save (the flat Page Editor / section tools treat such a doc as read-only).
|
|
1032
|
+
// Derived from the already-sanitized tree, so the section HTML is safe.
|
|
1033
|
+
out.sections = layoutTreeToSections(sanitizedLayout);
|
|
1034
|
+
}
|
|
1035
|
+
if (envelope.pageSettings !== undefined) {
|
|
1036
|
+
out._pageSettings = envelope.pageSettings;
|
|
1037
|
+
}
|
|
1038
|
+
return out;
|
|
1039
|
+
}
|
|
1040
|
+
/** Pull `layout` / `pageSettings` from a write payload, returning the
|
|
1041
|
+
* envelope and the cleaned `data` body separately. Callers can then merge
|
|
1042
|
+
* the envelope back into `data` with {@link lowerPageBuilderEnvelope}. */
|
|
1043
|
+
function extractPageBuilderEnvelope(input) {
|
|
1044
|
+
const { layout, pageSettings, ...rest } = input;
|
|
1045
|
+
const envelope = {};
|
|
1046
|
+
if (layout !== undefined)
|
|
1047
|
+
envelope.layout = layout;
|
|
1048
|
+
if (pageSettings !== undefined)
|
|
1049
|
+
envelope.pageSettings = pageSettings;
|
|
1050
|
+
return { envelope, rest };
|
|
1051
|
+
}
|
|
1052
|
+
/** Retrieve a single document by ID. */
|
|
1053
|
+
export async function getDocument(collection, id, ctx) {
|
|
1054
|
+
const db = prisma(ctx);
|
|
1055
|
+
const doc = await db.document.findFirst({
|
|
1056
|
+
where: { id, collection, deletedAt: null },
|
|
1057
|
+
});
|
|
1058
|
+
if (!doc)
|
|
1059
|
+
return null;
|
|
1060
|
+
const docForAccess = doc.data && typeof doc.data === 'object'
|
|
1061
|
+
? stripInternalKeys(doc.data)
|
|
1062
|
+
: undefined;
|
|
1063
|
+
await checkCollectionAccess(collection, 'read', ctx, docForAccess);
|
|
1064
|
+
if (doc.data && typeof doc.data === 'object') {
|
|
1065
|
+
const rawData = doc.data;
|
|
1066
|
+
let data = stripInternalKeys(rawData);
|
|
1067
|
+
const fields = getCollectionFields(collection);
|
|
1068
|
+
if (fields) {
|
|
1069
|
+
const user = { id: ctx.userId, role: ctx.role };
|
|
1070
|
+
data = await applyFieldAccess('read', fields, data, user);
|
|
1071
|
+
}
|
|
1072
|
+
// Lift _layout / _pageSettings to the wire envelope so the admin UI
|
|
1073
|
+
// and consumers see a single canonical shape: page builder data lives
|
|
1074
|
+
// at the top level of the document, not nested inside `data`.
|
|
1075
|
+
const out = { ...doc, data };
|
|
1076
|
+
if (rawData._layout !== undefined)
|
|
1077
|
+
out.layout = rawData._layout;
|
|
1078
|
+
if (rawData._pageSettings !== undefined)
|
|
1079
|
+
out.pageSettings = rawData._pageSettings;
|
|
1080
|
+
return out;
|
|
1081
|
+
}
|
|
1082
|
+
return asDocRecord(doc);
|
|
1083
|
+
}
|
|
1084
|
+
/** List documents with pagination, sorting, and filtering. */
|
|
1085
|
+
export async function listDocuments(options, ctx) {
|
|
1086
|
+
await checkCollectionAccess(options.collection, 'read', ctx);
|
|
1087
|
+
const db = prisma(ctx);
|
|
1088
|
+
// Clamp before skip — negative page yields negative Prisma OFFSET → 500 (#561).
|
|
1089
|
+
const page = Math.max(1, Math.floor(Number(options.page) || 1));
|
|
1090
|
+
const pageSize = Math.min(100, Math.max(1, Math.floor(Number(options.pageSize) || 20)));
|
|
1091
|
+
const skip = (page - 1) * pageSize;
|
|
1092
|
+
const where = {
|
|
1093
|
+
collection: options.collection,
|
|
1094
|
+
deletedAt: null,
|
|
1095
|
+
};
|
|
1096
|
+
if (options.status) {
|
|
1097
|
+
where.status = options.status;
|
|
1098
|
+
}
|
|
1099
|
+
if (options.slug) {
|
|
1100
|
+
where.slug = options.slug;
|
|
1101
|
+
}
|
|
1102
|
+
if (options.locale) {
|
|
1103
|
+
where.locale = options.locale;
|
|
1104
|
+
}
|
|
1105
|
+
if (options.folderId === 'none') {
|
|
1106
|
+
where.folderId = null;
|
|
1107
|
+
}
|
|
1108
|
+
else if (options.folderId) {
|
|
1109
|
+
where.folderId = options.folderId;
|
|
1110
|
+
}
|
|
1111
|
+
const ALLOWED_FILTERS = new Set([
|
|
1112
|
+
'status',
|
|
1113
|
+
'locale',
|
|
1114
|
+
'collection',
|
|
1115
|
+
'siteId',
|
|
1116
|
+
'templateId',
|
|
1117
|
+
'folderId',
|
|
1118
|
+
]);
|
|
1119
|
+
if (options.filters) {
|
|
1120
|
+
for (const [key, value] of Object.entries(options.filters)) {
|
|
1121
|
+
if (ALLOWED_FILTERS.has(key) && typeof value !== 'object') {
|
|
1122
|
+
where[key] = value;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
if (options.dataFilters && options.dataFilters.length > 0) {
|
|
1127
|
+
where.AND = options.dataFilters.map((f) => f.kind === 'array'
|
|
1128
|
+
? {
|
|
1129
|
+
// JSONB containment matches a subset object inside any array
|
|
1130
|
+
// element, so `[{ tag: "AI" }]` matches rows with extra keys too.
|
|
1131
|
+
// Legacy sites store plain strings — accept either shape.
|
|
1132
|
+
OR: [
|
|
1133
|
+
{ data: { path: [f.field], array_contains: [{ tag: f.value }] } },
|
|
1134
|
+
{ data: { path: [f.field], array_contains: [f.value] } },
|
|
1135
|
+
],
|
|
1136
|
+
}
|
|
1137
|
+
: { data: { path: [f.field], equals: f.value } });
|
|
1138
|
+
}
|
|
1139
|
+
const ALLOWED_SORT = new Set(['createdAt', 'updatedAt', 'publishedAt', 'status', 'collection']);
|
|
1140
|
+
const orderBy = {};
|
|
1141
|
+
const sortField = ALLOWED_SORT.has(options.sort ?? '') ? options.sort : 'createdAt';
|
|
1142
|
+
orderBy[sortField] = options.order ?? 'desc';
|
|
1143
|
+
const [rawDocs, total] = await Promise.all([
|
|
1144
|
+
db.document.findMany({
|
|
1145
|
+
where,
|
|
1146
|
+
skip,
|
|
1147
|
+
take: pageSize,
|
|
1148
|
+
orderBy,
|
|
1149
|
+
}),
|
|
1150
|
+
db.document.count({ where }),
|
|
1151
|
+
]);
|
|
1152
|
+
const fields = getCollectionFields(options.collection);
|
|
1153
|
+
const user = { id: ctx.userId, role: ctx.role };
|
|
1154
|
+
const docs = await Promise.all(rawDocs.map(async (doc) => {
|
|
1155
|
+
if (doc.data && typeof doc.data === 'object') {
|
|
1156
|
+
const rawData = doc.data;
|
|
1157
|
+
let data = stripInternalKeys(rawData);
|
|
1158
|
+
if (fields) {
|
|
1159
|
+
data = await applyFieldAccess('read', fields, data, user);
|
|
1160
|
+
}
|
|
1161
|
+
// See `getDocument` — page builder envelope must be top-level on
|
|
1162
|
+
// the wire. Without this, list views can't show titles/slugs that
|
|
1163
|
+
// the page builder UI stores under `_pageSettings`.
|
|
1164
|
+
const out = { ...doc, data };
|
|
1165
|
+
if (rawData._layout !== undefined)
|
|
1166
|
+
out.layout = rawData._layout;
|
|
1167
|
+
if (rawData._pageSettings !== undefined)
|
|
1168
|
+
out.pageSettings = rawData._pageSettings;
|
|
1169
|
+
return out;
|
|
1170
|
+
}
|
|
1171
|
+
return asDocRecord(doc);
|
|
1172
|
+
}));
|
|
1173
|
+
return {
|
|
1174
|
+
docs,
|
|
1175
|
+
total,
|
|
1176
|
+
page,
|
|
1177
|
+
pageSize,
|
|
1178
|
+
totalPages: Math.ceil(total / pageSize),
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
/** Duplicate a document, resetting status to DRAFT and appending "(Copy)" to the title. */
|
|
1182
|
+
export async function duplicateDocument(collection, sourceId, ctx) {
|
|
1183
|
+
const db = prisma(ctx);
|
|
1184
|
+
const source = await db.document.findFirst({
|
|
1185
|
+
where: { id: sourceId, collection, deletedAt: null },
|
|
1186
|
+
});
|
|
1187
|
+
if (!source) {
|
|
1188
|
+
throw new Error(`Source document "${sourceId}" not found in collection "${collection}"`);
|
|
1189
|
+
}
|
|
1190
|
+
const clonedData = { ...source.data };
|
|
1191
|
+
if (typeof clonedData.title === 'string') {
|
|
1192
|
+
clonedData.title += ' (Copy)';
|
|
1193
|
+
}
|
|
1194
|
+
else if (typeof clonedData.name === 'string') {
|
|
1195
|
+
clonedData.name += ' (Copy)';
|
|
1196
|
+
}
|
|
1197
|
+
if (typeof clonedData.slug === 'string') {
|
|
1198
|
+
clonedData.slug += '-copy';
|
|
1199
|
+
}
|
|
1200
|
+
const { plainText, contentHash } = await computeTextFields(clonedData);
|
|
1201
|
+
const pendingEffects = [];
|
|
1202
|
+
const doc = await db.$transaction(async (tx) => {
|
|
1203
|
+
const created = await tx.document.create({
|
|
1204
|
+
data: {
|
|
1205
|
+
collection,
|
|
1206
|
+
data: clonedData,
|
|
1207
|
+
status: 'DRAFT',
|
|
1208
|
+
locale: source.locale,
|
|
1209
|
+
createdById: ctx.userId,
|
|
1210
|
+
updatedById: ctx.userId,
|
|
1211
|
+
plainText,
|
|
1212
|
+
contentHash,
|
|
1213
|
+
siteId: source.siteId,
|
|
1214
|
+
templateId: source.templateId,
|
|
1215
|
+
},
|
|
1216
|
+
});
|
|
1217
|
+
await tx.version.create({
|
|
1218
|
+
data: {
|
|
1219
|
+
documentId: created.id,
|
|
1220
|
+
data: clonedData,
|
|
1221
|
+
changedById: ctx.userId,
|
|
1222
|
+
changeType: 'CREATE',
|
|
1223
|
+
},
|
|
1224
|
+
});
|
|
1225
|
+
await syncMediaUsageForDocument(tx, created.id, clonedData);
|
|
1226
|
+
pendingEffects.push({
|
|
1227
|
+
kind: 'webhook',
|
|
1228
|
+
event: 'document.created',
|
|
1229
|
+
payload: { id: created.id, collection, title: created.title, slug: created.slug },
|
|
1230
|
+
});
|
|
1231
|
+
pendingEffects.push({ kind: 'plugin-hook', event: 'afterCreate', doc: asDocRecord(created) });
|
|
1232
|
+
pendingEffects.push({
|
|
1233
|
+
kind: 'cache-invalidate',
|
|
1234
|
+
tags: invalidationTagsForDocumentWrite(collection, created.id, publicPathTagsFor(collection, created)),
|
|
1235
|
+
});
|
|
1236
|
+
return created;
|
|
1237
|
+
});
|
|
1238
|
+
await flushEffects(pendingEffects, ctx);
|
|
1239
|
+
return doc;
|
|
1240
|
+
}
|
|
1241
|
+
/** Retrieve a global's data. Globals are stored as single-row collections keyed by slug. */
|
|
1242
|
+
export async function getGlobal(slug, ctx) {
|
|
1243
|
+
const db = prisma(ctx);
|
|
1244
|
+
const doc = await db.document.findFirst({
|
|
1245
|
+
where: { collection: slug, deletedAt: null },
|
|
1246
|
+
});
|
|
1247
|
+
if (!doc)
|
|
1248
|
+
return null;
|
|
1249
|
+
return doc.data && typeof doc.data === 'object' ? doc.data : {};
|
|
1250
|
+
}
|
|
1251
|
+
/** Update a global's data. Creates the document if it doesn't exist (upsert). */
|
|
1252
|
+
export async function updateGlobal(slug, data, ctx) {
|
|
1253
|
+
const db = prisma(ctx);
|
|
1254
|
+
const { plainText, contentHash } = await computeTextFields(data);
|
|
1255
|
+
const existing = await db.document.findFirst({
|
|
1256
|
+
where: { collection: slug, deletedAt: null },
|
|
1257
|
+
});
|
|
1258
|
+
const result = existing
|
|
1259
|
+
? await db.$transaction(async (tx) => {
|
|
1260
|
+
const updated = await tx.document.update({
|
|
1261
|
+
where: { id: existing.id },
|
|
1262
|
+
data: {
|
|
1263
|
+
data,
|
|
1264
|
+
updatedById: ctx.userId,
|
|
1265
|
+
plainText,
|
|
1266
|
+
contentHash,
|
|
1267
|
+
},
|
|
1268
|
+
});
|
|
1269
|
+
await tx.version.create({
|
|
1270
|
+
data: {
|
|
1271
|
+
documentId: existing.id,
|
|
1272
|
+
data,
|
|
1273
|
+
changedById: ctx.userId,
|
|
1274
|
+
changeType: 'UPDATE',
|
|
1275
|
+
},
|
|
1276
|
+
});
|
|
1277
|
+
await syncMediaUsageForDocument(tx, existing.id, data);
|
|
1278
|
+
return updated;
|
|
1279
|
+
})
|
|
1280
|
+
: await db.$transaction(async (tx) => {
|
|
1281
|
+
const created = await tx.document.create({
|
|
1282
|
+
data: {
|
|
1283
|
+
collection: slug,
|
|
1284
|
+
data,
|
|
1285
|
+
status: 'DRAFT',
|
|
1286
|
+
createdById: ctx.userId,
|
|
1287
|
+
updatedById: ctx.userId,
|
|
1288
|
+
plainText,
|
|
1289
|
+
contentHash,
|
|
1290
|
+
},
|
|
1291
|
+
});
|
|
1292
|
+
await tx.version.create({
|
|
1293
|
+
data: {
|
|
1294
|
+
documentId: created.id,
|
|
1295
|
+
data,
|
|
1296
|
+
changedById: ctx.userId,
|
|
1297
|
+
changeType: 'CREATE',
|
|
1298
|
+
},
|
|
1299
|
+
});
|
|
1300
|
+
await syncMediaUsageForDocument(tx, created.id, data);
|
|
1301
|
+
return created;
|
|
1302
|
+
});
|
|
1303
|
+
// Globals are site chrome (header/footer/settings). Fire document.updated
|
|
1304
|
+
// with status PUBLISHED so purge-on-publish receivers (subscribed to the
|
|
1305
|
+
// publish lifecycle) evict the edge — cache tags alone never reach Astro CDN.
|
|
1306
|
+
await flushEffects([
|
|
1307
|
+
{ kind: 'cache-invalidate', tags: invalidationTagsForGlobalWrite(slug) },
|
|
1308
|
+
{
|
|
1309
|
+
kind: 'webhook',
|
|
1310
|
+
event: 'document.updated',
|
|
1311
|
+
payload: {
|
|
1312
|
+
id: result.id,
|
|
1313
|
+
collection: slug,
|
|
1314
|
+
slug,
|
|
1315
|
+
status: 'PUBLISHED',
|
|
1316
|
+
title: typeof result.data?.title === 'string'
|
|
1317
|
+
? result.data.title
|
|
1318
|
+
: null,
|
|
1319
|
+
},
|
|
1320
|
+
},
|
|
1321
|
+
], ctx);
|
|
1322
|
+
return result;
|
|
1323
|
+
}
|
|
1324
|
+
//# sourceMappingURL=actions.js.map
|