dineway 0.1.48 → 0.2.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/dist/{activity-events-C9u37D5z.mjs → activity-events-y6eT8UW6.mjs} +6 -38
- package/dist/actor-CrObAPV0.mjs +37 -0
- package/dist/after-BfniwgIf.mjs +9 -0
- package/dist/{allowed-origins-DhipQNLb.mjs → allowed-origins-_oeyP6x-.mjs} +1 -1
- package/dist/api/route-utils.d.mts +10 -10
- package/dist/api/route-utils.mjs +17 -14
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -4
- package/dist/{api-Eiy8_zVZ.mjs → api-ByrU2q-Z.mjs} +61 -37
- package/dist/{api-tokens-DtvdtIkm.mjs → api-tokens-CjVMQT-X.mjs} +6 -2
- package/dist/{apply-CX3no7XE.mjs → apply-bZswmZPm.mjs} +117 -77
- package/dist/astro/image-endpoint.d.mts +7 -0
- package/dist/astro/image-endpoint.mjs +54 -0
- package/dist/astro/index.d.mts +35 -11
- package/dist/astro/index.mjs +157 -23
- package/dist/astro/integration/shims/use-sync-external-store-with-selector.js +71 -0
- package/dist/astro/integration/shims/use-sync-external-store.js +1 -0
- package/dist/astro/middleware/auth.d.mts +10 -10
- package/dist/astro/middleware/auth.mjs +42 -24
- package/dist/astro/middleware/redirect.mjs +14 -5
- package/dist/astro/middleware/request-context.mjs +9 -6
- 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.mjs +334 -193
- package/dist/astro/routes/admin.astro +6 -1
- package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +7 -6
- package/dist/astro/routes/api/admin/allowed-domains/index.mjs +7 -6
- package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
- package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
- package/dist/astro/routes/api/admin/briefing.mjs +22 -18
- package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
- package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -8
- package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -8
- package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -8
- package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +18 -15
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +18 -15
- package/dist/astro/routes/api/admin/bylines/index.mjs +18 -15
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +15 -13
- package/dist/astro/routes/api/admin/comments/_id_.mjs +7 -6
- package/dist/astro/routes/api/admin/comments/bulk.mjs +12 -10
- package/dist/astro/routes/api/admin/comments/counts.mjs +7 -6
- package/dist/astro/routes/api/admin/comments/index.mjs +12 -10
- package/dist/astro/routes/api/admin/context/_id_/history.mjs +27 -25
- package/dist/astro/routes/api/admin/context/_id_/index.mjs +27 -25
- package/dist/astro/routes/api/admin/context/_id_/review.mjs +32 -29
- package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +32 -29
- package/dist/astro/routes/api/admin/context/diff.mjs +31 -28
- package/dist/astro/routes/api/admin/context/index.mjs +32 -29
- package/dist/astro/routes/api/admin/context/stale.mjs +31 -28
- package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +27 -25
- package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +31 -28
- package/dist/astro/routes/api/admin/hitl-requests/index.mjs +31 -28
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +28 -26
- package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
- package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
- package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
- package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +56 -52
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +56 -52
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +48 -44
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +54 -50
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +53 -49
- package/dist/astro/routes/api/admin/plugins/index.mjs +48 -44
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +47 -43
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +53 -49
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +47 -43
- package/dist/astro/routes/api/admin/plugins/updates.mjs +47 -43
- package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +6 -6
- package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +32 -28
- package/dist/astro/routes/api/admin/review-requests/index.mjs +11 -10
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +47 -43
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +47 -43
- package/dist/astro/routes/api/admin/users/_id_/disable.mjs +3 -3
- package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
- package/dist/astro/routes/api/admin/users/_id_/index.mjs +8 -7
- package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +4 -4
- package/dist/astro/routes/api/admin/users/index.mjs +7 -6
- package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
- package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
- package/dist/astro/routes/api/auth/invite/complete.mjs +12 -11
- package/dist/astro/routes/api/auth/invite/index.mjs +9 -8
- package/dist/astro/routes/api/auth/invite/register-options.mjs +11 -10
- package/dist/astro/routes/api/auth/logout.mjs +2 -2
- package/dist/astro/routes/api/auth/magic-link/send.mjs +11 -10
- package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
- package/dist/astro/routes/api/auth/me.mjs +10 -9
- 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 +2 -2
- package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -5
- package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
- package/dist/astro/routes/api/auth/passkey/options.mjs +12 -11
- package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -9
- package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -10
- package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -10
- 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 +12 -11
- package/dist/astro/routes/api/auth/signup/request.mjs +11 -10
- package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
- package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +16 -14
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts +8 -0
- package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +160 -0
- package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +12 -11
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +17 -15
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +6 -6
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -6
- package/dist/astro/routes/api/dashboard.mjs +10 -9
- 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 +23 -11
- package/dist/astro/routes/api/import/wordpress/analyze.mjs +9 -6
- package/dist/astro/routes/api/import/wordpress/execute.d.mts +19 -1
- package/dist/astro/routes/api/import/wordpress/execute.mjs +85 -38
- package/dist/astro/routes/api/import/wordpress/media.d.mts +13 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +20 -14
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +36 -33
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +18 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +121 -101
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +25 -13
- package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +56 -2
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +284 -56
- package/dist/astro/routes/api/manifest.mjs +14 -5
- package/dist/astro/routes/api/mcp.mjs +266 -70
- package/dist/astro/routes/api/media/_id_/confirm.mjs +39 -11
- package/dist/astro/routes/api/media/_id_.mjs +11 -7
- 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 +12 -11
- package/dist/astro/routes/api/media.mjs +28 -35
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +32 -29
- package/dist/astro/routes/api/menus/_name_/items.mjs +32 -29
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +32 -29
- package/dist/astro/routes/api/menus/_name_/translations.mjs +32 -29
- package/dist/astro/routes/api/menus/_name_.mjs +32 -29
- package/dist/astro/routes/api/menus/index.mjs +32 -29
- package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
- package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
- 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 +6 -6
- package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
- package/dist/astro/routes/api/oauth/token.mjs +6 -6
- package/dist/astro/routes/api/openapi.json.mjs +4 -3
- package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +30 -30
- package/dist/astro/routes/api/redirects/404s/index.mjs +12 -11
- package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -11
- package/dist/astro/routes/api/redirects/_id_.mjs +33 -30
- package/dist/astro/routes/api/redirects/index.mjs +33 -30
- 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 +48 -44
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +48 -44
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +48 -44
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +48 -44
- package/dist/astro/routes/api/schema/collections/index.mjs +48 -44
- package/dist/astro/routes/api/schema/index.mjs +13 -14
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +47 -43
- package/dist/astro/routes/api/schema/orphans/index.mjs +47 -43
- package/dist/astro/routes/api/search/enable.mjs +12 -11
- package/dist/astro/routes/api/search/index.mjs +11 -10
- package/dist/astro/routes/api/search/rebuild.mjs +12 -11
- package/dist/astro/routes/api/search/stats.mjs +7 -7
- package/dist/astro/routes/api/search/suggest.mjs +11 -10
- package/dist/astro/routes/api/sections/_slug_.mjs +32 -29
- package/dist/astro/routes/api/sections/index.mjs +32 -29
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +32 -29
- package/dist/astro/routes/api/setup/admin-verify.mjs +14 -13
- package/dist/astro/routes/api/setup/admin.mjs +12 -11
- package/dist/astro/routes/api/setup/dev-bypass.mjs +32 -26
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +30 -26
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +9 -8
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +35 -32
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +35 -32
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +35 -32
- package/dist/astro/routes/api/taxonomies/index.mjs +35 -32
- package/dist/astro/routes/api/themes/preview.mjs +6 -6
- 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 +31 -28
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +32 -29
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +32 -29
- package/dist/astro/routes/api/widget-areas/_name_.mjs +29 -27
- package/dist/astro/routes/api/widget-areas/index.mjs +32 -29
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +9 -8
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +24 -15
- package/dist/astro/routes/sitemap.xml.mjs +10 -9
- package/dist/astro/session-driver.d.mts +1 -1
- package/dist/astro/session-driver.mjs +3 -3
- package/dist/astro/types.d.mts +21 -13
- package/dist/{audit-D1cbG7xH.mjs → audit-ByVKIwWF.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-Dr14I98m.mjs → auth-control-guard-CqeUmQsv.mjs} +1 -1
- package/dist/{authorize-BLO0m7fW.mjs → authorize-CcBxcHtz.mjs} +1 -1
- package/dist/{briefing-CObXGOGz.mjs → briefing-BJaJI8dm.mjs} +2 -1
- package/dist/{briefing-gKWiGLt1.mjs → briefing-CawZ59CY.mjs} +90 -28
- package/dist/bundle-7C_DpkEq.mjs +602 -0
- package/dist/{byline-1ntDwv8c.mjs → byline-e51-fWRs.mjs} +30 -62
- package/dist/{byline-fields-BX7rWKNU.d.mts → byline-fields-CUvbslGc.d.mts} +49 -6
- package/dist/{byline-fields-C9_iaPaM.mjs → byline-fields-D-N5qVIG.mjs} +1 -1
- package/dist/{byline-fields-B-ZkoVft.mjs → byline-fields-DOJO16Gm.mjs} +3 -3
- package/dist/{byline-registry-CUSvkasJ.mjs → byline-registry-87nNnYl4.mjs} +2 -2
- package/dist/{bylines-bC15ZqAv.mjs → bylines-CMQNCNFh.mjs} +9 -3
- package/dist/{bylines-DtxChhN_.mjs → bylines-y4LO-dTj.mjs} +5 -5
- package/dist/{cache-DbKyr60Q.mjs → cache-C-FNTFYK.mjs} +2 -2
- package/dist/{chunks-C5zp2xir.mjs → chunks-CxBt-GxR.mjs} +1 -1
- package/dist/cli/index.mjs +820 -1276
- package/dist/client/external-auth-headers.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +2 -1
- package/dist/{comment-CXDOQ93N.mjs → comment-DlA4iChg.mjs} +13 -3
- package/dist/comment-reaction-DfFao1ST.mjs +58 -0
- package/dist/{comments-hK-rdzJ9.mjs → comments-DApFGMsP.mjs} +1 -1
- package/dist/{content-QaryevFO.mjs → content-Bh4BDjv8.mjs} +51 -34
- package/dist/content-refresh-CgutSUfO.mjs +1576 -0
- package/dist/{context-CoYb_fvK.mjs → context-C5W3G18y.mjs} +111 -50
- package/dist/{context-DBL1ib4v.mjs → context-CK4ym2Sf.mjs} +2 -2
- package/dist/{context-route-helpers-CYQVmbIm.mjs → context-route-helpers-MASyGgWf.mjs} +2 -1
- package/dist/{cron-DxCAU_Sn.mjs → cron-cKcNTix_.mjs} +7 -3
- package/dist/{dashboard-DNlqsknJ.mjs → dashboard-DQkVT7Ei.mjs} +4 -4
- 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-DygsFPGL.mjs → device-flow-BnqRH-T9.mjs} +5 -5
- package/dist/{placeholder-BDo81Is5.mjs → enrich-DIFIFA8O.mjs} +36 -9
- package/dist/{error-DCSuUAZW.mjs → error-CytFlgcd.mjs} +5 -0
- package/dist/field-defs-cache-DRNdhBJv.mjs +49 -0
- package/dist/{fts-manager-CIZlScg5.mjs → fts-manager-Crzypjqu.mjs} +1 -1
- package/dist/hitl-Hw1RmWOq.mjs +677 -0
- package/dist/{hitl-requests-CGQwOEiq.mjs → hitl-requests-B4Vbcmaq.mjs} +2 -2
- package/dist/{hitl-route-helpers-GSDLNPpN.mjs → hitl-route-helpers-hEVzvP8l.mjs} +5 -4
- package/dist/import-Bh9biJfx.mjs +1354 -0
- package/dist/{index-CwRuZ-u8.d.mts → index-D4y6NGiy.d.mts} +75 -3
- package/dist/index.d.mts +17 -16
- package/dist/index.mjs +81 -69
- package/dist/{jsonld-DZ67souc.d.mts → jsonld-Dq0gsnOH.d.mts} +8 -4
- package/dist/{load-xE01Jm0V.mjs → load-DmYeniXl.mjs} +1 -1
- package/dist/{loader-tg63WSY2.mjs → loader-CjWqjweO.mjs} +117 -31
- package/dist/{manifest-schema-qh2P7RDX.mjs → manifest-schema-BxVPYMJR.mjs} +34 -1
- package/dist/mcp-reviewed-executor-TwVbMzG6.mjs +555 -0
- package/dist/media/image-endpoint.d.mts +32 -0
- package/dist/media/image-endpoint.mjs +111 -0
- package/dist/media/index.d.mts +27 -2
- package/dist/media/index.mjs +5 -3
- package/dist/media/local-runtime.d.mts +16 -11
- package/dist/media/local-runtime.mjs +10 -8
- package/dist/{media-DUAjMfvR.mjs → media-DMj0grzC.mjs} +3 -1
- package/dist/{media-allowlist-BsXkT9RK.mjs → media-allowlist-BlVCSzHx.mjs} +1 -1
- package/dist/media-url-lEKSrpr9.mjs +20 -0
- package/dist/{menus-WpFRMXjz.mjs → menus-TaW1gKnk.mjs} +19 -5
- package/dist/{menus-DU1eZqw_.mjs → menus-xvsnVZXw.mjs} +80 -15
- package/dist/{normalize-DUnoXAa9.mjs → normalize-5ek_z7de.mjs} +8 -1
- package/dist/{oauth-authorization-D-1p52Je.mjs → oauth-authorization-DiaGvRVz.mjs} +5 -5
- package/dist/{oauth-clients-CzeMGyUU.mjs → oauth-clients-Dl9E8dEM.mjs} +2 -2
- package/dist/object-cache/memory.d.mts +14 -0
- package/dist/object-cache/memory.mjs +55 -0
- package/dist/object-cache-D51qOseS.mjs +419 -0
- package/dist/page/index.d.mts +4 -3
- package/dist/page/index.mjs +2 -2
- package/dist/{parse-CneSgl7-.mjs → parse-CbymENaR.mjs} +1 -1
- package/dist/{parser-DxfsARXL.mjs → parser-C1nYd-81.mjs} +151 -9
- package/dist/{placeholder-CXfoCtCd.d.mts → placeholder-uvNRZBX9.d.mts} +12 -4
- package/dist/plugin-utils.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
- package/dist/plugins/adapt-sandbox-entry.mjs +11 -2
- package/dist/{plugins-C57YQi4l.mjs → plugins-BolVa-tl.mjs} +832 -64
- package/dist/{transport-LSdZVXHF.mjs → portable-text-dA_UlJwW.mjs} +1 -134
- package/dist/{preview-D5rvDhRt.mjs → preview-vSVg6fwG.mjs} +4 -3
- package/dist/process-cache-7xgAO9JY.mjs +106 -0
- package/dist/{provider-loader-9it4vd6L.d.mts → provider-loader-MD8zAbnH.d.mts} +1 -1
- package/dist/{public-url-DLUM5OOv.mjs → public-url-BEz_sM9n.mjs} +24 -18
- package/dist/{public-url-B5HaoGzj.d.mts → public-url-gsp3oUbu.d.mts} +5 -4
- package/dist/{query-BYc3oruA.mjs → query-CfRCdaL3.mjs} +281 -76
- package/dist/{query-DKEwzobh.mjs → query-jaAmw8E1.mjs} +11 -6
- package/dist/{rate-limit-i0G3IAOX.mjs → rate-limit-ZLdyWoZF.mjs} +2 -2
- package/dist/{redirect-C2zXRj3c.mjs → redirect-BAjt4Z6b.mjs} +2 -2
- package/dist/{redirects-YZo_znWG.mjs → redirects-BTdwpQtE.mjs} +47 -24
- package/dist/{redirects-ocRJmQHP.mjs → redirects-CA-xylPG.mjs} +19 -11
- package/dist/{registry-CTkbIDB9.mjs → registry-CtyVedcN.mjs} +130 -77
- package/dist/request-context.d.mts +2 -0
- package/dist/{request-meta-DAb6xaP9.mjs → request-meta-CUypToDJ.mjs} +1 -1
- package/dist/{review-requests-C0un5kdV.mjs → review-requests-C9Ff11Vq.mjs} +1 -1
- package/dist/{review-requests-gGMyYYhy.mjs → review-requests-DUyEmtmG.mjs} +1 -1
- package/dist/{runner-D4FL9usy.d.mts → runner-1tC2tIRV.d.mts} +1 -1
- package/dist/runner-DB7CRfOF.mjs +6740 -0
- package/dist/{runtime-DEWQpZ-4.d.mts → runtime-BOeiQsCv.d.mts} +2028 -1564
- package/dist/runtime.d.mts +10 -10
- package/dist/runtime.mjs +4 -4
- package/dist/schema-DXdYj4R3.mjs +8 -0
- package/dist/{search-axGQ1KY3.mjs → search-DSaLgEFI.mjs} +5 -3
- package/dist/{secrets-062Izo8i.mjs → secrets-CDZo2k8L.mjs} +15 -12
- package/dist/{sections-OLKgXL10.mjs → sections-PVVXHGfp.mjs} +2 -2
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +22 -19
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.mjs +3 -12
- package/dist/{seo-Cd45Po8L.mjs → seo-CQG3GCHQ.mjs} +5 -2
- package/dist/{seo-contributions-CqVvReEj.mjs → seo-contributions-C1EnikHB.mjs} +11 -3
- package/dist/{seo-5lJOtB5J.mjs → seo-qa7Dn0jK.mjs} +22 -4
- package/dist/{service-Bwad8s5h.mjs → service-DiN4ZuPp.mjs} +2 -2
- package/dist/session-user-CAKImna3.mjs +22 -0
- package/dist/{settings-yLjz_I4T.mjs → settings-BbqgHWpU.mjs} +28 -55
- package/dist/{settings-lAHjaUit.mjs → settings-i4VPP8bT.mjs} +2 -2
- package/dist/{setup-complete--PradA4R.mjs → setup-complete-B8fl-mjV.mjs} +1 -1
- package/dist/{site-activity-D7Xyropw.mjs → site-activity-Dy3FROs0.mjs} +1 -1
- package/dist/{site-context-DaN9Z91j.mjs → site-context-DQiL8Fl5.mjs} +23 -652
- package/dist/{site-url-DpGZo9Z6.mjs → site-url-BML3GQYm.mjs} +1 -1
- package/dist/status-DANd8ERo.mjs +21 -0
- 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 +1 -1
- package/dist/{taxonomies-uXVEoQso.mjs → taxonomies-9s-v03H-.mjs} +36 -29
- package/dist/taxonomies-DRiixp_E.mjs +443 -0
- package/dist/{taxonomy-CBmkmMuU.mjs → taxonomy-Dvsw6BOs.mjs} +44 -9
- package/dist/{tokens-CjSgb0AC.mjs → tokens-1RK1n6ED.mjs} +1 -1
- package/dist/transport-BNmCqLu7.mjs +134 -0
- package/dist/types-4garmdWa.mjs +66 -0
- package/dist/{types-DSPGWjxO.d.mts → types-C8XW6L19.d.mts} +225 -4
- package/dist/{types-GaCtZ1k9.d.mts → types-CDpH6MA4.d.mts} +18 -0
- package/dist/{types-DRIKLmJI.d.mts → types-C_ly5eTp.d.mts} +17 -2
- package/dist/types-DF7ZuGGk.d.mts +118 -0
- package/dist/types-DU0bU2Wu.d.mts +2392 -0
- package/dist/{types-CwawBUTa.d.mts → types-DW_-sFyz.d.mts} +2 -1
- package/dist/{types-DfuD0Afl.mjs → types-Dq1qT19x.mjs} +2 -2
- package/dist/ui/server-runtime.d.mts +15 -15
- package/dist/ui/server-runtime.mjs +25 -21
- package/dist/url-Cac7a9QZ.mjs +33 -0
- package/dist/{user-DtNmjNYt.mjs → user-BIZPzCb9.mjs} +2 -2
- package/dist/{utils-wv-zvC-Y.mjs → utils-CMDhr5Xd.mjs} +129 -7
- package/dist/{validate-BMs11tan.d.mts → validate-CZvb-BKB.d.mts} +10 -7
- package/dist/{validate-7SYRbz2f.mjs → validate-DNs0pTSc.mjs} +11 -6
- package/dist/version-BTvfRGc6.mjs +6 -0
- package/dist/{widgets-DR8EHuRO.mjs → widgets-f0ibZUIq.mjs} +46 -43
- package/dist/{wordpress-slugs-Dvhxh4cl.mjs → wordpress-slugs-BhHJX8XE.mjs} +1 -1
- package/dist/{zod-generator-BS9-umbk.mjs → zod-generator-B7TMjyFJ.mjs} +41 -13
- package/package.json +31 -8
- package/src/components/Block.astro +50 -0
- package/src/components/Comments.astro +143 -1
- package/src/components/DinewayHead.astro +19 -2
- package/src/components/DinewayImage.astro +66 -33
- package/src/components/DinewayMedia.astro +1 -2
- package/src/components/Image.astro +85 -40
- package/src/components/InlinePortableTextEditor.tsx +12 -2
- package/src/components/JsonLdScript.astro +9 -0
- package/src/components/LiveSearch.astro +40 -4
- package/src/components/index.ts +4 -0
- package/src/components/live-search-routing.ts +30 -0
- package/src/components/portable-text-text-align.ts +15 -0
- package/src/ui.ts +2 -0
- package/dist/entity-aliases-Egjmqc7I.mjs +0 -51
- package/dist/import-CvHY6sf5.mjs +0 -684
- package/dist/runner-B-tbV751.mjs +0 -2741
- package/dist/schema-B6zyB-Xn.mjs +0 -8
- package/dist/taxonomies-CNOGeC-3.mjs +0 -327
- package/dist/types-eu5UDgHN.d.mts +0 -652
- package/dist/version-xlzMSXF2.mjs +0 -6
- /package/dist/{adapters-OQCImOL7.d.mts → adapters-NVSs4UH7.d.mts} +0 -0
- /package/dist/{api-tokens-CYUoFGo7.mjs → api-tokens-2r7OWi_I.mjs} +0 -0
- /package/dist/{base64-C1Q9yr0B.mjs → base64-F8-DUraK.mjs} +0 -0
- /package/dist/{challenge-store-CRSz-Xim.mjs → challenge-store-Bjlepa2E.mjs} +0 -0
- /package/dist/{components--pg6zBvu.mjs → components-Bclf98Be.mjs} +0 -0
- /package/dist/{context-types-DQh_XKkn.mjs → context-types-DqTo6C79.mjs} +0 -0
- /package/dist/{default-B6iaLvP7.mjs → default--K40jqm0.mjs} +0 -0
- /package/dist/{email-console-BOVqIYpB.mjs → email-console-ChgKFO8-.mjs} +0 -0
- /package/dist/{escape-BDgouFFY.mjs → escape-Bd4P_xKg.mjs} +0 -0
- /package/dist/{experimental-workflows-Dh4DUoD_.mjs → experimental-workflows-BMsUnIAw.mjs} +0 -0
- /package/dist/{mime-8pAB8-77.mjs → mime-CA7Lgovc.mjs} +0 -0
- /package/dist/{mode-CpyEz8pe.mjs → mode-C4CIyjtR.mjs} +0 -0
- /package/dist/{oauth-state-store-qncPB_IU.mjs → oauth-state-store-CNoXafF7.mjs} +0 -0
- /package/dist/{oauth-user-lookup-BFjWF8wK.mjs → oauth-user-lookup-Ygw4bNyt.mjs} +0 -0
- /package/dist/{options-BvJoSSJR.mjs → options-DQPTH5n0.mjs} +0 -0
- /package/dist/{passkey-config-DzHQK90v.mjs → passkey-config-BUwu8BA3.mjs} +0 -0
- /package/dist/{patterns-r-0n824Y.mjs → patterns-BhAvqO0S.mjs} +0 -0
- /package/dist/{provider-loader-DzUxejk7.mjs → provider-loader-D0w9dqjm.mjs} +0 -0
- /package/dist/{redirect-BjIBtDWY.mjs → redirect-wphRBv4y.mjs} +0 -0
- /package/dist/{request-cache-CYMbwZc6.mjs → request-cache-D9GQBxMP.mjs} +0 -0
- /package/dist/{resolve-DTuDyYKs.mjs → resolve-Cb6Dbz-C.mjs} +0 -0
- /package/dist/{setup-nonce-pyGfc9hV.mjs → setup-nonce-CoyjILvW.mjs} +0 -0
- /package/dist/{sidecar-client-mJxwayYN.mjs → sidecar-client-C3mqXg4C.mjs} +0 -0
- /package/dist/{slugify-BzGxlOFx.mjs → slugify-KSsVD_D3.mjs} +0 -0
- /package/dist/{ssrf-DiKqWd3N.mjs → ssrf-DWe8jwAp.mjs} +0 -0
- /package/dist/{transaction-CShMWIej.mjs → transaction-C2EOMTJA.mjs} +0 -0
- /package/dist/{transport-BnsNxh2l.d.mts → transport-CcJu3Co8.d.mts} +0 -0
- /package/dist/{trusted-proxy-BgIIcbsN.mjs → trusted-proxy-DTXQ2IMv.mjs} +0 -0
- /package/dist/{types-BO8TGjS8.mjs → types-B3t5cxhU.mjs} +0 -0
- /package/dist/{types-nP9vGUFq.d.mts → types-C46EvNdc.d.mts} +0 -0
- /package/dist/{types-Cg276-3z.mjs → types-C5CVgwsV.mjs} +0 -0
- /package/dist/{types-DZpT-PnG.d.mts → types-POH8PQZh.d.mts} +0 -0
- /package/dist/{types-Dryvv7LH.d.mts → types-Rc3gQqqw.d.mts} +0 -0
- /package/dist/{url-w7Mp5qAD.mjs → url-CpyFDFpO.mjs} +0 -0
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { _ as UpdateFieldInput, f as FieldValidation, g as UpdateCollectionInput, i as CollectionWithFields, o as CreateCollectionInput, s as CreateFieldInput, t as Collection, u as Field } from "./types-
|
|
2
|
-
import { f as UpdateContentInput, i as ContentItem, l as FindManyOptions, o as ContentSeoInput, r as ContentDateField, s as CreateContentInput, t as BylineSummary, u as FindManyResult } from "./types-
|
|
3
|
-
import { t as Database } from "./types-
|
|
4
|
-
import { A as PageMetadataContribution,
|
|
5
|
-
import {
|
|
6
|
-
import { t as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
1
|
+
import { _ as UpdateFieldInput, f as FieldValidation, g as UpdateCollectionInput, i as CollectionWithFields, o as CreateCollectionInput, s as CreateFieldInput, t as Collection, u as Field } from "./types-DW_-sFyz.mjs";
|
|
2
|
+
import { f as UpdateContentInput, i as ContentItem, l as FindManyOptions, o as ContentSeoInput, r as ContentDateField, s as CreateContentInput, t as BylineSummary, u as FindManyResult } from "./types-C_ly5eTp.mjs";
|
|
3
|
+
import { t as Database } from "./types-DU0bU2Wu.mjs";
|
|
4
|
+
import { A as PageMetadataContribution, D as PageFragmentContribution, Dt as StandardPluginDefinition, F as PluginActor, G as PluginManifest, J as PluginMcpCommandTool, O as PageFragmentEvent, U as PluginDefinition, V as PluginCapability, X as PluginMcpExecutionContext, _ as FieldWidgetConfig, a as CommentAfterModerateEvent, at as PluginMcpTargetAuthorizer$1, et as PluginMcpResource, g as EmailMessage, gt as PortableTextBlockConfig, h as CronEvent, ht as PluginTargetScope, j as PageMetadataEvent, mt as PluginStorageConfig, ot as PluginMcpTool, r as CommentAfterCreateEvent, s as CommentBeforeCreateEvent, w as MediaItem$1, xt as ResolvedPlugin, yt as RequestMeta } from "./types-C8XW6L19.mjs";
|
|
5
|
+
import { d as Storage } from "./types-POH8PQZh.mjs";
|
|
6
|
+
import { r as AuthProviderDescriptor, t as AuthDescriptor } from "./types-Rc3gQqqw.mjs";
|
|
7
|
+
import { t as DatabaseDescriptor } from "./adapters-NVSs4UH7.mjs";
|
|
8
|
+
import { _ as MediaValue, m as MediaProviderDescriptor } from "./placeholder-uvNRZBX9.mjs";
|
|
9
|
+
import { r as ObjectCacheDescriptor } from "./types-DF7ZuGGk.mjs";
|
|
10
|
+
import { E as ContentBylineInput } from "./index-D4y6NGiy.mjs";
|
|
11
|
+
import { i as SiteSettings, r as SiteSettingKey } from "./types-C46EvNdc.mjs";
|
|
12
|
+
import { Dialect, Kysely, Transaction } from "kysely";
|
|
12
13
|
import { z } from "astro/zod";
|
|
13
14
|
import { z as z$1 } from "zod";
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
16
|
import { LiveLoader } from "astro/loaders";
|
|
15
17
|
import { MiddlewareHandler } from "astro";
|
|
16
18
|
|
|
@@ -227,6 +229,139 @@ interface DatabaseConfig {
|
|
|
227
229
|
authToken?: string;
|
|
228
230
|
}
|
|
229
231
|
//#endregion
|
|
232
|
+
//#region src/loader.d.ts
|
|
233
|
+
/**
|
|
234
|
+
* Entry data type - generic object
|
|
235
|
+
*/
|
|
236
|
+
type EntryData = Record<string, unknown>;
|
|
237
|
+
/**
|
|
238
|
+
* Sort direction
|
|
239
|
+
*/
|
|
240
|
+
type SortDirection$1 = "asc" | "desc";
|
|
241
|
+
/**
|
|
242
|
+
* Order by specification - field name to direction
|
|
243
|
+
* @example { created_at: "desc" } - Sort by created_at descending
|
|
244
|
+
* @example { title: "asc" } - Sort by title ascending
|
|
245
|
+
*/
|
|
246
|
+
type OrderBySpec$1 = Record<string, SortDirection$1>;
|
|
247
|
+
/**
|
|
248
|
+
* Range filter for comparison operators on field values.
|
|
249
|
+
* ISO 8601 timestamps sort lexicographically in the same order as time.
|
|
250
|
+
*/
|
|
251
|
+
interface WhereRange {
|
|
252
|
+
gt?: string;
|
|
253
|
+
gte?: string;
|
|
254
|
+
lt?: string;
|
|
255
|
+
lte?: string;
|
|
256
|
+
}
|
|
257
|
+
type WhereValue = string | string[] | WhereRange;
|
|
258
|
+
/**
|
|
259
|
+
* Fields shared by every collection filter, independent of pagination mode.
|
|
260
|
+
*/
|
|
261
|
+
interface CollectionFilterBase$1 {
|
|
262
|
+
type: string;
|
|
263
|
+
status?: "draft" | "published" | "archived";
|
|
264
|
+
limit?: number;
|
|
265
|
+
/**
|
|
266
|
+
* Filter by field values, taxonomy terms, byline credits, or ranges.
|
|
267
|
+
*
|
|
268
|
+
* Taxonomy names are detected automatically and filtered by term.
|
|
269
|
+
* The reserved `byline` key filters by byline credit in any position,
|
|
270
|
+
* not just the primary credit. Other keys are treated as content table
|
|
271
|
+
* column filters.
|
|
272
|
+
*/
|
|
273
|
+
where?: Record<string, WhereValue>;
|
|
274
|
+
/** Case-insensitive substring search across the provided columns. */
|
|
275
|
+
q?: string;
|
|
276
|
+
searchColumns?: string[];
|
|
277
|
+
/**
|
|
278
|
+
* Order results by field(s)
|
|
279
|
+
* @default { created_at: "desc" }
|
|
280
|
+
*/
|
|
281
|
+
orderBy?: OrderBySpec$1;
|
|
282
|
+
/**
|
|
283
|
+
* Filter by locale (e.g. 'en', 'fr').
|
|
284
|
+
* When set, only returns content in this locale.
|
|
285
|
+
*/
|
|
286
|
+
locale?: string;
|
|
287
|
+
}
|
|
288
|
+
/** Keyset-paginated collection filter. Cannot also carry an offset. */
|
|
289
|
+
interface CursorCollectionFilter$1 extends CollectionFilterBase$1 {
|
|
290
|
+
/**
|
|
291
|
+
* Opaque cursor for keyset pagination.
|
|
292
|
+
* Pass the `nextCursor` value from a previous result to fetch the next page.
|
|
293
|
+
*/
|
|
294
|
+
cursor?: string;
|
|
295
|
+
offset?: never;
|
|
296
|
+
}
|
|
297
|
+
/** Offset-paginated collection filter. Cannot also carry a cursor. */
|
|
298
|
+
interface OffsetCollectionFilter$1 extends CollectionFilterBase$1 {
|
|
299
|
+
/**
|
|
300
|
+
* Skip this many rows before returning results. Use with `limit` for numbered
|
|
301
|
+
* archives, for example `offset = (page - 1) * perPage`.
|
|
302
|
+
*/
|
|
303
|
+
offset?: number;
|
|
304
|
+
cursor?: never;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Filter for loadCollection - type is required.
|
|
308
|
+
*
|
|
309
|
+
* Cursor and offset are mutually exclusive pagination modes. Runtime callers
|
|
310
|
+
* that supply both are treated as cursor-paginated so the two skips do not stack.
|
|
311
|
+
*/
|
|
312
|
+
type CollectionFilter$1 = CursorCollectionFilter$1 | OffsetCollectionFilter$1;
|
|
313
|
+
/**
|
|
314
|
+
* Filter for loadEntry - type and id are required
|
|
315
|
+
*/
|
|
316
|
+
interface EntryFilter {
|
|
317
|
+
type: string;
|
|
318
|
+
id: string;
|
|
319
|
+
/**
|
|
320
|
+
* When set, fetch content data from this revision instead of the content table.
|
|
321
|
+
* Used by preview mode to serve draft revision data.
|
|
322
|
+
*/
|
|
323
|
+
revisionId?: string;
|
|
324
|
+
/**
|
|
325
|
+
* Locale to scope slug lookup. Only affects slug resolution;
|
|
326
|
+
* IDs are globally unique and always resolve regardless of locale.
|
|
327
|
+
*/
|
|
328
|
+
locale?: string;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get the database instance. Used by query wrapper functions and middleware.
|
|
332
|
+
*
|
|
333
|
+
* Checks the ALS request context first — if a per-request DB override is set
|
|
334
|
+
* (e.g. by preview or playground middleware), it takes precedence over the
|
|
335
|
+
* module-level cached instance. This allows preview flows to route queries
|
|
336
|
+
* to an isolated session database without modifying any calling code.
|
|
337
|
+
*
|
|
338
|
+
* Initializes the default database on first call using config from virtual module.
|
|
339
|
+
*/
|
|
340
|
+
declare function getDb(): Promise<Kysely<Database>>;
|
|
341
|
+
/**
|
|
342
|
+
* Create a Dineway Live Collections loader
|
|
343
|
+
*
|
|
344
|
+
* This loader handles ALL content types in a single Astro collection.
|
|
345
|
+
* Use `getDinewayCollection()` and `getDinewayEntry()` to query
|
|
346
|
+
* specific content types.
|
|
347
|
+
*
|
|
348
|
+
* Database is configured in astro.config.mjs via the dineway() integration.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```ts
|
|
352
|
+
* // src/live.config.ts
|
|
353
|
+
* import { defineLiveCollection } from "astro:content";
|
|
354
|
+
* import { dinewayLoader } from "dineway";
|
|
355
|
+
*
|
|
356
|
+
* export const collections = {
|
|
357
|
+
* dineway: defineLiveCollection({
|
|
358
|
+
* loader: dinewayLoader(),
|
|
359
|
+
* }),
|
|
360
|
+
* };
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
declare function dinewayLoader(): LiveLoader<EntryData, EntryFilter, CollectionFilter$1>;
|
|
364
|
+
//#endregion
|
|
230
365
|
//#region src/database/repositories/content.d.ts
|
|
231
366
|
/**
|
|
232
367
|
* Repository for content CRUD operations
|
|
@@ -301,7 +436,7 @@ declare class ContentRepository {
|
|
|
301
436
|
/**
|
|
302
437
|
* Restore content from trash
|
|
303
438
|
*/
|
|
304
|
-
restore(type: string, id: string): Promise<
|
|
439
|
+
restore(type: string, id: string): Promise<ContentItem | null>;
|
|
305
440
|
/**
|
|
306
441
|
* Permanently delete a soft-deleted content row.
|
|
307
442
|
*/
|
|
@@ -490,6 +625,8 @@ declare class MediaRepository {
|
|
|
490
625
|
width?: number;
|
|
491
626
|
height?: number;
|
|
492
627
|
size?: number;
|
|
628
|
+
blurhash?: string;
|
|
629
|
+
dominantColor?: string;
|
|
493
630
|
}): Promise<MediaItem | null>;
|
|
494
631
|
/**
|
|
495
632
|
* Mark upload as failed
|
|
@@ -561,6 +698,7 @@ interface PublicComment {
|
|
|
561
698
|
isRegisteredUser: boolean;
|
|
562
699
|
body: string;
|
|
563
700
|
createdAt: string;
|
|
701
|
+
reactions?: Record<string, number>;
|
|
564
702
|
replies?: PublicComment[];
|
|
565
703
|
}
|
|
566
704
|
//#endregion
|
|
@@ -806,12 +944,14 @@ declare function handleContentDuplicate(db: Kysely<Database>, collection: string
|
|
|
806
944
|
*/
|
|
807
945
|
declare function handleContentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
|
|
808
946
|
deleted: true;
|
|
947
|
+
id: string;
|
|
809
948
|
}>>;
|
|
810
949
|
/**
|
|
811
950
|
* Restore content item from trash
|
|
812
951
|
*/
|
|
813
952
|
declare function handleContentRestore(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
|
|
814
953
|
restored: true;
|
|
954
|
+
item: ContentItem;
|
|
815
955
|
}>>;
|
|
816
956
|
/**
|
|
817
957
|
* Permanently delete content item (cannot be undone).
|
|
@@ -819,6 +959,7 @@ declare function handleContentRestore(db: Kysely<Database>, collection: string,
|
|
|
819
959
|
*/
|
|
820
960
|
declare function handleContentPermanentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
|
|
821
961
|
deleted: true;
|
|
962
|
+
id: string;
|
|
822
963
|
}>>;
|
|
823
964
|
/**
|
|
824
965
|
* List trashed content items
|
|
@@ -895,392 +1036,443 @@ declare function handleContentTranslations(db: Kysely<Database>, collection: str
|
|
|
895
1036
|
}>;
|
|
896
1037
|
}>>;
|
|
897
1038
|
//#endregion
|
|
898
|
-
//#region src/
|
|
899
|
-
interface CollectionDefinition {
|
|
900
|
-
schema: {
|
|
901
|
-
_def?: {
|
|
902
|
-
shape?: () => Record<string, unknown>;
|
|
903
|
-
};
|
|
904
|
-
shape?: Record<string, unknown>;
|
|
905
|
-
};
|
|
906
|
-
admin: {
|
|
907
|
-
label: string;
|
|
908
|
-
labelSingular?: string;
|
|
909
|
-
supports?: string[];
|
|
910
|
-
};
|
|
911
|
-
}
|
|
912
|
-
type CollectionMap = Record<string, CollectionDefinition>;
|
|
1039
|
+
//#region src/plugins/email.d.ts
|
|
913
1040
|
/**
|
|
914
|
-
*
|
|
1041
|
+
* EmailPipeline orchestrates email delivery through the plugin hook system.
|
|
1042
|
+
*
|
|
1043
|
+
* The pipeline runs in three stages:
|
|
1044
|
+
* 1. email:beforeSend — middleware hooks that can transform or cancel messages
|
|
1045
|
+
* 2. email:deliver — exclusive hook dispatching to the selected provider
|
|
1046
|
+
* 3. email:afterSend — fire-and-forget hooks for logging/analytics
|
|
915
1047
|
*/
|
|
916
|
-
declare
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1048
|
+
declare class EmailPipeline {
|
|
1049
|
+
private pipeline;
|
|
1050
|
+
constructor(pipeline: HookPipeline);
|
|
1051
|
+
/**
|
|
1052
|
+
* Replace the underlying hook pipeline.
|
|
1053
|
+
*
|
|
1054
|
+
* Called by the runtime when rebuilding the hook pipeline after a
|
|
1055
|
+
* plugin is enabled or disabled, so the email pipeline dispatches
|
|
1056
|
+
* to the current set of active hooks.
|
|
1057
|
+
*/
|
|
1058
|
+
setPipeline(pipeline: HookPipeline): void;
|
|
1059
|
+
/**
|
|
1060
|
+
* Send an email through the full pipeline.
|
|
1061
|
+
*
|
|
1062
|
+
* @param message - The email to send
|
|
1063
|
+
* @param source - Where the email originated ("system" for auth, plugin ID for plugins)
|
|
1064
|
+
* @throws EmailNotConfiguredError if no provider is selected
|
|
1065
|
+
* @throws EmailRecursionError if called re-entrantly from within a hook
|
|
1066
|
+
* @throws Error if the provider handler throws
|
|
1067
|
+
*/
|
|
1068
|
+
send(message: EmailMessage, source: string): Promise<void>;
|
|
1069
|
+
/**
|
|
1070
|
+
* Inner send implementation, separated from the recursion guard.
|
|
1071
|
+
*/
|
|
1072
|
+
private sendInner;
|
|
1073
|
+
/**
|
|
1074
|
+
* Check if an email provider is configured and available.
|
|
1075
|
+
*
|
|
1076
|
+
* Returns true if an email:deliver provider is selected in the exclusive
|
|
1077
|
+
* hook system. Plugins and auth code use this to decide whether to show
|
|
1078
|
+
* "send invite" vs "copy invite link" UI.
|
|
1079
|
+
*/
|
|
1080
|
+
isAvailable(): boolean;
|
|
1081
|
+
}
|
|
923
1082
|
//#endregion
|
|
924
|
-
//#region src/
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1083
|
+
//#region src/plugins/context.d.ts
|
|
1084
|
+
/**
|
|
1085
|
+
* Options for creating site info
|
|
1086
|
+
*/
|
|
1087
|
+
interface SiteInfoOptions {
|
|
1088
|
+
/** Site name from options table */
|
|
1089
|
+
siteName?: string;
|
|
1090
|
+
/** Site URL from options table or Astro config */
|
|
1091
|
+
siteUrl?: string;
|
|
1092
|
+
/** Site locale from options table */
|
|
1093
|
+
locale?: string;
|
|
928
1094
|
}
|
|
929
|
-
interface
|
|
930
|
-
|
|
1095
|
+
interface PluginContextFactoryOptions {
|
|
1096
|
+
db: Kysely<Database>;
|
|
1097
|
+
/**
|
|
1098
|
+
* Resolver for the current database connection. When omitted, `db` is used.
|
|
1099
|
+
* Runtime code provides this so plugin hooks and routes honor request-scoped
|
|
1100
|
+
* database overrides from preview/playground sidecars.
|
|
1101
|
+
*/
|
|
1102
|
+
getDb?: () => Kysely<Database>;
|
|
1103
|
+
/**
|
|
1104
|
+
* Storage backend for direct media uploads.
|
|
1105
|
+
* If not provided, upload() will throw.
|
|
1106
|
+
*/
|
|
1107
|
+
storage?: Storage;
|
|
1108
|
+
/**
|
|
1109
|
+
* Function to generate upload URLs for media.
|
|
1110
|
+
* If not provided, media write operations will throw.
|
|
1111
|
+
*/
|
|
1112
|
+
getUploadUrl?: (filename: string, contentType: string) => Promise<{
|
|
1113
|
+
uploadUrl: string;
|
|
1114
|
+
mediaId: string;
|
|
1115
|
+
}>;
|
|
1116
|
+
/**
|
|
1117
|
+
* Site information for ctx.site and ctx.url().
|
|
1118
|
+
* If not provided, site info will have empty defaults.
|
|
1119
|
+
*/
|
|
1120
|
+
siteInfo?: SiteInfoOptions;
|
|
1121
|
+
/**
|
|
1122
|
+
* Callback to notify the cron scheduler that the next due time may have changed.
|
|
1123
|
+
* If not provided, ctx.cron will not be available.
|
|
1124
|
+
*/
|
|
1125
|
+
cronReschedule?: () => void;
|
|
1126
|
+
/**
|
|
1127
|
+
* Email pipeline instance for ctx.email.
|
|
1128
|
+
* If not provided (or no provider configured), ctx.email will be undefined.
|
|
1129
|
+
*/
|
|
1130
|
+
emailPipeline?: EmailPipeline;
|
|
1131
|
+
/**
|
|
1132
|
+
* Trusted reverse-proxy headers for request metadata IP extraction.
|
|
1133
|
+
*/
|
|
1134
|
+
trustedProxyHeaders?: string[];
|
|
931
1135
|
}
|
|
1136
|
+
//#endregion
|
|
1137
|
+
//#region src/plugins/hooks.d.ts
|
|
1138
|
+
type HookNameV2 = "plugin:install" | "plugin:activate" | "plugin:deactivate" | "plugin:uninstall" | "content:beforeSave" | "content:afterSave" | "content:beforeDelete" | "content:afterDelete" | "content:afterPublish" | "content:afterUnpublish" | "content:afterRestore" | "content:afterSchedule" | "content:afterUnschedule" | "media:beforeUpload" | "media:afterUpload" | "cron" | "email:beforeSend" | "email:deliver" | "email:afterSend" | "comment:beforeCreate" | "comment:moderate" | "comment:afterCreate" | "comment:afterModerate" | "page:metadata" | "page:fragments";
|
|
932
1139
|
/**
|
|
933
|
-
*
|
|
1140
|
+
* Hook execution result
|
|
934
1141
|
*/
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1142
|
+
interface HookResult<T> {
|
|
1143
|
+
success: boolean;
|
|
1144
|
+
value?: T;
|
|
1145
|
+
error?: Error;
|
|
1146
|
+
pluginId: string;
|
|
1147
|
+
duration: number;
|
|
1148
|
+
}
|
|
938
1149
|
/**
|
|
939
|
-
*
|
|
1150
|
+
* Hook pipeline for executing hooks in order
|
|
940
1151
|
*/
|
|
941
|
-
declare
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
items: MediaItem[];
|
|
950
|
-
nextCursor?: string;
|
|
951
|
-
}
|
|
952
|
-
interface MediaResponse {
|
|
953
|
-
item: MediaItem;
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
|
-
* List media items
|
|
957
|
-
*/
|
|
958
|
-
declare function handleMediaList(db: Kysely<Database>, params: {
|
|
959
|
-
cursor?: string;
|
|
960
|
-
limit?: number;
|
|
961
|
-
mimeType?: string | readonly string[];
|
|
962
|
-
q?: string;
|
|
963
|
-
}): Promise<ApiResult<MediaListResponse>>;
|
|
964
|
-
/**
|
|
965
|
-
* Get single media item
|
|
966
|
-
*/
|
|
967
|
-
declare function handleMediaGet(db: Kysely<Database>, id: string): Promise<ApiResult<MediaResponse>>;
|
|
968
|
-
/**
|
|
969
|
-
* Create media item (after file upload)
|
|
970
|
-
*/
|
|
971
|
-
declare function handleMediaCreate(db: Kysely<Database>, input: {
|
|
972
|
-
filename: string;
|
|
973
|
-
mimeType: string;
|
|
974
|
-
size?: number;
|
|
975
|
-
width?: number;
|
|
976
|
-
height?: number;
|
|
977
|
-
alt?: string;
|
|
978
|
-
storageKey: string;
|
|
979
|
-
contentHash?: string;
|
|
980
|
-
blurhash?: string;
|
|
981
|
-
dominantColor?: string;
|
|
982
|
-
authorId?: string;
|
|
983
|
-
}): Promise<ApiResult<MediaResponse>>;
|
|
984
|
-
/**
|
|
985
|
-
* Update media metadata
|
|
986
|
-
*/
|
|
987
|
-
declare function handleMediaUpdate(db: Kysely<Database>, id: string, input: {
|
|
988
|
-
alt?: string;
|
|
989
|
-
caption?: string;
|
|
990
|
-
width?: number;
|
|
991
|
-
height?: number;
|
|
992
|
-
}): Promise<ApiResult<MediaResponse>>;
|
|
993
|
-
/**
|
|
994
|
-
* Delete media item
|
|
995
|
-
*/
|
|
996
|
-
declare function handleMediaDelete(db: Kysely<Database>, id: string): Promise<ApiResult<{
|
|
997
|
-
deleted: true;
|
|
998
|
-
}>>;
|
|
999
|
-
//#endregion
|
|
1000
|
-
//#region src/schema/registry.d.ts
|
|
1001
|
-
/**
|
|
1002
|
-
* Error thrown when a schema operation fails
|
|
1003
|
-
*/
|
|
1004
|
-
declare class SchemaError extends Error {
|
|
1005
|
-
code: string;
|
|
1006
|
-
details?: Record<string, unknown> | undefined;
|
|
1007
|
-
constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
|
|
1008
|
-
}
|
|
1009
|
-
/**
|
|
1010
|
-
* Schema Registry
|
|
1011
|
-
*
|
|
1012
|
-
* Manages collection and field definitions stored in the database.
|
|
1013
|
-
* Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).
|
|
1014
|
-
*/
|
|
1015
|
-
declare class SchemaRegistry {
|
|
1016
|
-
private db;
|
|
1017
|
-
constructor(db: Kysely<Database>);
|
|
1152
|
+
declare class HookPipeline {
|
|
1153
|
+
private hooks;
|
|
1154
|
+
private pluginMap;
|
|
1155
|
+
private contextFactory;
|
|
1156
|
+
/** Stored so setContextFactory can merge incrementally. */
|
|
1157
|
+
private contextFactoryOptions;
|
|
1158
|
+
/** Hook names where at least one handler declared exclusive: true */
|
|
1159
|
+
private exclusiveHookNames;
|
|
1018
1160
|
/**
|
|
1019
|
-
*
|
|
1161
|
+
* Selected provider plugin ID for each exclusive hook.
|
|
1162
|
+
* Set by the PluginManager after resolution.
|
|
1020
1163
|
*/
|
|
1021
|
-
|
|
1164
|
+
private exclusiveSelections;
|
|
1165
|
+
constructor(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions);
|
|
1022
1166
|
/**
|
|
1023
|
-
*
|
|
1167
|
+
* Set or update the context factory options.
|
|
1168
|
+
*
|
|
1169
|
+
* When called on a pipeline that already has a factory, the new options
|
|
1170
|
+
* are merged on top of the existing ones so that callers don't need to
|
|
1171
|
+
* repeat every field (e.g. adding `cronReschedule` without losing
|
|
1172
|
+
* `storage` / `getUploadUrl`).
|
|
1024
1173
|
*/
|
|
1025
|
-
|
|
1174
|
+
setContextFactory(options: Partial<PluginContextFactoryOptions>): void;
|
|
1026
1175
|
/**
|
|
1027
|
-
* Get
|
|
1176
|
+
* Get context for a plugin
|
|
1028
1177
|
*/
|
|
1029
|
-
|
|
1178
|
+
private getContext;
|
|
1030
1179
|
/**
|
|
1031
|
-
* Get
|
|
1180
|
+
* Get typed hooks for a specific hook name.
|
|
1181
|
+
* The internal map stores ResolvedHook<unknown>, but we know each name
|
|
1182
|
+
* maps to a specific handler type via HookHandlerMap.
|
|
1183
|
+
*
|
|
1184
|
+
* Exclusive hooks that have a selected provider are filtered out — they
|
|
1185
|
+
* should only run via invokeExclusiveHook(), not in the regular pipeline.
|
|
1032
1186
|
*/
|
|
1033
|
-
|
|
1187
|
+
private getTypedHooks;
|
|
1034
1188
|
/**
|
|
1035
|
-
*
|
|
1189
|
+
* Register all hooks from plugins.
|
|
1190
|
+
*
|
|
1191
|
+
* Registers each hook name individually to preserve type safety. The
|
|
1192
|
+
* internal map stores ResolvedHook<unknown> since it's keyed by string,
|
|
1193
|
+
* but getTypedHooks() restores the correct handler type on retrieval.
|
|
1036
1194
|
*/
|
|
1037
|
-
|
|
1195
|
+
private registerPlugins;
|
|
1038
1196
|
/**
|
|
1039
|
-
*
|
|
1197
|
+
* Maps hook names to the capability required to register them.
|
|
1198
|
+
*
|
|
1199
|
+
* Hooks not listed here have no capability requirement (e.g. lifecycle
|
|
1200
|
+
* hooks, cron). Any plugin declaring a listed hook without the required
|
|
1201
|
+
* capability will have that hook silently skipped at registration time.
|
|
1040
1202
|
*/
|
|
1041
|
-
|
|
1042
|
-
private validateUrlPattern;
|
|
1043
|
-
private checkLabelUniqueness;
|
|
1044
|
-
private checkUrlPatternUniqueness;
|
|
1203
|
+
private static readonly HOOK_REQUIRED_CAPABILITY;
|
|
1045
1204
|
/**
|
|
1046
|
-
*
|
|
1205
|
+
* Register a single plugin's hook by name
|
|
1047
1206
|
*/
|
|
1048
|
-
|
|
1049
|
-
force?: boolean;
|
|
1050
|
-
}): Promise<void>;
|
|
1207
|
+
private registerPluginHook;
|
|
1051
1208
|
/**
|
|
1052
|
-
*
|
|
1209
|
+
* Register a single hook
|
|
1053
1210
|
*/
|
|
1054
|
-
|
|
1211
|
+
private registerHook;
|
|
1055
1212
|
/**
|
|
1056
|
-
*
|
|
1213
|
+
* Sort hooks by priority and dependencies
|
|
1057
1214
|
*/
|
|
1058
|
-
|
|
1215
|
+
private sortHooks;
|
|
1059
1216
|
/**
|
|
1060
|
-
*
|
|
1217
|
+
* Execute a hook with timeout
|
|
1061
1218
|
*/
|
|
1062
|
-
|
|
1219
|
+
private executeWithTimeout;
|
|
1063
1220
|
/**
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1066
|
-
* This repairs interrupted schema creation where the metadata row exists but
|
|
1067
|
-
* the physical `ec_*` table was not created.
|
|
1221
|
+
* Run plugin:install hooks
|
|
1068
1222
|
*/
|
|
1069
|
-
|
|
1223
|
+
runPluginInstall(pluginId: string): Promise<HookResult<void>[]>;
|
|
1070
1224
|
/**
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1073
|
-
* This repairs interrupted field creation where `_dineway_fields` was written
|
|
1074
|
-
* but `ALTER TABLE ec_* ADD COLUMN` did not complete.
|
|
1225
|
+
* Run plugin:activate hooks
|
|
1075
1226
|
*/
|
|
1076
|
-
|
|
1227
|
+
runPluginActivate(pluginId: string): Promise<HookResult<void>[]>;
|
|
1077
1228
|
/**
|
|
1078
|
-
*
|
|
1229
|
+
* Run plugin:deactivate hooks
|
|
1079
1230
|
*/
|
|
1080
|
-
|
|
1231
|
+
runPluginDeactivate(pluginId: string): Promise<HookResult<void>[]>;
|
|
1081
1232
|
/**
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
* Schema writes must not first-time enable FTS. Initial enablement stays in
|
|
1085
|
-
* explicit seed/import/admin flows where FTS failures can be handled deliberately.
|
|
1233
|
+
* Run plugin:uninstall hooks
|
|
1086
1234
|
*/
|
|
1087
|
-
|
|
1235
|
+
runPluginUninstall(pluginId: string, deleteData: boolean): Promise<HookResult<void>[]>;
|
|
1236
|
+
private runLifecycleHook;
|
|
1088
1237
|
/**
|
|
1089
|
-
*
|
|
1238
|
+
* Run content:beforeSave hooks
|
|
1239
|
+
* Returns modified content from the pipeline
|
|
1090
1240
|
*/
|
|
1091
|
-
|
|
1241
|
+
runContentBeforeSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<{
|
|
1242
|
+
content: Record<string, unknown>;
|
|
1243
|
+
results: HookResult<Record<string, unknown>>[];
|
|
1244
|
+
}>;
|
|
1092
1245
|
/**
|
|
1093
|
-
*
|
|
1246
|
+
* Run content:afterSave hooks
|
|
1094
1247
|
*/
|
|
1095
|
-
|
|
1248
|
+
runContentAfterSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<HookResult<void>[]>;
|
|
1096
1249
|
/**
|
|
1097
|
-
*
|
|
1250
|
+
* Run content:beforeDelete hooks
|
|
1251
|
+
* Returns whether deletion is allowed
|
|
1098
1252
|
*/
|
|
1099
|
-
|
|
1253
|
+
runContentBeforeDelete(id: string, collection: string): Promise<{
|
|
1254
|
+
allowed: boolean;
|
|
1255
|
+
results: HookResult<boolean>[];
|
|
1256
|
+
}>;
|
|
1100
1257
|
/**
|
|
1101
|
-
*
|
|
1258
|
+
* Run content:afterDelete hooks
|
|
1102
1259
|
*/
|
|
1103
|
-
|
|
1260
|
+
runContentAfterDelete(id: string, collection: string, permanent: boolean): Promise<HookResult<void>[]>;
|
|
1104
1261
|
/**
|
|
1105
|
-
*
|
|
1262
|
+
* Run content:afterPublish hooks (fire-and-forget).
|
|
1106
1263
|
*/
|
|
1107
|
-
|
|
1264
|
+
runContentAfterPublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
1108
1265
|
/**
|
|
1109
|
-
*
|
|
1266
|
+
* Run content:afterUnpublish hooks (fire-and-forget).
|
|
1110
1267
|
*/
|
|
1111
|
-
|
|
1268
|
+
runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
1112
1269
|
/**
|
|
1113
|
-
*
|
|
1270
|
+
* Run content:afterRestore hooks (fire-and-forget).
|
|
1114
1271
|
*/
|
|
1115
|
-
|
|
1272
|
+
runContentAfterRestore(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
1116
1273
|
/**
|
|
1117
|
-
*
|
|
1274
|
+
* Run content:afterSchedule hooks (fire-and-forget).
|
|
1118
1275
|
*/
|
|
1119
|
-
|
|
1276
|
+
runContentAfterSchedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
1120
1277
|
/**
|
|
1121
|
-
*
|
|
1278
|
+
* Run content:afterUnschedule hooks (fire-and-forget).
|
|
1122
1279
|
*/
|
|
1123
|
-
|
|
1280
|
+
runContentAfterUnschedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
1281
|
+
private runContentStateChangeHook;
|
|
1124
1282
|
/**
|
|
1125
|
-
*
|
|
1283
|
+
* Run media:beforeUpload hooks
|
|
1126
1284
|
*/
|
|
1127
|
-
|
|
1285
|
+
runMediaBeforeUpload(file: {
|
|
1286
|
+
name: string;
|
|
1287
|
+
type: string;
|
|
1288
|
+
size: number;
|
|
1289
|
+
}): Promise<{
|
|
1290
|
+
file: {
|
|
1291
|
+
name: string;
|
|
1292
|
+
type: string;
|
|
1293
|
+
size: number;
|
|
1294
|
+
};
|
|
1295
|
+
results: HookResult<{
|
|
1296
|
+
name: string;
|
|
1297
|
+
type: string;
|
|
1298
|
+
size: number;
|
|
1299
|
+
}>[];
|
|
1300
|
+
}>;
|
|
1128
1301
|
/**
|
|
1129
|
-
*
|
|
1130
|
-
*
|
|
1131
|
-
* SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant
|
|
1132
|
-
* expression — parameterized values cannot be used here. We manually escape
|
|
1133
|
-
* single quotes and coerce types to ensure the output is safe.
|
|
1134
|
-
*
|
|
1135
|
-
* INTEGER/REAL values are coerced through `Number()` which can only produce
|
|
1136
|
-
* digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.
|
|
1137
|
-
* TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).
|
|
1302
|
+
* Run media:afterUpload hooks
|
|
1138
1303
|
*/
|
|
1139
|
-
|
|
1304
|
+
runMediaAfterUpload(media: {
|
|
1305
|
+
id: string;
|
|
1306
|
+
filename: string;
|
|
1307
|
+
mimeType: string;
|
|
1308
|
+
size: number | null;
|
|
1309
|
+
url: string;
|
|
1310
|
+
createdAt: string;
|
|
1311
|
+
}): Promise<HookResult<void>[]>;
|
|
1140
1312
|
/**
|
|
1141
|
-
*
|
|
1313
|
+
* Invoke the cron hook for a specific plugin.
|
|
1314
|
+
*
|
|
1315
|
+
* Unlike other hooks which broadcast to all plugins, the cron hook is
|
|
1316
|
+
* dispatched only to the target plugin — the one that owns the task.
|
|
1142
1317
|
*/
|
|
1143
|
-
|
|
1318
|
+
invokeCronHook(pluginId: string, event: CronEvent): Promise<HookResult<void>>;
|
|
1144
1319
|
/**
|
|
1145
|
-
*
|
|
1320
|
+
* Run email:beforeSend hooks (middleware pipeline).
|
|
1321
|
+
*
|
|
1322
|
+
* Each handler receives the message and returns a modified message or
|
|
1323
|
+
* `false` to cancel delivery. The pipeline chains message transformations —
|
|
1324
|
+
* each handler receives the output of the previous one.
|
|
1146
1325
|
*/
|
|
1147
|
-
|
|
1326
|
+
runEmailBeforeSend(message: EmailMessage, source: string): Promise<{
|
|
1327
|
+
message: EmailMessage | false;
|
|
1328
|
+
results: HookResult<EmailMessage | false>[];
|
|
1329
|
+
}>;
|
|
1148
1330
|
/**
|
|
1149
|
-
*
|
|
1331
|
+
* Run email:afterSend hooks (fire-and-forget).
|
|
1332
|
+
*
|
|
1333
|
+
* Errors are logged but don't propagate — they don't affect the caller.
|
|
1150
1334
|
*/
|
|
1151
|
-
|
|
1335
|
+
runEmailAfterSend(message: EmailMessage, source: string): Promise<HookResult<void>[]>;
|
|
1152
1336
|
/**
|
|
1153
|
-
*
|
|
1337
|
+
* Run comment:beforeCreate hooks (middleware pipeline).
|
|
1154
1338
|
*
|
|
1155
|
-
*
|
|
1156
|
-
*
|
|
1339
|
+
* Each handler receives the event and returns a modified event or
|
|
1340
|
+
* `false` to reject the comment. The pipeline chains transformations —
|
|
1341
|
+
* each handler receives the output of the previous one.
|
|
1157
1342
|
*/
|
|
1158
|
-
|
|
1159
|
-
slug: string;
|
|
1160
|
-
tableName: string;
|
|
1161
|
-
rowCount: number;
|
|
1162
|
-
}>>;
|
|
1343
|
+
runCommentBeforeCreate(event: CommentBeforeCreateEvent): Promise<CommentBeforeCreateEvent | false>;
|
|
1163
1344
|
/**
|
|
1164
|
-
*
|
|
1345
|
+
* Run comment:afterCreate hooks (fire-and-forget).
|
|
1165
1346
|
*
|
|
1166
|
-
*
|
|
1347
|
+
* Errors are logged but don't propagate — they don't affect the caller.
|
|
1167
1348
|
*/
|
|
1168
|
-
|
|
1169
|
-
label?: string;
|
|
1170
|
-
labelSingular?: string;
|
|
1171
|
-
description?: string;
|
|
1172
|
-
}): Promise<Collection>;
|
|
1349
|
+
runCommentAfterCreate(event: CommentAfterCreateEvent): Promise<void>;
|
|
1173
1350
|
/**
|
|
1174
|
-
*
|
|
1351
|
+
* Run comment:afterModerate hooks (fire-and-forget).
|
|
1352
|
+
*
|
|
1353
|
+
* Errors are logged but don't propagate — they don't affect the caller.
|
|
1175
1354
|
*/
|
|
1176
|
-
|
|
1355
|
+
runCommentAfterModerate(event: CommentAfterModerateEvent): Promise<void>;
|
|
1356
|
+
/**
|
|
1357
|
+
* Run page:metadata hooks. Each handler returns contributions that are
|
|
1358
|
+
* merged by the metadata collector. Errors are logged but don't propagate.
|
|
1359
|
+
*/
|
|
1360
|
+
runPageMetadata(event: PageMetadataEvent): Promise<Array<{
|
|
1361
|
+
pluginId: string;
|
|
1362
|
+
contributions: PageMetadataContribution[];
|
|
1363
|
+
}>>;
|
|
1364
|
+
/**
|
|
1365
|
+
* Run page:fragments hooks. Only trusted plugins should be registered
|
|
1366
|
+
* for this hook. Errors are logged but don't propagate.
|
|
1367
|
+
*/
|
|
1368
|
+
runPageFragments(event: PageFragmentEvent): Promise<Array<{
|
|
1369
|
+
pluginId: string;
|
|
1370
|
+
contributions: PageFragmentContribution[];
|
|
1371
|
+
}>>;
|
|
1372
|
+
/**
|
|
1373
|
+
* Check if any hooks are registered for a given name
|
|
1374
|
+
*/
|
|
1375
|
+
hasHooks(name: HookNameV2): boolean;
|
|
1376
|
+
/**
|
|
1377
|
+
* Get hook count for debugging
|
|
1378
|
+
*/
|
|
1379
|
+
getHookCount(name: HookNameV2): number;
|
|
1380
|
+
/**
|
|
1381
|
+
* Get all registered hook names
|
|
1382
|
+
*/
|
|
1383
|
+
getRegisteredHooks(): HookNameV2[];
|
|
1384
|
+
/**
|
|
1385
|
+
* Returns hook names where at least one handler declared exclusive: true
|
|
1386
|
+
*/
|
|
1387
|
+
getRegisteredExclusiveHooks(): string[];
|
|
1388
|
+
/**
|
|
1389
|
+
* Check if a hook is exclusive
|
|
1390
|
+
*/
|
|
1391
|
+
isExclusiveHook(name: string): boolean;
|
|
1392
|
+
/**
|
|
1393
|
+
* Set the selected provider for an exclusive hook.
|
|
1394
|
+
* Called by PluginManager after resolution.
|
|
1395
|
+
*/
|
|
1396
|
+
setExclusiveSelection(hookName: string, pluginId: string): void;
|
|
1397
|
+
/**
|
|
1398
|
+
* Clear the selected provider for an exclusive hook.
|
|
1399
|
+
*/
|
|
1400
|
+
clearExclusiveSelection(hookName: string): void;
|
|
1401
|
+
/**
|
|
1402
|
+
* Get the selected provider for an exclusive hook (if any).
|
|
1403
|
+
*/
|
|
1404
|
+
getExclusiveSelection(hookName: string): string | undefined;
|
|
1405
|
+
/**
|
|
1406
|
+
* Get all plugins that registered a handler for a given exclusive hook.
|
|
1407
|
+
*/
|
|
1408
|
+
getExclusiveHookProviders(hookName: string): Array<{
|
|
1409
|
+
pluginId: string;
|
|
1410
|
+
}>;
|
|
1411
|
+
/**
|
|
1412
|
+
* Get all plugins that registered a non-exclusive handler for a given hook,
|
|
1413
|
+
* preserving priority order. This partitions with getExclusiveHookProviders().
|
|
1414
|
+
*/
|
|
1415
|
+
getHookProviders(hookName: string): Array<{
|
|
1416
|
+
pluginId: string;
|
|
1417
|
+
}>;
|
|
1418
|
+
/**
|
|
1419
|
+
* Invoke an exclusive hook — dispatch only to the selected provider.
|
|
1420
|
+
* Returns null if no provider is selected or if the selected hook
|
|
1421
|
+
* is not found in the pipeline.
|
|
1422
|
+
*
|
|
1423
|
+
* This is a generic dispatch used by the email pipeline and other
|
|
1424
|
+
* exclusive hook consumers. The handler type is unknown — callers
|
|
1425
|
+
* must know the expected signature.
|
|
1426
|
+
*
|
|
1427
|
+
* Errors are isolated: a failing handler returns an error result
|
|
1428
|
+
* instead of propagating the exception to the caller.
|
|
1429
|
+
*/
|
|
1430
|
+
invokeExclusiveHook(hookName: string, event: unknown): Promise<{
|
|
1431
|
+
result: unknown;
|
|
1432
|
+
pluginId: string;
|
|
1433
|
+
error?: Error;
|
|
1434
|
+
duration: number;
|
|
1435
|
+
} | null>;
|
|
1177
1436
|
}
|
|
1178
|
-
//#endregion
|
|
1179
|
-
//#region src/schema/query.d.ts
|
|
1180
1437
|
/**
|
|
1181
|
-
*
|
|
1182
|
-
*
|
|
1183
|
-
* @example
|
|
1184
|
-
* ```ts
|
|
1185
|
-
* import { getCollectionInfo } from "dineway";
|
|
1186
|
-
*
|
|
1187
|
-
* const info = await getCollectionInfo("posts");
|
|
1188
|
-
* if (info?.commentsEnabled) {
|
|
1189
|
-
* // render comment UI
|
|
1190
|
-
* }
|
|
1191
|
-
* ```
|
|
1438
|
+
* Create a hook pipeline from plugins
|
|
1192
1439
|
*/
|
|
1193
|
-
declare function
|
|
1440
|
+
declare function createHookPipeline(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions): HookPipeline;
|
|
1194
1441
|
//#endregion
|
|
1195
|
-
//#region src/
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
* Section as returned to templates/admin
|
|
1202
|
-
*/
|
|
1203
|
-
interface Section {
|
|
1204
|
-
id: string;
|
|
1205
|
-
slug: string;
|
|
1206
|
-
title: string;
|
|
1207
|
-
description?: string;
|
|
1208
|
-
keywords: string[];
|
|
1209
|
-
content: PortableTextBlock$1[];
|
|
1210
|
-
previewUrl?: string;
|
|
1211
|
-
source: SectionSource;
|
|
1212
|
-
themeId?: string;
|
|
1213
|
-
createdAt: string;
|
|
1214
|
-
updatedAt: string;
|
|
1215
|
-
}
|
|
1216
|
-
/**
|
|
1217
|
-
* Input for creating a section
|
|
1218
|
-
*/
|
|
1219
|
-
interface CreateSectionInput {
|
|
1220
|
-
slug: string;
|
|
1221
|
-
title: string;
|
|
1222
|
-
description?: string;
|
|
1223
|
-
keywords?: string[];
|
|
1224
|
-
content: PortableTextBlock$1[];
|
|
1225
|
-
previewMediaId?: string;
|
|
1226
|
-
source?: SectionSource;
|
|
1227
|
-
themeId?: string;
|
|
1228
|
-
}
|
|
1229
|
-
/**
|
|
1230
|
-
* Input for updating a section
|
|
1231
|
-
*/
|
|
1232
|
-
interface UpdateSectionInput {
|
|
1233
|
-
slug?: string;
|
|
1234
|
-
title?: string;
|
|
1235
|
-
description?: string;
|
|
1236
|
-
keywords?: string[];
|
|
1237
|
-
content?: PortableTextBlock$1[];
|
|
1238
|
-
previewMediaId?: string | null;
|
|
1239
|
-
}
|
|
1240
|
-
/**
|
|
1241
|
-
* Options for querying sections
|
|
1242
|
-
*/
|
|
1243
|
-
interface GetSectionsOptions {
|
|
1244
|
-
/** Filter by source */
|
|
1245
|
-
source?: SectionSource;
|
|
1246
|
-
/** Search title, description, keywords */
|
|
1247
|
-
search?: string;
|
|
1248
|
-
/** Limit results */
|
|
1249
|
-
limit?: number;
|
|
1250
|
-
/** Cursor for pagination */
|
|
1251
|
-
cursor?: string;
|
|
1442
|
+
//#region src/plugins/mcp.d.ts
|
|
1443
|
+
interface RegisteredPluginMcpTool {
|
|
1444
|
+
pluginId: string;
|
|
1445
|
+
pluginVersion: string;
|
|
1446
|
+
tool: PluginMcpTool;
|
|
1447
|
+
authorizeTarget?: PluginMcpTargetAuthorizer$1;
|
|
1252
1448
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
* const results = await getSections({ search: "pricing" });
|
|
1281
|
-
* ```
|
|
1282
|
-
*/
|
|
1283
|
-
declare function getSections(options?: GetSectionsOptions): Promise<FindManyResult<Section>>;
|
|
1449
|
+
interface RegisteredPluginMcpResource {
|
|
1450
|
+
pluginId: string;
|
|
1451
|
+
pluginVersion: string;
|
|
1452
|
+
resource: PluginMcpResource;
|
|
1453
|
+
authorizeTarget?: PluginMcpTargetAuthorizer$1;
|
|
1454
|
+
}
|
|
1455
|
+
interface PluginMcpRegistry {
|
|
1456
|
+
tools: RegisteredPluginMcpTool[];
|
|
1457
|
+
resources: RegisteredPluginMcpResource[];
|
|
1458
|
+
}
|
|
1459
|
+
interface PluginMcpTargetAuthorizationRequest {
|
|
1460
|
+
restaurantPermission: string;
|
|
1461
|
+
target: PluginTargetScope;
|
|
1462
|
+
context: PluginMcpExecutionContext;
|
|
1463
|
+
}
|
|
1464
|
+
type PluginMcpTargetAuthorizer = (request: PluginMcpTargetAuthorizationRequest) => Promise<void>;
|
|
1465
|
+
interface PluginMcpReviewMetadata {
|
|
1466
|
+
hitlRequestId?: string;
|
|
1467
|
+
quickActionHash?: string;
|
|
1468
|
+
}
|
|
1469
|
+
interface PluginMcpCommandExecutionRequest {
|
|
1470
|
+
target?: PluginTargetScope;
|
|
1471
|
+
review: PluginMcpReviewMetadata;
|
|
1472
|
+
}
|
|
1473
|
+
type PluginMcpCommandExecutor = (command: RegisteredPluginMcpTool & {
|
|
1474
|
+
tool: PluginMcpCommandTool;
|
|
1475
|
+
}, input: Record<string, unknown>, context: PluginMcpExecutionContext, request: PluginMcpCommandExecutionRequest) => Promise<Record<string, unknown>>;
|
|
1284
1476
|
//#endregion
|
|
1285
1477
|
//#region src/plugins/sandbox/types.d.ts
|
|
1286
1478
|
/**
|
|
@@ -1384,6 +1576,8 @@ interface SerializedRequest {
|
|
|
1384
1576
|
headers: Record<string, string>;
|
|
1385
1577
|
/** Normalized request metadata extracted before RPC serialization */
|
|
1386
1578
|
meta: RequestMeta;
|
|
1579
|
+
/** Safe authenticated actor metadata; null for unauthenticated public routes. */
|
|
1580
|
+
actor?: PluginActor | null;
|
|
1387
1581
|
}
|
|
1388
1582
|
/**
|
|
1389
1583
|
* Sandbox runner interface.
|
|
@@ -1430,1429 +1624,1654 @@ interface SandboxRunner {
|
|
|
1430
1624
|
*/
|
|
1431
1625
|
type SandboxRunnerFactory = (options: SandboxOptions) => SandboxRunner;
|
|
1432
1626
|
//#endregion
|
|
1433
|
-
//#region src/
|
|
1434
|
-
/**
|
|
1435
|
-
* Portable Text Types
|
|
1436
|
-
*
|
|
1437
|
-
* Defines the structure of Portable Text blocks used in Dineway.
|
|
1438
|
-
*/
|
|
1627
|
+
//#region src/plugins/routes.d.ts
|
|
1439
1628
|
/**
|
|
1440
|
-
*
|
|
1629
|
+
* Result from a route invocation
|
|
1441
1630
|
*/
|
|
1442
|
-
interface
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1631
|
+
interface RouteResult<T = unknown> {
|
|
1632
|
+
success: boolean;
|
|
1633
|
+
data?: T;
|
|
1634
|
+
error?: {
|
|
1635
|
+
code: string;
|
|
1636
|
+
message: string;
|
|
1637
|
+
details?: unknown;
|
|
1638
|
+
};
|
|
1639
|
+
status: number;
|
|
1447
1640
|
}
|
|
1448
1641
|
/**
|
|
1449
|
-
*
|
|
1642
|
+
* Route invocation options
|
|
1450
1643
|
*/
|
|
1451
|
-
interface
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1644
|
+
interface InvokeRouteOptions {
|
|
1645
|
+
/** The original request */
|
|
1646
|
+
request: Request;
|
|
1647
|
+
/** Request body (already parsed) */
|
|
1648
|
+
body?: unknown;
|
|
1649
|
+
/** Exact request bytes for routes that declare body: "raw". */
|
|
1650
|
+
rawBody?: Uint8Array;
|
|
1651
|
+
/** Normalized authenticated actor supplied by the core route boundary. */
|
|
1652
|
+
actor?: PluginActor | null;
|
|
1455
1653
|
}
|
|
1456
1654
|
/**
|
|
1457
|
-
*
|
|
1655
|
+
* Error class for plugin routes
|
|
1656
|
+
* Allows plugins to return structured errors with specific HTTP status codes
|
|
1458
1657
|
*/
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1658
|
+
declare class PluginRouteError extends Error {
|
|
1659
|
+
code: string;
|
|
1660
|
+
status: number;
|
|
1661
|
+
details?: unknown | undefined;
|
|
1662
|
+
constructor(code: string, message: string, status?: number, details?: unknown | undefined);
|
|
1663
|
+
/**
|
|
1664
|
+
* Create a bad request error (400)
|
|
1665
|
+
*/
|
|
1666
|
+
static badRequest(message: string, details?: unknown): PluginRouteError;
|
|
1667
|
+
/**
|
|
1668
|
+
* Create an unauthorized error (401)
|
|
1669
|
+
*/
|
|
1670
|
+
static unauthorized(message?: string): PluginRouteError;
|
|
1671
|
+
/**
|
|
1672
|
+
* Create a forbidden error (403)
|
|
1673
|
+
*/
|
|
1674
|
+
static forbidden(message?: string): PluginRouteError;
|
|
1675
|
+
/**
|
|
1676
|
+
* Create a not found error (404)
|
|
1677
|
+
*/
|
|
1678
|
+
static notFound(message?: string): PluginRouteError;
|
|
1679
|
+
/**
|
|
1680
|
+
* Create a conflict error (409)
|
|
1681
|
+
*/
|
|
1682
|
+
static conflict(message: string, details?: unknown): PluginRouteError;
|
|
1683
|
+
/**
|
|
1684
|
+
* Create an internal error (500)
|
|
1685
|
+
*/
|
|
1686
|
+
static internal(message?: string): PluginRouteError;
|
|
1463
1687
|
}
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
_key: string;
|
|
1470
|
-
style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote";
|
|
1471
|
-
listItem?: "bullet" | "number";
|
|
1472
|
-
level?: number;
|
|
1473
|
-
children: PortableTextSpan[];
|
|
1474
|
-
markDefs?: PortableTextMarkDef[];
|
|
1688
|
+
//#endregion
|
|
1689
|
+
//#region src/plugins/sandbox/runtime-options.d.ts
|
|
1690
|
+
interface SandboxRunnerRuntimeOptions extends SandboxOptions {
|
|
1691
|
+
mediaStorage?: Storage;
|
|
1692
|
+
cronReschedule?: () => void;
|
|
1475
1693
|
}
|
|
1694
|
+
//#endregion
|
|
1695
|
+
//#region src/dineway-runtime.d.ts
|
|
1476
1696
|
/**
|
|
1477
|
-
*
|
|
1697
|
+
* Sandboxed plugin entry from virtual module
|
|
1478
1698
|
*/
|
|
1479
|
-
interface
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1699
|
+
interface SandboxedPluginEntry {
|
|
1700
|
+
id: string;
|
|
1701
|
+
version: string;
|
|
1702
|
+
options: Record<string, unknown>;
|
|
1703
|
+
code: string;
|
|
1704
|
+
/** Capabilities the plugin requests */
|
|
1705
|
+
capabilities: PluginCapability[];
|
|
1706
|
+
/** Allowed hosts for network:request */
|
|
1707
|
+
allowedHosts: string[];
|
|
1708
|
+
/** Declared storage collections */
|
|
1709
|
+
storage: PluginStorageConfig;
|
|
1710
|
+
/** Admin pages */
|
|
1711
|
+
adminPages?: Array<{
|
|
1712
|
+
path: string;
|
|
1713
|
+
label?: string;
|
|
1714
|
+
icon?: string;
|
|
1715
|
+
}>;
|
|
1716
|
+
/** Dashboard widgets */
|
|
1717
|
+
adminWidgets?: Array<{
|
|
1718
|
+
id: string;
|
|
1719
|
+
title?: string;
|
|
1720
|
+
size?: string;
|
|
1721
|
+
}>;
|
|
1722
|
+
/** Portable Text block types contributed to the editor through declarative Block Kit. */
|
|
1723
|
+
portableTextBlocks?: PortableTextBlockConfig[];
|
|
1724
|
+
/** Field widget types contributed for schema-field editing UIs. */
|
|
1725
|
+
fieldWidgets?: FieldWidgetConfig[];
|
|
1726
|
+
/** Admin entry module */
|
|
1727
|
+
adminEntry?: string;
|
|
1728
|
+
/**
|
|
1729
|
+
* Exclusive hooks this plugin should be auto-selected for.
|
|
1730
|
+
* Weaker than an existing admin DB selection — config order wins when no selection exists.
|
|
1731
|
+
*/
|
|
1732
|
+
preferred?: string[];
|
|
1733
|
+
}
|
|
1734
|
+
//#endregion
|
|
1735
|
+
//#region src/api/handlers/manifest.d.ts
|
|
1736
|
+
interface CollectionDefinition {
|
|
1737
|
+
schema: {
|
|
1738
|
+
_def?: {
|
|
1739
|
+
shape?: () => Record<string, unknown>;
|
|
1740
|
+
};
|
|
1741
|
+
shape?: Record<string, unknown>;
|
|
1742
|
+
};
|
|
1743
|
+
admin: {
|
|
1744
|
+
label: string;
|
|
1745
|
+
labelSingular?: string;
|
|
1746
|
+
supports?: string[];
|
|
1486
1747
|
};
|
|
1487
|
-
alt?: string;
|
|
1488
|
-
caption?: string;
|
|
1489
|
-
/** Original image width */
|
|
1490
|
-
width?: number;
|
|
1491
|
-
/** Original image height */
|
|
1492
|
-
height?: number;
|
|
1493
|
-
/** Display width for this instance (overrides original) */
|
|
1494
|
-
displayWidth?: number;
|
|
1495
|
-
/** Display height for this instance (overrides original) */
|
|
1496
|
-
displayHeight?: number;
|
|
1497
1748
|
}
|
|
1749
|
+
type CollectionMap = Record<string, CollectionDefinition>;
|
|
1498
1750
|
/**
|
|
1499
|
-
*
|
|
1751
|
+
* Generate admin manifest from collections
|
|
1500
1752
|
*/
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1753
|
+
declare function generateManifest(collections: CollectionMap, plugins?: Record<string, {
|
|
1754
|
+
adminPages?: Array<{
|
|
1755
|
+
path: string;
|
|
1756
|
+
component: string;
|
|
1757
|
+
}>;
|
|
1758
|
+
widgets?: string[];
|
|
1759
|
+
}>): Promise<ManifestResponse>;
|
|
1760
|
+
//#endregion
|
|
1761
|
+
//#region src/api/handlers/revision.d.ts
|
|
1762
|
+
interface RevisionListResponse {
|
|
1763
|
+
items: Revision[];
|
|
1764
|
+
total: number;
|
|
1507
1765
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
*/
|
|
1511
|
-
interface PortableTextHtmlBlock {
|
|
1512
|
-
_type: "htmlBlock";
|
|
1513
|
-
_key: string;
|
|
1514
|
-
html: string;
|
|
1766
|
+
interface RevisionResponse {
|
|
1767
|
+
item: Revision;
|
|
1515
1768
|
}
|
|
1516
1769
|
/**
|
|
1517
|
-
*
|
|
1770
|
+
* List revisions for a content entry
|
|
1518
1771
|
*/
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
[key: string]: unknown;
|
|
1523
|
-
}
|
|
1772
|
+
declare function handleRevisionList(db: Kysely<Database>, collection: string, entryId: string, params?: {
|
|
1773
|
+
limit?: number;
|
|
1774
|
+
}): Promise<ApiResult<RevisionListResponse>>;
|
|
1524
1775
|
/**
|
|
1525
|
-
*
|
|
1776
|
+
* Get a specific revision
|
|
1526
1777
|
*/
|
|
1527
|
-
|
|
1778
|
+
declare function handleRevisionGet(db: Kysely<Database>, revisionId: string): Promise<ApiResult<RevisionResponse>>;
|
|
1528
1779
|
/**
|
|
1529
|
-
*
|
|
1780
|
+
* Restore a revision (updates content to this revision's data and creates new revision)
|
|
1530
1781
|
*/
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
attrs?: Record<string, unknown>;
|
|
1538
|
-
content?: ProseMirrorNode[];
|
|
1539
|
-
marks?: ProseMirrorMark[];
|
|
1540
|
-
text?: string;
|
|
1782
|
+
declare function handleRevisionRestore(db: Kysely<Database>, revisionId: string, callerUserId: string): Promise<ApiResult<ContentResponse>>;
|
|
1783
|
+
//#endregion
|
|
1784
|
+
//#region src/api/handlers/media.d.ts
|
|
1785
|
+
interface MediaListResponse {
|
|
1786
|
+
items: MediaItem[];
|
|
1787
|
+
nextCursor?: string;
|
|
1541
1788
|
}
|
|
1542
|
-
interface
|
|
1543
|
-
|
|
1544
|
-
content: ProseMirrorNode[];
|
|
1789
|
+
interface MediaResponse {
|
|
1790
|
+
item: MediaItem;
|
|
1545
1791
|
}
|
|
1546
|
-
//#endregion
|
|
1547
|
-
//#region src/content/converters/prosemirror-to-portable-text.d.ts
|
|
1548
1792
|
/**
|
|
1549
|
-
*
|
|
1793
|
+
* List media items
|
|
1550
1794
|
*/
|
|
1551
|
-
declare function
|
|
1552
|
-
|
|
1553
|
-
|
|
1795
|
+
declare function handleMediaList(db: Kysely<Database>, params: {
|
|
1796
|
+
cursor?: string;
|
|
1797
|
+
limit?: number;
|
|
1798
|
+
mimeType?: string | readonly string[];
|
|
1799
|
+
q?: string;
|
|
1800
|
+
}): Promise<ApiResult<MediaListResponse>>;
|
|
1554
1801
|
/**
|
|
1555
|
-
*
|
|
1802
|
+
* Get single media item
|
|
1556
1803
|
*/
|
|
1557
|
-
declare function
|
|
1558
|
-
//#endregion
|
|
1559
|
-
//#region src/utils/hash.d.ts
|
|
1804
|
+
declare function handleMediaGet(db: Kysely<Database>, id: string): Promise<ApiResult<MediaResponse>>;
|
|
1560
1805
|
/**
|
|
1561
|
-
*
|
|
1562
|
-
* For cache invalidation / ETags — not for security.
|
|
1806
|
+
* Create media item (after file upload)
|
|
1563
1807
|
*/
|
|
1564
|
-
declare function
|
|
1808
|
+
declare function handleMediaCreate(db: Kysely<Database>, input: {
|
|
1809
|
+
filename: string;
|
|
1810
|
+
mimeType: string;
|
|
1811
|
+
size?: number;
|
|
1812
|
+
width?: number;
|
|
1813
|
+
height?: number;
|
|
1814
|
+
alt?: string;
|
|
1815
|
+
storageKey: string;
|
|
1816
|
+
contentHash?: string;
|
|
1817
|
+
blurhash?: string;
|
|
1818
|
+
dominantColor?: string;
|
|
1819
|
+
authorId?: string;
|
|
1820
|
+
}): Promise<ApiResult<MediaResponse>>;
|
|
1565
1821
|
/**
|
|
1566
|
-
*
|
|
1567
|
-
*
|
|
1568
|
-
* Uses SHA-1 which is the fastest option in SubtleCrypto.
|
|
1569
|
-
* SHA-1 is cryptographically weak but fine for content deduplication
|
|
1570
|
-
* where we only need to detect identical files, not resist attacks.
|
|
1571
|
-
*
|
|
1572
|
-
* Returns hex string prefixed with "sha1:" for future-proofing
|
|
1822
|
+
* Update media metadata
|
|
1573
1823
|
*/
|
|
1574
|
-
declare function
|
|
1824
|
+
declare function handleMediaUpdate(db: Kysely<Database>, id: string, input: {
|
|
1825
|
+
alt?: string;
|
|
1826
|
+
caption?: string;
|
|
1827
|
+
width?: number;
|
|
1828
|
+
height?: number;
|
|
1829
|
+
}): Promise<ApiResult<MediaResponse>>;
|
|
1830
|
+
/**
|
|
1831
|
+
* Delete media item
|
|
1832
|
+
*/
|
|
1833
|
+
declare function handleMediaDelete(db: Kysely<Database>, id: string): Promise<ApiResult<{
|
|
1834
|
+
deleted: true;
|
|
1835
|
+
}>>;
|
|
1575
1836
|
//#endregion
|
|
1576
|
-
//#region src/
|
|
1837
|
+
//#region src/schema/registry.d.ts
|
|
1577
1838
|
/**
|
|
1578
|
-
*
|
|
1579
|
-
*
|
|
1580
|
-
* Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
|
|
1581
|
-
* by allowlisting known-safe schemes before rendering into href attributes.
|
|
1839
|
+
* Error thrown when a schema operation fails
|
|
1582
1840
|
*/
|
|
1841
|
+
declare class SchemaError extends Error {
|
|
1842
|
+
code: string;
|
|
1843
|
+
details?: Record<string, unknown> | undefined;
|
|
1844
|
+
constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
|
|
1845
|
+
}
|
|
1583
1846
|
/**
|
|
1584
|
-
*
|
|
1585
|
-
*
|
|
1586
|
-
* Use this at the render layer as the primary defense against XSS via
|
|
1587
|
-
* dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
|
|
1847
|
+
* Schema Registry
|
|
1588
1848
|
*
|
|
1589
|
-
*
|
|
1590
|
-
*
|
|
1591
|
-
* sanitizeHref("https://example.com") // "https://example.com"
|
|
1592
|
-
* sanitizeHref("/about") // "/about"
|
|
1593
|
-
* sanitizeHref("#section") // "#section"
|
|
1594
|
-
* sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
|
|
1595
|
-
* sanitizeHref("javascript:alert(1)") // "#"
|
|
1596
|
-
* sanitizeHref("data:text/html,<script>") // "#"
|
|
1597
|
-
* sanitizeHref("") // "#"
|
|
1598
|
-
* ```
|
|
1599
|
-
*/
|
|
1600
|
-
declare function sanitizeHref(url: string | undefined | null): string;
|
|
1601
|
-
/**
|
|
1602
|
-
* Returns true if the URL uses a safe scheme for rendering in href attributes.
|
|
1603
|
-
*/
|
|
1604
|
-
declare function isSafeHref(url: string): boolean;
|
|
1605
|
-
//#endregion
|
|
1606
|
-
//#region src/loader.d.ts
|
|
1607
|
-
/**
|
|
1608
|
-
* Entry data type - generic object
|
|
1609
|
-
*/
|
|
1610
|
-
type EntryData = Record<string, unknown>;
|
|
1611
|
-
/**
|
|
1612
|
-
* Sort direction
|
|
1613
|
-
*/
|
|
1614
|
-
type SortDirection$1 = "asc" | "desc";
|
|
1615
|
-
/**
|
|
1616
|
-
* Order by specification - field name to direction
|
|
1617
|
-
* @example { created_at: "desc" } - Sort by created_at descending
|
|
1618
|
-
* @example { title: "asc" } - Sort by title ascending
|
|
1619
|
-
*/
|
|
1620
|
-
type OrderBySpec$1 = Record<string, SortDirection$1>;
|
|
1621
|
-
/**
|
|
1622
|
-
* Range filter for comparison operators on field values.
|
|
1623
|
-
* ISO 8601 timestamps sort lexicographically in the same order as time.
|
|
1624
|
-
*/
|
|
1625
|
-
interface WhereRange {
|
|
1626
|
-
gt?: string;
|
|
1627
|
-
gte?: string;
|
|
1628
|
-
lt?: string;
|
|
1629
|
-
lte?: string;
|
|
1630
|
-
}
|
|
1631
|
-
type WhereValue = string | string[] | WhereRange;
|
|
1632
|
-
/**
|
|
1633
|
-
* Filter for loadCollection - type is required
|
|
1849
|
+
* Manages collection and field definitions stored in the database.
|
|
1850
|
+
* Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).
|
|
1634
1851
|
*/
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
limit?: number;
|
|
1852
|
+
declare class SchemaRegistry {
|
|
1853
|
+
private db;
|
|
1854
|
+
constructor(db: Kysely<Database>);
|
|
1639
1855
|
/**
|
|
1640
|
-
*
|
|
1641
|
-
* Pass the `nextCursor` value from a previous result to fetch the next page.
|
|
1856
|
+
* List all collections
|
|
1642
1857
|
*/
|
|
1643
|
-
|
|
1858
|
+
listCollections(): Promise<Collection[]>;
|
|
1644
1859
|
/**
|
|
1645
|
-
*
|
|
1860
|
+
* List all collections with their fields using bounded query shapes.
|
|
1861
|
+
*/
|
|
1862
|
+
listCollectionsWithFields(): Promise<CollectionWithFields[]>;
|
|
1863
|
+
/**
|
|
1864
|
+
* Get a collection by slug
|
|
1865
|
+
*/
|
|
1866
|
+
getCollection(slug: string): Promise<Collection | null>;
|
|
1867
|
+
/**
|
|
1868
|
+
* Get a collection with all its fields
|
|
1869
|
+
*/
|
|
1870
|
+
getCollectionWithFields(slug: string): Promise<CollectionWithFields | null>;
|
|
1871
|
+
/**
|
|
1872
|
+
* Create a new collection
|
|
1873
|
+
*/
|
|
1874
|
+
createCollection(input: CreateCollectionInput): Promise<Collection>;
|
|
1875
|
+
/**
|
|
1876
|
+
* Update a collection
|
|
1877
|
+
*/
|
|
1878
|
+
updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection>;
|
|
1879
|
+
private validateUrlPattern;
|
|
1880
|
+
private checkLabelUniqueness;
|
|
1881
|
+
private checkUrlPatternUniqueness;
|
|
1882
|
+
/**
|
|
1883
|
+
* Delete a collection
|
|
1884
|
+
*/
|
|
1885
|
+
deleteCollection(slug: string, options?: {
|
|
1886
|
+
force?: boolean;
|
|
1887
|
+
}): Promise<void>;
|
|
1888
|
+
/**
|
|
1889
|
+
* List fields for a collection
|
|
1890
|
+
*/
|
|
1891
|
+
listFields(collectionId: string): Promise<Field[]>;
|
|
1892
|
+
/**
|
|
1893
|
+
* Get a field by slug within a collection
|
|
1894
|
+
*/
|
|
1895
|
+
getField(collectionSlug: string, fieldSlug: string): Promise<Field | null>;
|
|
1896
|
+
/**
|
|
1897
|
+
* Create a new field
|
|
1898
|
+
*/
|
|
1899
|
+
createField(collectionSlug: string, input: CreateFieldInput): Promise<Field>;
|
|
1900
|
+
/**
|
|
1901
|
+
* Ensure the content table for an existing collection exists.
|
|
1646
1902
|
*
|
|
1647
|
-
*
|
|
1648
|
-
*
|
|
1649
|
-
* not just the primary credit. Other keys are treated as content table
|
|
1650
|
-
* column filters.
|
|
1903
|
+
* This repairs interrupted schema creation where the metadata row exists but
|
|
1904
|
+
* the physical `ec_*` table was not created.
|
|
1651
1905
|
*/
|
|
1652
|
-
|
|
1653
|
-
/** Case-insensitive substring search across the provided columns. */
|
|
1654
|
-
q?: string;
|
|
1655
|
-
searchColumns?: string[];
|
|
1906
|
+
ensureCollectionContentTable(collectionSlug: string): Promise<boolean>;
|
|
1656
1907
|
/**
|
|
1657
|
-
*
|
|
1658
|
-
*
|
|
1908
|
+
* Ensure the physical column for an existing field exists on its content table.
|
|
1909
|
+
*
|
|
1910
|
+
* This repairs interrupted field creation where `_dineway_fields` was written
|
|
1911
|
+
* but `ALTER TABLE ec_* ADD COLUMN` did not complete.
|
|
1659
1912
|
*/
|
|
1660
|
-
|
|
1913
|
+
ensureFieldColumn(collectionSlug: string, fieldSlug: string): Promise<boolean>;
|
|
1661
1914
|
/**
|
|
1662
|
-
*
|
|
1663
|
-
* When set, only returns content in this locale.
|
|
1915
|
+
* Update a field
|
|
1664
1916
|
*/
|
|
1665
|
-
|
|
1666
|
-
}
|
|
1667
|
-
/**
|
|
1668
|
-
* Filter for loadEntry - type and id are required
|
|
1669
|
-
*/
|
|
1670
|
-
interface EntryFilter {
|
|
1671
|
-
type: string;
|
|
1672
|
-
id: string;
|
|
1917
|
+
updateField(collectionSlug: string, fieldSlug: string, input: UpdateFieldInput): Promise<Field>;
|
|
1673
1918
|
/**
|
|
1674
|
-
*
|
|
1675
|
-
*
|
|
1919
|
+
* Synchronize an existing FTS index with the collection's current state.
|
|
1920
|
+
*
|
|
1921
|
+
* Schema writes must not first-time enable FTS. Initial enablement stays in
|
|
1922
|
+
* explicit seed/import/admin flows where FTS failures can be handled deliberately.
|
|
1676
1923
|
*/
|
|
1677
|
-
|
|
1924
|
+
private syncSearchState;
|
|
1678
1925
|
/**
|
|
1679
|
-
*
|
|
1680
|
-
* IDs are globally unique and always resolve regardless of locale.
|
|
1926
|
+
* Delete a field
|
|
1681
1927
|
*/
|
|
1682
|
-
|
|
1928
|
+
deleteField(collectionSlug: string, fieldSlug: string): Promise<void>;
|
|
1929
|
+
/**
|
|
1930
|
+
* Reorder fields
|
|
1931
|
+
*/
|
|
1932
|
+
reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void>;
|
|
1933
|
+
/**
|
|
1934
|
+
* Create a content table for a collection
|
|
1935
|
+
*/
|
|
1936
|
+
private createContentTable;
|
|
1937
|
+
/**
|
|
1938
|
+
* Drop a content table
|
|
1939
|
+
*/
|
|
1940
|
+
private dropContentTable;
|
|
1941
|
+
/**
|
|
1942
|
+
* Add a column to a content table
|
|
1943
|
+
*/
|
|
1944
|
+
private addColumn;
|
|
1945
|
+
/**
|
|
1946
|
+
* Drop a column from a content table
|
|
1947
|
+
*/
|
|
1948
|
+
private dropColumn;
|
|
1949
|
+
/**
|
|
1950
|
+
* Check if a collection has any content
|
|
1951
|
+
*/
|
|
1952
|
+
private collectionHasContent;
|
|
1953
|
+
/**
|
|
1954
|
+
* Get table name for a collection
|
|
1955
|
+
*/
|
|
1956
|
+
private getTableName;
|
|
1957
|
+
/**
|
|
1958
|
+
* Get column name for a field
|
|
1959
|
+
*/
|
|
1960
|
+
private getColumnName;
|
|
1961
|
+
/**
|
|
1962
|
+
* Validate a slug
|
|
1963
|
+
*/
|
|
1964
|
+
private validateSlug;
|
|
1965
|
+
/**
|
|
1966
|
+
* Format a default value for SQL.
|
|
1967
|
+
*
|
|
1968
|
+
* SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant
|
|
1969
|
+
* expression — parameterized values cannot be used here. We manually escape
|
|
1970
|
+
* single quotes and coerce types to ensure the output is safe.
|
|
1971
|
+
*
|
|
1972
|
+
* INTEGER/REAL values are coerced through `Number()` which can only produce
|
|
1973
|
+
* digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.
|
|
1974
|
+
* TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).
|
|
1975
|
+
*/
|
|
1976
|
+
private formatDefaultValue;
|
|
1977
|
+
/**
|
|
1978
|
+
* Get empty default for a field type
|
|
1979
|
+
*/
|
|
1980
|
+
private getEmptyDefault;
|
|
1981
|
+
/**
|
|
1982
|
+
* Map a collection row to a Collection object
|
|
1983
|
+
*/
|
|
1984
|
+
private mapCollectionRow;
|
|
1985
|
+
/**
|
|
1986
|
+
* Map a field row to a Field object
|
|
1987
|
+
*/
|
|
1988
|
+
private mapFieldRow;
|
|
1989
|
+
/**
|
|
1990
|
+
* Discover orphaned content tables
|
|
1991
|
+
*
|
|
1992
|
+
* Finds ec_* tables that exist in the database but don't have a
|
|
1993
|
+
* corresponding entry in _dineway_collections.
|
|
1994
|
+
*/
|
|
1995
|
+
discoverOrphanedTables(): Promise<Array<{
|
|
1996
|
+
slug: string;
|
|
1997
|
+
tableName: string;
|
|
1998
|
+
rowCount: number;
|
|
1999
|
+
}>>;
|
|
2000
|
+
/**
|
|
2001
|
+
* Register an orphaned table as a collection
|
|
2002
|
+
*
|
|
2003
|
+
* Creates a _dineway_collections entry for an existing ec_* table.
|
|
2004
|
+
*/
|
|
2005
|
+
registerOrphanedTable(slug: string, options?: {
|
|
2006
|
+
label?: string;
|
|
2007
|
+
labelSingular?: string;
|
|
2008
|
+
description?: string;
|
|
2009
|
+
}): Promise<Collection>;
|
|
2010
|
+
/**
|
|
2011
|
+
* Convert slug to human-readable label
|
|
2012
|
+
*/
|
|
2013
|
+
private slugToLabel;
|
|
1683
2014
|
}
|
|
2015
|
+
//#endregion
|
|
2016
|
+
//#region src/schema/query.d.ts
|
|
1684
2017
|
/**
|
|
1685
|
-
* Get
|
|
1686
|
-
*
|
|
1687
|
-
* Checks the ALS request context first — if a per-request DB override is set
|
|
1688
|
-
* (e.g. by preview or playground middleware), it takes precedence over the
|
|
1689
|
-
* module-level cached instance. This allows preview flows to route queries
|
|
1690
|
-
* to an isolated session database without modifying any calling code.
|
|
1691
|
-
*
|
|
1692
|
-
* Initializes the default database on first call using config from virtual module.
|
|
1693
|
-
*/
|
|
1694
|
-
declare function getDb(): Promise<Kysely<Database>>;
|
|
1695
|
-
/**
|
|
1696
|
-
* Create a Dineway Live Collections loader
|
|
1697
|
-
*
|
|
1698
|
-
* This loader handles ALL content types in a single Astro collection.
|
|
1699
|
-
* Use `getDinewayCollection()` and `getDinewayEntry()` to query
|
|
1700
|
-
* specific content types.
|
|
1701
|
-
*
|
|
1702
|
-
* Database is configured in astro.config.mjs via the dineway() integration.
|
|
2018
|
+
* Get collection metadata by slug.
|
|
1703
2019
|
*
|
|
1704
2020
|
* @example
|
|
1705
2021
|
* ```ts
|
|
1706
|
-
*
|
|
1707
|
-
* import { defineLiveCollection } from "astro:content";
|
|
1708
|
-
* import { dinewayLoader } from "dineway";
|
|
2022
|
+
* import { getCollectionInfo } from "dineway";
|
|
1709
2023
|
*
|
|
1710
|
-
*
|
|
1711
|
-
*
|
|
1712
|
-
*
|
|
1713
|
-
*
|
|
1714
|
-
*
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
declare function dinewayLoader(): LiveLoader<EntryData, EntryFilter, CollectionFilter$1>;
|
|
2024
|
+
* const info = await getCollectionInfo("posts");
|
|
2025
|
+
* if (info?.commentsEnabled) {
|
|
2026
|
+
* // render comment UI
|
|
2027
|
+
* }
|
|
2028
|
+
* ```
|
|
2029
|
+
*/
|
|
2030
|
+
declare function getCollectionInfo(slug: string): Promise<Collection | null>;
|
|
1718
2031
|
//#endregion
|
|
1719
|
-
//#region src/
|
|
2032
|
+
//#region src/sections/types.d.ts
|
|
1720
2033
|
/**
|
|
1721
|
-
*
|
|
1722
|
-
*
|
|
1723
|
-
* Creates Proxy objects that emit data-dineway-ref attributes when spread onto elements.
|
|
2034
|
+
* Section source types
|
|
1724
2035
|
*/
|
|
1725
|
-
|
|
1726
|
-
|
|
2036
|
+
type SectionSource = "theme" | "user" | "import";
|
|
2037
|
+
/**
|
|
2038
|
+
* Section as returned to templates/admin
|
|
2039
|
+
*/
|
|
2040
|
+
interface Section {
|
|
1727
2041
|
id: string;
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
2042
|
+
slug: string;
|
|
2043
|
+
title: string;
|
|
2044
|
+
description?: string;
|
|
2045
|
+
keywords: string[];
|
|
2046
|
+
content: PortableTextBlock$1[];
|
|
2047
|
+
previewUrl?: string;
|
|
2048
|
+
source: SectionSource;
|
|
2049
|
+
themeId?: string;
|
|
2050
|
+
createdAt: string;
|
|
2051
|
+
updatedAt: string;
|
|
1737
2052
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
2053
|
+
/**
|
|
2054
|
+
* Input for creating a section
|
|
2055
|
+
*/
|
|
2056
|
+
interface CreateSectionInput {
|
|
2057
|
+
slug: string;
|
|
2058
|
+
title: string;
|
|
2059
|
+
description?: string;
|
|
2060
|
+
keywords?: string[];
|
|
2061
|
+
content: PortableTextBlock$1[];
|
|
2062
|
+
previewMediaId?: string;
|
|
2063
|
+
source?: SectionSource;
|
|
2064
|
+
themeId?: string;
|
|
1743
2065
|
}
|
|
1744
2066
|
/**
|
|
1745
|
-
*
|
|
1746
|
-
*
|
|
1747
|
-
* Usage:
|
|
1748
|
-
* - `{...entry.edit}` - entry-level annotation (includes status/hasDraft)
|
|
1749
|
-
* - `{...entry.edit.title}` - field-level annotation
|
|
1750
|
-
* - `{...entry.edit['nested.field']}` - nested field (bracket notation)
|
|
2067
|
+
* Input for updating a section
|
|
1751
2068
|
*/
|
|
1752
|
-
|
|
2069
|
+
interface UpdateSectionInput {
|
|
2070
|
+
slug?: string;
|
|
2071
|
+
title?: string;
|
|
2072
|
+
description?: string;
|
|
2073
|
+
keywords?: string[];
|
|
2074
|
+
content?: PortableTextBlock$1[];
|
|
2075
|
+
previewMediaId?: string | null;
|
|
2076
|
+
}
|
|
1753
2077
|
/**
|
|
1754
|
-
*
|
|
1755
|
-
* Spreading this produces no attributes.
|
|
2078
|
+
* Options for querying sections
|
|
1756
2079
|
*/
|
|
1757
|
-
|
|
2080
|
+
interface GetSectionsOptions {
|
|
2081
|
+
/** Filter by source */
|
|
2082
|
+
source?: SectionSource;
|
|
2083
|
+
/** Search title, description, keywords */
|
|
2084
|
+
search?: string;
|
|
2085
|
+
/** Limit results */
|
|
2086
|
+
limit?: number;
|
|
2087
|
+
/** Cursor for pagination */
|
|
2088
|
+
cursor?: string;
|
|
2089
|
+
}
|
|
2090
|
+
//#endregion
|
|
2091
|
+
//#region src/sections/index.d.ts
|
|
1758
2092
|
/**
|
|
1759
|
-
*
|
|
2093
|
+
* Get a section by slug
|
|
1760
2094
|
*
|
|
1761
|
-
*
|
|
1762
|
-
*
|
|
2095
|
+
* @example
|
|
2096
|
+
* ```ts
|
|
2097
|
+
* import { getSection } from "dineway";
|
|
1763
2098
|
*
|
|
1764
|
-
*
|
|
2099
|
+
* const section = await getSection("hero-centered");
|
|
2100
|
+
* if (section) {
|
|
2101
|
+
* console.log(section.content); // Portable Text array
|
|
2102
|
+
* }
|
|
2103
|
+
* ```
|
|
1765
2104
|
*/
|
|
1766
|
-
|
|
1767
|
-
readonly [field: string]: Partial<FieldAnnotation>;
|
|
1768
|
-
};
|
|
1769
|
-
//#endregion
|
|
1770
|
-
//#region src/query.d.ts
|
|
2105
|
+
declare function getSection(slug: string): Promise<Section | null>;
|
|
1771
2106
|
/**
|
|
1772
|
-
*
|
|
1773
|
-
*
|
|
1774
|
-
* This interface is extended by the generated dineway-env.d.ts file
|
|
1775
|
-
* to provide type inference for collection names and their data shapes.
|
|
2107
|
+
* Get all sections with optional filtering
|
|
1776
2108
|
*
|
|
1777
2109
|
* @example
|
|
1778
2110
|
* ```ts
|
|
1779
|
-
*
|
|
1780
|
-
* declare module "dineway" {
|
|
1781
|
-
* interface DinewayCollections {
|
|
1782
|
-
* posts: { title: string; content: PortableTextBlock[]; };
|
|
1783
|
-
* pages: { title: string; body: PortableTextBlock[]; };
|
|
1784
|
-
* }
|
|
1785
|
-
* }
|
|
2111
|
+
* import { getSections } from "dineway";
|
|
1786
2112
|
*
|
|
1787
|
-
* //
|
|
1788
|
-
* const
|
|
1789
|
-
*
|
|
2113
|
+
* // Get all theme-provided sections
|
|
2114
|
+
* const themeSections = await getSections({ source: "theme" });
|
|
2115
|
+
*
|
|
2116
|
+
* // Search sections
|
|
2117
|
+
* const results = await getSections({ search: "pricing" });
|
|
1790
2118
|
* ```
|
|
1791
2119
|
*/
|
|
1792
|
-
|
|
2120
|
+
declare function getSections(options?: GetSectionsOptions): Promise<FindManyResult<Section>>;
|
|
2121
|
+
//#endregion
|
|
2122
|
+
//#region src/content/converters/types.d.ts
|
|
1793
2123
|
/**
|
|
1794
|
-
*
|
|
1795
|
-
*
|
|
2124
|
+
* Portable Text Types
|
|
2125
|
+
*
|
|
2126
|
+
* Defines the structure of Portable Text blocks used in Dineway.
|
|
1796
2127
|
*/
|
|
1797
|
-
type InferCollectionData<T extends string> = T extends keyof DinewayCollections ? DinewayCollections[T] : Record<string, unknown>;
|
|
1798
2128
|
/**
|
|
1799
|
-
*
|
|
2129
|
+
* Base span (inline text)
|
|
1800
2130
|
*/
|
|
1801
|
-
|
|
2131
|
+
interface PortableTextSpan {
|
|
2132
|
+
_type: "span";
|
|
2133
|
+
_key: string;
|
|
2134
|
+
text: string;
|
|
2135
|
+
marks?: string[];
|
|
2136
|
+
}
|
|
1802
2137
|
/**
|
|
1803
|
-
*
|
|
1804
|
-
* @example { created_at: "desc" } - Sort by created_at descending
|
|
1805
|
-
* @example { title: "asc" } - Sort by title ascending
|
|
1806
|
-
* @example { published_at: "desc", title: "asc" } - Multi-field sort
|
|
2138
|
+
* Mark definition (bold, italic, link, etc.)
|
|
1807
2139
|
*/
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
/**
|
|
1813
|
-
* Opaque cursor for keyset pagination.
|
|
1814
|
-
* Pass the `nextCursor` value from a previous result to fetch the next page.
|
|
1815
|
-
* @example
|
|
1816
|
-
* ```ts
|
|
1817
|
-
* const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
|
|
1818
|
-
* const { entries, nextCursor } = await getDinewayCollection("posts", {
|
|
1819
|
-
* limit: 10,
|
|
1820
|
-
* cursor,
|
|
1821
|
-
* });
|
|
1822
|
-
* ```
|
|
1823
|
-
*/
|
|
1824
|
-
cursor?: string;
|
|
1825
|
-
/**
|
|
1826
|
-
* Filter by field values, taxonomy terms, byline credits, or ranges.
|
|
1827
|
-
*
|
|
1828
|
-
* Taxonomy names are detected automatically and filtered by term.
|
|
1829
|
-
* The reserved `byline` key filters by byline credit in any position,
|
|
1830
|
-
* not just the primary credit. It accepts one or more byline translation
|
|
1831
|
-
* groups, or concrete byline row IDs.
|
|
1832
|
-
* Other keys are treated as content table column filters.
|
|
1833
|
-
*
|
|
1834
|
-
* @example { category: 'news' } - Filter by taxonomy term
|
|
1835
|
-
* @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
|
|
1836
|
-
* @example { byline: '01HXYZ...' } - Entries credited to a byline (any position)
|
|
1837
|
-
* @example { byline: ['01HXYZ...', '01HABC...'] } - Credited to any of these bylines (OR)
|
|
1838
|
-
* @example { series: 'main' } - Exact match on a content field
|
|
1839
|
-
* @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - Date range
|
|
1840
|
-
*/
|
|
1841
|
-
where?: Record<string, WhereValue>;
|
|
1842
|
-
/**
|
|
1843
|
-
* Case-insensitive substring search across selected content fields.
|
|
1844
|
-
*
|
|
1845
|
-
* `searchColumns` must contain concrete field slugs or system column names.
|
|
1846
|
-
* When `q` is present without `searchColumns`, no search condition is applied.
|
|
1847
|
-
*/
|
|
1848
|
-
q?: string;
|
|
1849
|
-
searchColumns?: string[];
|
|
1850
|
-
/**
|
|
1851
|
-
* Order results by field(s)
|
|
1852
|
-
* @default { created_at: "desc" }
|
|
1853
|
-
* @example { created_at: "desc" } - Sort by created_at descending (default)
|
|
1854
|
-
* @example { title: "asc" } - Sort by title ascending
|
|
1855
|
-
* @example { published_at: "desc", title: "asc" } - Multi-field sort
|
|
1856
|
-
*/
|
|
1857
|
-
orderBy?: OrderBySpec;
|
|
1858
|
-
/**
|
|
1859
|
-
* Filter by locale. When set, only returns entries in this locale.
|
|
1860
|
-
* Only relevant when i18n is configured.
|
|
1861
|
-
* @example "en" — English entries only
|
|
1862
|
-
* @example "fr" — French entries only
|
|
1863
|
-
*/
|
|
1864
|
-
locale?: string;
|
|
1865
|
-
}
|
|
1866
|
-
interface ContentEntry<T = Record<string, unknown>> {
|
|
1867
|
-
id: string;
|
|
1868
|
-
data: T;
|
|
1869
|
-
/** Visual editing annotations. Spread onto elements: {...entry.edit.title} */
|
|
1870
|
-
edit: EditProxy;
|
|
1871
|
-
}
|
|
1872
|
-
/** Cache hint returned by the content loader for route caching */
|
|
1873
|
-
interface CacheHint {
|
|
1874
|
-
tags?: string[];
|
|
1875
|
-
lastModified?: Date;
|
|
2140
|
+
interface PortableTextMarkDef {
|
|
2141
|
+
_type: string;
|
|
2142
|
+
_key: string;
|
|
2143
|
+
[key: string]: unknown;
|
|
1876
2144
|
}
|
|
1877
2145
|
/**
|
|
1878
|
-
*
|
|
2146
|
+
* Link mark definition
|
|
1879
2147
|
*/
|
|
1880
|
-
interface
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
error?: Error;
|
|
1885
|
-
/** Cache hint for route caching (pass to Astro.cache.set()) */
|
|
1886
|
-
cacheHint: CacheHint;
|
|
1887
|
-
/**
|
|
1888
|
-
* Opaque cursor for the next page.
|
|
1889
|
-
* Undefined when there are no more results.
|
|
1890
|
-
* Pass this as `cursor` in the next query to get the next page.
|
|
1891
|
-
*/
|
|
1892
|
-
nextCursor?: string;
|
|
1893
|
-
/**
|
|
1894
|
-
* Total number of entries matching the current filter, excluding cursor and limit.
|
|
1895
|
-
*/
|
|
1896
|
-
total?: number;
|
|
2148
|
+
interface PortableTextLinkMark extends PortableTextMarkDef {
|
|
2149
|
+
_type: "link";
|
|
2150
|
+
href: string;
|
|
2151
|
+
blank?: boolean;
|
|
1897
2152
|
}
|
|
1898
2153
|
/**
|
|
1899
|
-
*
|
|
2154
|
+
* Text block (paragraph, heading, etc.)
|
|
1900
2155
|
*/
|
|
1901
|
-
interface
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
/** Cache hint for route caching (pass to Astro.cache.set()) */
|
|
1911
|
-
cacheHint: CacheHint;
|
|
1912
|
-
}
|
|
1913
|
-
/** Edit metadata attached to PT arrays in edit mode */
|
|
1914
|
-
interface EditFieldMeta {
|
|
1915
|
-
collection: string;
|
|
1916
|
-
id: string;
|
|
1917
|
-
field: string;
|
|
2156
|
+
interface PortableTextTextBlock {
|
|
2157
|
+
_type: "block";
|
|
2158
|
+
_key: string;
|
|
2159
|
+
style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote";
|
|
2160
|
+
listItem?: "bullet" | "number";
|
|
2161
|
+
level?: number;
|
|
2162
|
+
children: PortableTextSpan[];
|
|
2163
|
+
markDefs?: PortableTextMarkDef[];
|
|
2164
|
+
textAlign?: "left" | "center" | "right" | "justify";
|
|
1918
2165
|
}
|
|
1919
2166
|
/**
|
|
1920
|
-
*
|
|
1921
|
-
* Uses Object.getOwnPropertyDescriptor to access Symbol-keyed property
|
|
1922
|
-
* without an unsafe type assertion.
|
|
2167
|
+
* Image block
|
|
1923
2168
|
*/
|
|
1924
|
-
|
|
2169
|
+
interface PortableTextImageBlock {
|
|
2170
|
+
_type: "image";
|
|
2171
|
+
_key: string;
|
|
2172
|
+
asset: {
|
|
2173
|
+
_ref: string;
|
|
2174
|
+
url?: string; /** Provider ID for external media (e.g., "image-cdn") */
|
|
2175
|
+
provider?: string;
|
|
2176
|
+
};
|
|
2177
|
+
alt?: string;
|
|
2178
|
+
caption?: string;
|
|
2179
|
+
/** Original image width */
|
|
2180
|
+
width?: number;
|
|
2181
|
+
/** Original image height */
|
|
2182
|
+
height?: number;
|
|
2183
|
+
/** Display width for this instance (overrides original) */
|
|
2184
|
+
displayWidth?: number;
|
|
2185
|
+
/** Display height for this instance (overrides original) */
|
|
2186
|
+
displayHeight?: number;
|
|
2187
|
+
}
|
|
1925
2188
|
/**
|
|
1926
|
-
*
|
|
1927
|
-
*
|
|
1928
|
-
* Returns { entries, error } for graceful error handling.
|
|
1929
|
-
*
|
|
1930
|
-
* When dineway-env.d.ts is generated, the collection name will be
|
|
1931
|
-
* type-checked and the return type will be inferred automatically.
|
|
1932
|
-
*
|
|
1933
|
-
* @example
|
|
1934
|
-
* ```ts
|
|
1935
|
-
* import { getDinewayCollection } from "dineway";
|
|
1936
|
-
*
|
|
1937
|
-
* const { entries: posts, error } = await getDinewayCollection("posts");
|
|
1938
|
-
* if (error) {
|
|
1939
|
-
* console.error("Failed to load posts:", error);
|
|
1940
|
-
* return;
|
|
1941
|
-
* }
|
|
1942
|
-
* // posts[0].data.title is typed (if dineway-env.d.ts exists)
|
|
1943
|
-
*
|
|
1944
|
-
* // With filters
|
|
1945
|
-
* const { entries: drafts } = await getDinewayCollection("posts", { status: "draft" });
|
|
1946
|
-
* ```
|
|
2189
|
+
* Code block
|
|
1947
2190
|
*/
|
|
1948
|
-
|
|
2191
|
+
interface PortableTextCodeBlock {
|
|
2192
|
+
_type: "code";
|
|
2193
|
+
_key: string;
|
|
2194
|
+
code: string;
|
|
2195
|
+
language?: string;
|
|
2196
|
+
filename?: string;
|
|
2197
|
+
}
|
|
1949
2198
|
/**
|
|
1950
|
-
*
|
|
1951
|
-
*
|
|
1952
|
-
* Returns { entry, error, isPreview } for graceful error handling.
|
|
1953
|
-
* - entry is null if not found (not an error)
|
|
1954
|
-
* - error is set only for actual errors (db issues, etc.)
|
|
1955
|
-
*
|
|
1956
|
-
* Preview mode is detected automatically from request context (ALS).
|
|
1957
|
-
* When the URL has a valid `_preview` token, the middleware sets preview
|
|
1958
|
-
* context and this function serves draft revision data if available.
|
|
1959
|
-
*
|
|
1960
|
-
* @example
|
|
1961
|
-
* ```ts
|
|
1962
|
-
* import { getDinewayEntry } from "dineway";
|
|
1963
|
-
*
|
|
1964
|
-
* // Simple usage — preview just works via middleware
|
|
1965
|
-
* const { entry: post, isPreview, error } = await getDinewayEntry("posts", "my-slug");
|
|
1966
|
-
* if (!post) return Astro.redirect("/404");
|
|
1967
|
-
* ```
|
|
2199
|
+
* HTML block (raw HTML content)
|
|
1968
2200
|
*/
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
2201
|
+
interface PortableTextHtmlBlock {
|
|
2202
|
+
_type: "htmlBlock";
|
|
2203
|
+
_key: string;
|
|
2204
|
+
html: string;
|
|
2205
|
+
}
|
|
1972
2206
|
/**
|
|
1973
|
-
*
|
|
2207
|
+
* Unknown/custom block (preserved for plugin compatibility)
|
|
1974
2208
|
*/
|
|
1975
|
-
interface
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
locale: string;
|
|
1980
|
-
/** URL slug */
|
|
1981
|
-
slug: string | null;
|
|
1982
|
-
/** Current status */
|
|
1983
|
-
status: string;
|
|
2209
|
+
interface PortableTextUnknownBlock {
|
|
2210
|
+
_type: string;
|
|
2211
|
+
_key: string;
|
|
2212
|
+
[key: string]: unknown;
|
|
1984
2213
|
}
|
|
1985
2214
|
/**
|
|
1986
|
-
*
|
|
2215
|
+
* Any Portable Text block
|
|
1987
2216
|
*/
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
2217
|
+
type PortableTextBlock = PortableTextTextBlock | PortableTextImageBlock | PortableTextCodeBlock | PortableTextHtmlBlock | PortableTextUnknownBlock;
|
|
2218
|
+
/**
|
|
2219
|
+
* ProseMirror JSON types (simplified for TipTap)
|
|
2220
|
+
*/
|
|
2221
|
+
interface ProseMirrorMark {
|
|
2222
|
+
type: string;
|
|
2223
|
+
attrs?: Record<string, unknown>;
|
|
2224
|
+
}
|
|
2225
|
+
interface ProseMirrorNode {
|
|
2226
|
+
type: string;
|
|
2227
|
+
attrs?: Record<string, unknown>;
|
|
2228
|
+
content?: ProseMirrorNode[];
|
|
2229
|
+
marks?: ProseMirrorMark[];
|
|
2230
|
+
text?: string;
|
|
1995
2231
|
}
|
|
2232
|
+
interface ProseMirrorDocument {
|
|
2233
|
+
type: "doc";
|
|
2234
|
+
content: ProseMirrorNode[];
|
|
2235
|
+
}
|
|
2236
|
+
//#endregion
|
|
2237
|
+
//#region src/content/converters/prosemirror-to-portable-text.d.ts
|
|
1996
2238
|
/**
|
|
1997
|
-
*
|
|
1998
|
-
*
|
|
1999
|
-
* Given a content entry, returns all locale variants that share the same
|
|
2000
|
-
* translation group. This is useful for building language switcher UI.
|
|
2001
|
-
*
|
|
2002
|
-
* @example
|
|
2003
|
-
* ```ts
|
|
2004
|
-
* import { getDinewayEntry, getTranslations } from "dineway";
|
|
2005
|
-
*
|
|
2006
|
-
* const { entry: post } = await getDinewayEntry("posts", "hello-world", { locale: "en" });
|
|
2007
|
-
* const { translations } = await getTranslations("posts", post.data.id);
|
|
2008
|
-
* // translations = [{ id: "...", locale: "en", slug: "hello-world", status: "published" }, ...]
|
|
2009
|
-
* ```
|
|
2239
|
+
* Convert ProseMirror document to Portable Text
|
|
2010
2240
|
*/
|
|
2011
|
-
declare function
|
|
2241
|
+
declare function prosemirrorToPortableText(doc: ProseMirrorDocument): PortableTextBlock[];
|
|
2242
|
+
//#endregion
|
|
2243
|
+
//#region src/content/converters/portable-text-to-prosemirror.d.ts
|
|
2012
2244
|
/**
|
|
2013
|
-
*
|
|
2245
|
+
* Convert Portable Text to ProseMirror document
|
|
2014
2246
|
*/
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
/** The collection slug that matched */
|
|
2019
|
-
collection: string;
|
|
2020
|
-
/** Extracted parameters from the URL pattern (e.g. { slug: "my-post" }) */
|
|
2021
|
-
params: Record<string, string>;
|
|
2022
|
-
}
|
|
2247
|
+
declare function portableTextToProsemirror(blocks: PortableTextBlock[]): ProseMirrorDocument;
|
|
2248
|
+
//#endregion
|
|
2249
|
+
//#region src/utils/hash.d.ts
|
|
2023
2250
|
/**
|
|
2024
|
-
*
|
|
2025
|
-
*
|
|
2026
|
-
|
|
2027
|
-
|
|
2251
|
+
* SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
|
|
2252
|
+
* For cache invalidation / ETags — not for security.
|
|
2253
|
+
*/
|
|
2254
|
+
declare function hashString(content: string): Promise<string>;
|
|
2255
|
+
/**
|
|
2256
|
+
* Compute content hash using Web Crypto API
|
|
2028
2257
|
*
|
|
2029
|
-
*
|
|
2030
|
-
*
|
|
2031
|
-
*
|
|
2258
|
+
* Uses SHA-1 which is the fastest option in SubtleCrypto.
|
|
2259
|
+
* SHA-1 is cryptographically weak but fine for content deduplication
|
|
2260
|
+
* where we only need to detect identical files, not resist attacks.
|
|
2032
2261
|
*
|
|
2033
|
-
*
|
|
2034
|
-
* const result = await resolveDinewayPath("/blog/hello-world");
|
|
2035
|
-
* if (result) {
|
|
2036
|
-
* console.log(result.collection); // "posts"
|
|
2037
|
-
* console.log(result.params.slug); // "hello-world"
|
|
2038
|
-
* console.log(result.entry.data); // post data
|
|
2039
|
-
* }
|
|
2040
|
-
* ```
|
|
2262
|
+
* Returns hex string prefixed with "sha1:" for future-proofing
|
|
2041
2263
|
*/
|
|
2042
|
-
declare function
|
|
2264
|
+
declare function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string>;
|
|
2043
2265
|
//#endregion
|
|
2044
|
-
//#region src/
|
|
2266
|
+
//#region src/utils/url.d.ts
|
|
2045
2267
|
/**
|
|
2046
|
-
*
|
|
2268
|
+
* URL scheme validation utilities
|
|
2047
2269
|
*
|
|
2048
|
-
*
|
|
2049
|
-
*
|
|
2050
|
-
* pending work; callers that need stronger durability should await their own
|
|
2051
|
-
* operation instead of using this helper.
|
|
2270
|
+
* Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
|
|
2271
|
+
* by allowlisting known-safe schemes before rendering into href attributes.
|
|
2052
2272
|
*/
|
|
2053
|
-
type AfterCallback = () => void | Promise<void>;
|
|
2054
|
-
declare function after(fn: AfterCallback): void;
|
|
2055
|
-
//#endregion
|
|
2056
|
-
//#region src/i18n/config.d.ts
|
|
2057
2273
|
/**
|
|
2058
|
-
*
|
|
2274
|
+
* Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
|
|
2059
2275
|
*
|
|
2060
|
-
*
|
|
2061
|
-
*
|
|
2276
|
+
* Use this at the render layer as the primary defense against XSS via
|
|
2277
|
+
* dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
|
|
2278
|
+
*
|
|
2279
|
+
* @example
|
|
2280
|
+
* ```ts
|
|
2281
|
+
* sanitizeHref("https://example.com") // "https://example.com"
|
|
2282
|
+
* sanitizeHref("/about") // "/about"
|
|
2283
|
+
* sanitizeHref("#section") // "#section"
|
|
2284
|
+
* sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
|
|
2285
|
+
* sanitizeHref("javascript:alert(1)") // "#"
|
|
2286
|
+
* sanitizeHref("data:text/html,<script>") // "#"
|
|
2287
|
+
* sanitizeHref("") // "#"
|
|
2288
|
+
* ```
|
|
2062
2289
|
*/
|
|
2063
|
-
|
|
2064
|
-
defaultLocale: string;
|
|
2065
|
-
locales: string[];
|
|
2066
|
-
fallback?: Record<string, string>;
|
|
2067
|
-
prefixDefaultLocale?: boolean;
|
|
2068
|
-
}
|
|
2290
|
+
declare function sanitizeHref(url: string | undefined | null): string;
|
|
2069
2291
|
/**
|
|
2070
|
-
*
|
|
2071
|
-
* Returns null if i18n is not configured.
|
|
2292
|
+
* Returns true if the URL uses a safe scheme for rendering in href attributes.
|
|
2072
2293
|
*/
|
|
2073
|
-
declare function
|
|
2294
|
+
declare function isSafeHref(url: string): boolean;
|
|
2295
|
+
//#endregion
|
|
2296
|
+
//#region src/auth/rate-limit.d.ts
|
|
2074
2297
|
/**
|
|
2075
|
-
*
|
|
2076
|
-
* Returns true when multiple locales are configured.
|
|
2298
|
+
* Result of a rate limit check.
|
|
2077
2299
|
*/
|
|
2078
|
-
|
|
2300
|
+
interface RateLimitResult {
|
|
2301
|
+
/** Whether the request is allowed (within limit). */
|
|
2302
|
+
allowed: boolean;
|
|
2303
|
+
/** Current request count in this window. */
|
|
2304
|
+
count: number;
|
|
2305
|
+
/** Maximum requests allowed in this window. */
|
|
2306
|
+
limit: number;
|
|
2307
|
+
}
|
|
2079
2308
|
/**
|
|
2080
|
-
*
|
|
2081
|
-
*
|
|
2082
|
-
*
|
|
2309
|
+
* Check (and increment) the rate limit for a given IP + endpoint.
|
|
2310
|
+
*
|
|
2311
|
+
* If `ip` is null (no trusted IP available), rate limiting is skipped
|
|
2312
|
+
* and the request is allowed. There's no meaningful key to rate limit
|
|
2313
|
+
* on when the IP is unknown.
|
|
2314
|
+
*
|
|
2315
|
+
* Returns whether the request is allowed. The counter is always
|
|
2316
|
+
* incremented — even when the limit is exceeded — so that repeated
|
|
2317
|
+
* abuse doesn't reset the window.
|
|
2318
|
+
*
|
|
2319
|
+
* Piggybacks cleanup of expired entries with a 1% probability
|
|
2320
|
+
* to prevent unbounded table growth.
|
|
2083
2321
|
*/
|
|
2084
|
-
declare function
|
|
2322
|
+
declare function checkRateLimit(db: Kysely<Database>, ip: string | null, endpoint: string, maxRequests: number, windowSeconds: number): Promise<RateLimitResult>;
|
|
2085
2323
|
//#endregion
|
|
2086
|
-
//#region src/
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
exp: number;
|
|
2096
|
-
sig: string;
|
|
2097
|
-
}
|
|
2098
|
-
interface PreviewSidecarClient {
|
|
2099
|
-
signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
|
|
2100
|
-
buildSnapshotSignatureHeader(signature: PreviewSidecarSignature): string;
|
|
2101
|
-
}
|
|
2102
|
-
declare function signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
|
|
2103
|
-
declare function buildPreviewSignatureHeader(signature: PreviewSidecarSignature): string;
|
|
2104
|
-
declare function parsePreviewSignatureHeader(header: string): PreviewSidecarSignature | null;
|
|
2105
|
-
declare function verifyPreviewSignature(source: string, exp: number, sig: string, secret: string): Promise<boolean>;
|
|
2106
|
-
declare const defaultPreviewSidecarClient: PreviewSidecarClient;
|
|
2107
|
-
//#endregion
|
|
2108
|
-
//#region src/preview/session-database-factory.d.ts
|
|
2109
|
-
interface SessionDatabaseInfo {
|
|
2110
|
-
id: string;
|
|
2111
|
-
dbPath: string;
|
|
2112
|
-
createdAt: number;
|
|
2324
|
+
//#region src/security/guest-access-tokens.d.ts
|
|
2325
|
+
interface GuestAccessTokenClaims {
|
|
2326
|
+
version: 1;
|
|
2327
|
+
tokenId: string;
|
|
2328
|
+
purpose: string;
|
|
2329
|
+
subjectType: string;
|
|
2330
|
+
subjectId: string;
|
|
2331
|
+
locationId: string;
|
|
2332
|
+
issuedAt: number;
|
|
2113
2333
|
expiresAt: number;
|
|
2114
|
-
lastTouchedAt: number;
|
|
2115
|
-
}
|
|
2116
|
-
interface SessionDatabaseHandle {
|
|
2117
|
-
created: boolean;
|
|
2118
|
-
session: SessionDatabaseInfo;
|
|
2119
|
-
db: Kysely<Database>;
|
|
2120
|
-
close(): Promise<void>;
|
|
2121
|
-
}
|
|
2122
|
-
interface SessionCleanupResult {
|
|
2123
|
-
removedSessionIds: string[];
|
|
2124
|
-
removedPaths: string[];
|
|
2125
2334
|
}
|
|
2126
|
-
interface
|
|
2127
|
-
|
|
2335
|
+
interface IssueGuestAccessTokenOptions {
|
|
2336
|
+
secret: string;
|
|
2337
|
+
purpose: string;
|
|
2338
|
+
subjectType: string;
|
|
2339
|
+
subjectId: string;
|
|
2340
|
+
locationId: string;
|
|
2341
|
+
/** Reuses an already persisted identifier to reconstruct the exact same capability. */
|
|
2342
|
+
tokenId?: string;
|
|
2343
|
+
expiresIn?: string | number;
|
|
2128
2344
|
now?: number;
|
|
2129
2345
|
}
|
|
2130
|
-
interface
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2346
|
+
interface IssuedGuestAccessToken {
|
|
2347
|
+
token: string;
|
|
2348
|
+
tokenHash: string;
|
|
2349
|
+
claims: GuestAccessTokenClaims;
|
|
2350
|
+
}
|
|
2351
|
+
interface GuestAccessExpectedScope {
|
|
2352
|
+
purpose: string;
|
|
2353
|
+
subjectType: string;
|
|
2354
|
+
subjectId?: string;
|
|
2355
|
+
locationId?: string;
|
|
2356
|
+
}
|
|
2357
|
+
interface VerifyGuestAccessTokenOptions {
|
|
2358
|
+
token: string | null | undefined;
|
|
2359
|
+
/** Primary secret first, followed by retained rotation secrets. */
|
|
2360
|
+
secrets: string | readonly string[];
|
|
2361
|
+
expected: GuestAccessExpectedScope;
|
|
2362
|
+
now?: number;
|
|
2139
2363
|
}
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2364
|
+
type VerifyGuestAccessTokenResult = {
|
|
2365
|
+
valid: true;
|
|
2366
|
+
claims: GuestAccessTokenClaims;
|
|
2367
|
+
tokenHash: string;
|
|
2368
|
+
} | {
|
|
2369
|
+
valid: false;
|
|
2370
|
+
error: "none" | "malformed" | "invalid" | "expired" | "scope_mismatch";
|
|
2371
|
+
};
|
|
2372
|
+
declare class GuestAccessTokenConfigurationError extends Error {
|
|
2373
|
+
readonly code: "INVALID_GUEST_TOKEN_SECRET" | "INVALID_GUEST_TOKEN_INPUT";
|
|
2374
|
+
readonly name = "GuestAccessTokenConfigurationError";
|
|
2375
|
+
constructor(message: string, code: "INVALID_GUEST_TOKEN_SECRET" | "INVALID_GUEST_TOKEN_INPUT");
|
|
2145
2376
|
}
|
|
2146
|
-
|
|
2147
|
-
|
|
2377
|
+
/**
|
|
2378
|
+
* Issues an expiring capability for one guest purpose and one restaurant target.
|
|
2379
|
+
* Persist only tokenHash/tokenId and revocation metadata; never persist or log token.
|
|
2380
|
+
*/
|
|
2381
|
+
declare function issueGuestAccessToken(options: IssueGuestAccessTokenOptions): Promise<IssuedGuestAccessToken>;
|
|
2382
|
+
/**
|
|
2383
|
+
* Verifies signature, expiry, and the caller-declared purpose/target scope.
|
|
2384
|
+
* A valid result still requires the plugin to check its revocation record by tokenHash.
|
|
2385
|
+
*/
|
|
2386
|
+
declare function verifyGuestAccessToken(options: VerifyGuestAccessTokenOptions): Promise<VerifyGuestAccessTokenResult>;
|
|
2387
|
+
/** Returns the non-reversible identifier stored for revocation and lookup. */
|
|
2388
|
+
declare function hashGuestAccessToken(token: string): Promise<string>;
|
|
2389
|
+
//#endregion
|
|
2390
|
+
//#region src/visual-editing/editable.d.ts
|
|
2391
|
+
/**
|
|
2392
|
+
* Visual editing annotation system
|
|
2393
|
+
*
|
|
2394
|
+
* Creates Proxy objects that emit data-dineway-ref attributes when spread onto elements.
|
|
2395
|
+
*/
|
|
2396
|
+
interface CMSAnnotation {
|
|
2397
|
+
collection: string;
|
|
2398
|
+
id: string;
|
|
2399
|
+
field?: string;
|
|
2400
|
+
/** Entry status — only present on entry-level annotations (not field-level) */
|
|
2401
|
+
status?: string;
|
|
2402
|
+
/** Whether the entry has unpublished draft changes */
|
|
2403
|
+
hasDraft?: boolean;
|
|
2148
2404
|
}
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
private readonly sessionsDir;
|
|
2153
|
-
private readonly maxDiskBytes;
|
|
2154
|
-
constructor(options: FileSessionDatabaseFactoryOptions);
|
|
2155
|
-
open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
|
|
2156
|
-
openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
|
|
2157
|
-
destroy(id: string): Promise<boolean>;
|
|
2158
|
-
cleanup(now?: number): Promise<SessionCleanupResult>;
|
|
2159
|
-
close(): Promise<void>;
|
|
2160
|
-
private createHandle;
|
|
2161
|
-
private getSessionRow;
|
|
2162
|
-
private toSessionInfo;
|
|
2163
|
-
private deleteSession;
|
|
2164
|
-
private getActiveDiskBytes;
|
|
2165
|
-
private getDbPath;
|
|
2166
|
-
private getManagedPaths;
|
|
2167
|
-
private listSessionRows;
|
|
2168
|
-
private listDbPathRows;
|
|
2405
|
+
/** The shape returned when spreading an edit annotation onto an element */
|
|
2406
|
+
interface FieldAnnotation {
|
|
2407
|
+
"data-dineway-ref": string;
|
|
2169
2408
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
ttlSeconds?: number;
|
|
2176
|
-
cookieName?: string;
|
|
2177
|
-
snapshotPath?: string;
|
|
2178
|
-
maxSessionDiskBytes?: number;
|
|
2179
|
-
sessionFactory?: SessionDatabaseFactory;
|
|
2180
|
-
fetch?: typeof globalThis.fetch;
|
|
2409
|
+
interface EditableOptions {
|
|
2410
|
+
/** Entry status: "draft", "published", "scheduled" */
|
|
2411
|
+
status?: string;
|
|
2412
|
+
/** true when draftRevisionId exists and differs from liveRevisionId */
|
|
2413
|
+
hasDraft?: boolean;
|
|
2181
2414
|
}
|
|
2182
|
-
declare function createFilePreviewMiddleware(config: FilePreviewMiddlewareConfig): MiddlewareHandler;
|
|
2183
|
-
//#endregion
|
|
2184
|
-
//#region src/plugins/define-plugin.d.ts
|
|
2185
2415
|
/**
|
|
2186
|
-
*
|
|
2416
|
+
* Create an editable proxy for an entry.
|
|
2187
2417
|
*
|
|
2188
|
-
*
|
|
2189
|
-
*
|
|
2418
|
+
* Usage:
|
|
2419
|
+
* - `{...entry.edit}` - entry-level annotation (includes status/hasDraft)
|
|
2420
|
+
* - `{...entry.edit.title}` - field-level annotation
|
|
2421
|
+
* - `{...entry.edit['nested.field']}` - nested field (bracket notation)
|
|
2422
|
+
*/
|
|
2423
|
+
declare function createEditable(collection: string, id: string, options?: EditableOptions): EditProxy;
|
|
2424
|
+
/**
|
|
2425
|
+
* Create a noop proxy for production mode.
|
|
2426
|
+
* Spreading this produces no attributes.
|
|
2427
|
+
*/
|
|
2428
|
+
declare function createNoop(): EditProxy;
|
|
2429
|
+
/**
|
|
2430
|
+
* Visual editing proxy type.
|
|
2190
2431
|
*
|
|
2191
|
-
*
|
|
2192
|
-
*
|
|
2193
|
-
* import { definePlugin } from "dineway";
|
|
2432
|
+
* Spread directly onto elements for entry-level annotations: `{...entry.edit}`
|
|
2433
|
+
* Access a field for field-level annotations: `{...entry.edit.title}`
|
|
2194
2434
|
*
|
|
2195
|
-
*
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
*
|
|
2204
|
-
* status: {
|
|
2205
|
-
* handler: async (routeCtx, ctx) => ({ ok: true }),
|
|
2206
|
-
* },
|
|
2207
|
-
* },
|
|
2208
|
-
* });
|
|
2209
|
-
* ```
|
|
2435
|
+
* In production, spreading produces no attributes (noop).
|
|
2436
|
+
*/
|
|
2437
|
+
type EditProxy = {
|
|
2438
|
+
readonly [field: string]: Partial<FieldAnnotation>;
|
|
2439
|
+
};
|
|
2440
|
+
//#endregion
|
|
2441
|
+
//#region src/query.d.ts
|
|
2442
|
+
/**
|
|
2443
|
+
* Collection type registry for type-safe queries.
|
|
2210
2444
|
*
|
|
2211
|
-
*
|
|
2212
|
-
*
|
|
2445
|
+
* This interface is extended by the generated dineway-env.d.ts file
|
|
2446
|
+
* to provide type inference for collection names and their data shapes.
|
|
2213
2447
|
*
|
|
2214
2448
|
* @example
|
|
2215
|
-
* ```
|
|
2216
|
-
*
|
|
2217
|
-
*
|
|
2218
|
-
*
|
|
2219
|
-
*
|
|
2220
|
-
*
|
|
2221
|
-
* capabilities: ["content:read"],
|
|
2222
|
-
* hooks: {
|
|
2223
|
-
* "content:beforeSave": async (event, ctx) => {
|
|
2224
|
-
* ctx.log.info("Saving content", { collection: event.collection });
|
|
2225
|
-
* return event.content;
|
|
2226
|
-
* }
|
|
2227
|
-
* },
|
|
2228
|
-
* routes: {
|
|
2229
|
-
* "sync": {
|
|
2230
|
-
* handler: async (ctx) => {
|
|
2231
|
-
* return { status: "ok" };
|
|
2232
|
-
* }
|
|
2233
|
-
* }
|
|
2449
|
+
* ```ts
|
|
2450
|
+
* // In dineway-env.d.ts (generated):
|
|
2451
|
+
* declare module "dineway" {
|
|
2452
|
+
* interface DinewayCollections {
|
|
2453
|
+
* posts: { title: string; content: PortableTextBlock[]; };
|
|
2454
|
+
* pages: { title: string; body: PortableTextBlock[]; };
|
|
2234
2455
|
* }
|
|
2235
|
-
* }
|
|
2456
|
+
* }
|
|
2457
|
+
*
|
|
2458
|
+
* // Then in your code:
|
|
2459
|
+
* const { entries } = await getDinewayCollection("posts");
|
|
2460
|
+
* // entries[0].data.title is typed as string
|
|
2236
2461
|
* ```
|
|
2237
2462
|
*/
|
|
2238
|
-
|
|
2239
|
-
declare function definePlugin(definition: StandardPluginDefinition): StandardPluginDefinition;
|
|
2240
|
-
//#endregion
|
|
2241
|
-
//#region src/plugins/manifest-schema.d.ts
|
|
2463
|
+
interface DinewayCollections {}
|
|
2242
2464
|
/**
|
|
2243
|
-
*
|
|
2244
|
-
*
|
|
2245
|
-
* Every JSON.parse of a manifest.json should validate through this.
|
|
2465
|
+
* Helper type to infer the data type for a collection.
|
|
2466
|
+
* Returns the registered type if known, otherwise falls back to Record<string, unknown>.
|
|
2246
2467
|
*/
|
|
2247
|
-
|
|
2248
|
-
id: z$1.ZodString;
|
|
2249
|
-
version: z$1.ZodString;
|
|
2250
|
-
capabilities: z$1.ZodArray<z$1.ZodEnum<{
|
|
2251
|
-
"network:request": "network:request";
|
|
2252
|
-
"network:request:unrestricted": "network:request:unrestricted";
|
|
2253
|
-
"content:read": "content:read";
|
|
2254
|
-
"content:write": "content:write";
|
|
2255
|
-
"media:read": "media:read";
|
|
2256
|
-
"media:write": "media:write";
|
|
2257
|
-
"users:read": "users:read";
|
|
2258
|
-
"email:send": "email:send";
|
|
2259
|
-
"hooks.email-transport:register": "hooks.email-transport:register";
|
|
2260
|
-
"hooks.email-events:register": "hooks.email-events:register";
|
|
2261
|
-
"hooks.page-fragments:register": "hooks.page-fragments:register";
|
|
2262
|
-
}>>;
|
|
2263
|
-
allowedHosts: z$1.ZodArray<z$1.ZodString>;
|
|
2264
|
-
storage: z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
|
|
2265
|
-
indexes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>;
|
|
2266
|
-
uniqueIndexes: z$1.ZodOptional<z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>>;
|
|
2267
|
-
}, z$1.core.$strip>>;
|
|
2268
|
-
hooks: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodEnum<{
|
|
2269
|
-
"plugin:install": "plugin:install";
|
|
2270
|
-
"plugin:activate": "plugin:activate";
|
|
2271
|
-
"plugin:deactivate": "plugin:deactivate";
|
|
2272
|
-
"plugin:uninstall": "plugin:uninstall";
|
|
2273
|
-
"content:beforeSave": "content:beforeSave";
|
|
2274
|
-
"content:afterSave": "content:afterSave";
|
|
2275
|
-
"content:beforeDelete": "content:beforeDelete";
|
|
2276
|
-
"content:afterDelete": "content:afterDelete";
|
|
2277
|
-
"content:afterPublish": "content:afterPublish";
|
|
2278
|
-
"content:afterUnpublish": "content:afterUnpublish";
|
|
2279
|
-
"media:beforeUpload": "media:beforeUpload";
|
|
2280
|
-
"media:afterUpload": "media:afterUpload";
|
|
2281
|
-
cron: "cron";
|
|
2282
|
-
"email:beforeSend": "email:beforeSend";
|
|
2283
|
-
"email:deliver": "email:deliver";
|
|
2284
|
-
"email:afterSend": "email:afterSend";
|
|
2285
|
-
"comment:beforeCreate": "comment:beforeCreate";
|
|
2286
|
-
"comment:moderate": "comment:moderate";
|
|
2287
|
-
"comment:afterCreate": "comment:afterCreate";
|
|
2288
|
-
"comment:afterModerate": "comment:afterModerate";
|
|
2289
|
-
"page:metadata": "page:metadata";
|
|
2290
|
-
"page:fragments": "page:fragments";
|
|
2291
|
-
}>, z$1.ZodObject<{
|
|
2292
|
-
name: z$1.ZodEnum<{
|
|
2293
|
-
"plugin:install": "plugin:install";
|
|
2294
|
-
"plugin:activate": "plugin:activate";
|
|
2295
|
-
"plugin:deactivate": "plugin:deactivate";
|
|
2296
|
-
"plugin:uninstall": "plugin:uninstall";
|
|
2297
|
-
"content:beforeSave": "content:beforeSave";
|
|
2298
|
-
"content:afterSave": "content:afterSave";
|
|
2299
|
-
"content:beforeDelete": "content:beforeDelete";
|
|
2300
|
-
"content:afterDelete": "content:afterDelete";
|
|
2301
|
-
"content:afterPublish": "content:afterPublish";
|
|
2302
|
-
"content:afterUnpublish": "content:afterUnpublish";
|
|
2303
|
-
"media:beforeUpload": "media:beforeUpload";
|
|
2304
|
-
"media:afterUpload": "media:afterUpload";
|
|
2305
|
-
cron: "cron";
|
|
2306
|
-
"email:beforeSend": "email:beforeSend";
|
|
2307
|
-
"email:deliver": "email:deliver";
|
|
2308
|
-
"email:afterSend": "email:afterSend";
|
|
2309
|
-
"comment:beforeCreate": "comment:beforeCreate";
|
|
2310
|
-
"comment:moderate": "comment:moderate";
|
|
2311
|
-
"comment:afterCreate": "comment:afterCreate";
|
|
2312
|
-
"comment:afterModerate": "comment:afterModerate";
|
|
2313
|
-
"page:metadata": "page:metadata";
|
|
2314
|
-
"page:fragments": "page:fragments";
|
|
2315
|
-
}>;
|
|
2316
|
-
exclusive: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
2317
|
-
priority: z$1.ZodOptional<z$1.ZodNumber>;
|
|
2318
|
-
timeout: z$1.ZodOptional<z$1.ZodNumber>;
|
|
2319
|
-
}, z$1.core.$strip>]>>;
|
|
2320
|
-
routes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodObject<{
|
|
2321
|
-
name: z$1.ZodString;
|
|
2322
|
-
public: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
2323
|
-
}, z$1.core.$strip>]>>;
|
|
2324
|
-
admin: z$1.ZodObject<{
|
|
2325
|
-
entry: z$1.ZodOptional<z$1.ZodString>;
|
|
2326
|
-
settingsSchema: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{
|
|
2327
|
-
type: z$1.ZodLiteral<"string">;
|
|
2328
|
-
default: z$1.ZodOptional<z$1.ZodString>;
|
|
2329
|
-
multiline: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
2330
|
-
label: z$1.ZodString;
|
|
2331
|
-
description: z$1.ZodOptional<z$1.ZodString>;
|
|
2332
|
-
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
2333
|
-
type: z$1.ZodLiteral<"number">;
|
|
2334
|
-
default: z$1.ZodOptional<z$1.ZodNumber>;
|
|
2335
|
-
min: z$1.ZodOptional<z$1.ZodNumber>;
|
|
2336
|
-
max: z$1.ZodOptional<z$1.ZodNumber>;
|
|
2337
|
-
label: z$1.ZodString;
|
|
2338
|
-
description: z$1.ZodOptional<z$1.ZodString>;
|
|
2339
|
-
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
2340
|
-
type: z$1.ZodLiteral<"boolean">;
|
|
2341
|
-
default: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
2342
|
-
label: z$1.ZodString;
|
|
2343
|
-
description: z$1.ZodOptional<z$1.ZodString>;
|
|
2344
|
-
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
2345
|
-
type: z$1.ZodLiteral<"select">;
|
|
2346
|
-
options: z$1.ZodArray<z$1.ZodObject<{
|
|
2347
|
-
value: z$1.ZodString;
|
|
2348
|
-
label: z$1.ZodString;
|
|
2349
|
-
}, z$1.core.$strip>>;
|
|
2350
|
-
default: z$1.ZodOptional<z$1.ZodString>;
|
|
2351
|
-
label: z$1.ZodString;
|
|
2352
|
-
description: z$1.ZodOptional<z$1.ZodString>;
|
|
2353
|
-
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
2354
|
-
type: z$1.ZodLiteral<"secret">;
|
|
2355
|
-
label: z$1.ZodString;
|
|
2356
|
-
description: z$1.ZodOptional<z$1.ZodString>;
|
|
2357
|
-
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
2358
|
-
type: z$1.ZodLiteral<"url">;
|
|
2359
|
-
default: z$1.ZodOptional<z$1.ZodString>;
|
|
2360
|
-
placeholder: z$1.ZodOptional<z$1.ZodString>;
|
|
2361
|
-
label: z$1.ZodString;
|
|
2362
|
-
description: z$1.ZodOptional<z$1.ZodString>;
|
|
2363
|
-
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
2364
|
-
type: z$1.ZodLiteral<"email">;
|
|
2365
|
-
default: z$1.ZodOptional<z$1.ZodString>;
|
|
2366
|
-
placeholder: z$1.ZodOptional<z$1.ZodString>;
|
|
2367
|
-
label: z$1.ZodString;
|
|
2368
|
-
description: z$1.ZodOptional<z$1.ZodString>;
|
|
2369
|
-
}, z$1.core.$strip>], "type">>>;
|
|
2370
|
-
pages: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
2371
|
-
path: z$1.ZodString;
|
|
2372
|
-
label: z$1.ZodString;
|
|
2373
|
-
icon: z$1.ZodOptional<z$1.ZodString>;
|
|
2374
|
-
}, z$1.core.$strip>>>;
|
|
2375
|
-
widgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
2376
|
-
id: z$1.ZodString;
|
|
2377
|
-
size: z$1.ZodOptional<z$1.ZodEnum<{
|
|
2378
|
-
full: "full";
|
|
2379
|
-
half: "half";
|
|
2380
|
-
third: "third";
|
|
2381
|
-
}>>;
|
|
2382
|
-
title: z$1.ZodOptional<z$1.ZodString>;
|
|
2383
|
-
}, z$1.core.$strip>>>;
|
|
2384
|
-
fieldWidgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
2385
|
-
name: z$1.ZodString;
|
|
2386
|
-
label: z$1.ZodString;
|
|
2387
|
-
fieldTypes: z$1.ZodArray<z$1.ZodEnum<{
|
|
2388
|
-
string: "string";
|
|
2389
|
-
number: "number";
|
|
2390
|
-
boolean: "boolean";
|
|
2391
|
-
file: "file";
|
|
2392
|
-
slug: "slug";
|
|
2393
|
-
text: "text";
|
|
2394
|
-
integer: "integer";
|
|
2395
|
-
datetime: "datetime";
|
|
2396
|
-
select: "select";
|
|
2397
|
-
multiSelect: "multiSelect";
|
|
2398
|
-
portableText: "portableText";
|
|
2399
|
-
image: "image";
|
|
2400
|
-
reference: "reference";
|
|
2401
|
-
json: "json";
|
|
2402
|
-
repeater: "repeater";
|
|
2403
|
-
}>>;
|
|
2404
|
-
elements: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
2405
|
-
type: z$1.ZodString;
|
|
2406
|
-
action_id: z$1.ZodString;
|
|
2407
|
-
label: z$1.ZodOptional<z$1.ZodString>;
|
|
2408
|
-
}, z$1.core.$loose>>>;
|
|
2409
|
-
}, z$1.core.$strip>>>;
|
|
2410
|
-
}, z$1.core.$strip>;
|
|
2411
|
-
}, z$1.core.$strip>;
|
|
2412
|
-
type ValidatedPluginManifest = z$1.infer<typeof pluginManifestSchema>;
|
|
2413
|
-
//#endregion
|
|
2414
|
-
//#region src/plugins/hooks.d.ts
|
|
2415
|
-
type HookNameV2 = "plugin:install" | "plugin:activate" | "plugin:deactivate" | "plugin:uninstall" | "content:beforeSave" | "content:afterSave" | "content:beforeDelete" | "content:afterDelete" | "content:afterPublish" | "content:afterUnpublish" | "media:beforeUpload" | "media:afterUpload" | "cron" | "email:beforeSend" | "email:deliver" | "email:afterSend" | "comment:beforeCreate" | "comment:moderate" | "comment:afterCreate" | "comment:afterModerate" | "page:metadata" | "page:fragments";
|
|
2468
|
+
type InferCollectionData<T extends string> = T extends keyof DinewayCollections ? DinewayCollections[T] : Record<string, unknown>;
|
|
2416
2469
|
/**
|
|
2417
|
-
*
|
|
2470
|
+
* Sort direction
|
|
2418
2471
|
*/
|
|
2419
|
-
|
|
2420
|
-
success: boolean;
|
|
2421
|
-
value?: T;
|
|
2422
|
-
error?: Error;
|
|
2423
|
-
pluginId: string;
|
|
2424
|
-
duration: number;
|
|
2425
|
-
}
|
|
2472
|
+
type SortDirection = "asc" | "desc";
|
|
2426
2473
|
/**
|
|
2427
|
-
*
|
|
2474
|
+
* Order by specification - field name to direction
|
|
2475
|
+
* @example { created_at: "desc" } - Sort by created_at descending
|
|
2476
|
+
* @example { title: "asc" } - Sort by title ascending
|
|
2477
|
+
* @example { published_at: "desc", title: "asc" } - Multi-field sort
|
|
2428
2478
|
*/
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
private exclusiveHookNames;
|
|
2437
|
-
/**
|
|
2438
|
-
* Selected provider plugin ID for each exclusive hook.
|
|
2439
|
-
* Set by the PluginManager after resolution.
|
|
2440
|
-
*/
|
|
2441
|
-
private exclusiveSelections;
|
|
2442
|
-
constructor(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions);
|
|
2443
|
-
/**
|
|
2444
|
-
* Set or update the context factory options.
|
|
2445
|
-
*
|
|
2446
|
-
* When called on a pipeline that already has a factory, the new options
|
|
2447
|
-
* are merged on top of the existing ones so that callers don't need to
|
|
2448
|
-
* repeat every field (e.g. adding `cronReschedule` without losing
|
|
2449
|
-
* `storage` / `getUploadUrl`).
|
|
2450
|
-
*/
|
|
2451
|
-
setContextFactory(options: Partial<PluginContextFactoryOptions>): void;
|
|
2452
|
-
/**
|
|
2453
|
-
* Get context for a plugin
|
|
2454
|
-
*/
|
|
2455
|
-
private getContext;
|
|
2479
|
+
type OrderBySpec = Record<string, SortDirection>;
|
|
2480
|
+
/**
|
|
2481
|
+
* Fields shared by every collection query, independent of pagination mode.
|
|
2482
|
+
*/
|
|
2483
|
+
interface CollectionFilterBase {
|
|
2484
|
+
status?: "draft" | "published" | "archived";
|
|
2485
|
+
limit?: number;
|
|
2456
2486
|
/**
|
|
2457
|
-
*
|
|
2458
|
-
* The internal map stores ResolvedHook<unknown>, but we know each name
|
|
2459
|
-
* maps to a specific handler type via HookHandlerMap.
|
|
2487
|
+
* Filter by field values, taxonomy terms, byline credits, or ranges.
|
|
2460
2488
|
*
|
|
2461
|
-
*
|
|
2462
|
-
*
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
* Register all hooks from plugins.
|
|
2489
|
+
* Taxonomy names are detected automatically and filtered by term.
|
|
2490
|
+
* The reserved `byline` key filters by byline credit in any position,
|
|
2491
|
+
* not just the primary credit. It accepts one or more byline translation
|
|
2492
|
+
* groups, or concrete byline row IDs.
|
|
2493
|
+
* Other keys are treated as content table column filters.
|
|
2467
2494
|
*
|
|
2468
|
-
*
|
|
2469
|
-
*
|
|
2470
|
-
*
|
|
2495
|
+
* @example { category: 'news' } - Filter by taxonomy term
|
|
2496
|
+
* @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
|
|
2497
|
+
* @example { byline: '01HXYZ...' } - Entries credited to a byline (any position)
|
|
2498
|
+
* @example { byline: ['01HXYZ...', '01HABC...'] } - Credited to any of these bylines (OR)
|
|
2499
|
+
* @example { series: 'main' } - Exact match on a content field
|
|
2500
|
+
* @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - Date range
|
|
2471
2501
|
*/
|
|
2472
|
-
|
|
2502
|
+
where?: Record<string, WhereValue>;
|
|
2473
2503
|
/**
|
|
2474
|
-
*
|
|
2504
|
+
* Case-insensitive substring search across selected content fields.
|
|
2475
2505
|
*
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
2478
|
-
* capability will have that hook silently skipped at registration time.
|
|
2479
|
-
*/
|
|
2480
|
-
private static readonly HOOK_REQUIRED_CAPABILITY;
|
|
2481
|
-
/**
|
|
2482
|
-
* Register a single plugin's hook by name
|
|
2483
|
-
*/
|
|
2484
|
-
private registerPluginHook;
|
|
2485
|
-
/**
|
|
2486
|
-
* Register a single hook
|
|
2487
|
-
*/
|
|
2488
|
-
private registerHook;
|
|
2489
|
-
/**
|
|
2490
|
-
* Sort hooks by priority and dependencies
|
|
2506
|
+
* `searchColumns` must contain concrete field slugs or system column names.
|
|
2507
|
+
* When `q` is present without `searchColumns`, no search condition is applied.
|
|
2491
2508
|
*/
|
|
2492
|
-
|
|
2509
|
+
q?: string;
|
|
2510
|
+
searchColumns?: string[];
|
|
2493
2511
|
/**
|
|
2494
|
-
*
|
|
2512
|
+
* Order results by field(s)
|
|
2513
|
+
* @default { created_at: "desc" }
|
|
2514
|
+
* @example { created_at: "desc" } - Sort by created_at descending (default)
|
|
2515
|
+
* @example { title: "asc" } - Sort by title ascending
|
|
2516
|
+
* @example { published_at: "desc", title: "asc" } - Multi-field sort
|
|
2495
2517
|
*/
|
|
2496
|
-
|
|
2518
|
+
orderBy?: OrderBySpec;
|
|
2497
2519
|
/**
|
|
2498
|
-
*
|
|
2520
|
+
* Filter by locale. When set, only returns entries in this locale.
|
|
2521
|
+
* Only relevant when i18n is configured.
|
|
2522
|
+
* @example "en" — English entries only
|
|
2523
|
+
* @example "fr" — French entries only
|
|
2499
2524
|
*/
|
|
2500
|
-
|
|
2525
|
+
locale?: string;
|
|
2526
|
+
}
|
|
2527
|
+
/** Keyset-paginated query filter. Cannot also carry an offset. */
|
|
2528
|
+
interface CursorCollectionFilter extends CollectionFilterBase {
|
|
2501
2529
|
/**
|
|
2502
|
-
*
|
|
2530
|
+
* Opaque cursor for keyset pagination.
|
|
2531
|
+
* Pass the `nextCursor` value from a previous result to fetch the next page.
|
|
2532
|
+
* @example
|
|
2533
|
+
* ```ts
|
|
2534
|
+
* const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
|
|
2535
|
+
* const { entries, nextCursor } = await getDinewayCollection("posts", {
|
|
2536
|
+
* limit: 10,
|
|
2537
|
+
* cursor,
|
|
2538
|
+
* });
|
|
2539
|
+
* ```
|
|
2503
2540
|
*/
|
|
2504
|
-
|
|
2541
|
+
cursor?: string;
|
|
2542
|
+
offset?: never;
|
|
2543
|
+
}
|
|
2544
|
+
/** Offset-paginated query filter. Cannot also carry a cursor. */
|
|
2545
|
+
interface OffsetCollectionFilter extends CollectionFilterBase {
|
|
2505
2546
|
/**
|
|
2506
|
-
*
|
|
2547
|
+
* Skip this many entries before returning results. Use with `limit` for
|
|
2548
|
+
* numbered archive routes, for example `offset = (page - 1) * perPage`.
|
|
2507
2549
|
*/
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
}>;
|
|
2534
|
-
/**
|
|
2535
|
-
* Run content:afterDelete hooks
|
|
2536
|
-
*/
|
|
2537
|
-
runContentAfterDelete(id: string, collection: string, permanent: boolean): Promise<HookResult<void>[]>;
|
|
2538
|
-
/**
|
|
2539
|
-
* Run content:afterPublish hooks (fire-and-forget).
|
|
2540
|
-
*/
|
|
2541
|
-
runContentAfterPublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
2542
|
-
/**
|
|
2543
|
-
* Run content:afterUnpublish hooks (fire-and-forget).
|
|
2544
|
-
*/
|
|
2545
|
-
runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
2546
|
-
/**
|
|
2547
|
-
* Run media:beforeUpload hooks
|
|
2548
|
-
*/
|
|
2549
|
-
runMediaBeforeUpload(file: {
|
|
2550
|
-
name: string;
|
|
2551
|
-
type: string;
|
|
2552
|
-
size: number;
|
|
2553
|
-
}): Promise<{
|
|
2554
|
-
file: {
|
|
2555
|
-
name: string;
|
|
2556
|
-
type: string;
|
|
2557
|
-
size: number;
|
|
2558
|
-
};
|
|
2559
|
-
results: HookResult<{
|
|
2560
|
-
name: string;
|
|
2561
|
-
type: string;
|
|
2562
|
-
size: number;
|
|
2563
|
-
}>[];
|
|
2564
|
-
}>;
|
|
2565
|
-
/**
|
|
2566
|
-
* Run media:afterUpload hooks
|
|
2567
|
-
*/
|
|
2568
|
-
runMediaAfterUpload(media: {
|
|
2569
|
-
id: string;
|
|
2570
|
-
filename: string;
|
|
2571
|
-
mimeType: string;
|
|
2572
|
-
size: number | null;
|
|
2573
|
-
url: string;
|
|
2574
|
-
createdAt: string;
|
|
2575
|
-
}): Promise<HookResult<void>[]>;
|
|
2576
|
-
/**
|
|
2577
|
-
* Invoke the cron hook for a specific plugin.
|
|
2578
|
-
*
|
|
2579
|
-
* Unlike other hooks which broadcast to all plugins, the cron hook is
|
|
2580
|
-
* dispatched only to the target plugin — the one that owns the task.
|
|
2581
|
-
*/
|
|
2582
|
-
invokeCronHook(pluginId: string, event: CronEvent): Promise<HookResult<void>>;
|
|
2583
|
-
/**
|
|
2584
|
-
* Run email:beforeSend hooks (middleware pipeline).
|
|
2585
|
-
*
|
|
2586
|
-
* Each handler receives the message and returns a modified message or
|
|
2587
|
-
* `false` to cancel delivery. The pipeline chains message transformations —
|
|
2588
|
-
* each handler receives the output of the previous one.
|
|
2589
|
-
*/
|
|
2590
|
-
runEmailBeforeSend(message: EmailMessage, source: string): Promise<{
|
|
2591
|
-
message: EmailMessage | false;
|
|
2592
|
-
results: HookResult<EmailMessage | false>[];
|
|
2593
|
-
}>;
|
|
2594
|
-
/**
|
|
2595
|
-
* Run email:afterSend hooks (fire-and-forget).
|
|
2596
|
-
*
|
|
2597
|
-
* Errors are logged but don't propagate — they don't affect the caller.
|
|
2598
|
-
*/
|
|
2599
|
-
runEmailAfterSend(message: EmailMessage, source: string): Promise<HookResult<void>[]>;
|
|
2600
|
-
/**
|
|
2601
|
-
* Run comment:beforeCreate hooks (middleware pipeline).
|
|
2602
|
-
*
|
|
2603
|
-
* Each handler receives the event and returns a modified event or
|
|
2604
|
-
* `false` to reject the comment. The pipeline chains transformations —
|
|
2605
|
-
* each handler receives the output of the previous one.
|
|
2606
|
-
*/
|
|
2607
|
-
runCommentBeforeCreate(event: CommentBeforeCreateEvent): Promise<CommentBeforeCreateEvent | false>;
|
|
2608
|
-
/**
|
|
2609
|
-
* Run comment:afterCreate hooks (fire-and-forget).
|
|
2610
|
-
*
|
|
2611
|
-
* Errors are logged but don't propagate — they don't affect the caller.
|
|
2612
|
-
*/
|
|
2613
|
-
runCommentAfterCreate(event: CommentAfterCreateEvent): Promise<void>;
|
|
2614
|
-
/**
|
|
2615
|
-
* Run comment:afterModerate hooks (fire-and-forget).
|
|
2616
|
-
*
|
|
2617
|
-
* Errors are logged but don't propagate — they don't affect the caller.
|
|
2618
|
-
*/
|
|
2619
|
-
runCommentAfterModerate(event: CommentAfterModerateEvent): Promise<void>;
|
|
2620
|
-
/**
|
|
2621
|
-
* Run page:metadata hooks. Each handler returns contributions that are
|
|
2622
|
-
* merged by the metadata collector. Errors are logged but don't propagate.
|
|
2623
|
-
*/
|
|
2624
|
-
runPageMetadata(event: PageMetadataEvent): Promise<Array<{
|
|
2625
|
-
pluginId: string;
|
|
2626
|
-
contributions: PageMetadataContribution[];
|
|
2627
|
-
}>>;
|
|
2628
|
-
/**
|
|
2629
|
-
* Run page:fragments hooks. Only trusted plugins should be registered
|
|
2630
|
-
* for this hook. Errors are logged but don't propagate.
|
|
2631
|
-
*/
|
|
2632
|
-
runPageFragments(event: PageFragmentEvent): Promise<Array<{
|
|
2633
|
-
pluginId: string;
|
|
2634
|
-
contributions: PageFragmentContribution[];
|
|
2635
|
-
}>>;
|
|
2636
|
-
/**
|
|
2637
|
-
* Check if any hooks are registered for a given name
|
|
2638
|
-
*/
|
|
2639
|
-
hasHooks(name: HookNameV2): boolean;
|
|
2640
|
-
/**
|
|
2641
|
-
* Get hook count for debugging
|
|
2642
|
-
*/
|
|
2643
|
-
getHookCount(name: HookNameV2): number;
|
|
2644
|
-
/**
|
|
2645
|
-
* Get all registered hook names
|
|
2646
|
-
*/
|
|
2647
|
-
getRegisteredHooks(): HookNameV2[];
|
|
2648
|
-
/**
|
|
2649
|
-
* Returns hook names where at least one handler declared exclusive: true
|
|
2650
|
-
*/
|
|
2651
|
-
getRegisteredExclusiveHooks(): string[];
|
|
2652
|
-
/**
|
|
2653
|
-
* Check if a hook is exclusive
|
|
2654
|
-
*/
|
|
2655
|
-
isExclusiveHook(name: string): boolean;
|
|
2656
|
-
/**
|
|
2657
|
-
* Set the selected provider for an exclusive hook.
|
|
2658
|
-
* Called by PluginManager after resolution.
|
|
2659
|
-
*/
|
|
2660
|
-
setExclusiveSelection(hookName: string, pluginId: string): void;
|
|
2661
|
-
/**
|
|
2662
|
-
* Clear the selected provider for an exclusive hook.
|
|
2663
|
-
*/
|
|
2664
|
-
clearExclusiveSelection(hookName: string): void;
|
|
2665
|
-
/**
|
|
2666
|
-
* Get the selected provider for an exclusive hook (if any).
|
|
2667
|
-
*/
|
|
2668
|
-
getExclusiveSelection(hookName: string): string | undefined;
|
|
2550
|
+
offset?: number;
|
|
2551
|
+
cursor?: never;
|
|
2552
|
+
}
|
|
2553
|
+
type CollectionFilter = CursorCollectionFilter | OffsetCollectionFilter;
|
|
2554
|
+
interface ContentEntry<T = Record<string, unknown>> {
|
|
2555
|
+
id: string;
|
|
2556
|
+
data: T;
|
|
2557
|
+
/** Visual editing annotations. Spread onto elements: {...entry.edit.title} */
|
|
2558
|
+
edit: EditProxy;
|
|
2559
|
+
}
|
|
2560
|
+
/** Cache hint returned by the content loader for route caching */
|
|
2561
|
+
interface CacheHint {
|
|
2562
|
+
tags?: string[];
|
|
2563
|
+
lastModified?: Date;
|
|
2564
|
+
}
|
|
2565
|
+
/**
|
|
2566
|
+
* Result from getDinewayCollection
|
|
2567
|
+
*/
|
|
2568
|
+
interface CollectionResult<T> {
|
|
2569
|
+
/** The entries (empty array if error or none found) */
|
|
2570
|
+
entries: ContentEntry<T>[];
|
|
2571
|
+
/** Error if the query failed */
|
|
2572
|
+
error?: Error;
|
|
2573
|
+
/** Cache hint for route caching (pass to Astro.cache.set()) */
|
|
2574
|
+
cacheHint: CacheHint;
|
|
2669
2575
|
/**
|
|
2670
|
-
*
|
|
2576
|
+
* Opaque cursor for the next page.
|
|
2577
|
+
* Undefined when there are no more results.
|
|
2578
|
+
* Pass this as `cursor` in the next query to get the next page.
|
|
2671
2579
|
*/
|
|
2672
|
-
|
|
2673
|
-
pluginId: string;
|
|
2674
|
-
}>;
|
|
2580
|
+
nextCursor?: string;
|
|
2675
2581
|
/**
|
|
2676
|
-
*
|
|
2677
|
-
*
|
|
2582
|
+
* Whether more entries exist beyond this page. Set whenever `limit` is
|
|
2583
|
+
* provided, including offset-paginated numbered archives.
|
|
2678
2584
|
*/
|
|
2679
|
-
|
|
2680
|
-
pluginId: string;
|
|
2681
|
-
}>;
|
|
2585
|
+
hasMore?: boolean;
|
|
2682
2586
|
/**
|
|
2683
|
-
*
|
|
2684
|
-
* Returns null if no provider is selected or if the selected hook
|
|
2685
|
-
* is not found in the pipeline.
|
|
2686
|
-
*
|
|
2687
|
-
* This is a generic dispatch used by the email pipeline and other
|
|
2688
|
-
* exclusive hook consumers. The handler type is unknown — callers
|
|
2689
|
-
* must know the expected signature.
|
|
2690
|
-
*
|
|
2691
|
-
* Errors are isolated: a failing handler returns an error result
|
|
2692
|
-
* instead of propagating the exception to the caller.
|
|
2587
|
+
* Total number of entries matching the current filter, excluding cursor and limit.
|
|
2693
2588
|
*/
|
|
2694
|
-
|
|
2695
|
-
result: unknown;
|
|
2696
|
-
pluginId: string;
|
|
2697
|
-
error?: Error;
|
|
2698
|
-
duration: number;
|
|
2699
|
-
} | null>;
|
|
2589
|
+
total?: number;
|
|
2700
2590
|
}
|
|
2701
2591
|
/**
|
|
2702
|
-
*
|
|
2592
|
+
* Result from getDinewayEntry
|
|
2703
2593
|
*/
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2594
|
+
interface EntryResult<T> {
|
|
2595
|
+
/** The entry, or null if not found */
|
|
2596
|
+
entry: ContentEntry<T> | null;
|
|
2597
|
+
/** Error if the query failed (not set for "not found", only for actual errors) */
|
|
2598
|
+
error?: Error;
|
|
2599
|
+
/** Whether we're in preview mode (valid token was provided) */
|
|
2600
|
+
isPreview: boolean;
|
|
2601
|
+
/** Set when a fallback locale was used instead of the requested locale */
|
|
2602
|
+
fallbackLocale?: string;
|
|
2603
|
+
/** Cache hint for route caching (pass to Astro.cache.set()) */
|
|
2604
|
+
cacheHint: CacheHint;
|
|
2605
|
+
}
|
|
2606
|
+
/** Edit metadata attached to PT arrays in edit mode */
|
|
2607
|
+
interface EditFieldMeta {
|
|
2608
|
+
collection: string;
|
|
2609
|
+
id: string;
|
|
2610
|
+
field: string;
|
|
2611
|
+
}
|
|
2707
2612
|
/**
|
|
2708
|
-
*
|
|
2709
|
-
*
|
|
2710
|
-
*
|
|
2711
|
-
* 1. email:beforeSend — middleware hooks that can transform or cancel messages
|
|
2712
|
-
* 2. email:deliver — exclusive hook dispatching to the selected provider
|
|
2713
|
-
* 3. email:afterSend — fire-and-forget hooks for logging/analytics
|
|
2613
|
+
* Read edit metadata from a value (returns undefined if not tagged).
|
|
2614
|
+
* Uses Object.getOwnPropertyDescriptor to access Symbol-keyed property
|
|
2615
|
+
* without an unsafe type assertion.
|
|
2714
2616
|
*/
|
|
2715
|
-
declare
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2617
|
+
declare function getEditMeta(value: unknown): EditFieldMeta | undefined;
|
|
2618
|
+
/**
|
|
2619
|
+
* Get all entries of a content type
|
|
2620
|
+
*
|
|
2621
|
+
* Returns { entries, error } for graceful error handling.
|
|
2622
|
+
*
|
|
2623
|
+
* When dineway-env.d.ts is generated, the collection name will be
|
|
2624
|
+
* type-checked and the return type will be inferred automatically.
|
|
2625
|
+
*
|
|
2626
|
+
* @example
|
|
2627
|
+
* ```ts
|
|
2628
|
+
* import { getDinewayCollection } from "dineway";
|
|
2629
|
+
*
|
|
2630
|
+
* const { entries: posts, error } = await getDinewayCollection("posts");
|
|
2631
|
+
* if (error) {
|
|
2632
|
+
* console.error("Failed to load posts:", error);
|
|
2633
|
+
* return;
|
|
2634
|
+
* }
|
|
2635
|
+
* // posts[0].data.title is typed (if dineway-env.d.ts exists)
|
|
2636
|
+
*
|
|
2637
|
+
* // With filters
|
|
2638
|
+
* const { entries: drafts } = await getDinewayCollection("posts", { status: "draft" });
|
|
2639
|
+
* ```
|
|
2640
|
+
*/
|
|
2641
|
+
declare function getDinewayCollection<T extends string, D = InferCollectionData<T>>(type: T, filter?: CollectionFilter): Promise<CollectionResult<D>>;
|
|
2642
|
+
/**
|
|
2643
|
+
* Get a single entry by type and ID/slug
|
|
2644
|
+
*
|
|
2645
|
+
* Returns { entry, error, isPreview } for graceful error handling.
|
|
2646
|
+
* - entry is null if not found (not an error)
|
|
2647
|
+
* - error is set only for actual errors (db issues, etc.)
|
|
2648
|
+
*
|
|
2649
|
+
* Preview mode is detected automatically from request context (ALS).
|
|
2650
|
+
* When the URL has a valid `_preview` token, the middleware sets preview
|
|
2651
|
+
* context and this function serves draft revision data if available.
|
|
2652
|
+
*
|
|
2653
|
+
* @example
|
|
2654
|
+
* ```ts
|
|
2655
|
+
* import { getDinewayEntry } from "dineway";
|
|
2656
|
+
*
|
|
2657
|
+
* // Simple usage — preview just works via middleware
|
|
2658
|
+
* const { entry: post, isPreview, error } = await getDinewayEntry("posts", "my-slug");
|
|
2659
|
+
* if (!post) return Astro.redirect("/404");
|
|
2660
|
+
* ```
|
|
2661
|
+
*/
|
|
2662
|
+
declare function getDinewayEntry<T extends string, D = InferCollectionData<T>>(type: T, id: string, options?: {
|
|
2663
|
+
locale?: string;
|
|
2664
|
+
}): Promise<EntryResult<D>>;
|
|
2665
|
+
/**
|
|
2666
|
+
* Translation summary for a single locale variant
|
|
2667
|
+
*/
|
|
2668
|
+
interface TranslationSummary {
|
|
2669
|
+
/** Content item ID */
|
|
2670
|
+
id: string;
|
|
2671
|
+
/** Locale code (e.g. "en", "fr") */
|
|
2672
|
+
locale: string;
|
|
2673
|
+
/** URL slug */
|
|
2674
|
+
slug: string | null;
|
|
2675
|
+
/** Current status */
|
|
2676
|
+
status: string;
|
|
2677
|
+
}
|
|
2678
|
+
/**
|
|
2679
|
+
* Result from getTranslations
|
|
2680
|
+
*/
|
|
2681
|
+
interface TranslationsResult {
|
|
2682
|
+
/** The translation group ID (shared across locales) */
|
|
2683
|
+
translationGroup: string;
|
|
2684
|
+
/** All locale variants in this group */
|
|
2685
|
+
translations: TranslationSummary[];
|
|
2686
|
+
/** Error if the query failed */
|
|
2687
|
+
error?: Error;
|
|
2748
2688
|
}
|
|
2689
|
+
/**
|
|
2690
|
+
* Get all translations of a content item.
|
|
2691
|
+
*
|
|
2692
|
+
* Given a content entry, returns all locale variants that share the same
|
|
2693
|
+
* translation group. This is useful for building language switcher UI.
|
|
2694
|
+
*
|
|
2695
|
+
* @example
|
|
2696
|
+
* ```ts
|
|
2697
|
+
* import { getDinewayEntry, getTranslations } from "dineway";
|
|
2698
|
+
*
|
|
2699
|
+
* const { entry: post } = await getDinewayEntry("posts", "hello-world", { locale: "en" });
|
|
2700
|
+
* const { translations } = await getTranslations("posts", post.data.id);
|
|
2701
|
+
* // translations = [{ id: "...", locale: "en", slug: "hello-world", status: "published" }, ...]
|
|
2702
|
+
* ```
|
|
2703
|
+
*/
|
|
2704
|
+
declare function getTranslations(type: string, id: string): Promise<TranslationsResult>;
|
|
2705
|
+
/**
|
|
2706
|
+
* Result from resolveDinewayPath
|
|
2707
|
+
*/
|
|
2708
|
+
interface ResolvePathResult<T = Record<string, unknown>> {
|
|
2709
|
+
/** The matched entry */
|
|
2710
|
+
entry: ContentEntry<T>;
|
|
2711
|
+
/** The collection slug that matched */
|
|
2712
|
+
collection: string;
|
|
2713
|
+
/** Extracted parameters from the URL pattern (e.g. { slug: "my-post" }) */
|
|
2714
|
+
params: Record<string, string>;
|
|
2715
|
+
}
|
|
2716
|
+
/**
|
|
2717
|
+
* Resolve a URL path to a content entry by matching against collection URL patterns.
|
|
2718
|
+
*
|
|
2719
|
+
* Loads all collections with a `urlPattern` set, converts each pattern to a regex,
|
|
2720
|
+
* and tests the given path. On match, extracts the slug and fetches the entry.
|
|
2721
|
+
*
|
|
2722
|
+
* @example
|
|
2723
|
+
* ```ts
|
|
2724
|
+
* import { resolveDinewayPath } from "dineway";
|
|
2725
|
+
*
|
|
2726
|
+
* // Given pages with urlPattern "/{slug}" and posts with "/blog/{slug}":
|
|
2727
|
+
* const result = await resolveDinewayPath("/blog/hello-world");
|
|
2728
|
+
* if (result) {
|
|
2729
|
+
* console.log(result.collection); // "posts"
|
|
2730
|
+
* console.log(result.params.slug); // "hello-world"
|
|
2731
|
+
* console.log(result.entry.data); // post data
|
|
2732
|
+
* }
|
|
2733
|
+
* ```
|
|
2734
|
+
*/
|
|
2735
|
+
declare function resolveDinewayPath<T = Record<string, unknown>>(path: string): Promise<ResolvePathResult<T> | null>;
|
|
2736
|
+
//#endregion
|
|
2737
|
+
//#region src/after.d.ts
|
|
2738
|
+
/**
|
|
2739
|
+
* Defer work past the current synchronous path.
|
|
2740
|
+
*
|
|
2741
|
+
* Use this for best-effort bookkeeping that should not block runtime
|
|
2742
|
+
* initialization or response handling. Node keeps the process alive for
|
|
2743
|
+
* pending work; callers that need stronger durability should await their own
|
|
2744
|
+
* operation instead of using this helper.
|
|
2745
|
+
*/
|
|
2746
|
+
type AfterCallback = () => void | Promise<void>;
|
|
2747
|
+
declare function after(fn: AfterCallback): void;
|
|
2748
|
+
//#endregion
|
|
2749
|
+
//#region src/object-cache/index.d.ts
|
|
2750
|
+
/** Options for {@link cachedQuery}. */
|
|
2751
|
+
interface CachedQueryOptions<T> {
|
|
2752
|
+
/**
|
|
2753
|
+
* Invalidation namespace(s). A single string for self-contained data
|
|
2754
|
+
* (`settings`, `menus`), or several when the cached value depends on data
|
|
2755
|
+
* owned by other namespaces — e.g. a content entry hydrates bylines and
|
|
2756
|
+
* taxonomy terms, so it caches under
|
|
2757
|
+
* `[content:posts, "bylines", "taxonomies"]` and is invalidated when *any*
|
|
2758
|
+
* of them is bumped. Every namespace's epoch is folded into the key.
|
|
2759
|
+
*/
|
|
2760
|
+
namespace: string | readonly string[];
|
|
2761
|
+
/** Stable, fully-qualifying cache key *within* the namespace. */
|
|
2762
|
+
key: string;
|
|
2763
|
+
/** Loader run on a miss (or when caching is disabled/bypassed). */
|
|
2764
|
+
load: () => Promise<T>;
|
|
2765
|
+
/** TTL override in seconds. Falls back to the configured `defaultTtl`. */
|
|
2766
|
+
ttl?: number;
|
|
2767
|
+
/**
|
|
2768
|
+
* Predicate gating whether a freshly-loaded value is stored. Defaults to
|
|
2769
|
+
* always-cache. Use it to skip caching error/empty sentinels.
|
|
2770
|
+
*/
|
|
2771
|
+
cacheable?: (value: T) => boolean;
|
|
2772
|
+
}
|
|
2773
|
+
/**
|
|
2774
|
+
* Distributed read-through cache around `load`.
|
|
2775
|
+
*
|
|
2776
|
+
* `T` must be the value as it should be *stored* — i.e. JSON-serializable with
|
|
2777
|
+
* the codec's `Date` support, carrying no functions or symbol-keyed props.
|
|
2778
|
+
* Callers caching richer objects (content entries) reduce to a serializable
|
|
2779
|
+
* snapshot here and rebuild on the way out; see `query.ts`.
|
|
2780
|
+
*
|
|
2781
|
+
* On a miss or when the cache is disabled/bypassed, this is equivalent to
|
|
2782
|
+
* `await load()`. Backend errors never propagate: a failing `get` is a miss, a
|
|
2783
|
+
* failing `set` is dropped.
|
|
2784
|
+
*/
|
|
2785
|
+
declare function cachedQuery<T>(options: CachedQueryOptions<T>): Promise<T>;
|
|
2786
|
+
/** Whether object-cache reads are active for the current request. */
|
|
2787
|
+
declare function isObjectCacheActive(): Promise<boolean>;
|
|
2788
|
+
/**
|
|
2789
|
+
* Invalidate every cached value in `namespace` by bumping its epoch.
|
|
2790
|
+
*
|
|
2791
|
+
* Sync and non-blocking: the local epoch is stamped immediately (so the
|
|
2792
|
+
* writing isolate is instantly consistent) and the backend write is deferred
|
|
2793
|
+
* via `after`. Other isolates pick up the new epoch within their `revalidate`
|
|
2794
|
+
* window. No-ops when the cache is disabled.
|
|
2795
|
+
*/
|
|
2796
|
+
declare function invalidateObjectCache(namespace: string): void;
|
|
2797
|
+
/**
|
|
2798
|
+
* Fixed namespaces for data shared across collections. Content reads fold the
|
|
2799
|
+
* `BYLINES` and `TAXONOMIES` epochs into their keys (via {@link cachedQuery})
|
|
2800
|
+
* because entries hydrate byline and taxonomy-term data — so renaming an
|
|
2801
|
+
* author or a category correctly invalidates every cached entry that displays
|
|
2802
|
+
* it, without tracking which collections reference it.
|
|
2803
|
+
*/
|
|
2804
|
+
declare const CacheNamespace: {
|
|
2805
|
+
readonly SETTINGS: "settings";
|
|
2806
|
+
readonly MENUS: "menus";
|
|
2807
|
+
readonly TAXONOMIES: "taxonomies";
|
|
2808
|
+
readonly BYLINES: "bylines"; /** Collection schema/metadata (label, supports, commentsEnabled, fields). */
|
|
2809
|
+
readonly SCHEMA: "schema"; /** Public (approved) comments. */
|
|
2810
|
+
readonly COMMENTS: "comments";
|
|
2811
|
+
};
|
|
2812
|
+
/** Namespace for a content collection's cached queries. */
|
|
2813
|
+
declare function contentNamespace(collection: string): string;
|
|
2814
|
+
/**
|
|
2815
|
+
* Namespaces a content read depends on: the collection itself plus the shared
|
|
2816
|
+
* byline/taxonomy data folded into each entry.
|
|
2817
|
+
*/
|
|
2818
|
+
declare function contentNamespaces(collection: string): readonly string[];
|
|
2819
|
+
/**
|
|
2820
|
+
* Invalidate all cached reads (list + entry) for a content collection.
|
|
2821
|
+
* Call from every write path that mutates rows in `ec_<collection>`.
|
|
2822
|
+
*/
|
|
2823
|
+
declare function invalidateCollectionCache(collection: string): void;
|
|
2824
|
+
/** Invalidate cached taxonomy definitions/terms and all content that hydrates them. */
|
|
2825
|
+
declare function invalidateTaxonomyObjectCache(): void;
|
|
2826
|
+
/** Invalidate cached bylines and all content that hydrates them. */
|
|
2827
|
+
declare function invalidateBylineObjectCache(): void;
|
|
2828
|
+
/** Invalidate cached navigation menus. */
|
|
2829
|
+
declare function invalidateMenuObjectCache(): void;
|
|
2830
|
+
/** Invalidate cached collection schema/metadata reads (e.g. getCollectionInfo). */
|
|
2831
|
+
declare function invalidateSchemaObjectCache(): void;
|
|
2832
|
+
/** Invalidate cached public comment reads. */
|
|
2833
|
+
declare function invalidateCommentObjectCache(): void;
|
|
2834
|
+
//#endregion
|
|
2835
|
+
//#region src/i18n/config.d.ts
|
|
2836
|
+
/**
|
|
2837
|
+
* Dineway i18n Configuration
|
|
2838
|
+
*
|
|
2839
|
+
* Reads locale configuration from the virtual module (sourced from Astro config).
|
|
2840
|
+
* Initialized during runtime startup, then available via getI18nConfig().
|
|
2841
|
+
*/
|
|
2842
|
+
interface I18nConfig {
|
|
2843
|
+
defaultLocale: string;
|
|
2844
|
+
locales: string[];
|
|
2845
|
+
fallback?: Record<string, string>;
|
|
2846
|
+
prefixDefaultLocale?: boolean;
|
|
2847
|
+
}
|
|
2848
|
+
/**
|
|
2849
|
+
* Get the current i18n config.
|
|
2850
|
+
* Returns null if i18n is not configured.
|
|
2851
|
+
*/
|
|
2852
|
+
declare function getI18nConfig(): I18nConfig | null;
|
|
2853
|
+
/**
|
|
2854
|
+
* Check if i18n is enabled.
|
|
2855
|
+
* Returns true when multiple locales are configured.
|
|
2856
|
+
*/
|
|
2857
|
+
declare function isI18nEnabled(): boolean;
|
|
2858
|
+
/**
|
|
2859
|
+
* Resolve fallback locale chain for a given locale.
|
|
2860
|
+
* Returns array of locales to try, from most preferred to least.
|
|
2861
|
+
* Always ends with defaultLocale.
|
|
2862
|
+
*/
|
|
2863
|
+
declare function getFallbackChain(locale: string): string[];
|
|
2864
|
+
//#endregion
|
|
2865
|
+
//#region src/preview/sidecar-client.d.ts
|
|
2866
|
+
/**
|
|
2867
|
+
* Preview sidecar protocol helpers.
|
|
2868
|
+
*
|
|
2869
|
+
* These utilities define the signed URL and snapshot-auth contract shared
|
|
2870
|
+
* by preview sidecars and the source site serving snapshot exports.
|
|
2871
|
+
*/
|
|
2872
|
+
interface PreviewSidecarSignature {
|
|
2873
|
+
source: string;
|
|
2874
|
+
exp: number;
|
|
2875
|
+
sig: string;
|
|
2876
|
+
}
|
|
2877
|
+
interface PreviewSidecarClient {
|
|
2878
|
+
signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
|
|
2879
|
+
buildSnapshotSignatureHeader(signature: PreviewSidecarSignature): string;
|
|
2880
|
+
}
|
|
2881
|
+
declare function signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
|
|
2882
|
+
declare function buildPreviewSignatureHeader(signature: PreviewSidecarSignature): string;
|
|
2883
|
+
declare function parsePreviewSignatureHeader(header: string): PreviewSidecarSignature | null;
|
|
2884
|
+
declare function verifyPreviewSignature(source: string, exp: number, sig: string, secret: string): Promise<boolean>;
|
|
2885
|
+
declare const defaultPreviewSidecarClient: PreviewSidecarClient;
|
|
2886
|
+
//#endregion
|
|
2887
|
+
//#region src/preview/session-database-factory.d.ts
|
|
2888
|
+
interface SessionDatabaseInfo {
|
|
2889
|
+
id: string;
|
|
2890
|
+
dbPath: string;
|
|
2891
|
+
createdAt: number;
|
|
2892
|
+
expiresAt: number;
|
|
2893
|
+
lastTouchedAt: number;
|
|
2894
|
+
}
|
|
2895
|
+
interface SessionDatabaseHandle {
|
|
2896
|
+
created: boolean;
|
|
2897
|
+
session: SessionDatabaseInfo;
|
|
2898
|
+
db: Kysely<Database>;
|
|
2899
|
+
close(): Promise<void>;
|
|
2900
|
+
}
|
|
2901
|
+
interface SessionCleanupResult {
|
|
2902
|
+
removedSessionIds: string[];
|
|
2903
|
+
removedPaths: string[];
|
|
2904
|
+
}
|
|
2905
|
+
interface SessionOpenOptions {
|
|
2906
|
+
id: string;
|
|
2907
|
+
now?: number;
|
|
2908
|
+
}
|
|
2909
|
+
interface SessionOpenOrCreateOptions extends SessionOpenOptions {
|
|
2910
|
+
ttlMs: number;
|
|
2911
|
+
}
|
|
2912
|
+
interface SessionDatabaseFactory {
|
|
2913
|
+
open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
|
|
2914
|
+
openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
|
|
2915
|
+
destroy(id: string): Promise<boolean>;
|
|
2916
|
+
cleanup(now?: number): Promise<SessionCleanupResult>;
|
|
2917
|
+
close(): Promise<void>;
|
|
2918
|
+
}
|
|
2919
|
+
interface FileSessionDatabaseFactoryOptions {
|
|
2920
|
+
rootDir: string;
|
|
2921
|
+
maxDiskBytes?: number;
|
|
2922
|
+
registryFileName?: string;
|
|
2923
|
+
sessionsDirName?: string;
|
|
2924
|
+
}
|
|
2925
|
+
declare class SessionDatabaseLimitError extends Error {
|
|
2926
|
+
constructor(message?: string);
|
|
2927
|
+
}
|
|
2928
|
+
declare class FileSessionDatabaseFactory implements SessionDatabaseFactory {
|
|
2929
|
+
private readonly options;
|
|
2930
|
+
private readonly registry;
|
|
2931
|
+
private readonly sessionsDir;
|
|
2932
|
+
private readonly maxDiskBytes;
|
|
2933
|
+
constructor(options: FileSessionDatabaseFactoryOptions);
|
|
2934
|
+
open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
|
|
2935
|
+
openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
|
|
2936
|
+
destroy(id: string): Promise<boolean>;
|
|
2937
|
+
cleanup(now?: number): Promise<SessionCleanupResult>;
|
|
2938
|
+
close(): Promise<void>;
|
|
2939
|
+
private createHandle;
|
|
2940
|
+
private getSessionRow;
|
|
2941
|
+
private toSessionInfo;
|
|
2942
|
+
private deleteSession;
|
|
2943
|
+
private getActiveDiskBytes;
|
|
2944
|
+
private getDbPath;
|
|
2945
|
+
private getManagedPaths;
|
|
2946
|
+
private listSessionRows;
|
|
2947
|
+
private listDbPathRows;
|
|
2948
|
+
}
|
|
2949
|
+
//#endregion
|
|
2950
|
+
//#region src/preview/middleware.d.ts
|
|
2951
|
+
interface FilePreviewMiddlewareConfig {
|
|
2952
|
+
rootDir?: string;
|
|
2953
|
+
secret: string;
|
|
2954
|
+
ttlSeconds?: number;
|
|
2955
|
+
cookieName?: string;
|
|
2956
|
+
snapshotPath?: string;
|
|
2957
|
+
maxSessionDiskBytes?: number;
|
|
2958
|
+
sessionFactory?: SessionDatabaseFactory;
|
|
2959
|
+
fetch?: typeof globalThis.fetch;
|
|
2960
|
+
}
|
|
2961
|
+
declare function createFilePreviewMiddleware(config: FilePreviewMiddlewareConfig): MiddlewareHandler;
|
|
2962
|
+
//#endregion
|
|
2963
|
+
//#region src/plugins/define-plugin.d.ts
|
|
2964
|
+
/**
|
|
2965
|
+
* Define a Dineway plugin.
|
|
2966
|
+
*
|
|
2967
|
+
* **Standard format** -- the canonical format for plugins that work in both
|
|
2968
|
+
* trusted and sandboxed modes. No id/version -- those come from the descriptor.
|
|
2969
|
+
*
|
|
2970
|
+
* @example
|
|
2971
|
+
* ```typescript
|
|
2972
|
+
* import { definePlugin } from "dineway";
|
|
2973
|
+
*
|
|
2974
|
+
* export default definePlugin({
|
|
2975
|
+
* hooks: {
|
|
2976
|
+
* "content:afterSave": {
|
|
2977
|
+
* handler: async (event, ctx) => {
|
|
2978
|
+
* await ctx.kv.set("lastSave", Date.now());
|
|
2979
|
+
* },
|
|
2980
|
+
* },
|
|
2981
|
+
* },
|
|
2982
|
+
* routes: {
|
|
2983
|
+
* status: {
|
|
2984
|
+
* handler: async (routeCtx, ctx) => ({ ok: true }),
|
|
2985
|
+
* },
|
|
2986
|
+
* },
|
|
2987
|
+
* });
|
|
2988
|
+
* ```
|
|
2989
|
+
*
|
|
2990
|
+
* **Native format** -- for plugins that need React admin, direct DB access,
|
|
2991
|
+
* or other capabilities not available in the sandbox.
|
|
2992
|
+
*
|
|
2993
|
+
* @example
|
|
2994
|
+
* ```typescript
|
|
2995
|
+
* import { definePlugin } from "dineway";
|
|
2996
|
+
*
|
|
2997
|
+
* export default definePlugin({
|
|
2998
|
+
* id: "my-plugin",
|
|
2999
|
+
* version: "1.0.0",
|
|
3000
|
+
* capabilities: ["content:read"],
|
|
3001
|
+
* hooks: {
|
|
3002
|
+
* "content:beforeSave": async (event, ctx) => {
|
|
3003
|
+
* ctx.log.info("Saving content", { collection: event.collection });
|
|
3004
|
+
* return event.content;
|
|
3005
|
+
* }
|
|
3006
|
+
* },
|
|
3007
|
+
* routes: {
|
|
3008
|
+
* "sync": {
|
|
3009
|
+
* handler: async (ctx) => {
|
|
3010
|
+
* return { status: "ok" };
|
|
3011
|
+
* }
|
|
3012
|
+
* }
|
|
3013
|
+
* }
|
|
3014
|
+
* });
|
|
3015
|
+
* ```
|
|
3016
|
+
*/
|
|
3017
|
+
declare function definePlugin<TStorage extends PluginStorageConfig>(definition: PluginDefinition<TStorage>): ResolvedPlugin<TStorage>;
|
|
3018
|
+
declare function definePlugin(definition: StandardPluginDefinition): StandardPluginDefinition;
|
|
3019
|
+
//#endregion
|
|
3020
|
+
//#region src/plugins/manifest-schema.d.ts
|
|
3021
|
+
/**
|
|
3022
|
+
* Zod schema matching the PluginManifest interface from types.ts.
|
|
3023
|
+
*
|
|
3024
|
+
* Every JSON.parse of a manifest.json should validate through this.
|
|
3025
|
+
*/
|
|
3026
|
+
declare const pluginManifestSchema: z$1.ZodObject<{
|
|
3027
|
+
id: z$1.ZodString;
|
|
3028
|
+
version: z$1.ZodString;
|
|
3029
|
+
declaredAccess: z$1.ZodOptional<z$1.ZodObject<{
|
|
3030
|
+
content: z$1.ZodOptional<z$1.ZodObject<{
|
|
3031
|
+
read: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3032
|
+
write: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3033
|
+
}, z$1.core.$strip>>;
|
|
3034
|
+
media: z$1.ZodOptional<z$1.ZodObject<{
|
|
3035
|
+
read: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3036
|
+
write: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3037
|
+
}, z$1.core.$strip>>;
|
|
3038
|
+
network: z$1.ZodOptional<z$1.ZodObject<{
|
|
3039
|
+
request: z$1.ZodOptional<z$1.ZodObject<{
|
|
3040
|
+
allowedHosts: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>;
|
|
3041
|
+
}, z$1.core.$strip>>;
|
|
3042
|
+
}, z$1.core.$strip>>;
|
|
3043
|
+
email: z$1.ZodOptional<z$1.ZodObject<{
|
|
3044
|
+
send: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3045
|
+
events: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3046
|
+
transport: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3047
|
+
}, z$1.core.$strip>>;
|
|
3048
|
+
page: z$1.ZodOptional<z$1.ZodObject<{
|
|
3049
|
+
fragments: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3050
|
+
}, z$1.core.$strip>>;
|
|
3051
|
+
users: z$1.ZodOptional<z$1.ZodObject<{
|
|
3052
|
+
read: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
|
|
3053
|
+
}, z$1.core.$strip>>;
|
|
3054
|
+
}, z$1.core.$strip>>;
|
|
3055
|
+
capabilities: z$1.ZodArray<z$1.ZodEnum<{
|
|
3056
|
+
"network:request": "network:request";
|
|
3057
|
+
"network:request:unrestricted": "network:request:unrestricted";
|
|
3058
|
+
"content:read": "content:read";
|
|
3059
|
+
"content:write": "content:write";
|
|
3060
|
+
"media:read": "media:read";
|
|
3061
|
+
"media:write": "media:write";
|
|
3062
|
+
"users:read": "users:read";
|
|
3063
|
+
"email:send": "email:send";
|
|
3064
|
+
"hooks.email-transport:register": "hooks.email-transport:register";
|
|
3065
|
+
"hooks.email-events:register": "hooks.email-events:register";
|
|
3066
|
+
"hooks.page-fragments:register": "hooks.page-fragments:register";
|
|
3067
|
+
}>>;
|
|
3068
|
+
allowedHosts: z$1.ZodArray<z$1.ZodString>;
|
|
3069
|
+
storage: z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
|
|
3070
|
+
indexes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>;
|
|
3071
|
+
uniqueIndexes: z$1.ZodOptional<z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>>;
|
|
3072
|
+
}, z$1.core.$strip>>;
|
|
3073
|
+
hooks: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodEnum<{
|
|
3074
|
+
"plugin:install": "plugin:install";
|
|
3075
|
+
"plugin:activate": "plugin:activate";
|
|
3076
|
+
"plugin:deactivate": "plugin:deactivate";
|
|
3077
|
+
"plugin:uninstall": "plugin:uninstall";
|
|
3078
|
+
"content:beforeSave": "content:beforeSave";
|
|
3079
|
+
"content:afterSave": "content:afterSave";
|
|
3080
|
+
"content:beforeDelete": "content:beforeDelete";
|
|
3081
|
+
"content:afterDelete": "content:afterDelete";
|
|
3082
|
+
"content:afterPublish": "content:afterPublish";
|
|
3083
|
+
"content:afterUnpublish": "content:afterUnpublish";
|
|
3084
|
+
"content:afterRestore": "content:afterRestore";
|
|
3085
|
+
"content:afterSchedule": "content:afterSchedule";
|
|
3086
|
+
"content:afterUnschedule": "content:afterUnschedule";
|
|
3087
|
+
"media:beforeUpload": "media:beforeUpload";
|
|
3088
|
+
"media:afterUpload": "media:afterUpload";
|
|
3089
|
+
cron: "cron";
|
|
3090
|
+
"email:beforeSend": "email:beforeSend";
|
|
3091
|
+
"email:deliver": "email:deliver";
|
|
3092
|
+
"email:afterSend": "email:afterSend";
|
|
3093
|
+
"comment:beforeCreate": "comment:beforeCreate";
|
|
3094
|
+
"comment:moderate": "comment:moderate";
|
|
3095
|
+
"comment:afterCreate": "comment:afterCreate";
|
|
3096
|
+
"comment:afterModerate": "comment:afterModerate";
|
|
3097
|
+
"page:metadata": "page:metadata";
|
|
3098
|
+
"page:fragments": "page:fragments";
|
|
3099
|
+
}>, z$1.ZodObject<{
|
|
3100
|
+
name: z$1.ZodEnum<{
|
|
3101
|
+
"plugin:install": "plugin:install";
|
|
3102
|
+
"plugin:activate": "plugin:activate";
|
|
3103
|
+
"plugin:deactivate": "plugin:deactivate";
|
|
3104
|
+
"plugin:uninstall": "plugin:uninstall";
|
|
3105
|
+
"content:beforeSave": "content:beforeSave";
|
|
3106
|
+
"content:afterSave": "content:afterSave";
|
|
3107
|
+
"content:beforeDelete": "content:beforeDelete";
|
|
3108
|
+
"content:afterDelete": "content:afterDelete";
|
|
3109
|
+
"content:afterPublish": "content:afterPublish";
|
|
3110
|
+
"content:afterUnpublish": "content:afterUnpublish";
|
|
3111
|
+
"content:afterRestore": "content:afterRestore";
|
|
3112
|
+
"content:afterSchedule": "content:afterSchedule";
|
|
3113
|
+
"content:afterUnschedule": "content:afterUnschedule";
|
|
3114
|
+
"media:beforeUpload": "media:beforeUpload";
|
|
3115
|
+
"media:afterUpload": "media:afterUpload";
|
|
3116
|
+
cron: "cron";
|
|
3117
|
+
"email:beforeSend": "email:beforeSend";
|
|
3118
|
+
"email:deliver": "email:deliver";
|
|
3119
|
+
"email:afterSend": "email:afterSend";
|
|
3120
|
+
"comment:beforeCreate": "comment:beforeCreate";
|
|
3121
|
+
"comment:moderate": "comment:moderate";
|
|
3122
|
+
"comment:afterCreate": "comment:afterCreate";
|
|
3123
|
+
"comment:afterModerate": "comment:afterModerate";
|
|
3124
|
+
"page:metadata": "page:metadata";
|
|
3125
|
+
"page:fragments": "page:fragments";
|
|
3126
|
+
}>;
|
|
3127
|
+
exclusive: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
3128
|
+
priority: z$1.ZodOptional<z$1.ZodNumber>;
|
|
3129
|
+
timeout: z$1.ZodOptional<z$1.ZodNumber>;
|
|
3130
|
+
}, z$1.core.$strip>]>>;
|
|
3131
|
+
routes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodObject<{
|
|
3132
|
+
name: z$1.ZodString;
|
|
3133
|
+
public: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
3134
|
+
}, z$1.core.$strip>]>>;
|
|
3135
|
+
admin: z$1.ZodObject<{
|
|
3136
|
+
entry: z$1.ZodOptional<z$1.ZodString>;
|
|
3137
|
+
settingsSchema: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{
|
|
3138
|
+
type: z$1.ZodLiteral<"string">;
|
|
3139
|
+
default: z$1.ZodOptional<z$1.ZodString>;
|
|
3140
|
+
multiline: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
3141
|
+
label: z$1.ZodString;
|
|
3142
|
+
description: z$1.ZodOptional<z$1.ZodString>;
|
|
3143
|
+
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
3144
|
+
type: z$1.ZodLiteral<"number">;
|
|
3145
|
+
default: z$1.ZodOptional<z$1.ZodNumber>;
|
|
3146
|
+
min: z$1.ZodOptional<z$1.ZodNumber>;
|
|
3147
|
+
max: z$1.ZodOptional<z$1.ZodNumber>;
|
|
3148
|
+
label: z$1.ZodString;
|
|
3149
|
+
description: z$1.ZodOptional<z$1.ZodString>;
|
|
3150
|
+
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
3151
|
+
type: z$1.ZodLiteral<"boolean">;
|
|
3152
|
+
default: z$1.ZodOptional<z$1.ZodBoolean>;
|
|
3153
|
+
label: z$1.ZodString;
|
|
3154
|
+
description: z$1.ZodOptional<z$1.ZodString>;
|
|
3155
|
+
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
3156
|
+
type: z$1.ZodLiteral<"select">;
|
|
3157
|
+
options: z$1.ZodArray<z$1.ZodObject<{
|
|
3158
|
+
value: z$1.ZodString;
|
|
3159
|
+
label: z$1.ZodString;
|
|
3160
|
+
}, z$1.core.$strip>>;
|
|
3161
|
+
default: z$1.ZodOptional<z$1.ZodString>;
|
|
3162
|
+
label: z$1.ZodString;
|
|
3163
|
+
description: z$1.ZodOptional<z$1.ZodString>;
|
|
3164
|
+
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
3165
|
+
type: z$1.ZodLiteral<"secret">;
|
|
3166
|
+
label: z$1.ZodString;
|
|
3167
|
+
description: z$1.ZodOptional<z$1.ZodString>;
|
|
3168
|
+
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
3169
|
+
type: z$1.ZodLiteral<"url">;
|
|
3170
|
+
default: z$1.ZodOptional<z$1.ZodString>;
|
|
3171
|
+
placeholder: z$1.ZodOptional<z$1.ZodString>;
|
|
3172
|
+
label: z$1.ZodString;
|
|
3173
|
+
description: z$1.ZodOptional<z$1.ZodString>;
|
|
3174
|
+
}, z$1.core.$strip>, z$1.ZodObject<{
|
|
3175
|
+
type: z$1.ZodLiteral<"email">;
|
|
3176
|
+
default: z$1.ZodOptional<z$1.ZodString>;
|
|
3177
|
+
placeholder: z$1.ZodOptional<z$1.ZodString>;
|
|
3178
|
+
label: z$1.ZodString;
|
|
3179
|
+
description: z$1.ZodOptional<z$1.ZodString>;
|
|
3180
|
+
}, z$1.core.$strip>], "type">>>;
|
|
3181
|
+
pages: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
3182
|
+
path: z$1.ZodString;
|
|
3183
|
+
label: z$1.ZodString;
|
|
3184
|
+
icon: z$1.ZodOptional<z$1.ZodString>;
|
|
3185
|
+
}, z$1.core.$strip>>>;
|
|
3186
|
+
widgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
3187
|
+
id: z$1.ZodString;
|
|
3188
|
+
size: z$1.ZodOptional<z$1.ZodEnum<{
|
|
3189
|
+
full: "full";
|
|
3190
|
+
half: "half";
|
|
3191
|
+
third: "third";
|
|
3192
|
+
}>>;
|
|
3193
|
+
title: z$1.ZodOptional<z$1.ZodString>;
|
|
3194
|
+
}, z$1.core.$strip>>>;
|
|
3195
|
+
fieldWidgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
3196
|
+
name: z$1.ZodString;
|
|
3197
|
+
label: z$1.ZodString;
|
|
3198
|
+
fieldTypes: z$1.ZodArray<z$1.ZodEnum<{
|
|
3199
|
+
string: "string";
|
|
3200
|
+
number: "number";
|
|
3201
|
+
boolean: "boolean";
|
|
3202
|
+
file: "file";
|
|
3203
|
+
slug: "slug";
|
|
3204
|
+
text: "text";
|
|
3205
|
+
integer: "integer";
|
|
3206
|
+
datetime: "datetime";
|
|
3207
|
+
select: "select";
|
|
3208
|
+
multiSelect: "multiSelect";
|
|
3209
|
+
portableText: "portableText";
|
|
3210
|
+
image: "image";
|
|
3211
|
+
reference: "reference";
|
|
3212
|
+
json: "json";
|
|
3213
|
+
repeater: "repeater";
|
|
3214
|
+
}>>;
|
|
3215
|
+
elements: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
|
|
3216
|
+
type: z$1.ZodString;
|
|
3217
|
+
action_id: z$1.ZodString;
|
|
3218
|
+
label: z$1.ZodOptional<z$1.ZodString>;
|
|
3219
|
+
}, z$1.core.$loose>>>;
|
|
3220
|
+
}, z$1.core.$strip>>>;
|
|
3221
|
+
}, z$1.core.$strip>;
|
|
3222
|
+
}, z$1.core.$strip>;
|
|
3223
|
+
type ValidatedPluginManifest = z$1.infer<typeof pluginManifestSchema>;
|
|
2749
3224
|
//#endregion
|
|
2750
|
-
//#region src/
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
interface PluginContextFactoryOptions {
|
|
2763
|
-
db: Kysely<Database>;
|
|
2764
|
-
/**
|
|
2765
|
-
* Storage backend for direct media uploads.
|
|
2766
|
-
* If not provided, upload() will throw.
|
|
2767
|
-
*/
|
|
2768
|
-
storage?: Storage;
|
|
2769
|
-
/**
|
|
2770
|
-
* Function to generate upload URLs for media.
|
|
2771
|
-
* If not provided, media write operations will throw.
|
|
2772
|
-
*/
|
|
2773
|
-
getUploadUrl?: (filename: string, contentType: string) => Promise<{
|
|
2774
|
-
uploadUrl: string;
|
|
2775
|
-
mediaId: string;
|
|
2776
|
-
}>;
|
|
2777
|
-
/**
|
|
2778
|
-
* Site information for ctx.site and ctx.url().
|
|
2779
|
-
* If not provided, site info will have empty defaults.
|
|
2780
|
-
*/
|
|
2781
|
-
siteInfo?: SiteInfoOptions;
|
|
2782
|
-
/**
|
|
2783
|
-
* Callback to notify the cron scheduler that the next due time may have changed.
|
|
2784
|
-
* If not provided, ctx.cron will not be available.
|
|
2785
|
-
*/
|
|
2786
|
-
cronReschedule?: () => void;
|
|
2787
|
-
/**
|
|
2788
|
-
* Email pipeline instance for ctx.email.
|
|
2789
|
-
* If not provided (or no provider configured), ctx.email will be undefined.
|
|
2790
|
-
*/
|
|
2791
|
-
emailPipeline?: EmailPipeline;
|
|
2792
|
-
/**
|
|
2793
|
-
* Trusted reverse-proxy headers for request metadata IP extraction.
|
|
2794
|
-
*/
|
|
2795
|
-
trustedProxyHeaders?: string[];
|
|
3225
|
+
//#region src/config/secrets.d.ts
|
|
3226
|
+
interface ParsedEncryptionKey {
|
|
3227
|
+
kid: string;
|
|
3228
|
+
key: Uint8Array;
|
|
3229
|
+
raw: string;
|
|
3230
|
+
}
|
|
3231
|
+
interface SecretsEnv {
|
|
3232
|
+
DINEWAY_ENCRYPTION_KEY?: string;
|
|
3233
|
+
DINEWAY_PREVIEW_SECRET?: string;
|
|
3234
|
+
PREVIEW_SECRET?: string;
|
|
3235
|
+
DINEWAY_IP_SALT?: string;
|
|
3236
|
+
IP_SALT?: string;
|
|
2796
3237
|
}
|
|
2797
3238
|
//#endregion
|
|
2798
|
-
//#region src/plugins/
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
message: string;
|
|
2808
|
-
details?: unknown;
|
|
2809
|
-
};
|
|
2810
|
-
status: number;
|
|
3239
|
+
//#region src/plugins/secrets.d.ts
|
|
3240
|
+
interface PluginSecretStatus {
|
|
3241
|
+
pluginId: string;
|
|
3242
|
+
name: string;
|
|
3243
|
+
present: true;
|
|
3244
|
+
fingerprint: string;
|
|
3245
|
+
keyId: string;
|
|
3246
|
+
createdAt: string;
|
|
3247
|
+
updatedAt: string;
|
|
2811
3248
|
}
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
interface InvokeRouteOptions {
|
|
2816
|
-
/** The original request */
|
|
2817
|
-
request: Request;
|
|
2818
|
-
/** Request body (already parsed) */
|
|
2819
|
-
body?: unknown;
|
|
3249
|
+
interface PluginSecretStoreOptions {
|
|
3250
|
+
env?: Pick<SecretsEnv, "DINEWAY_ENCRYPTION_KEY">;
|
|
3251
|
+
keys?: readonly ParsedEncryptionKey[];
|
|
2820
3252
|
}
|
|
2821
3253
|
/**
|
|
2822
|
-
*
|
|
2823
|
-
*
|
|
3254
|
+
* Encrypted storage for trusted plugin credentials.
|
|
3255
|
+
*
|
|
3256
|
+
* Management surfaces must use set/status/list/delete and never echo the value
|
|
3257
|
+
* passed to set. resolveForRuntime is reserved for trusted server-side provider
|
|
3258
|
+
* calls and must not be exposed through plugin routes, MCP, logs, or audit data.
|
|
2824
3259
|
*/
|
|
2825
|
-
declare class
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
* Create an unauthorized error (401)
|
|
2836
|
-
*/
|
|
2837
|
-
static unauthorized(message?: string): PluginRouteError;
|
|
2838
|
-
/**
|
|
2839
|
-
* Create a forbidden error (403)
|
|
2840
|
-
*/
|
|
2841
|
-
static forbidden(message?: string): PluginRouteError;
|
|
2842
|
-
/**
|
|
2843
|
-
* Create a not found error (404)
|
|
2844
|
-
*/
|
|
2845
|
-
static notFound(message?: string): PluginRouteError;
|
|
2846
|
-
/**
|
|
2847
|
-
* Create a conflict error (409)
|
|
2848
|
-
*/
|
|
2849
|
-
static conflict(message: string, details?: unknown): PluginRouteError;
|
|
2850
|
-
/**
|
|
2851
|
-
* Create an internal error (500)
|
|
2852
|
-
*/
|
|
2853
|
-
static internal(message?: string): PluginRouteError;
|
|
3260
|
+
declare class PluginSecretStore {
|
|
3261
|
+
private readonly repository;
|
|
3262
|
+
private readonly keysPromise;
|
|
3263
|
+
constructor(db: Kysely<Database> | Transaction<Database>, options?: PluginSecretStoreOptions);
|
|
3264
|
+
set(pluginId: string, name: string, value: string): Promise<PluginSecretStatus>;
|
|
3265
|
+
status(pluginId: string, name: string): Promise<PluginSecretStatus | null>;
|
|
3266
|
+
list(pluginId: string): Promise<PluginSecretStatus[]>;
|
|
3267
|
+
delete(pluginId: string, name: string): Promise<boolean>;
|
|
3268
|
+
resolveForRuntime(pluginId: string, name: string): Promise<string | null>;
|
|
3269
|
+
private requireKeys;
|
|
2854
3270
|
}
|
|
2855
3271
|
//#endregion
|
|
3272
|
+
//#region src/plugins/mcp-reviewed-executor.d.ts
|
|
3273
|
+
declare function createReviewedPluginMcpCommandExecutor(): PluginMcpCommandExecutor;
|
|
3274
|
+
//#endregion
|
|
2856
3275
|
//#region src/plugins/manager.d.ts
|
|
2857
3276
|
/**
|
|
2858
3277
|
* Plugin state in the manager
|
|
@@ -2952,6 +3371,18 @@ declare class PluginManager {
|
|
|
2952
3371
|
* Run content:afterUnpublish hooks across all active plugins
|
|
2953
3372
|
*/
|
|
2954
3373
|
runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
3374
|
+
/**
|
|
3375
|
+
* Run content:afterRestore hooks across all active plugins
|
|
3376
|
+
*/
|
|
3377
|
+
runContentAfterRestore(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
3378
|
+
/**
|
|
3379
|
+
* Run content:afterSchedule hooks across all active plugins
|
|
3380
|
+
*/
|
|
3381
|
+
runContentAfterSchedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
3382
|
+
/**
|
|
3383
|
+
* Run content:afterUnschedule hooks across all active plugins
|
|
3384
|
+
*/
|
|
3385
|
+
runContentAfterUnschedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
|
|
2955
3386
|
/**
|
|
2956
3387
|
* Run media:beforeUpload hooks across all active plugins
|
|
2957
3388
|
*/
|
|
@@ -3108,12 +3539,6 @@ declare class NoopSandboxRunner implements SandboxRunner {
|
|
|
3108
3539
|
*/
|
|
3109
3540
|
declare function createNoopSandboxRunner(_options?: SandboxOptions): SandboxRunner;
|
|
3110
3541
|
//#endregion
|
|
3111
|
-
//#region src/plugins/sandbox/runtime-options.d.ts
|
|
3112
|
-
interface SandboxRunnerRuntimeOptions extends SandboxOptions {
|
|
3113
|
-
mediaStorage?: Storage;
|
|
3114
|
-
cronReschedule?: () => void;
|
|
3115
|
-
}
|
|
3116
|
-
//#endregion
|
|
3117
3542
|
//#region src/plugins/sandbox/node.d.ts
|
|
3118
3543
|
declare class NodeSandboxRunner implements SandboxRunner {
|
|
3119
3544
|
private readonly options;
|
|
@@ -3457,6 +3882,8 @@ interface GetCommentsOptions {
|
|
|
3457
3882
|
collection: string;
|
|
3458
3883
|
contentId: string;
|
|
3459
3884
|
threaded?: boolean;
|
|
3885
|
+
reactions?: boolean;
|
|
3886
|
+
sort?: "oldest" | "best";
|
|
3460
3887
|
}
|
|
3461
3888
|
interface GetCommentsResult {
|
|
3462
3889
|
items: PublicComment[];
|
|
@@ -3915,6 +4342,8 @@ interface Suggestion {
|
|
|
3915
4342
|
collection: string;
|
|
3916
4343
|
/** Entry ID */
|
|
3917
4344
|
id: string;
|
|
4345
|
+
/** Entry slug, when available */
|
|
4346
|
+
slug?: string | null;
|
|
3918
4347
|
/** Entry title */
|
|
3919
4348
|
title: string;
|
|
3920
4349
|
}
|
|
@@ -4262,6 +4691,13 @@ interface PluginDescriptor<TOptions = Record<string, unknown>> {
|
|
|
4262
4691
|
adminPages?: PluginAdminPage[];
|
|
4263
4692
|
/** Dashboard widgets */
|
|
4264
4693
|
adminWidgets?: PluginDashboardWidget[];
|
|
4694
|
+
/**
|
|
4695
|
+
* Portable Text block types this plugin contributes to the editor.
|
|
4696
|
+
* Declarative Block Kit config consumed from the admin manifest.
|
|
4697
|
+
*/
|
|
4698
|
+
portableTextBlocks?: PortableTextBlockConfig[];
|
|
4699
|
+
/** Field widget types this plugin contributes for schema-field editing UIs. */
|
|
4700
|
+
fieldWidgets?: FieldWidgetConfig[];
|
|
4265
4701
|
/**
|
|
4266
4702
|
* Capabilities the plugin requests.
|
|
4267
4703
|
* For standard-format plugins, capabilities are enforced in both trusted and
|
|
@@ -4317,6 +4753,33 @@ interface DinewayConfig {
|
|
|
4317
4753
|
* Storage configuration (for media)
|
|
4318
4754
|
*/
|
|
4319
4755
|
storage?: StorageDescriptor;
|
|
4756
|
+
/**
|
|
4757
|
+
* Optional object cache for public query results.
|
|
4758
|
+
*
|
|
4759
|
+
* This cache is disabled by default. When configured, it sits beneath
|
|
4760
|
+
* request-scoped caching and above the database for anonymous, non-preview,
|
|
4761
|
+
* non-edit reads. Preview, visual editing, and isolated playground databases
|
|
4762
|
+
* bypass it so editors always see live data.
|
|
4763
|
+
*
|
|
4764
|
+
* @example
|
|
4765
|
+
* ```ts
|
|
4766
|
+
* import { memoryCache } from "dineway/astro";
|
|
4767
|
+
*
|
|
4768
|
+
* dineway({
|
|
4769
|
+
* objectCache: memoryCache({ defaultTtl: 600 }),
|
|
4770
|
+
* })
|
|
4771
|
+
* ```
|
|
4772
|
+
*/
|
|
4773
|
+
objectCache?: ObjectCacheDescriptor;
|
|
4774
|
+
/**
|
|
4775
|
+
* Image optimization.
|
|
4776
|
+
*
|
|
4777
|
+
* By default Dineway wraps Astro's image endpoint so storage-backed media can
|
|
4778
|
+
* be optimized through the normal `<Image>` / `getImage` pipeline while
|
|
4779
|
+
* loading source bytes directly from the storage adapter. Set to `false` to
|
|
4780
|
+
* leave Astro's image endpoint untouched.
|
|
4781
|
+
*/
|
|
4782
|
+
images?: boolean;
|
|
4320
4783
|
/**
|
|
4321
4784
|
* Trusted plugins to load (run in main isolate)
|
|
4322
4785
|
*
|
|
@@ -4497,8 +4960,9 @@ interface DinewayConfig {
|
|
|
4497
4960
|
* while the browser uses `https://`, which breaks WebAuthn, CSRF, OAuth, and redirect URLs.
|
|
4498
4961
|
*
|
|
4499
4962
|
* Set to the full origin users type in the address bar (no path), e.g.
|
|
4500
|
-
* `https://mysite.example.com`.
|
|
4501
|
-
*
|
|
4963
|
+
* `https://mysite.example.com`. `DINEWAY_SITE_URL` is an explicit runtime
|
|
4964
|
+
* override for container deployments; otherwise this falls back to `SITE_URL`,
|
|
4965
|
+
* then to the request URL's origin.
|
|
4502
4966
|
*
|
|
4503
4967
|
* Replaces `passkeyPublicOrigin` (which only fixed passkeys).
|
|
4504
4968
|
*/
|
|
@@ -4614,4 +5078,4 @@ declare global {
|
|
|
4614
5078
|
var __dinewayConfig: DinewayConfig | undefined;
|
|
4615
5079
|
}
|
|
4616
5080
|
//#endregion
|
|
4617
|
-
export { CreateMenuItemInput as $,
|
|
5081
|
+
export { CreateMenuItemInput as $, EntryData as $i, createEditable as $n, SandboxedPluginEntry as $r, FileSessionDatabaseFactory as $t, UpdateWidgetInput as A, handleContentTranslations as Ai, invalidateTaxonomyObjectCache as An, getSection as Ar, GeneratePreviewTokenOptions as At, getTerm as B, ImageValue as Bi, EntryResult as Bn, MediaListResponse as Br, SandboxNotAvailableError as Bt, getWidgetArea as C, handleContentGetIncludingTrashed as Ci, contentNamespaces as Cn, PortableTextMarkDef as Cr, renderPreviewLoadingPage as Ct, CreateWidgetInput as D, handleContentPublish as Di, invalidateMenuObjectCache as Dn, ProseMirrorDocument as Dr, GetPreviewUrlOptions as Dt, CreateWidgetAreaInput as E, handleContentPermanentDelete as Ei, invalidateCommentObjectCache as En, PortableTextUnknownBlock as Er, isPreviewRequest as Et, getEntriesByTerm as F, reference as Fi, CollectionFilter as Fn, SectionSource as Fr, parseContentId as Ft, TaxonomyTermRow as G, RelationRepository as Gi, getDinewayCollection as Gn, handleMediaList as Gr, PluginSecretStatus as Gt, CreateTermInput as H, ContentReference as Hi, ResolvePathResult as Hn, handleMediaCreate as Hr, PluginManager as Ht, getEntryTerms as I, image as Ii, CollectionResult as In, UpdateSectionInput as Ir, verifyPreviewToken as It, getBylineBySlug as J, CreateMediaInput as Ji, getTranslations as Jn, RevisionResponse as Jr, ValidatedPluginManifest as Jt, UpdateTermInput as K, UpdateRelationInput as Ki, getDinewayEntry as Kn, handleMediaUpdate as Kr, PluginSecretStore as Kt, getTaxonomyDef as L, FieldDefinition as Li, ContentEntry as Ln, getCollectionInfo as Lr, NodeSandboxRunner as Lt, WidgetArea as M, handleContentUnschedule as Mi, AfterCallback as Mn, CreateSectionInput as Mr, VerifyPreviewTokenOptions as Mt, WidgetComponentDef as N, handleContentUpdate as Ni, after as Nn, GetSectionsOptions as Nr, VerifyPreviewTokenResult as Nt, PropDef as O, handleContentRestore as Oi, invalidateObjectCache as On, ProseMirrorMark as Or, buildPreviewUrl as Ot, WidgetType as P, portableText as Pi, CacheHint as Pn, Section as Pr, generatePreviewToken as Pt, CreateMenuInput as Q, CollectionFilter$1 as Qi, FieldAnnotation as Qn, generateManifest as Qr, createFilePreviewMiddleware as Qt, getTaxonomyDefs as R, FieldUIHints as Ri, DinewayCollections as Rn, SchemaError as Rr, createNodeSandboxRunner as Rt, Suggestion as S, handleContentGet as Si, contentNamespace as Sn, PortableTextLinkMark as Sr, Snapshot as St, getWidgetComponents as T, handleContentListTrashed as Ti, invalidateCollectionCache as Tn, PortableTextTextBlock as Tr, getPreviewToken as Tt, TaxonomyDef as U, CreateRelationInput as Ui, TranslationSummary as Un, handleMediaDelete as Ur, createPluginManager as Ut, getTermsForEntries as V, PortableTextBlock$1 as Vi, InferCollectionData as Vn, MediaResponse as Vr, createNoopSandboxRunner as Vt, TaxonomyTerm as W, Relation as Wi, TranslationsResult as Wn, handleMediaGet as Wr, createReviewedPluginMcpCommandExecutor as Wt, getMenu as X, MediaRepository as Xi, CMSAnnotation as Xn, handleRevisionList as Xr, definePlugin as Xt, getEntriesByByline as Y, MediaItem as Yi, resolveDinewayPath as Yn, handleRevisionGet as Yr, pluginManifestSchema as Yt, getMenus as Z, ContentRepository as Zi, EditProxy as Zn, handleRevisionRestore as Zr, FilePreviewMiddlewareConfig as Zt, SearchOptions as _, ContentResponse as _a, handleContentCountTrashed as _i, getI18nConfig as _n, portableTextToProsemirror as _r, AppliedSnapshotMeta as _t, S3StorageConfig as a, DatabaseConfig as aa, SandboxRunnerFactory as ai, SessionDatabaseLimitError as an, IssuedGuestAccessToken as ar, UpdateMenuItemInput as at, SearchStats as b, ManifestResponse as ba, handleContentDiscardDraft as bi, CachedQueryOptions as bn, PortableTextHtmlBlock as br, dropSessionDatabaseTables as bt, extractSearchableFields as c, ParseResult as ca, PluginMcpRegistry as ci, PreviewSidecarClient as cn, hashGuestAccessToken as cr, getCommentCount as ct, search as d, parseQuery as da, HookResult as di, defaultPreviewSidecarClient as dn, RateLimitResult as dr, getPluginSettings as dt, EntryFilter as ea, PluginRouteError as ei, FileSessionDatabaseFactoryOptions as en, createNoop as er, Menu as et, searchCollection as f, apiError as fa, createHookPipeline as fi, parsePreviewSignatureHeader as fn, checkRateLimit as fr, getSiteSetting as ft, SearchConfig as g, ContentListResponse as ga, handleContentCountScheduled as gi, getFallbackChain as gn, hashString as gr, renderPreviewToolbar as gt, CollectionSearchOptions as h, ApiContext as ha, handleContentCompare as hi, I18nConfig as hn, computeContentHash as hr, PreviewToolbarConfig as ht, LocalStorageConfig as i, getDb as ia, SandboxRunner as ii, SessionDatabaseInfo as in, IssueGuestAccessTokenOptions as ir, UpdateMenuInput as it, Widget as j, handleContentUnpublish as ji, isObjectCacheActive as jn, getSections as jr, PreviewTokenPayload as jt, ReorderWidgetsInput as k, handleContentSchedule as ki, invalidateSchemaObjectCache as kn, ProseMirrorNode as kr, getPreviewUrl as kt, getSearchStats as l, isParseError as la, PluginMcpTargetAuthorizer as li, PreviewSidecarSignature as ln, issueGuestAccessToken as lr, getComments as lt, FTSManager as m, handleError as ma, handleContentAuthors as mi, verifyPreviewSignature as mn, sanitizeHref as mr, setSiteSettings as mt, PluginDescriptor as n, WhereValue as na, SandboxEmailSendCallback as ni, SessionDatabaseFactory as nn, GuestAccessTokenClaims as nr, MenuItemType as nt, StorageDescriptor as o, DinewayDatabaseError as oa, SandboxedPlugin as oi, SessionOpenOptions as on, VerifyGuestAccessTokenOptions as or, GetCommentsOptions as ot, searchWithDb as p, apiSuccess as pa, EmailPipeline as pi, signPreviewUrl as pn, isSafeHref as pr, getSiteSettings as pt, getByline as q, PublicComment as qi, getEditMeta as qn, RevisionListResponse as qr, PluginSecretStoreOptions as qt, getStoredConfig as r, dinewayLoader as ra, SandboxOptions as ri, SessionDatabaseHandle as rn, GuestAccessTokenConfigurationError as rr, ReorderMenuItemsInput as rt, extractPlainText as s, OptionsRepository as sa, SerializedRequest as si, SessionOpenOrCreateOptions as sn, VerifyGuestAccessTokenResult as sr, GetCommentsResult as st, DinewayConfig as t, WhereRange as ta, SandboxEmailMessage as ti, SessionCleanupResult as tn, GuestAccessExpectedScope as tr, MenuItem as tt, getSuggestions as u, parseBody as ua, HookPipeline as ui, buildPreviewSignatureHeader as un, verifyGuestAccessToken as ur, getPluginSetting as ut, SearchResponse as v, FieldDescriptor as va, handleContentCreate as vi, isI18nEnabled as vn, prosemirrorToPortableText as vr, ApplySnapshotToDatabaseOptions as vt, getWidgetAreas as w, handleContentList as wi, invalidateBylineObjectCache as wn, PortableTextSpan as wr, isBlockedInPreview as wt, SuggestOptions as x, handleContentDuplicate as xi, cachedQuery as xn, PortableTextImageBlock as xr, getAppliedSnapshotMeta as xt, SearchResult as y, ListResponse as ya, handleContentDelete as yi, CacheNamespace as yn, PortableTextCodeBlock as yr, applySnapshotToDatabase as yt, getTaxonomyTerms as z, FileValue as zi, EditFieldMeta as zn, SchemaRegistry as zr, NoopSandboxRunner as zt };
|