dineway 0.2.39 → 0.2.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{activity-LXZdjKwI.mjs → activity-BuhkMdv8.mjs} +2 -2
- package/dist/{activity-events-DoqeOM8x.mjs → activity-events-DkHsy7Y0.mjs} +1 -1
- package/dist/{allowed-origins-DiVrMLxh.mjs → allowed-origins-Clitkhiv.mjs} +1 -1
- package/dist/api/route-utils.d.mts +15 -12
- package/dist/api/route-utils.mjs +27 -20
- package/dist/api/schemas/index.d.mts +1 -1
- package/dist/api/schemas/index.mjs +10 -5
- package/dist/{api-COSxvdOi.mjs → api-CMbsIQ46.mjs} +41 -13
- package/dist/{api-tokens-CNHnKO57.mjs → api-tokens-ciHNTdN2.mjs} +1 -1
- package/dist/{apply-D4rZHDyg.mjs → apply-B5qoX19G.mjs} +62 -18
- package/dist/astro/index.d.mts +16 -13
- package/dist/astro/index.mjs +31 -5
- package/dist/astro/middleware/auth.d.mts +14 -11
- package/dist/astro/middleware/auth.mjs +8 -8
- package/dist/astro/middleware/redirect.mjs +10 -6
- package/dist/astro/middleware/request-context.mjs +5 -5
- package/dist/astro/middleware/seed.d.mts +1 -1
- package/dist/astro/middleware/seed.mjs +2 -2
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts +2 -2
- package/dist/astro/middleware.mjs +266 -176
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +12 -7
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +12 -7
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +7 -7
- package/dist/astro/routes/api/admin/briefing.mjs +41 -22
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +14 -10
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +14 -10
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +14 -10
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +25 -19
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +25 -19
- package/dist/astro/routes/api/admin/bylines/index.mjs +25 -19
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +20 -16
- package/dist/astro/routes/api/admin/comments/_id_.mjs +10 -7
- package/dist/astro/routes/api/admin/comments/bulk.mjs +18 -13
- package/dist/astro/routes/api/admin/comments/counts.mjs +10 -7
- package/dist/astro/routes/api/admin/comments/index.mjs +18 -13
- package/dist/astro/routes/api/admin/context/_id_/history.mjs +51 -39
- package/dist/astro/routes/api/admin/context/_id_/index.mjs +51 -39
- package/dist/astro/routes/api/admin/context/_id_/review.mjs +57 -44
- package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +57 -44
- package/dist/astro/routes/api/admin/context/diff.mjs +56 -43
- package/dist/astro/routes/api/admin/context/index.mjs +57 -44
- package/dist/astro/routes/api/admin/context/stale.mjs +56 -43
- package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +51 -39
- package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +56 -43
- package/dist/astro/routes/api/admin/hitl-requests/index.mjs +56 -43
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +52 -40
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +7 -7
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +7 -7
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +78 -68
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +78 -68
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +71 -60
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +78 -67
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +78 -67
- package/dist/astro/routes/api/admin/plugins/index.mjs +71 -60
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +71 -60
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +78 -67
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +71 -60
- package/dist/astro/routes/api/admin/plugins/updates.mjs +71 -60
- package/dist/astro/routes/api/admin/review-requests/_id_/image.mjs +38 -23
- package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +46 -36
- package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +63 -52
- package/dist/astro/routes/api/admin/review-requests/_id_/revoke.mjs +9 -9
- package/dist/astro/routes/api/admin/review-requests/index.mjs +61 -50
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +71 -60
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +71 -60
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +1 -1
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +11 -7
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
- package/dist/astro/routes/api/admin/users/index.mjs +12 -7
- package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
- package/dist/astro/routes/api/auth/invite/accept.mjs +1 -1
- package/dist/astro/routes/api/auth/invite/complete.mjs +17 -12
- package/dist/astro/routes/api/auth/invite/index.mjs +14 -9
- package/dist/astro/routes/api/auth/invite/register-options.mjs +16 -11
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +17 -12
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/me.mjs +14 -11
- package/dist/astro/routes/api/auth/mode.mjs +1 -1
- package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
- package/dist/astro/routes/api/auth/oauth/_provider_.mjs +3 -3
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +12 -7
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +19 -14
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +16 -11
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +17 -12
- package/dist/astro/routes/api/auth/passkey/verify.mjs +17 -12
- package/dist/astro/routes/api/auth/setup-token/index.mjs +6 -6
- package/dist/astro/routes/api/auth/setup-token/verify.mjs +2 -2
- package/dist/astro/routes/api/auth/signup/complete.mjs +17 -12
- package/dist/astro/routes/api/auth/signup/request.mjs +17 -12
- package/dist/astro/routes/api/auth/signup/verify.mjs +1 -1
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.d.mts +14 -11
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +23 -19
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +23 -18
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +25 -20
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +41 -31
- package/dist/astro/routes/api/content/_collection_/_id_/release-readiness.mjs +14 -9
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +41 -31
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +30 -20
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +8 -8
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +25 -14
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +25 -14
- package/dist/astro/routes/api/content/_collection_/trash.mjs +13 -8
- package/dist/astro/routes/api/dashboard.mjs +21 -13
- package/dist/astro/routes/api/dev/emails.mjs +2 -2
- package/dist/astro/routes/api/health.mjs +1 -1
- package/dist/astro/routes/api/import/probe.d.mts +3 -3
- package/dist/astro/routes/api/import/probe.mjs +30 -23
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +13 -10
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +14 -11
- package/dist/astro/routes/api/import/wordpress/execute.mjs +58 -47
- package/dist/astro/routes/api/import/wordpress/media.d.mts +14 -11
- package/dist/astro/routes/api/import/wordpress/media.mjs +17 -14
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +61 -48
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +15 -12
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +58 -45
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +32 -26
- package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +14 -11
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +63 -52
- package/dist/astro/routes/api/integration/artifact.mjs +9 -9
- package/dist/astro/routes/api/integration/dispatch.mjs +14 -14
- package/dist/astro/routes/api/integrations/_provider_.mjs +9 -9
- package/dist/astro/routes/api/integrations/index.mjs +8 -8
- package/dist/astro/routes/api/manifest.mjs +5 -5
- package/dist/astro/routes/api/mcp.mjs +141 -93
- package/dist/astro/routes/api/media/_id_/confirm.mjs +15 -12
- package/dist/astro/routes/api/media/_id_.mjs +14 -9
- package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
- package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
- package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
- package/dist/astro/routes/api/media/providers/index.mjs +2 -2
- package/dist/astro/routes/api/media/upload-url.mjs +16 -13
- package/dist/astro/routes/api/media.mjs +19 -16
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +57 -44
- package/dist/astro/routes/api/menus/_name_/items.mjs +57 -44
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +57 -44
- package/dist/astro/routes/api/menus/_name_/translations.mjs +57 -44
- package/dist/astro/routes/api/menus/_name_.mjs +57 -44
- package/dist/astro/routes/api/menus/index.mjs +57 -44
- package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
- package/dist/astro/routes/api/oauth/device/authorize.mjs +5 -5
- package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
- package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
- package/dist/astro/routes/api/oauth/register.mjs +4 -4
- package/dist/astro/routes/api/oauth/token/refresh.mjs +5 -5
- package/dist/astro/routes/api/oauth/token/revoke.mjs +5 -5
- package/dist/astro/routes/api/oauth/token.mjs +6 -6
- package/dist/astro/routes/api/openapi.json.mjs +10 -5
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
- package/dist/astro/routes/api/redirects/404s/index.mjs +15 -13
- package/dist/astro/routes/api/redirects/404s/summary.mjs +15 -13
- package/dist/astro/routes/api/redirects/_id_.mjs +57 -44
- package/dist/astro/routes/api/redirects/index.mjs +57 -44
- package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
- package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
- package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +73 -62
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +73 -62
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +73 -62
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +73 -62
- package/dist/astro/routes/api/schema/collections/index.mjs +73 -62
- package/dist/astro/routes/api/schema/index.mjs +13 -10
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +71 -60
- package/dist/astro/routes/api/schema/orphans/index.mjs +71 -60
- package/dist/astro/routes/api/search/enable.mjs +20 -13
- package/dist/astro/routes/api/search/index.mjs +19 -12
- package/dist/astro/routes/api/search/rebuild.mjs +20 -13
- package/dist/astro/routes/api/search/stats.mjs +12 -7
- package/dist/astro/routes/api/search/suggest.mjs +19 -12
- package/dist/astro/routes/api/sections/_slug_.mjs +57 -44
- package/dist/astro/routes/api/sections/index.mjs +57 -44
- package/dist/astro/routes/api/settings/email.mjs +5 -5
- package/dist/astro/routes/api/settings/reviews.mjs +11 -11
- package/dist/astro/routes/api/settings.mjs +57 -44
- package/dist/astro/routes/api/setup/admin-verify.mjs +19 -14
- package/dist/astro/routes/api/setup/admin.mjs +17 -12
- package/dist/astro/routes/api/setup/dev-bypass.mjs +44 -32
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +47 -34
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +9 -9
- package/dist/astro/routes/api/system/heartbeat.mjs +2 -2
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +60 -47
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +60 -47
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +60 -47
- package/dist/astro/routes/api/taxonomies/index.mjs +60 -47
- package/dist/astro/routes/api/themes/preview.mjs +7 -7
- package/dist/astro/routes/api/typegen.mjs +4 -4
- package/dist/astro/routes/api/well-known/auth.mjs +3 -3
- package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
- package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
- package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +56 -43
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +57 -44
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +57 -44
- package/dist/astro/routes/api/widget-areas/_name_.mjs +53 -41
- package/dist/astro/routes/api/widget-areas/index.mjs +57 -44
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +14 -9
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +20 -16
- package/dist/astro/routes/sitemap.xml.mjs +19 -15
- package/dist/astro/session-driver.d.mts +1 -1
- package/dist/astro/session-driver.mjs +8 -3
- package/dist/astro/types.d.mts +21 -14
- package/dist/{atomic-authority-CnBQJ14T.mjs → atomic-authority-Bf5QZboB.mjs} +2 -2
- package/dist/{audit-Cl495Ze3.mjs → audit-hXJBTPY0.mjs} +1 -1
- package/dist/auth/providers/github.d.mts +1 -1
- package/dist/auth/providers/google.d.mts +1 -1
- package/dist/{auth-control-guard-DbjgJdlo.mjs → auth-control-guard-DpUP6Fs_.mjs} +1 -1
- package/dist/{authorize-DDmgmnW-.mjs → authorize-DWNOqMKq.mjs} +1 -1
- package/dist/{briefing-DsD-Ouwc.mjs → briefing-BzvBeIJh.mjs} +1 -1
- package/dist/{briefing-COw-WcYz.mjs → briefing-DYiV93rg.mjs} +995 -7
- package/dist/{bundle-bhiszAui.mjs → bundle-DWn5eFKz.mjs} +2 -2
- package/dist/{byline-TYk2kad6.mjs → byline-3qjp1-oa.mjs} +65 -14
- package/dist/{byline-fields-CKhPED5o.d.mts → byline-fields-Bne2v0ti.d.mts} +42 -38
- package/dist/{byline-fields-BKj5f3Ub.mjs → byline-fields-DRMCc0V_.mjs} +1 -1
- package/dist/{byline-fields-DZ46DF10.mjs → byline-fields-wWu2Cb3l.mjs} +3 -3
- package/dist/{byline-registry-CJihchD1.mjs → byline-registry-Caj0_gbU.mjs} +1 -1
- package/dist/{bylines-6T9iVC9j.mjs → bylines-BSn9O1Wx.mjs} +3 -3
- package/dist/{bylines-CvTSCAw9.mjs → bylines-CGuJi-zu.mjs} +5 -5
- package/dist/{patterns-Ay-4KImK.mjs → cache-DsEbwFVE.mjs} +51 -1
- package/dist/{chunks-C8vSD_5L.mjs → chunks-Bb56aCtB.mjs} +1 -1
- package/dist/cli/index.mjs +488 -58
- package/dist/cli/plugin-kit.d.mts +14 -11
- package/dist/cli/plugin-kit.mjs +2 -2
- package/dist/client/external-auth-headers.d.mts +1 -1
- package/dist/client/index.d.mts +16 -13
- package/dist/client/index.mjs +2 -2
- package/dist/{client-factory-C1ZQCMog.mjs → client-factory-BLbm250o.mjs} +1 -1
- package/dist/{comment-DAQfUjqt.mjs → comment-BWDG1nQm.mjs} +2 -2
- package/dist/{comment-reaction-Dp3G7UZc.mjs → comment-reaction-B7pLTlQ7.mjs} +1 -1
- package/dist/{comments-BrvIaRAx.mjs → comments-xkten8nV.mjs} +1 -1
- package/dist/config-6R0bchVE.mjs +125 -0
- package/dist/{content-CIKsrvU9.mjs → content-BigS8BAv.mjs} +302 -45
- package/dist/content-Dr22fzA_.mjs +390 -0
- package/dist/{content-refresh-BilzqcLt.mjs → content-refresh-DJuFIqQ4.mjs} +14 -8
- package/dist/content-storage/index.d.mts +180 -0
- package/dist/content-storage/index.mjs +29 -0
- package/dist/content-storage/store.d.mts +3 -0
- package/dist/content-storage/store.mjs +5 -0
- package/dist/{review-payload-Bap86e75.mjs → content-write-DAZCNKWl.mjs} +838 -131
- package/dist/{context-DAs_MZjJ.mjs → context-0806nV9h.mjs} +292 -23
- package/dist/{context-DVTvucNb.mjs → context-CCsI5nTK.mjs} +2 -2
- package/dist/{context-route-helpers-BP-UJ4u8.mjs → context-route-helpers-TP3EqxRQ.mjs} +2 -2
- package/dist/{dashboard-BAjWCGCP.mjs → dashboard-CSrnhBO6.mjs} +4 -4
- package/dist/database/batch.d.mts +1 -1
- package/dist/database/batch.mjs +1 -1
- package/dist/database/d1/index.d.mts +14 -11
- package/dist/database/d1/index.mjs +4 -4
- package/dist/database/instrumentation.mjs +3 -2
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +1 -1
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{device-flow-Dh0rNlh1.mjs → device-flow-SoZh-HvN.mjs} +3 -3
- package/dist/{discovery-V0e0Gg8j.mjs → discovery-49qXmdwv.mjs} +4 -4
- package/dist/{enrich-B7PIJ8Iy.mjs → enrich-CAMsD1aT.mjs} +1 -1
- package/dist/{error-B5a45Tfb.mjs → error-sL4aemcW.mjs} +2 -0
- package/dist/{evidence-Vnp_fQbC.mjs → evidence-B3O9_VKm.mjs} +7 -7
- package/dist/{field-defs-cache-aXUeXJdC.mjs → field-defs-cache-dn5Tw79A.mjs} +4 -4
- package/dist/{fts-manager-BrPpYtK0.mjs → fts-manager-Zu5ITic0.mjs} +1 -1
- package/dist/{hitl-requests-BxMMON3s.mjs → hitl-requests-B5vOPseK.mjs} +2 -2
- package/dist/{hitl-route-helpers-sdnjpx2k.mjs → hitl-route-helpers-C3icmGdj.mjs} +5 -5
- package/dist/hook-events-BQw73jc7.d.mts +32 -0
- package/dist/{import-C2-v4FCs.mjs → import-CKnKQj3f.mjs} +9 -9
- package/dist/{index-BVGe04wF.d.mts → index-CLj17kW9.d.mts} +12 -5
- package/dist/index.d.mts +19 -16
- package/dist/index.mjs +107 -98
- package/dist/{integration-credentials-DMEXZU2J.mjs → integration-credentials-DpuRw1kx.mjs} +2 -2
- package/dist/{jsonld-XWmmAoVo.d.mts → jsonld-CN91qtDw.d.mts} +2 -2
- package/dist/{load-DvCVppOF.mjs → load-CiRTddkJ.mjs} +1 -1
- package/dist/{loader-Dp6zLmQm.mjs → loader-CCwWFQSh.mjs} +16 -5
- package/dist/{manifest-schema-CCvogfrP.mjs → manifest-schema-DaQpgyTB.mjs} +1 -1
- package/dist/{mcp-reviewed-executor-B8Gbin3T.mjs → mcp-reviewed-executor-DA6Q9sDc.mjs} +6 -6
- package/dist/media/image-endpoint.mjs +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +2 -2
- package/dist/media/local-runtime.d.mts +16 -13
- package/dist/media/local-runtime.mjs +3 -3
- package/dist/{media-C5ba8fvI.mjs → media-BjH5OD-A.mjs} +1 -1
- package/dist/{media-allowlist-DQvscVkS.mjs → media-allowlist-C8HJ2O61.mjs} +1 -1
- package/dist/{menus-CyNpBQrX.mjs → menus-CbBi7Ad7.mjs} +2 -2
- package/dist/{menus-w5xwT-f5.mjs → menus-D0c8CeVg.mjs} +7 -7
- package/dist/migration-DJuj7ZwN.mjs +526 -0
- package/dist/{migrations-CLlX25HO.mjs → migrations-BAjF60cl.mjs} +1 -1
- package/dist/{oauth-authorization-CdqJZUMf.mjs → oauth-authorization-CSSRMOKn.mjs} +4 -4
- package/dist/{oauth-clients-CHNb9MAZ.mjs → oauth-clients-DX5HIJJv.mjs} +2 -2
- package/dist/object-cache/memory.d.mts +1 -1
- package/dist/{object-cache-mxCW-Rpt.mjs → object-cache-DyI1SOBK.mjs} +3 -1
- package/dist/owned-metadata-BPmUjZqI.mjs +69 -0
- package/dist/page/index.d.mts +15 -12
- package/dist/page/index.mjs +1 -1
- package/dist/{parse-THHCpJLB.mjs → parse-C6kCR1OT.mjs} +1 -1
- package/dist/plugin-utils.d.mts +14 -11
- package/dist/plugins/adapt-sandbox-entry.d.mts +14 -11
- package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
- package/dist/{plugins-pfraURNp.mjs → plugins-V0W65r3v.mjs} +16 -962
- package/dist/{policy-B6mVa7ib.mjs → policy-DbceGc4P.mjs} +2 -2
- package/dist/{preview-Bh7D7F27.mjs → preview-CWiIjMDi.mjs} +2 -2
- package/dist/{provider-loader-DT7vQ5FI.d.mts → provider-loader-oLKm1AU8.d.mts} +1 -1
- package/dist/{public-url-Ccv0Xmue.d.mts → public-url-CEC1vj02.d.mts} +2 -2
- package/dist/{public-url-BvnTaacI.d.mts → public-url-CKrUov8D.d.mts} +1 -1
- package/dist/{publication-authorization-B_HJSnzR.mjs → publication-authorization-wMR-tEQ_.mjs} +43 -17
- package/dist/{query-xspvw7Ui.mjs → query-DDi367tF.mjs} +14 -14
- package/dist/{query-DLeahg3x.mjs → query-DLnnpEuf.mjs} +4 -4
- package/dist/{rate-limit-BsBr_U9g.mjs → rate-limit-DeVLLe4z.mjs} +2 -2
- package/dist/{redirect-BQFa1THe.mjs → redirect-CJ-FAbNK.mjs} +2 -2
- package/dist/{redirects-DJcsgz_X.mjs → redirects-BKi6mek4.mjs} +4 -5
- package/dist/{redirects-CVfxefrz.mjs → redirects-I78-ZYLV.mjs} +5 -386
- package/dist/{registry-Dclv9iHv.mjs → registry-zXXZezu-.mjs} +7 -7
- package/dist/{release-B3Q-9B7N.mjs → release-Cpi0-Bzq.mjs} +173 -22
- package/dist/request-context.d.mts +30 -0
- package/dist/{request-meta-CjORiJQ_.mjs → request-meta-DZYuLXx_.mjs} +1 -1
- package/dist/review-payload-Bhi52CbI.mjs +112 -0
- package/dist/{review-requests-CcSUTm_l.mjs → review-requests-C-ScxD9n.mjs} +2 -2
- package/dist/{review-requests-CUVn0RBl.mjs → review-requests-DZYM51yI.mjs} +2 -2
- package/dist/{review-route-helpers-CKBfGKCi.mjs → review-route-helpers-DXNDyx_q.mjs} +2 -2
- package/dist/{revision-W6FDfDqx.mjs → revision-B_HYO2AE.mjs} +42 -7
- package/dist/revisions-CQ7rMP5d.mjs +55 -0
- package/dist/{revocation-C_ZQvGRT.mjs → revocation-4we8kfBg.mjs} +2 -2
- package/dist/{runner-CRU7BXjr.mjs → runner-CuG8o1uW.mjs} +558 -487
- package/dist/{runner-SoP1rphP.d.mts → runner-DXQkyPeX.d.mts} +1 -1
- package/dist/{runs-BtaAiLTw.mjs → runs-BjgLfqCn.mjs} +5 -5
- package/dist/runtime-Bs2JMbb2.d.mts +45 -0
- package/dist/runtime-Ch5G-tnG.mjs +400 -0
- package/dist/runtime.d.mts +15 -12
- package/dist/runtime.mjs +9 -4
- package/dist/schema-BA05k0TN.mjs +8 -0
- package/dist/{search-BI9uKr7U.mjs → search-DMrzhfx_.mjs} +4 -98
- package/dist/{secrets-D_pergcD.mjs → secrets-CIYcw9T9.mjs} +4 -4
- package/dist/{sections-BqqYq9RW.mjs → sections-BTrSEhqB.mjs} +2 -2
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +38 -26
- package/dist/seo/index.d.mts +3 -3
- package/dist/seo/index.mjs +12 -9
- package/dist/{seo-Bs_DUxJf.mjs → seo-Cv7ud_m2.mjs} +44 -5
- package/dist/{seo-B-5PsaJO.mjs → seo-DkjtBh-y.mjs} +1 -1
- package/dist/{service-W2xuGLgw.mjs → service-BBJM08uD.mjs} +2 -2
- package/dist/{service-B65aJsN7.mjs → service-CkMuD5AE.mjs} +3 -3
- package/dist/{settings-DsBzKeUQ.mjs → settings-BUONaNnG.mjs} +7 -7
- package/dist/{settings-CyJ2-MKx.mjs → settings-CI-NtWEc.mjs} +2 -2
- package/dist/{setup-complete-DeivSVJi.mjs → setup-complete-DoVbVrHx.mjs} +1 -1
- package/dist/{site-activity-DU0UPDji.mjs → site-activity-hpfJkmxQ.mjs} +1 -1
- package/dist/{site-context-Dic2jHuw.mjs → site-context-BW3GRCJH.mjs} +15 -15
- package/dist/{site-url-Tw6CfBB2.mjs → site-url-CYatfe3q.mjs} +1 -1
- package/dist/{state-DM7blWfT.mjs → state-CKkqoA6i.mjs} +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.mjs +2 -2
- package/dist/{store-32e6dfD-.mjs → store-BzaAtszy.mjs} +3 -3
- package/dist/submission-DLgjQ_Ew.mjs +205 -0
- package/dist/{taxonomies-BFsUR7kc.mjs → taxonomies-C02-Vuh3.mjs} +3 -3
- package/dist/{taxonomies-lWGNLKgn.mjs → taxonomies-D5wO9zmB.mjs} +7 -7
- package/dist/{taxonomy-DN6i1upz.mjs → taxonomy-BK7JmHlo.mjs} +53 -3
- package/dist/terms-EskuqbKE.mjs +104 -0
- package/dist/text-extraction-CdqMGYQK.mjs +96 -0
- package/dist/{tokens-D-StaTAQ.mjs → tokens-D8HEH277.mjs} +1 -1
- package/dist/{trusted-proxy-hYufGFPK.mjs → trusted-proxy-Dg3U9Lrv.mjs} +1 -1
- package/dist/{types-RFzE_V1M.mjs → types-BI3ULB3A.mjs} +2 -2
- package/dist/{types-CJynaYg1.d.mts → types-C3jUu4Bc.d.mts} +90 -34
- package/dist/{types-B--VyN3n.d.mts → types-Dpv_MvwZ.d.mts} +1 -1
- package/dist/{types-CgcOeaiQ.d.mts → types-ex-UrNlz.d.mts} +1 -1
- package/dist/types-qOEot0UQ.d.mts +83 -0
- package/dist/ui/server-runtime.d.mts +18 -15
- package/dist/ui/server-runtime.mjs +29 -25
- package/dist/{user-Btai9rl3.mjs → user-Bl2_8rhJ.mjs} +2 -2
- package/dist/{utils-CYxGuO_P.mjs → utils-CklSLz9F.mjs} +2 -2
- package/dist/{validate-C05z0m7M.mjs → validate-C-yk7mmX.mjs} +3 -3
- package/dist/{validate-kmN2lS8H.d.mts → validate-DUscf6VG.d.mts} +3 -3
- package/dist/version-BlE1LEPb.mjs +6 -0
- package/dist/version-store-BXv2D0de.mjs +208 -0
- package/dist/version-store-B_THJCc0.d.mts +98 -0
- package/dist/{widgets-BOrDZdQ3.mjs → widgets-9xHBhL_L.mjs} +3 -3
- package/dist/{wordpress-slugs-ROzITIBK.mjs → wordpress-slugs-yaeD7cxn.mjs} +1 -1
- package/dist/{worker-Bg35R37I.mjs → worker-CC_Rt1pB.mjs} +10 -10
- package/dist/write-intent-DuHVqks9.mjs +108 -0
- package/dist/{zod-generator-DkrWuID7.mjs → zod-generator-B5Pt8fv0.mjs} +2 -2
- package/package.json +16 -4
- package/dist/cache-B5NSHhxG.mjs +0 -52
- package/dist/cron-C7HCJPPl.mjs +0 -271
- package/dist/schema-CosVhHJt.mjs +0 -8
- package/dist/submission-DJmRejGR.mjs +0 -411
- package/dist/version-BnLdwIT1.mjs +0 -6
- /package/dist/{actor-DxUAJgQX.mjs → actor-D0AW80ld.mjs} +0 -0
- /package/dist/{adapter-symbols-Bq3JsWGM.d.mts → adapter-symbols-B9mi-BUh.d.mts} +0 -0
- /package/dist/{adapters-C8nRpUuj.d.mts → adapters-lDnJjNDz.d.mts} +0 -0
- /package/dist/{api-tokens-0N3nafqZ.mjs → api-tokens-CdfsE9PL.mjs} +0 -0
- /package/dist/{base64-Cz-aU0X1.mjs → base64-qvSs0Gxy.mjs} +0 -0
- /package/dist/{challenge-store-BPn3goP9.mjs → challenge-store-7IZ_NqWg.mjs} +0 -0
- /package/dist/{components-rFN8NH3N.mjs → components-JA6tFHmE.mjs} +0 -0
- /package/dist/{context-types-CPWAJRs5.mjs → context-types-DDIJhGLs.mjs} +0 -0
- /package/dist/{default-BS6VQRkB.mjs → default-C2azCFSB.mjs} +0 -0
- /package/dist/{email-console-GqK6hgMJ.mjs → email-console-BYQp_5Qr.mjs} +0 -0
- /package/dist/{escape-CE7xOWzJ.mjs → escape-4_NNa6GR.mjs} +0 -0
- /package/dist/{experimental-workflows-BbxpWwBy.mjs → experimental-workflows-CPNiI2EL.mjs} +0 -0
- /package/dist/{forgeway-account-DcTxh3Gw.mjs → forgeway-account-YzraapbX.mjs} +0 -0
- /package/dist/{hash-D2Rqd2J2.mjs → hash-qSYPMJ8w.mjs} +0 -0
- /package/dist/{media-url-D9kdpoLS.mjs → media-url-D5E1a47B.mjs} +0 -0
- /package/dist/{mime-BnVhH671.mjs → mime-FkfazULS.mjs} +0 -0
- /package/dist/{mode-D0gePRtf.mjs → mode-C3RI5Z5t.mjs} +0 -0
- /package/dist/{normalize-aTwryvvi.mjs → normalize-DrmlLn40.mjs} +0 -0
- /package/dist/{oauth-authority-P5YMSk2z.mjs → oauth-authority-DVlLFhsZ.mjs} +0 -0
- /package/dist/{oauth-state-store-CMqLdo4I.mjs → oauth-state-store-nf-78RbK.mjs} +0 -0
- /package/dist/{options-JiLWB6Bt.mjs → options-yFkLUuTw.mjs} +0 -0
- /package/dist/{output-7HDrYTSQ.mjs → output-ljHaxIHX.mjs} +0 -0
- /package/dist/{parser-kettsjWc.mjs → parser-CTlxybRo.mjs} +0 -0
- /package/dist/{passkey-config-DVzQ3dv3.mjs → passkey-config-BLon3ct9.mjs} +0 -0
- /package/dist/{placeholder-DJLP_HY7.d.mts → placeholder-DdZV3I8x.d.mts} +0 -0
- /package/dist/{portable-text-tQhvPLf1.mjs → portable-text-CSbRjM-T.mjs} +0 -0
- /package/dist/{portable-text-BE7nszX6.d.mts → portable-text-HNmwL-7L.d.mts} +0 -0
- /package/dist/{process-cache-C19OA3am.mjs → process-cache-CMy5M80h.mjs} +0 -0
- /package/dist/{provider-loader-DERzBMUz.mjs → provider-loader-DlaT1usE.mjs} +0 -0
- /package/dist/{public-discovery-BGyhuD5U.mjs → public-discovery-BnqYofSK.mjs} +0 -0
- /package/dist/{public-url-DFXUU6Wp.mjs → public-url-BHjYWuaN.mjs} +0 -0
- /package/dist/{public-url-sR8SVmTt.mjs → public-url-GQygrYmg.mjs} +0 -0
- /package/dist/{redirect-BxacnBYL.mjs → redirect-CokmLN5o.mjs} +0 -0
- /package/dist/{request-cache-8_ifFzVw.mjs → request-cache-CizvDoxV.mjs} +0 -0
- /package/dist/{resolve-DEKC4qVa.mjs → resolve-BxFGSKYu.mjs} +0 -0
- /package/dist/{runtime-env-CPTzh0mZ.mjs → runtime-env-DpYGy4pT.mjs} +0 -0
- /package/dist/{scheduled-publish-BxdShRGs.d.mts → scheduled-publish-eCNGpvNm.d.mts} +0 -0
- /package/dist/{seo-contributions-LEFs1d7w.mjs → seo-contributions-ZKqrqsdT.mjs} +0 -0
- /package/dist/{service-kQ5ljRzX.mjs → service-DeX1PRNt.mjs} +0 -0
- /package/dist/{session-user-eweCNKzW.mjs → session-user-D36BRaZY.mjs} +0 -0
- /package/dist/{setup-nonce-B6A5Y1ea.mjs → setup-nonce-B9IO7PbK.mjs} +0 -0
- /package/dist/{sidecar-client-BwPhhz-F.mjs → sidecar-client-2hx5G46s.mjs} +0 -0
- /package/dist/{slugify-kD31VIv2.mjs → slugify-DvoaEPtL.mjs} +0 -0
- /package/dist/{ssrf-C9dyjU8O.mjs → ssrf-DcD8vn3E.mjs} +0 -0
- /package/dist/{stable-hash-B9Tbb2f_.mjs → stable-hash-9RDJgfif.mjs} +0 -0
- /package/dist/{status-Bjf_uSrW.mjs → status-B2xUokyJ.mjs} +0 -0
- /package/dist/{transport-BrU1aDY5.mjs → transport-BHYE4pox.mjs} +0 -0
- /package/dist/{transport-CZbtxgKZ.d.mts → transport-CVU5rp7W.d.mts} +0 -0
- /package/dist/{types-DNBL-4Sn.mjs → types-B3Uq7Czg.mjs} +0 -0
- /package/dist/{types-DsJTXStN.d.mts → types-BJztoTbF.d.mts} +0 -0
- /package/dist/{types-COvyXIp7.mjs → types-BgUxCuwu.mjs} +0 -0
- /package/dist/{types-KFzuijKE.d.mts → types-C0heD9oI.d.mts} +0 -0
- /package/dist/{types-B03h5jt_.d.mts → types-DheoByey.d.mts} +0 -0
- /package/dist/{types-SlLXjRpg.d.mts → types-I5LHzk_M.d.mts} +0 -0
- /package/dist/{types-PLJ9hlhh.mjs → types-Nm0cMxEh.mjs} +0 -0
- /package/dist/{types-CtGSEKEJ.d.mts → types-PxxPTFSl.d.mts} +0 -0
- /package/dist/{url-DGG3hw_h.mjs → url-Coamqvs4.mjs} +0 -0
- /package/dist/{url-DUz3LbCs.mjs → url-dn4mFfCI.mjs} +0 -0
- /package/dist/{workers-build-5UQ4j69Q.mjs → workers-build-4926MPc0.mjs} +0 -0
|
@@ -1,23 +1,304 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as __exportAll } from "./runner-CuG8o1uW.mjs";
|
|
2
|
+
import { getRequestContext } from "./request-context.mjs";
|
|
3
|
+
import { AtomicWriteConflict, atomicBatch, prepareAtomicChecks, rowUnchanged } from "./database/batch.mjs";
|
|
2
4
|
import { t as validateIdentifier } from "./validate-Co3j6T_K.mjs";
|
|
3
5
|
import { r as isI18nEnabled } from "./config-XW5tMrH8.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { t as
|
|
7
|
-
import {
|
|
8
|
-
import { t as
|
|
9
|
-
import { t as
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { t as
|
|
14
|
-
import {
|
|
15
|
-
import { t as
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
6
|
+
import { i as resolveContentPartition, n as contentDigest, o as ContentStorageError, s as ContentStorageReplay } from "./config-6R0bchVE.mjs";
|
|
7
|
+
import { d as contentPartitionWritable, p as readContentPartitionRoute, r as getContentStorage } from "./runtime-Ch5G-tnG.mjs";
|
|
8
|
+
import { n as readRevisionDataBatch, r as storedRevisionIndex, t as readRevisionData } from "./revisions-CQ7rMP5d.mjs";
|
|
9
|
+
import { r as encodeBase64, t as decodeBase64 } from "./base64-qvSs0Gxy.mjs";
|
|
10
|
+
import { n as ScheduledNotDueError, t as DinewayValidationError } from "./types-BI3ULB3A.mjs";
|
|
11
|
+
import { t as contentWriteChecks } from "./atomic-authority-Bf5QZboB.mjs";
|
|
12
|
+
import { a as prepareContentHookEvents, s as contentStorageHookSnapshotSchema, t as ContentRepository } from "./content-BigS8BAv.mjs";
|
|
13
|
+
import { r as requestCached } from "./request-cache-CizvDoxV.mjs";
|
|
14
|
+
import { o as invalidateCollectionCache, s as invalidateCommentObjectCache } from "./object-cache-DyI1SOBK.mjs";
|
|
15
|
+
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-Bb56aCtB.mjs";
|
|
16
|
+
import { t as BylineRepository } from "./byline-3qjp1-oa.mjs";
|
|
17
|
+
import { i as storedContentSeo, r as snapshotOwnedContentMetadata, t as contentEventBylines } from "./owned-metadata-BPmUjZqI.mjs";
|
|
18
|
+
import { t as RevisionRepository } from "./revision-B_HYO2AE.mjs";
|
|
19
|
+
import { t as UserRepository } from "./user-Bl2_8rhJ.mjs";
|
|
20
|
+
import { i as snapshotPartitionTerms, n as prepareContentTerms, r as snapshotContentTermChanges } from "./terms-EskuqbKE.mjs";
|
|
21
|
+
import { t as RedirectRepository } from "./redirect-CJ-FAbNK.mjs";
|
|
22
|
+
import { i as invalidateRedirectCache } from "./cache-DsEbwFVE.mjs";
|
|
23
|
+
import { r as parseAllowedMimeTypes, t as matchesMimeAllowlist } from "./mime-FkfazULS.mjs";
|
|
24
|
+
import { n as extractSearchableFields } from "./text-extraction-CdqMGYQK.mjs";
|
|
25
|
+
import { a as contentVersionSchema } from "./version-store-BXv2D0de.mjs";
|
|
26
|
+
import { r as markContentWriteReplay, t as beginContentWriteIntent } from "./write-intent-DuHVqks9.mjs";
|
|
27
|
+
import { t as SeoRepository } from "./seo-Cv7ud_m2.mjs";
|
|
19
28
|
import { sql } from "kysely";
|
|
29
|
+
import { ulid } from "ulidx";
|
|
30
|
+
import { z } from "zod";
|
|
20
31
|
|
|
32
|
+
//#region src/content-storage/partition-snapshot.ts
|
|
33
|
+
/** Resolver code sees only declared snapshots; their primary rows are fenced at activation. */
|
|
34
|
+
async function snapshotPartitionDependencies(db, collection, item, rule, changes) {
|
|
35
|
+
const checks = [];
|
|
36
|
+
const dependencies = {
|
|
37
|
+
taxonomies: {},
|
|
38
|
+
references: {}
|
|
39
|
+
};
|
|
40
|
+
if ("field" in rule.partitionBy) return {
|
|
41
|
+
dependencies,
|
|
42
|
+
checks
|
|
43
|
+
};
|
|
44
|
+
const taxonomies = {};
|
|
45
|
+
for (const name of rule.partitionBy.taxonomies ?? []) {
|
|
46
|
+
const snapshot = await snapshotPartitionTerms(db, collection, item.id, name, item.locale ?? "en", changes?.[name]);
|
|
47
|
+
taxonomies[name] = snapshot.terms;
|
|
48
|
+
checks.push(...snapshot.checks);
|
|
49
|
+
}
|
|
50
|
+
const references = {};
|
|
51
|
+
for (const [field, definition] of Object.entries(rule.partitionBy.references ?? {})) {
|
|
52
|
+
const value = item.data[field];
|
|
53
|
+
if (value == null || value === "") {
|
|
54
|
+
references[field] = null;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const id = typeof value === "string" ? value : z.object({
|
|
58
|
+
id: z.string(),
|
|
59
|
+
collection: z.literal(definition.collection).optional()
|
|
60
|
+
}).parse(value).id;
|
|
61
|
+
const snapshot = await new ContentRepository(db).snapshot(definition.collection, id);
|
|
62
|
+
if (!snapshot) throw new ContentStorageError("INVALID_PARTITION", `Partition reference ${field} does not exist.`);
|
|
63
|
+
checks.push(snapshot.check);
|
|
64
|
+
const relatedTerms = {};
|
|
65
|
+
for (const name of definition.taxonomies ?? []) {
|
|
66
|
+
const terms = await snapshotPartitionTerms(db, definition.collection, id, name, snapshot.item.locale ?? "en");
|
|
67
|
+
relatedTerms[name] = terms.terms;
|
|
68
|
+
checks.push(...terms.checks);
|
|
69
|
+
}
|
|
70
|
+
references[field] = {
|
|
71
|
+
collection: definition.collection,
|
|
72
|
+
id,
|
|
73
|
+
data: z.record(z.string(), z.json()).parse(snapshot.item.data),
|
|
74
|
+
taxonomies: relatedTerms
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
dependencies.taxonomies = taxonomies;
|
|
78
|
+
dependencies.references = references;
|
|
79
|
+
return {
|
|
80
|
+
dependencies,
|
|
81
|
+
checks
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/content-storage/projection.ts
|
|
87
|
+
/** A central list/search projection; full bodies are loaded through the directory. */
|
|
88
|
+
function contentProjectionValues(item, fields, full = false) {
|
|
89
|
+
const values = {
|
|
90
|
+
id: item.id,
|
|
91
|
+
slug: item.slug,
|
|
92
|
+
status: item.status,
|
|
93
|
+
author_id: item.authorId,
|
|
94
|
+
primary_byline_id: item.primaryBylineId,
|
|
95
|
+
created_at: item.createdAt,
|
|
96
|
+
updated_at: item.updatedAt,
|
|
97
|
+
published_at: item.publishedAt,
|
|
98
|
+
scheduled_at: item.scheduledAt,
|
|
99
|
+
version: item.version,
|
|
100
|
+
live_revision_id: item.liveRevisionId,
|
|
101
|
+
draft_revision_id: item.draftRevisionId,
|
|
102
|
+
locale: item.locale ?? "en",
|
|
103
|
+
translation_group: item.translationGroup
|
|
104
|
+
};
|
|
105
|
+
for (const field of fields) {
|
|
106
|
+
if (!full && field.type === "portableText" && field.searchable === 1 && field.unique !== 1) {
|
|
107
|
+
values[field.slug] = extractSearchableFields(item.data, [field.slug])[field.slug] ?? "";
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const value = full || field.column_type !== "JSON" || field.unique === 1 || field.searchable === 1 ? item.data[field.slug] : void 0;
|
|
111
|
+
values[field.slug] = value == null ? field.required ? "null" : null : typeof value === "object" ? JSON.stringify(value) : value;
|
|
112
|
+
}
|
|
113
|
+
return values;
|
|
114
|
+
}
|
|
115
|
+
function prepareContentProjection(db, collection, item, fields, create, full = false) {
|
|
116
|
+
const values = contentProjectionValues(item, fields, full);
|
|
117
|
+
const columns = Object.keys(values);
|
|
118
|
+
return create ? sql`INSERT INTO ${sql.table(`ec_${collection}`)} (${sql.join(columns.map((column) => sql.ref(column)))}) VALUES (${sql.join(columns.map((column) => values[column] === null ? sql`NULL` : sql`${values[column]}`))})`.compile(db) : sql`UPDATE ${sql.table(`ec_${collection}`)} SET ${sql.join(columns.filter((column) => column !== "id").map((column) => sql`${sql.ref(column)} = ${values[column] === null ? sql`NULL` : sql`${values[column]}`} `))} WHERE id = ${item.id}`.compile(db);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/content-storage/prepare-write.ts
|
|
123
|
+
async function prepareRoutedContentWrite(options) {
|
|
124
|
+
const { db, collection, item } = options;
|
|
125
|
+
const storage = getContentStorage(db, collection);
|
|
126
|
+
if (!storage) return void 0;
|
|
127
|
+
const location = await storage.coordinator.locate(collection, item.id);
|
|
128
|
+
const rootVersion = options.rootVersion ?? ulid();
|
|
129
|
+
const operationId = options.operationId ?? rootVersion;
|
|
130
|
+
const principalId = getRequestContext()?.writePrincipal?.id ?? "system";
|
|
131
|
+
const partitionSnapshot = await snapshotPartitionDependencies(db, collection, item, storage.runtime.config.rules[collection], options.terms);
|
|
132
|
+
const resolved = await resolveContentPartition(storage.runtime.config, {
|
|
133
|
+
collection,
|
|
134
|
+
id: item.id,
|
|
135
|
+
data: contentVersionSchema.shape.data.parse(item.data),
|
|
136
|
+
dependencies: partitionSnapshot.dependencies
|
|
137
|
+
}, storage.runtime.resolvers);
|
|
138
|
+
if (!resolved) throw new Error("Content storage rule is unavailable.");
|
|
139
|
+
const partition = await readContentPartitionRoute(db, collection, resolved.partition);
|
|
140
|
+
if (partition.route.state === "frozen") throw new ContentStorageError("FROZEN", "Content in this partition is temporarily read-only during migration. Please retry shortly.");
|
|
141
|
+
if (partition.route.target_store !== resolved.store) throw new Error("The partition mapping requires an explicit storage migration.");
|
|
142
|
+
const destination = {
|
|
143
|
+
partition: resolved.partition,
|
|
144
|
+
store: partition.route.store
|
|
145
|
+
};
|
|
146
|
+
if (partition.route.store === "primary") {
|
|
147
|
+
const data = contentVersionSchema.shape.data.parse(item.data);
|
|
148
|
+
const command = {
|
|
149
|
+
collection,
|
|
150
|
+
entryId: item.id,
|
|
151
|
+
store: "primary",
|
|
152
|
+
partition: destination.partition,
|
|
153
|
+
partitionEpoch: partition.route.epoch,
|
|
154
|
+
routingVersion: storage.runtime.config.version,
|
|
155
|
+
version: rootVersion,
|
|
156
|
+
digest: await contentDigest(data),
|
|
157
|
+
operationId,
|
|
158
|
+
principalId,
|
|
159
|
+
expectedVersion: location?.version ?? null
|
|
160
|
+
};
|
|
161
|
+
const history = location && location.store !== "primary" ? await db.selectFrom("revisions").selectAll().where("collection", "=", collection).where("entry_id", "=", item.id).execute() : [];
|
|
162
|
+
const snapshots = await readRevisionDataBatch(db, history);
|
|
163
|
+
const effects = options.effects ? await prepareContentHookEvents(db, command, options.effects.snapshot, options.effects.targets) : { statements: [] };
|
|
164
|
+
return {
|
|
165
|
+
checks: [
|
|
166
|
+
...options.checks,
|
|
167
|
+
...partitionSnapshot.checks,
|
|
168
|
+
partition.check,
|
|
169
|
+
...history.map((row) => rowUnchanged("revisions", row))
|
|
170
|
+
],
|
|
171
|
+
statements: [
|
|
172
|
+
...history.map((row, index) => db.updateTable("revisions").set({ data: JSON.stringify(snapshots[index]) }).where("id", "=", row.id).compile()),
|
|
173
|
+
...options.primaryStatements,
|
|
174
|
+
...effects.statements,
|
|
175
|
+
sql`INSERT INTO _dineway_content_locations (collection, entry_id, store, partition, routing_version, version, digest) VALUES (${collection}, ${item.id}, 'primary', ${destination.partition}, ${storage.runtime.config.version}, ${rootVersion}, ${command.digest}) ON CONFLICT (collection, entry_id) DO UPDATE SET store=excluded.store, partition=excluded.partition, routing_version=excluded.routing_version, version=excluded.version, digest=excluded.digest`.compile(db),
|
|
176
|
+
sql`INSERT INTO _dineway_content_operations (id, collection, entry_id, command, state, created_at, updated_at) VALUES (${operationId}, ${collection}, ${item.id}, ${JSON.stringify(command)}, 'committed', ${item.updatedAt}, ${item.updatedAt})`.compile(db)
|
|
177
|
+
]
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const metadata = {
|
|
181
|
+
slug: item.slug,
|
|
182
|
+
status: item.status,
|
|
183
|
+
authorId: item.authorId,
|
|
184
|
+
primaryBylineId: item.primaryBylineId,
|
|
185
|
+
createdAt: item.createdAt,
|
|
186
|
+
updatedAt: item.updatedAt,
|
|
187
|
+
publishedAt: item.publishedAt,
|
|
188
|
+
scheduledAt: item.scheduledAt,
|
|
189
|
+
liveRevisionId: item.liveRevisionId,
|
|
190
|
+
draftRevisionId: item.draftRevisionId,
|
|
191
|
+
version: item.version,
|
|
192
|
+
locale: item.locale,
|
|
193
|
+
translationGroup: item.translationGroup
|
|
194
|
+
};
|
|
195
|
+
const moving = !!location && location.store !== destination.store;
|
|
196
|
+
const existingRevisions = moving ? await db.selectFrom("revisions").selectAll().where("collection", "=", collection).where("entry_id", "=", item.id).execute() : [];
|
|
197
|
+
const history = [];
|
|
198
|
+
const retainedRevisions = existingRevisions.filter((revision) => !options.revisions.some((next) => next.id === revision.id));
|
|
199
|
+
const retainedData = await readRevisionDataBatch(db, retainedRevisions);
|
|
200
|
+
for (const [index, revision] of retainedRevisions.entries()) history.push({
|
|
201
|
+
id: revision.id,
|
|
202
|
+
data: retainedData[index],
|
|
203
|
+
authorId: revision.author_id ?? void 0
|
|
204
|
+
});
|
|
205
|
+
const historicalIds = new Set(history.map((revision) => revision.id));
|
|
206
|
+
const revisions = await Promise.all([...history, ...options.revisions].map(async (revision) => {
|
|
207
|
+
const data = contentVersionSchema.shape.data.parse(revision.data);
|
|
208
|
+
const version = historicalIds.has(revision.id) || revision.replace ? await contentDigest({
|
|
209
|
+
rootVersion,
|
|
210
|
+
revisionId: revision.id
|
|
211
|
+
}) : revision.id;
|
|
212
|
+
return {
|
|
213
|
+
revision,
|
|
214
|
+
data,
|
|
215
|
+
reference: {
|
|
216
|
+
collection,
|
|
217
|
+
entryId: item.id,
|
|
218
|
+
store: destination.store,
|
|
219
|
+
partition: destination.partition,
|
|
220
|
+
routingVersion: storage.runtime.config.version,
|
|
221
|
+
version,
|
|
222
|
+
digest: await contentDigest(data)
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}));
|
|
226
|
+
const payload = contentVersionSchema.shape.data.parse({
|
|
227
|
+
...item.data,
|
|
228
|
+
_dineway: {
|
|
229
|
+
...metadata,
|
|
230
|
+
...options.owned ? { owned: options.owned } : {},
|
|
231
|
+
partitionDependencies: partitionSnapshot.dependencies,
|
|
232
|
+
revisions: revisions.map((revision) => ({
|
|
233
|
+
id: revision.revision.id,
|
|
234
|
+
...revision.reference
|
|
235
|
+
}))
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
const command = {
|
|
239
|
+
partitionEpoch: partition.route.epoch,
|
|
240
|
+
collection,
|
|
241
|
+
entryId: item.id,
|
|
242
|
+
...destination,
|
|
243
|
+
routingVersion: storage.runtime.config.version,
|
|
244
|
+
version: rootVersion,
|
|
245
|
+
digest: await contentDigest(payload),
|
|
246
|
+
operationId,
|
|
247
|
+
principalId,
|
|
248
|
+
expectedVersion: location?.version ?? null
|
|
249
|
+
};
|
|
250
|
+
const projection = prepareContentProjection(db, collection, item, options.fields, options.create);
|
|
251
|
+
const effects = options.effects ? await prepareContentHookEvents(db, command, options.effects.snapshot, options.effects.targets) : { statements: [] };
|
|
252
|
+
return storage.coordinator.prepareCommit({
|
|
253
|
+
command,
|
|
254
|
+
data: payload
|
|
255
|
+
}, {
|
|
256
|
+
authorize: async () => options.create ? [] : contentWriteChecks(collection, item.id, "edit"),
|
|
257
|
+
prepare: async () => {
|
|
258
|
+
const statements = [];
|
|
259
|
+
const store = storage.stores[destination.store];
|
|
260
|
+
for (const revision of revisions) {
|
|
261
|
+
await store.prepare({
|
|
262
|
+
command: {
|
|
263
|
+
...revision.reference,
|
|
264
|
+
kind: "revision",
|
|
265
|
+
operationId: await contentDigest({
|
|
266
|
+
operationId,
|
|
267
|
+
revisionId: revision.revision.id
|
|
268
|
+
}),
|
|
269
|
+
principalId,
|
|
270
|
+
expectedVersion: null
|
|
271
|
+
},
|
|
272
|
+
data: revision.data
|
|
273
|
+
});
|
|
274
|
+
statements.push(historicalIds.has(revision.revision.id) || revision.revision.replace ? db.updateTable("revisions").set({ data: storedRevisionIndex(revision.reference) }).where("id", "=", revision.revision.id).compile() : db.insertInto("revisions").values({
|
|
275
|
+
id: revision.revision.id,
|
|
276
|
+
collection,
|
|
277
|
+
entry_id: item.id,
|
|
278
|
+
data: storedRevisionIndex(revision.reference),
|
|
279
|
+
author_id: revision.revision.authorId ?? null,
|
|
280
|
+
created_at: item.updatedAt
|
|
281
|
+
}).compile());
|
|
282
|
+
}
|
|
283
|
+
statements.push(projection);
|
|
284
|
+
return {
|
|
285
|
+
checks: [
|
|
286
|
+
...options.checks,
|
|
287
|
+
...partitionSnapshot.checks,
|
|
288
|
+
...existingRevisions.map((revision) => rowUnchanged("revisions", revision)),
|
|
289
|
+
...moving ? [sql`(SELECT COUNT(*) FROM revisions WHERE collection = ${collection} AND entry_id = ${item.id}) = ${existingRevisions.length}`] : []
|
|
290
|
+
],
|
|
291
|
+
statements: [
|
|
292
|
+
...statements,
|
|
293
|
+
...options.globalStatements,
|
|
294
|
+
...effects.statements
|
|
295
|
+
]
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
//#endregion
|
|
21
302
|
//#region src/api/rev.ts
|
|
22
303
|
/**
|
|
23
304
|
* Generate a _rev token from a content item's version and updatedAt.
|
|
@@ -135,6 +416,38 @@ async function validateMediaFields(db, collectionSlug, data) {
|
|
|
135
416
|
|
|
136
417
|
//#endregion
|
|
137
418
|
//#region src/api/handlers/content.ts
|
|
419
|
+
function contentStorageFailure(error) {
|
|
420
|
+
if (!(error instanceof ContentStorageError)) return void 0;
|
|
421
|
+
return {
|
|
422
|
+
success: false,
|
|
423
|
+
error: {
|
|
424
|
+
code: error.code === "INVALID_PARTITION" ? "VALIDATION_ERROR" : error.code === "CONFLICT" || error.code === "ROUTE_CHANGED" ? "CONFLICT" : "CONTENT_STORAGE_UNAVAILABLE",
|
|
425
|
+
message: {
|
|
426
|
+
FROZEN: "This content is temporarily read-only. Please retry shortly.",
|
|
427
|
+
UNAVAILABLE: "Content is temporarily unavailable. Please retry shortly.",
|
|
428
|
+
INVALID_CONFIG: "Content storage is temporarily unavailable. Please retry shortly.",
|
|
429
|
+
INVALID_PARTITION: "The fields used to organize this content are missing or inconsistent. Check them and try again.",
|
|
430
|
+
ROUTE_CHANGED: "Content routing changed. Reload and try again.",
|
|
431
|
+
CONFLICT: "Content changed during this operation. Reload and try again."
|
|
432
|
+
}[error.code]
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
async function commitRoutedContent(db, collection, input, metadata = {}) {
|
|
437
|
+
try {
|
|
438
|
+
const prepared = await prepareContentWrite(db, collection, {
|
|
439
|
+
...input,
|
|
440
|
+
bylines: metadata.bylines,
|
|
441
|
+
seo: metadata.hasSeo ? metadata.seo : void 0
|
|
442
|
+
});
|
|
443
|
+
await atomicBatch(db, prepared.batch);
|
|
444
|
+
prepared.afterCommit();
|
|
445
|
+
return handleContentGet(db, collection, prepared.id);
|
|
446
|
+
} catch (error) {
|
|
447
|
+
if (error instanceof ContentStorageReplay) return markContentWriteReplay(await handleContentGet(db, collection, error.location.entryId));
|
|
448
|
+
throw error;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
138
451
|
/**
|
|
139
452
|
* Extract a slug source (title or name) from content data.
|
|
140
453
|
* Returns null if no suitable string field is found.
|
|
@@ -400,6 +713,8 @@ async function handleContentList(db, collection, params) {
|
|
|
400
713
|
}
|
|
401
714
|
};
|
|
402
715
|
} catch (error) {
|
|
716
|
+
const storageError = contentStorageFailure(error);
|
|
717
|
+
if (storageError) return storageError;
|
|
403
718
|
console.error("Content list error:", error);
|
|
404
719
|
return {
|
|
405
720
|
success: false,
|
|
@@ -427,6 +742,8 @@ async function handleContentAuthors(db, collection) {
|
|
|
427
742
|
})).toSorted((a, b) => (a.name ?? a.email).localeCompare(b.name ?? b.email)) }
|
|
428
743
|
};
|
|
429
744
|
} catch (error) {
|
|
745
|
+
const storageError = contentStorageFailure(error);
|
|
746
|
+
if (storageError) return storageError;
|
|
430
747
|
console.error("Content authors error:", error);
|
|
431
748
|
return {
|
|
432
749
|
success: false,
|
|
@@ -460,6 +777,8 @@ async function handleContentGet(db, collection, id, locale) {
|
|
|
460
777
|
}
|
|
461
778
|
};
|
|
462
779
|
} catch (error) {
|
|
780
|
+
const storageError = contentStorageFailure(error);
|
|
781
|
+
if (storageError) return storageError;
|
|
463
782
|
console.error("Content get error:", error);
|
|
464
783
|
return {
|
|
465
784
|
success: false,
|
|
@@ -494,6 +813,8 @@ async function handleContentGetIncludingTrashed(db, collection, id, locale) {
|
|
|
494
813
|
}
|
|
495
814
|
};
|
|
496
815
|
} catch (error) {
|
|
816
|
+
const storageError = contentStorageFailure(error);
|
|
817
|
+
if (storageError) return storageError;
|
|
497
818
|
console.error("Content get error:", error);
|
|
498
819
|
return {
|
|
499
820
|
success: false,
|
|
@@ -527,6 +848,25 @@ async function handleContentCreate(db, collection, body) {
|
|
|
527
848
|
if (fieldCheck) return fieldCheck;
|
|
528
849
|
const mimeCheck = await validateMediaFields(db, collection, body.data);
|
|
529
850
|
if (!mimeCheck.success) return mimeCheck;
|
|
851
|
+
if (getContentStorage(db, collection)) {
|
|
852
|
+
if (body.status && body.status !== "draft" && body.status !== "published") throw new DinewayValidationError("Content must be created as a draft or published item.");
|
|
853
|
+
return await commitRoutedContent(db, collection, {
|
|
854
|
+
operationId: body.operationId,
|
|
855
|
+
data: body.data,
|
|
856
|
+
terms: body.terms,
|
|
857
|
+
slug: body.slug,
|
|
858
|
+
authorId: body.authorId,
|
|
859
|
+
locale: body.locale,
|
|
860
|
+
translationOf: body.translationOf,
|
|
861
|
+
createdAt: body.createdAt,
|
|
862
|
+
publishedAt: body.publishedAt,
|
|
863
|
+
publish: body.status === "published"
|
|
864
|
+
}, {
|
|
865
|
+
bylines: body.bylines,
|
|
866
|
+
seo: body.seo,
|
|
867
|
+
hasSeo
|
|
868
|
+
});
|
|
869
|
+
}
|
|
530
870
|
const repo = new ContentRepository(db);
|
|
531
871
|
let slug = body.slug;
|
|
532
872
|
if (!slug) {
|
|
@@ -546,6 +886,11 @@ async function handleContentCreate(db, collection, body) {
|
|
|
546
886
|
});
|
|
547
887
|
const checks = [...prepared.batch.checks ?? [], ...configuration.checks];
|
|
548
888
|
const statements = [...prepared.batch.statements];
|
|
889
|
+
if (body.terms) {
|
|
890
|
+
const terms = await prepareContentTerms(db, collection, prepared.id, body.terms, body.locale ?? "en");
|
|
891
|
+
checks.push(...terms.checks ?? []);
|
|
892
|
+
statements.push(...terms.statements);
|
|
893
|
+
}
|
|
549
894
|
if (usesDraftRevisions && (!body.status || body.status === "draft")) {
|
|
550
895
|
const draft = await repo.prepareDraftSnapshot(collection, prepared.id, body.authorId);
|
|
551
896
|
checks.push(...draft.checks ?? []);
|
|
@@ -577,6 +922,8 @@ async function handleContentCreate(db, collection, body) {
|
|
|
577
922
|
}
|
|
578
923
|
};
|
|
579
924
|
} catch (error) {
|
|
925
|
+
const storageError = contentStorageFailure(error);
|
|
926
|
+
if (storageError) return storageError;
|
|
580
927
|
console.error("Content create error:", error);
|
|
581
928
|
return {
|
|
582
929
|
success: false,
|
|
@@ -613,6 +960,30 @@ async function handleContentUpdate(db, collection, id, body, options = {}) {
|
|
|
613
960
|
}
|
|
614
961
|
const repo = new ContentRepository(db);
|
|
615
962
|
const resolvedId = await resolveId(repo, collection, id, body.locale) ?? id;
|
|
963
|
+
if (getContentStorage(db, collection)) {
|
|
964
|
+
const existing = await repo.findById(collection, resolvedId);
|
|
965
|
+
if (!existing) throw new ContentUpdateApiError("NOT_FOUND", `Content item not found: ${id}`);
|
|
966
|
+
if (body.status && body.status !== "draft" && body.status !== "published") throw new DinewayValidationError("Use the scheduling endpoint to change scheduled content.");
|
|
967
|
+
return await commitRoutedContent(db, collection, {
|
|
968
|
+
operationId: body.operationId,
|
|
969
|
+
id: resolvedId,
|
|
970
|
+
data: body.data,
|
|
971
|
+
terms: body.terms,
|
|
972
|
+
slug: body.slug,
|
|
973
|
+
authorId: body.authorId,
|
|
974
|
+
expectedRev: body._rev,
|
|
975
|
+
publishedAt: body.publishedAt,
|
|
976
|
+
stageDraft: !!options.stageDraft && !!body.data,
|
|
977
|
+
reuseDraftRevision: options.skipRevision,
|
|
978
|
+
publish: body.status === "published",
|
|
979
|
+
unpublish: existing.status === "published" && body.status === "draft",
|
|
980
|
+
status: body.status === "draft" ? "draft" : void 0
|
|
981
|
+
}, {
|
|
982
|
+
bylines: body.bylines,
|
|
983
|
+
seo: body.seo,
|
|
984
|
+
hasSeo
|
|
985
|
+
});
|
|
986
|
+
}
|
|
616
987
|
const snapshot = await repo.snapshot(collection, resolvedId);
|
|
617
988
|
if (!snapshot) throw new ContentUpdateApiError("NOT_FOUND", `Content item not found: ${id}`);
|
|
618
989
|
const existing = snapshot.item;
|
|
@@ -624,6 +995,11 @@ async function handleContentUpdate(db, collection, id, body, options = {}) {
|
|
|
624
995
|
...contentWriteChecks(collection, resolvedId, "edit")
|
|
625
996
|
];
|
|
626
997
|
const statements = [];
|
|
998
|
+
if (body.terms) {
|
|
999
|
+
const terms = await prepareContentTerms(db, collection, resolvedId, body.terms, existing.locale ?? "en");
|
|
1000
|
+
checks.push(...terms.checks ?? []);
|
|
1001
|
+
statements.push(...terms.statements);
|
|
1002
|
+
}
|
|
627
1003
|
const stageDraft = options.stageDraft && body.data && await collectionSupportsRevisions(db, collection);
|
|
628
1004
|
if (stageDraft) {
|
|
629
1005
|
const revisions = new RevisionRepository(db);
|
|
@@ -686,6 +1062,8 @@ async function handleContentUpdate(db, collection, id, body, options = {}) {
|
|
|
686
1062
|
}
|
|
687
1063
|
};
|
|
688
1064
|
} catch (error) {
|
|
1065
|
+
const storageError = contentStorageFailure(error);
|
|
1066
|
+
if (storageError) return storageError;
|
|
689
1067
|
if (error instanceof AtomicWriteConflict) return {
|
|
690
1068
|
success: false,
|
|
691
1069
|
error: {
|
|
@@ -722,6 +1100,43 @@ async function handleContentDuplicate(db, collection, id, authorId) {
|
|
|
722
1100
|
const hasSeo = configuration.row?.has_seo === 1;
|
|
723
1101
|
const repo = new ContentRepository(db);
|
|
724
1102
|
const resolvedId = await resolveId(repo, collection, id) ?? id;
|
|
1103
|
+
if (getContentStorage(db, collection)) {
|
|
1104
|
+
const snapshot = await repo.snapshot(collection, resolvedId);
|
|
1105
|
+
if (!snapshot) throw new DinewayValidationError("Content item not found");
|
|
1106
|
+
const data = { ...snapshot.item.data };
|
|
1107
|
+
if (typeof data.title === "string") data.title += " (Copy)";
|
|
1108
|
+
else if (typeof data.name === "string") data.name += " (Copy)";
|
|
1109
|
+
const terms = await snapshotContentTermChanges(db, collection, resolvedId);
|
|
1110
|
+
const metadata = await snapshotOwnedContentMetadata(db, collection, resolvedId);
|
|
1111
|
+
const bylines = await new BylineRepository(db).getContentBylines(collection, resolvedId, { locale: snapshot.item.locale ?? void 0 });
|
|
1112
|
+
const seo = hasSeo ? await new SeoRepository(db).get(collection, resolvedId) : void 0;
|
|
1113
|
+
const prepared = await prepareContentWrite(db, collection, {
|
|
1114
|
+
data,
|
|
1115
|
+
terms: terms.changes,
|
|
1116
|
+
bylines: bylines.map((credit) => ({
|
|
1117
|
+
bylineId: credit.byline.id,
|
|
1118
|
+
roleLabel: credit.roleLabel
|
|
1119
|
+
})),
|
|
1120
|
+
seo: seo ? {
|
|
1121
|
+
...seo,
|
|
1122
|
+
canonical: null
|
|
1123
|
+
} : void 0,
|
|
1124
|
+
authorId: authorId ?? snapshot.item.authorId,
|
|
1125
|
+
locale: snapshot.item.locale ?? void 0
|
|
1126
|
+
});
|
|
1127
|
+
await atomicBatch(db, {
|
|
1128
|
+
checks: [
|
|
1129
|
+
...prepared.batch.checks ?? [],
|
|
1130
|
+
...metadata.checks,
|
|
1131
|
+
...terms.checks,
|
|
1132
|
+
snapshot.check,
|
|
1133
|
+
...contentWriteChecks(collection, resolvedId, "edit")
|
|
1134
|
+
],
|
|
1135
|
+
statements: prepared.batch.statements
|
|
1136
|
+
});
|
|
1137
|
+
prepared.afterCommit();
|
|
1138
|
+
return await handleContentGet(db, collection, prepared.id);
|
|
1139
|
+
}
|
|
725
1140
|
const prepared = await repo.prepareDuplicate(collection, resolvedId, authorId);
|
|
726
1141
|
const bylines = await new BylineRepository(db).prepareCopyContentBylines(collection, resolvedId, prepared.id);
|
|
727
1142
|
const checks = [
|
|
@@ -750,6 +1165,8 @@ async function handleContentDuplicate(db, collection, id, authorId) {
|
|
|
750
1165
|
data: { item: duplicate }
|
|
751
1166
|
};
|
|
752
1167
|
} catch (err) {
|
|
1168
|
+
const storageError = contentStorageFailure(err);
|
|
1169
|
+
if (storageError) return storageError;
|
|
753
1170
|
if (err instanceof DinewayValidationError) return {
|
|
754
1171
|
success: false,
|
|
755
1172
|
error: {
|
|
@@ -793,6 +1210,8 @@ async function handleContentDelete(db, collection, id) {
|
|
|
793
1210
|
}
|
|
794
1211
|
};
|
|
795
1212
|
} catch (error) {
|
|
1213
|
+
const storageError = contentStorageFailure(error);
|
|
1214
|
+
if (storageError) return storageError;
|
|
796
1215
|
console.error("Content delete error:", error);
|
|
797
1216
|
return {
|
|
798
1217
|
success: false,
|
|
@@ -826,6 +1245,8 @@ async function handleContentRestore(db, collection, id) {
|
|
|
826
1245
|
}
|
|
827
1246
|
};
|
|
828
1247
|
} catch (error) {
|
|
1248
|
+
const storageError = contentStorageFailure(error);
|
|
1249
|
+
if (storageError) return storageError;
|
|
829
1250
|
console.error("Content restore error:", error);
|
|
830
1251
|
return {
|
|
831
1252
|
success: false,
|
|
@@ -844,22 +1265,8 @@ async function handleContentPermanentDelete(db, collection, id) {
|
|
|
844
1265
|
try {
|
|
845
1266
|
const repo = new ContentRepository(db);
|
|
846
1267
|
const resolvedId = await resolveIdIncludingTrashed(repo, collection, id) ?? id;
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
if (snapshot && deleted) {
|
|
850
|
-
await atomicBatch(db, {
|
|
851
|
-
checks: [snapshot.check, ...contentWriteChecks(collection, resolvedId, "permanent")],
|
|
852
|
-
statements: [
|
|
853
|
-
sql`DELETE FROM ${sql.table(`ec_${collection}`)} WHERE id = ${resolvedId} AND deleted_at IS NOT NULL`.compile(db),
|
|
854
|
-
db.deleteFrom("_dineway_seo").where("collection", "=", collection).where("content_id", "=", resolvedId).compile(),
|
|
855
|
-
db.deleteFrom("_dineway_comments").where("collection", "=", collection).where("content_id", "=", resolvedId).compile(),
|
|
856
|
-
db.deleteFrom("revisions").where("collection", "=", collection).where("entry_id", "=", resolvedId).compile(),
|
|
857
|
-
db.deleteFrom("_dineway_content_bylines").where("collection_slug", "=", collection).where("content_id", "=", resolvedId).compile()
|
|
858
|
-
]
|
|
859
|
-
});
|
|
860
|
-
invalidateCollectionCache(collection);
|
|
861
|
-
invalidateCommentObjectCache();
|
|
862
|
-
}
|
|
1268
|
+
const deleted = await repo.permanentDelete(collection, resolvedId);
|
|
1269
|
+
if (deleted) invalidateCommentObjectCache();
|
|
863
1270
|
if (!deleted) return {
|
|
864
1271
|
success: false,
|
|
865
1272
|
error: {
|
|
@@ -875,6 +1282,8 @@ async function handleContentPermanentDelete(db, collection, id) {
|
|
|
875
1282
|
}
|
|
876
1283
|
};
|
|
877
1284
|
} catch (error) {
|
|
1285
|
+
const storageError = contentStorageFailure(error);
|
|
1286
|
+
if (storageError) return storageError;
|
|
878
1287
|
console.error("Content permanent delete error:", error);
|
|
879
1288
|
return {
|
|
880
1289
|
success: false,
|
|
@@ -913,6 +1322,8 @@ async function handleContentListTrashed(db, collection, options = {}) {
|
|
|
913
1322
|
}
|
|
914
1323
|
};
|
|
915
1324
|
} catch (error) {
|
|
1325
|
+
const storageError = contentStorageFailure(error);
|
|
1326
|
+
if (storageError) return storageError;
|
|
916
1327
|
console.error("Content list trashed error:", error);
|
|
917
1328
|
return {
|
|
918
1329
|
success: false,
|
|
@@ -933,6 +1344,8 @@ async function handleContentCountTrashed(db, collection) {
|
|
|
933
1344
|
data: { count: await new ContentRepository(db).countTrashed(collection) }
|
|
934
1345
|
};
|
|
935
1346
|
} catch (error) {
|
|
1347
|
+
const storageError = contentStorageFailure(error);
|
|
1348
|
+
if (storageError) return storageError;
|
|
936
1349
|
console.error("Content count trashed error:", error);
|
|
937
1350
|
return {
|
|
938
1351
|
success: false,
|
|
@@ -957,6 +1370,8 @@ async function handleContentSchedule(db, collection, id, scheduledAt) {
|
|
|
957
1370
|
data: { item }
|
|
958
1371
|
};
|
|
959
1372
|
} catch (error) {
|
|
1373
|
+
const storageError = contentStorageFailure(error);
|
|
1374
|
+
if (storageError) return storageError;
|
|
960
1375
|
if (error instanceof DinewayValidationError) return {
|
|
961
1376
|
success: false,
|
|
962
1377
|
error: {
|
|
@@ -988,6 +1403,8 @@ async function handleContentUnschedule(db, collection, id) {
|
|
|
988
1403
|
data: { item }
|
|
989
1404
|
};
|
|
990
1405
|
} catch (error) {
|
|
1406
|
+
const storageError = contentStorageFailure(error);
|
|
1407
|
+
if (storageError) return storageError;
|
|
991
1408
|
if (error instanceof DinewayValidationError) return {
|
|
992
1409
|
success: false,
|
|
993
1410
|
error: {
|
|
@@ -1016,6 +1433,26 @@ async function prepareContentPublication(db, collection, id, options = {}) {
|
|
|
1016
1433
|
const configuration = await contentWriteConfiguration(db, collection);
|
|
1017
1434
|
const repo = new ContentRepository(db);
|
|
1018
1435
|
const resolvedId = await resolveId(repo, collection, id) ?? id;
|
|
1436
|
+
if (getContentStorage(db, collection)) {
|
|
1437
|
+
const snapshot = await repo.snapshot(collection, resolvedId);
|
|
1438
|
+
if (!snapshot) throw new DinewayValidationError("Content item not found");
|
|
1439
|
+
if (options.requireScheduledDue && (!snapshot.item.scheduledAt || snapshot.item.scheduledAt > (/* @__PURE__ */ new Date()).toISOString())) throw new ScheduledNotDueError();
|
|
1440
|
+
const prepared = await prepareContentWrite(db, collection, {
|
|
1441
|
+
id: resolvedId,
|
|
1442
|
+
publish: true,
|
|
1443
|
+
publishedAt: options.publishedAt,
|
|
1444
|
+
expectedRev: encodeRev(snapshot.item)
|
|
1445
|
+
});
|
|
1446
|
+
return {
|
|
1447
|
+
resolvedId,
|
|
1448
|
+
previous: snapshot.item,
|
|
1449
|
+
slugChanged: !!snapshot.item.slug && snapshot.item.slug !== prepared.item.slug,
|
|
1450
|
+
batch: {
|
|
1451
|
+
checks: [...prepared.batch.checks ?? [], snapshot.check],
|
|
1452
|
+
statements: [...prepared.batch.statements]
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1019
1456
|
const prepared = await repo.preparePublish(collection, resolvedId, options.publishedAt, options.requireScheduledDue);
|
|
1020
1457
|
const statements = [...prepared.batch.statements];
|
|
1021
1458
|
const existing = prepared.previous;
|
|
@@ -1047,6 +1484,8 @@ async function handleContentPublish(db, collection, id, options = {}) {
|
|
|
1047
1484
|
data: { item }
|
|
1048
1485
|
};
|
|
1049
1486
|
} catch (error) {
|
|
1487
|
+
const storageError = contentStorageFailure(error);
|
|
1488
|
+
if (storageError) return storageError;
|
|
1050
1489
|
if (error instanceof DinewayValidationError) return {
|
|
1051
1490
|
success: false,
|
|
1052
1491
|
error: {
|
|
@@ -1081,6 +1520,10 @@ async function handleContentUnpublish(db, collection, id) {
|
|
|
1081
1520
|
try {
|
|
1082
1521
|
const repo = new ContentRepository(db);
|
|
1083
1522
|
const resolvedId = await resolveId(repo, collection, id) ?? id;
|
|
1523
|
+
if (getContentStorage(db, collection)) return await commitRoutedContent(db, collection, {
|
|
1524
|
+
id: resolvedId,
|
|
1525
|
+
unpublish: true
|
|
1526
|
+
});
|
|
1084
1527
|
const item = await repo.unpublish(collection, resolvedId);
|
|
1085
1528
|
await hydrateSeo(db, collection, item, await collectionHasSeo(db, collection));
|
|
1086
1529
|
return {
|
|
@@ -1088,6 +1531,8 @@ async function handleContentUnpublish(db, collection, id) {
|
|
|
1088
1531
|
data: { item }
|
|
1089
1532
|
};
|
|
1090
1533
|
} catch (error) {
|
|
1534
|
+
const storageError = contentStorageFailure(error);
|
|
1535
|
+
if (storageError) return storageError;
|
|
1091
1536
|
if (error instanceof DinewayValidationError) return {
|
|
1092
1537
|
success: false,
|
|
1093
1538
|
error: {
|
|
@@ -1115,6 +1560,8 @@ async function handleContentCountScheduled(db, collection) {
|
|
|
1115
1560
|
data: { count: await new ContentRepository(db).countScheduled(collection) }
|
|
1116
1561
|
};
|
|
1117
1562
|
} catch (error) {
|
|
1563
|
+
const storageError = contentStorageFailure(error);
|
|
1564
|
+
if (storageError) return storageError;
|
|
1118
1565
|
console.error("Content count scheduled error:", error);
|
|
1119
1566
|
return {
|
|
1120
1567
|
success: false,
|
|
@@ -1139,6 +1586,8 @@ async function handleContentDiscardDraft(db, collection, id) {
|
|
|
1139
1586
|
data: { item }
|
|
1140
1587
|
};
|
|
1141
1588
|
} catch (error) {
|
|
1589
|
+
const storageError = contentStorageFailure(error);
|
|
1590
|
+
if (storageError) return storageError;
|
|
1142
1591
|
if (error instanceof DinewayValidationError) return {
|
|
1143
1592
|
success: false,
|
|
1144
1593
|
error: {
|
|
@@ -1181,6 +1630,8 @@ async function handleContentCompare(db, collection, id) {
|
|
|
1181
1630
|
}
|
|
1182
1631
|
};
|
|
1183
1632
|
} catch (error) {
|
|
1633
|
+
const storageError = contentStorageFailure(error);
|
|
1634
|
+
if (storageError) return storageError;
|
|
1184
1635
|
console.error("Content compare error:", error);
|
|
1185
1636
|
return {
|
|
1186
1637
|
success: false,
|
|
@@ -1234,6 +1685,8 @@ async function handleContentTranslations(db, collection, id) {
|
|
|
1234
1685
|
}
|
|
1235
1686
|
};
|
|
1236
1687
|
} catch (error) {
|
|
1688
|
+
const storageError = contentStorageFailure(error);
|
|
1689
|
+
if (storageError) return storageError;
|
|
1237
1690
|
if (error instanceof Error) console.error("Content translations error:", error);
|
|
1238
1691
|
return {
|
|
1239
1692
|
success: false,
|
|
@@ -1274,113 +1727,367 @@ function prepareNonTranslatableFields(db, collectionSlug, updatedItemId, transla
|
|
|
1274
1727
|
}
|
|
1275
1728
|
|
|
1276
1729
|
//#endregion
|
|
1277
|
-
//#region src/
|
|
1278
|
-
|
|
1279
|
-
|
|
1730
|
+
//#region src/api/handlers/content-write.ts
|
|
1731
|
+
var content_write_exports = /* @__PURE__ */ __exportAll({
|
|
1732
|
+
prepareContentWrite: () => prepareContentWrite,
|
|
1733
|
+
preparedContentReview: () => preparedContentReview
|
|
1734
|
+
});
|
|
1735
|
+
const fieldData = (data) => Object.fromEntries(Object.entries(data).filter(([key]) => !key.startsWith("_")));
|
|
1736
|
+
const reviews = /* @__PURE__ */ new WeakMap();
|
|
1737
|
+
function preparedContentReview(write) {
|
|
1738
|
+
const stored = reviews.get(write);
|
|
1739
|
+
if (!stored) throw new DinewayValidationError("Review requires an unmodified prepared content write.");
|
|
1740
|
+
return structuredClone(stored);
|
|
1280
1741
|
}
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1742
|
+
/** Prepare a draft or direct backing-row edit without committing site-owned writes separately. */
|
|
1743
|
+
async function prepareContentWrite(db, collection, input) {
|
|
1744
|
+
return prepareContentWriteInternal(db, collection, input, true);
|
|
1745
|
+
}
|
|
1746
|
+
async function prepareContentWriteInternal(db, collection, input, syncTranslations) {
|
|
1747
|
+
const configuration = await contentWriteConfiguration(db, collection);
|
|
1748
|
+
const supports = JSON.parse(configuration.row?.supports ?? "[]");
|
|
1749
|
+
const usesRevisions = Array.isArray(supports) && supports.includes("revisions");
|
|
1750
|
+
if (input.seo && configuration.row?.has_seo !== 1) throw new DinewayValidationError("SEO is not enabled for this content type.");
|
|
1751
|
+
if (input.status !== void 0 && input.status !== "draft") throw new DinewayValidationError("Prepared status changes must use publish or unpublish.");
|
|
1752
|
+
if (input.publish && input.unpublish) throw new DinewayValidationError("Publish and unpublish cannot be combined.");
|
|
1753
|
+
const validateData = async (data) => {
|
|
1754
|
+
const fields = await validateContentDataFields(db, collection, fieldData(data));
|
|
1755
|
+
if (fields && !fields.success) throw new DinewayValidationError(fields.error.message);
|
|
1756
|
+
const media = await validateMediaFields(db, collection, fieldData(data));
|
|
1757
|
+
if (!media.success) throw new DinewayValidationError(media.error.message);
|
|
1758
|
+
};
|
|
1759
|
+
if (input.data) await validateData(input.data);
|
|
1760
|
+
const intent = getContentStorage(db, collection) ? await beginContentWriteIntent(db, collection, input, JSON.parse(JSON.stringify(input))) : void 0;
|
|
1761
|
+
const revisionIdentity = intent ? {
|
|
1762
|
+
id: intent.revisionId,
|
|
1763
|
+
createdAt: intent.now
|
|
1764
|
+
} : void 0;
|
|
1765
|
+
const repo = new ContentRepository(db, { prepareIndexWrites: true });
|
|
1766
|
+
const checks = [...configuration.checks];
|
|
1767
|
+
const statements = [];
|
|
1768
|
+
const globalStatements = [];
|
|
1769
|
+
const storageRevisions = [];
|
|
1770
|
+
const translatedWrites = [];
|
|
1771
|
+
let termChanges = input.terms;
|
|
1772
|
+
if (!input.id && input.translationOf && getContentStorage(db, collection)) {
|
|
1773
|
+
const sourceTerms = await snapshotContentTermChanges(db, collection, input.translationOf);
|
|
1774
|
+
checks.push(...sourceTerms.checks);
|
|
1775
|
+
termChanges = {
|
|
1776
|
+
...sourceTerms.changes,
|
|
1777
|
+
...termChanges
|
|
1778
|
+
};
|
|
1287
1779
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1780
|
+
const appendGlobal = (...items) => {
|
|
1781
|
+
statements.push(...items);
|
|
1782
|
+
globalStatements.push(...items);
|
|
1783
|
+
};
|
|
1784
|
+
let item;
|
|
1785
|
+
let previousItem;
|
|
1786
|
+
let previousSlug = null;
|
|
1787
|
+
let wasPublished = false;
|
|
1788
|
+
let live = null;
|
|
1789
|
+
let draft = null;
|
|
1790
|
+
let now = intent?.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1791
|
+
if (input.id) {
|
|
1792
|
+
const snapshot = await repo.snapshot(collection, input.id);
|
|
1793
|
+
if (!snapshot) throw new DinewayValidationError("Content item not found.");
|
|
1794
|
+
previousItem = snapshot.item;
|
|
1795
|
+
if (input.expectedRev !== void 0 && encodeRev(snapshot.item) !== input.expectedRev) throw new AtomicWriteConflict();
|
|
1796
|
+
previousSlug = snapshot.item.slug;
|
|
1797
|
+
wasPublished = snapshot.item.status === "published";
|
|
1798
|
+
item = {
|
|
1799
|
+
...snapshot.item,
|
|
1800
|
+
updatedAt: now,
|
|
1801
|
+
version: snapshot.item.version + 1,
|
|
1802
|
+
publishedAt: input.publishedAt === void 0 ? snapshot.item.publishedAt : input.publishedAt
|
|
1803
|
+
};
|
|
1804
|
+
checks.push(snapshot.check, ...contentWriteChecks(collection, item.id, "edit"));
|
|
1805
|
+
if (getContentStorage(db, collection)) checks.push(contentPartitionWritable(collection, item.id));
|
|
1806
|
+
for (const [kind, id] of [["live", item.liveRevisionId], ["draft", item.draftRevisionId]]) {
|
|
1807
|
+
if (!id) continue;
|
|
1808
|
+
const revision = await db.selectFrom("revisions").selectAll().where("id", "=", id).executeTakeFirst();
|
|
1809
|
+
if (!revision || revision.collection !== collection || revision.entry_id !== item.id) throw new DinewayValidationError("Content revision is missing or belongs to another entry.");
|
|
1810
|
+
checks.push(rowUnchanged("revisions", revision));
|
|
1811
|
+
if (kind === "live") live = await readRevisionData(db, revision);
|
|
1812
|
+
else draft = await readRevisionData(db, revision);
|
|
1813
|
+
}
|
|
1814
|
+
const stage = input.stageDraft !== false && usesRevisions;
|
|
1815
|
+
const changedDraft = stage && (Object.keys(input.data ?? {}).length > 0 || input.slug !== void 0);
|
|
1816
|
+
if (changedDraft) draft = {
|
|
1817
|
+
...draft ?? item.data,
|
|
1818
|
+
...input.data,
|
|
1819
|
+
...input.slug === void 0 ? {} : { _slug: input.slug }
|
|
1820
|
+
};
|
|
1821
|
+
if (input.draftData) {
|
|
1822
|
+
const previous = draft ?? live ?? item.data;
|
|
1823
|
+
await validateData(Object.fromEntries(Object.entries(input.draftData).filter(([key, value]) => JSON.stringify(previous[key]) !== JSON.stringify(value))));
|
|
1824
|
+
draft = structuredClone(input.draftData);
|
|
1825
|
+
}
|
|
1826
|
+
if (!stage) {
|
|
1827
|
+
item.data = {
|
|
1828
|
+
...item.data,
|
|
1829
|
+
...await repo.normalizePreparedData(collection, fieldData(input.data ?? {}))
|
|
1830
|
+
};
|
|
1831
|
+
for (const [key, value] of Object.entries(item.data)) if (typeof value === "boolean") item.data[key] = Number(value);
|
|
1832
|
+
for (const [key, value] of Object.entries(item.data)) if (value === null || value === void 0) delete item.data[key];
|
|
1833
|
+
if (input.slug !== void 0) item.slug = input.slug;
|
|
1834
|
+
}
|
|
1835
|
+
if (!stage && input.slug && previousSlug && input.slug !== previousSlug) appendGlobal(...new RedirectRepository(db).prepareAutoRedirect(collection, previousSlug, input.slug, item.id, configuration.row?.url_pattern ?? null).statements);
|
|
1836
|
+
if (syncTranslations && !stage && isI18nEnabled() && input.data && item.translationGroup) {
|
|
1837
|
+
const sync = prepareNonTranslatableFields(db, collection, item.id, item.translationGroup, fieldData(input.data), configuration.fields.filter((field) => field.translatable === 0).map((field) => field.slug));
|
|
1838
|
+
if (sync) if (getContentStorage(db, collection)) {
|
|
1839
|
+
const sharedSlugs = new Set(configuration.fields.filter((field) => field.translatable === 0).map((field) => field.slug));
|
|
1840
|
+
const shared = Object.fromEntries(Object.entries(fieldData(input.data)).filter(([field]) => sharedSlugs.has(field)));
|
|
1841
|
+
const siblings = await sql`SELECT id FROM ${sql.table(`ec_${collection}`)} WHERE translation_group = ${item.translationGroup} AND id <> ${item.id} ORDER BY id`.execute(db);
|
|
1842
|
+
checks.push(sql`(SELECT COUNT(*) FROM ${sql.table(`ec_${collection}`)} WHERE translation_group = ${item.translationGroup} AND id <> ${item.id}) = ${siblings.rows.length}`);
|
|
1843
|
+
for (const sibling of siblings.rows) translatedWrites.push(await prepareContentWriteInternal(db, collection, {
|
|
1844
|
+
id: sibling.id,
|
|
1845
|
+
data: shared,
|
|
1846
|
+
stageDraft: false,
|
|
1847
|
+
operationId: intent ? `${intent.operationId}:${sibling.id}` : void 0
|
|
1848
|
+
}, false));
|
|
1849
|
+
} else appendGlobal(sync);
|
|
1850
|
+
}
|
|
1851
|
+
if (input.status !== void 0) item.status = input.status;
|
|
1852
|
+
if (input.authorId !== void 0) item.authorId = input.authorId;
|
|
1853
|
+
statements.push(repo.prepareUpdate(collection, item.id, {
|
|
1854
|
+
data: stage ? void 0 : input.data && fieldData(input.data),
|
|
1855
|
+
slug: stage ? void 0 : input.slug,
|
|
1856
|
+
status: input.status,
|
|
1857
|
+
authorId: input.authorId,
|
|
1858
|
+
publishedAt: input.publishedAt
|
|
1859
|
+
}, now));
|
|
1860
|
+
if (changedDraft || input.draftData || input.unpublish && !draft && live) {
|
|
1861
|
+
draft ??= live;
|
|
1862
|
+
if (draft) {
|
|
1863
|
+
const replace = !!input.reuseDraftRevision && !!item.draftRevisionId && item.draftRevisionId !== item.liveRevisionId;
|
|
1864
|
+
const revision = replace ? {
|
|
1865
|
+
id: item.draftRevisionId,
|
|
1866
|
+
statement: db.updateTable("revisions").set({ data: JSON.stringify(draft) }).where("id", "=", item.draftRevisionId).compile()
|
|
1867
|
+
} : new RevisionRepository(db, { prepareIndexWrites: true }).prepareCreateSnapshot({
|
|
1868
|
+
collection,
|
|
1869
|
+
entryId: item.id,
|
|
1870
|
+
data: sql`${JSON.stringify(draft)}`,
|
|
1871
|
+
authorId: input.authorId ?? void 0
|
|
1872
|
+
}, revisionIdentity);
|
|
1873
|
+
storageRevisions.push({
|
|
1874
|
+
id: revision.id,
|
|
1875
|
+
data: draft,
|
|
1876
|
+
authorId: input.authorId ?? void 0,
|
|
1877
|
+
replace
|
|
1878
|
+
});
|
|
1879
|
+
item.draftRevisionId = revision.id;
|
|
1880
|
+
statements.push(revision.statement, sql`UPDATE ${sql.table(`ec_${collection}`)} SET draft_revision_id=${revision.id} WHERE id=${item.id}`.compile(db));
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
} else {
|
|
1884
|
+
if (input.expectedRev !== void 0 || input.unpublish) throw new DinewayValidationError("A new draft cannot reference an existing revision.");
|
|
1885
|
+
const data = fieldData(input.data ?? {});
|
|
1886
|
+
if (input.draftData) await validateData(input.draftData);
|
|
1887
|
+
const slugSource = [data.title, data.name].find((value) => typeof value === "string" && value.length > 0);
|
|
1888
|
+
const slug = input.slug ?? (slugSource ? await repo.generateUniqueSlug(collection, slugSource, input.locale) : void 0);
|
|
1889
|
+
if (slug) checks.push(sql`NOT EXISTS(SELECT 1 FROM ${sql.table(`ec_${collection}`)} WHERE slug=${slug} ${input.locale ? sql`AND locale=${input.locale}` : sql``})`);
|
|
1890
|
+
const created = await repo.prepareCreate({
|
|
1891
|
+
type: collection,
|
|
1892
|
+
data,
|
|
1893
|
+
slug,
|
|
1894
|
+
status: "draft",
|
|
1895
|
+
authorId: input.authorId ?? void 0,
|
|
1896
|
+
locale: input.locale,
|
|
1897
|
+
translationOf: input.translationOf,
|
|
1898
|
+
createdAt: input.createdAt,
|
|
1899
|
+
publishedAt: input.publishedAt
|
|
1900
|
+
}, {
|
|
1901
|
+
captureDefaults: true,
|
|
1902
|
+
id: intent?.entryId,
|
|
1903
|
+
now: intent?.now
|
|
1305
1904
|
});
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1905
|
+
item = created.item;
|
|
1906
|
+
now = item.updatedAt;
|
|
1907
|
+
checks.push(...created.batch.checks ?? []);
|
|
1908
|
+
statements.push(...created.batch.statements);
|
|
1909
|
+
if (usesRevisions || input.draftData) {
|
|
1910
|
+
draft = structuredClone(input.draftData ?? {
|
|
1911
|
+
...item.data,
|
|
1912
|
+
...Object.fromEntries(Object.entries(input.data ?? {}).filter(([key]) => key.startsWith("_")))
|
|
1913
|
+
});
|
|
1914
|
+
const revision = new RevisionRepository(db, { prepareIndexWrites: true }).prepareCreateSnapshot({
|
|
1915
|
+
collection,
|
|
1916
|
+
entryId: item.id,
|
|
1917
|
+
data: sql`${JSON.stringify(draft)}`,
|
|
1918
|
+
authorId: input.authorId ?? void 0
|
|
1919
|
+
}, revisionIdentity);
|
|
1920
|
+
storageRevisions.push({
|
|
1921
|
+
id: revision.id,
|
|
1922
|
+
data: draft,
|
|
1923
|
+
authorId: input.authorId ?? void 0
|
|
1924
|
+
});
|
|
1925
|
+
item.draftRevisionId = revision.id;
|
|
1926
|
+
statements.push(revision.statement, sql`UPDATE ${sql.table(`ec_${collection}`)} SET draft_revision_id=${revision.id} WHERE id=${item.id}`.compile(db));
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
if (input.publish) {
|
|
1930
|
+
const authority = contentWriteChecks(collection, item.id, "publish");
|
|
1931
|
+
if (input.id) checks.push(...authority);
|
|
1932
|
+
else appendGlobal(...prepareAtomicChecks(db, authority));
|
|
1933
|
+
const data = draft ?? live ?? item.data;
|
|
1934
|
+
let revisionId = item.draftRevisionId ?? item.liveRevisionId;
|
|
1935
|
+
if (!revisionId) {
|
|
1936
|
+
const revision = new RevisionRepository(db, { prepareIndexWrites: true }).prepareCreateSnapshot({
|
|
1937
|
+
collection,
|
|
1938
|
+
entryId: item.id,
|
|
1939
|
+
data: sql`${JSON.stringify(data)}`,
|
|
1940
|
+
authorId: input.authorId ?? void 0
|
|
1941
|
+
}, revisionIdentity);
|
|
1942
|
+
revisionId = revision.id;
|
|
1943
|
+
storageRevisions.push({
|
|
1944
|
+
id: revision.id,
|
|
1945
|
+
data,
|
|
1946
|
+
authorId: input.authorId ?? void 0
|
|
1947
|
+
});
|
|
1948
|
+
statements.push(revision.statement);
|
|
1949
|
+
}
|
|
1950
|
+
const sync = repo.prepareSyncDataColumns(collection, item.id, data);
|
|
1951
|
+
if (sync) statements.push(sync);
|
|
1952
|
+
const slug = typeof data._slug === "string" ? data._slug : item.slug;
|
|
1953
|
+
if (wasPublished && previousSlug && slug && previousSlug !== slug) appendGlobal(...new RedirectRepository(db).prepareAutoRedirect(collection, previousSlug, slug, item.id, configuration.row?.url_pattern ?? null).statements);
|
|
1954
|
+
item = {
|
|
1955
|
+
...item,
|
|
1956
|
+
slug,
|
|
1957
|
+
status: "published",
|
|
1958
|
+
liveRevisionId: revisionId,
|
|
1959
|
+
draftRevisionId: null,
|
|
1960
|
+
scheduledAt: null,
|
|
1961
|
+
publishedAt: item.publishedAt ?? now,
|
|
1962
|
+
updatedAt: now,
|
|
1963
|
+
data: {
|
|
1964
|
+
...item.data,
|
|
1965
|
+
...await repo.normalizePreparedData(collection, fieldData(data))
|
|
1342
1966
|
}
|
|
1343
1967
|
};
|
|
1968
|
+
for (const [key, value] of Object.entries(item.data)) {
|
|
1969
|
+
if (typeof value === "boolean") item.data[key] = Number(value);
|
|
1970
|
+
if (value === null || value === void 0) delete item.data[key];
|
|
1971
|
+
}
|
|
1972
|
+
statements.push(sql`UPDATE ${sql.table(`ec_${collection}`)} SET slug=${slug},status='published',live_revision_id=${revisionId},draft_revision_id=NULL,scheduled_at=NULL,published_at=${item.publishedAt},updated_at=${now} WHERE id=${item.id}`.compile(db));
|
|
1973
|
+
live = data;
|
|
1974
|
+
draft = null;
|
|
1344
1975
|
}
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
const entryId = stringOrNull(item.id);
|
|
1352
|
-
const reviewedRev = stringOrNull(payload._rev);
|
|
1353
|
-
if (!entryId) throw new Error("Content item is missing id");
|
|
1354
|
-
if (!reviewedRev) throw new Error("Content item is missing _rev for review binding");
|
|
1355
|
-
const data = asRecord(item.data) ?? {};
|
|
1356
|
-
const title = stringOrNull(data.title) ?? stringOrNull(item.title) ?? stringOrNull(item.slug);
|
|
1357
|
-
return {
|
|
1358
|
-
entryId,
|
|
1359
|
-
reviewedRev,
|
|
1360
|
-
liveRevisionId: stringOrNull(item.liveRevisionId),
|
|
1361
|
-
draftRevisionId: stringOrNull(item.draftRevisionId),
|
|
1362
|
-
slug: stringOrNull(item.slug),
|
|
1363
|
-
status: stringOrNull(item.status),
|
|
1364
|
-
updatedAt: stringOrNull(item.updatedAt),
|
|
1365
|
-
displayTitle: title,
|
|
1366
|
-
data
|
|
1367
|
-
};
|
|
1976
|
+
if (input.unpublish) {
|
|
1977
|
+
checks.push(...contentWriteChecks(collection, item.id, "publish"));
|
|
1978
|
+
item.liveRevisionId = null;
|
|
1979
|
+
item.status = "draft";
|
|
1980
|
+
live = null;
|
|
1981
|
+
statements.push(sql`UPDATE ${sql.table(`ec_${collection}`)} SET live_revision_id=NULL,status='draft' WHERE id=${item.id}`.compile(db));
|
|
1368
1982
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1983
|
+
const metadata = getContentStorage(db, collection) ? await snapshotOwnedContentMetadata(db, collection, item.id) : void 0;
|
|
1984
|
+
if (metadata) checks.push(...metadata.checks);
|
|
1985
|
+
const previousBylines = metadata?.owned.bylines;
|
|
1986
|
+
const previousSeo = metadata && configuration.row?.has_seo === 1 ? storedContentSeo(metadata.owned.seo) : void 0;
|
|
1987
|
+
if (termChanges) {
|
|
1988
|
+
const terms = await prepareContentTerms(db, collection, item.id, termChanges, item.locale ?? "en");
|
|
1989
|
+
checks.push(...terms.checks ?? []);
|
|
1990
|
+
appendGlobal(...terms.statements);
|
|
1991
|
+
if (metadata) metadata.owned.terms = [...metadata.owned.terms.filter((row) => !terms.replaced.includes(row.taxonomy_id)), ...terms.assignments.map((taxonomy_id) => ({
|
|
1992
|
+
collection,
|
|
1993
|
+
entry_id: item.id,
|
|
1994
|
+
taxonomy_id
|
|
1995
|
+
}))].toSorted((a, b) => a.taxonomy_id.localeCompare(b.taxonomy_id));
|
|
1373
1996
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1997
|
+
if (input.bylines !== void 0) {
|
|
1998
|
+
const bylines = await new BylineRepository(db).prepareContentBylines(collection, item.id, input.bylines, {
|
|
1999
|
+
prefix: intent?.rootVersion,
|
|
2000
|
+
now,
|
|
2001
|
+
primaryIndex: true
|
|
2002
|
+
});
|
|
2003
|
+
checks.push(...bylines.checks ?? []);
|
|
2004
|
+
appendGlobal(...bylines.statements);
|
|
2005
|
+
item.primaryBylineId = bylines.rows[0]?.byline_id ?? null;
|
|
2006
|
+
if (metadata) metadata.owned.bylines = bylines.rows;
|
|
2007
|
+
}
|
|
2008
|
+
if (input.seo) {
|
|
2009
|
+
const seo = new SeoRepository(db, { prepareIndexWrites: true }).prepareUpsert(collection, item.id, input.seo, now);
|
|
2010
|
+
if (seo) {
|
|
2011
|
+
appendGlobal(seo);
|
|
2012
|
+
if (metadata) {
|
|
2013
|
+
const previous = metadata.owned.seo[0];
|
|
2014
|
+
metadata.owned.seo = [{
|
|
2015
|
+
collection,
|
|
2016
|
+
content_id: item.id,
|
|
2017
|
+
seo_title: input.seo.title === void 0 ? previous?.seo_title ?? null : input.seo.title,
|
|
2018
|
+
seo_description: input.seo.description === void 0 ? previous?.seo_description ?? null : input.seo.description,
|
|
2019
|
+
seo_image: input.seo.image === void 0 ? previous?.seo_image ?? null : input.seo.image,
|
|
2020
|
+
seo_canonical: input.seo.canonical === void 0 ? previous?.seo_canonical ?? null : input.seo.canonical,
|
|
2021
|
+
seo_no_index: input.seo.noIndex === void 0 ? previous?.seo_no_index ?? 0 : Number(input.seo.noIndex),
|
|
2022
|
+
created_at: previous?.created_at ?? now,
|
|
2023
|
+
updated_at: now
|
|
2024
|
+
}];
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
const effectContext = syncTranslations ? getRequestContext()?.contentWriteEffects : void 0;
|
|
2029
|
+
const effectTargets = syncTranslations ? effectContext?.targets ?? getContentStorage(db, collection)?.runtime.hookTargets?.([input.publish ? "content:afterPublish" : input.unpublish ? "content:afterUnpublish" : "content:afterSave"]) : void 0;
|
|
2030
|
+
const eventContent = {
|
|
2031
|
+
...item,
|
|
2032
|
+
...effectTargets?.length && metadata ? await contentEventBylines(db, item, metadata.owned.bylines) : {},
|
|
2033
|
+
...metadata && configuration.row?.has_seo === 1 ? { seo: storedContentSeo(metadata.owned.seo) } : {}
|
|
2034
|
+
};
|
|
2035
|
+
const priorEventContent = effectContext?.previousContent ?? (previousItem ? {
|
|
2036
|
+
...previousItem,
|
|
2037
|
+
...effectTargets?.length && previousBylines ? await contentEventBylines(db, previousItem, previousBylines) : {},
|
|
2038
|
+
...previousSeo ? { seo: previousSeo } : {}
|
|
2039
|
+
} : void 0);
|
|
2040
|
+
const ownBatch = await prepareRoutedContentWrite({
|
|
2041
|
+
db,
|
|
2042
|
+
collection,
|
|
2043
|
+
item,
|
|
2044
|
+
create: !input.id,
|
|
2045
|
+
operationId: intent?.operationId,
|
|
2046
|
+
rootVersion: intent?.rootVersion,
|
|
2047
|
+
owned: metadata?.owned,
|
|
2048
|
+
effects: effectTargets?.length ? {
|
|
2049
|
+
targets: effectTargets,
|
|
2050
|
+
snapshot: contentStorageHookSnapshotSchema.parse(JSON.parse(JSON.stringify({
|
|
2051
|
+
collection,
|
|
2052
|
+
id: item.id,
|
|
2053
|
+
isNew: !input.id,
|
|
2054
|
+
permanent: false,
|
|
2055
|
+
content: eventContent,
|
|
2056
|
+
previousContent: priorEventContent
|
|
2057
|
+
})))
|
|
2058
|
+
} : void 0,
|
|
2059
|
+
terms: termChanges,
|
|
2060
|
+
checks,
|
|
2061
|
+
globalStatements,
|
|
2062
|
+
primaryStatements: statements,
|
|
2063
|
+
revisions: storageRevisions,
|
|
2064
|
+
fields: configuration.fields
|
|
2065
|
+
}) ?? {
|
|
2066
|
+
checks,
|
|
2067
|
+
statements
|
|
2068
|
+
};
|
|
2069
|
+
const prepared = {
|
|
2070
|
+
id: item.id,
|
|
2071
|
+
item,
|
|
2072
|
+
rev: encodeRev(item),
|
|
2073
|
+
draftData: draft,
|
|
2074
|
+
batch: {
|
|
2075
|
+
checks: [...ownBatch.checks ?? [], ...translatedWrites.flatMap((write) => write.batch.checks ?? [])],
|
|
2076
|
+
statements: [...ownBatch.statements, ...translatedWrites.flatMap((write) => write.batch.statements)]
|
|
2077
|
+
},
|
|
2078
|
+
afterCommit: () => {
|
|
2079
|
+
invalidateCollectionCache(collection);
|
|
2080
|
+
if (previousSlug !== item.slug) invalidateRedirectCache();
|
|
2081
|
+
for (const write of translatedWrites) write.afterCommit();
|
|
2082
|
+
}
|
|
2083
|
+
};
|
|
2084
|
+
reviews.set(prepared, structuredClone({
|
|
2085
|
+
item,
|
|
2086
|
+
live,
|
|
2087
|
+
draft
|
|
2088
|
+
}));
|
|
2089
|
+
return prepared;
|
|
1383
2090
|
}
|
|
1384
2091
|
|
|
1385
2092
|
//#endregion
|
|
1386
|
-
export {
|
|
2093
|
+
export { prepareContentProjection as A, handleContentUnschedule as C, encodeRev as D, decodeRev as E, validateRev as O, handleContentUnpublish as S, prepareContentPublication as T, handleContentPermanentDelete as _, handleContentAuthors as a, handleContentSchedule as b, handleContentCountTrashed as c, handleContentDiscardDraft as d, handleContentDuplicate as f, handleContentListTrashed as g, handleContentList as h, contentWriteConfiguration as i, snapshotPartitionDependencies as j, contentProjectionValues as k, handleContentCreate as l, handleContentGetIncludingTrashed as m, prepareContentWrite as n, handleContentCompare as o, handleContentGet as p, preparedContentReview as r, handleContentCountScheduled as s, content_write_exports as t, handleContentDelete as u, handleContentPublish as v, handleContentUpdate as w, handleContentTranslations as x, handleContentRestore as y };
|