dineway 0.1.49 → 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-CwM7yxPW.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-CyGnbgBd.mjs → allowed-origins-_oeyP6x-.mjs} +1 -1
- package/dist/api/route-utils.d.mts +10 -10
- package/dist/api/route-utils.mjs +16 -13
- package/dist/api/schemas/index.d.mts +2 -2
- package/dist/api/schemas/index.mjs +5 -4
- package/dist/{api-BMIxRIEN.mjs → api-ByrU2q-Z.mjs} +60 -36
- package/dist/{api-tokens-DtvdtIkm.mjs → api-tokens-CjVMQT-X.mjs} +6 -2
- package/dist/{apply-D_RlTYtC.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 +13 -4
- package/dist/astro/middleware/request-context.mjs +8 -5
- package/dist/astro/middleware/seed.d.mts +1 -1
- package/dist/astro/middleware/seed.mjs +2 -2
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.mjs +333 -192
- 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 +21 -17
- 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 +17 -14
- package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +17 -14
- package/dist/astro/routes/api/admin/bylines/index.mjs +17 -14
- package/dist/astro/routes/api/admin/comments/_id_/status.mjs +14 -12
- package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -5
- package/dist/astro/routes/api/admin/comments/bulk.mjs +11 -9
- package/dist/astro/routes/api/admin/comments/counts.mjs +6 -5
- package/dist/astro/routes/api/admin/comments/index.mjs +11 -9
- package/dist/astro/routes/api/admin/context/_id_/history.mjs +26 -24
- package/dist/astro/routes/api/admin/context/_id_/index.mjs +26 -24
- package/dist/astro/routes/api/admin/context/_id_/review.mjs +31 -28
- package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +31 -28
- package/dist/astro/routes/api/admin/context/diff.mjs +30 -27
- package/dist/astro/routes/api/admin/context/index.mjs +31 -28
- package/dist/astro/routes/api/admin/context/stale.mjs +30 -27
- package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +26 -24
- package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +30 -27
- package/dist/astro/routes/api/admin/hitl-requests/index.mjs +30 -27
- package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +27 -25
- 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 +55 -51
- package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +55 -51
- package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +47 -43
- package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +53 -49
- package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +52 -48
- package/dist/astro/routes/api/admin/plugins/index.mjs +47 -43
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +46 -42
- package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +52 -48
- package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +46 -42
- package/dist/astro/routes/api/admin/plugins/updates.mjs +46 -42
- package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +5 -5
- package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +31 -27
- package/dist/astro/routes/api/admin/review-requests/index.mjs +10 -9
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +46 -42
- package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
- package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +46 -42
- 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 +9 -8
- 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 +5 -5
- 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 +15 -13
- 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 +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -10
- package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +10 -9
- package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +10 -9
- package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +16 -14
- package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +5 -5
- package/dist/astro/routes/api/content/_collection_/_id_.mjs +10 -9
- package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
- package/dist/astro/routes/api/content/_collection_/index.mjs +10 -9
- package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -6
- package/dist/astro/routes/api/dashboard.mjs +9 -8
- 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 +22 -10
- 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 +84 -37
- package/dist/astro/routes/api/import/wordpress/media.d.mts +13 -1
- package/dist/astro/routes/api/import/wordpress/media.mjs +19 -13
- package/dist/astro/routes/api/import/wordpress/prepare.mjs +35 -32
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +18 -1
- package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +120 -100
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
- package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +24 -12
- package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +56 -2
- package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +283 -55
- package/dist/astro/routes/api/manifest.mjs +14 -5
- package/dist/astro/routes/api/mcp.mjs +265 -69
- package/dist/astro/routes/api/media/_id_/confirm.mjs +38 -10
- 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 +11 -10
- package/dist/astro/routes/api/media.mjs +27 -34
- package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +31 -28
- package/dist/astro/routes/api/menus/_name_/items.mjs +31 -28
- package/dist/astro/routes/api/menus/_name_/reorder.mjs +31 -28
- package/dist/astro/routes/api/menus/_name_/translations.mjs +31 -28
- package/dist/astro/routes/api/menus/_name_.mjs +31 -28
- package/dist/astro/routes/api/menus/index.mjs +31 -28
- 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 +11 -10
- package/dist/astro/routes/api/redirects/404s/summary.mjs +11 -10
- package/dist/astro/routes/api/redirects/_id_.mjs +32 -29
- package/dist/astro/routes/api/redirects/index.mjs +32 -29
- 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 +47 -43
- package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +47 -43
- package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +47 -43
- package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +47 -43
- package/dist/astro/routes/api/schema/collections/index.mjs +47 -43
- package/dist/astro/routes/api/schema/index.mjs +13 -14
- package/dist/astro/routes/api/schema/orphans/_slug_.mjs +46 -42
- package/dist/astro/routes/api/schema/orphans/index.mjs +46 -42
- package/dist/astro/routes/api/search/enable.mjs +11 -10
- package/dist/astro/routes/api/search/index.mjs +10 -9
- package/dist/astro/routes/api/search/rebuild.mjs +11 -10
- package/dist/astro/routes/api/search/stats.mjs +6 -6
- package/dist/astro/routes/api/search/suggest.mjs +10 -9
- package/dist/astro/routes/api/sections/_slug_.mjs +31 -28
- package/dist/astro/routes/api/sections/index.mjs +31 -28
- package/dist/astro/routes/api/settings/email.mjs +4 -4
- package/dist/astro/routes/api/settings.mjs +31 -28
- 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 +31 -25
- package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
- package/dist/astro/routes/api/setup/index.mjs +29 -25
- package/dist/astro/routes/api/setup/status.mjs +3 -3
- package/dist/astro/routes/api/snapshot.mjs +8 -7
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +34 -31
- package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +34 -31
- package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +34 -31
- package/dist/astro/routes/api/taxonomies/index.mjs +34 -31
- package/dist/astro/routes/api/themes/preview.mjs +5 -5
- 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 +30 -27
- package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +31 -28
- package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +31 -28
- package/dist/astro/routes/api/widget-areas/_name_.mjs +28 -26
- package/dist/astro/routes/api/widget-areas/index.mjs +31 -28
- package/dist/astro/routes/api/widget-components.mjs +2 -2
- package/dist/astro/routes/robots.txt.mjs +8 -7
- package/dist/astro/routes/sitemap-_collection_.xml.mjs +23 -14
- package/dist/astro/routes/sitemap.xml.mjs +9 -8
- package/dist/astro/session-driver.d.mts +1 -1
- package/dist/astro/session-driver.mjs +2 -2
- package/dist/astro/types.d.mts +21 -13
- package/dist/{audit-BeNsSyfU.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-DJX6irto.mjs → briefing-BJaJI8dm.mjs} +2 -1
- package/dist/{briefing-CkTee1ex.mjs → briefing-CawZ59CY.mjs} +90 -28
- package/dist/bundle-7C_DpkEq.mjs +602 -0
- package/dist/{byline-BVC1lV6G.mjs → byline-e51-fWRs.mjs} +30 -62
- package/dist/{byline-fields-uJlygdzM.d.mts → byline-fields-CUvbslGc.d.mts} +80 -37
- package/dist/{byline-fields-Cj39WhXC.mjs → byline-fields-D-N5qVIG.mjs} +1 -1
- package/dist/{byline-fields-cNrLJVRs.mjs → byline-fields-DOJO16Gm.mjs} +3 -3
- package/dist/{byline-registry-4v6tXMNX.mjs → byline-registry-87nNnYl4.mjs} +2 -2
- package/dist/{bylines-LN9XISRo.mjs → bylines-CMQNCNFh.mjs} +9 -3
- package/dist/{bylines-DwokOFj6.mjs → bylines-y4LO-dTj.mjs} +5 -5
- package/dist/{cache-Bac05gBd.mjs → cache-C-FNTFYK.mjs} +2 -2
- package/dist/{chunks-CuUt7K50.mjs → chunks-CxBt-GxR.mjs} +1 -1
- package/dist/cli/index.mjs +94 -659
- 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-Beue8-15.mjs → comment-DlA4iChg.mjs} +13 -3
- package/dist/comment-reaction-DfFao1ST.mjs +58 -0
- package/dist/{comments-DcjFIfqX.mjs → comments-DApFGMsP.mjs} +1 -1
- package/dist/{content-CBxYGWfL.mjs → content-Bh4BDjv8.mjs} +51 -34
- package/dist/content-refresh-CgutSUfO.mjs +1576 -0
- package/dist/{context-CQVNZaR8.mjs → context-C5W3G18y.mjs} +111 -50
- package/dist/{context-Df1xVYyr.mjs → context-CK4ym2Sf.mjs} +2 -2
- package/dist/{context-route-helpers-B9wj8Rmh.mjs → context-route-helpers-MASyGgWf.mjs} +2 -1
- package/dist/{cron-DxCAU_Sn.mjs → cron-cKcNTix_.mjs} +7 -3
- package/dist/{dashboard-B7ZUNuyF.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-BZVGftqi.mjs → device-flow-BnqRH-T9.mjs} +5 -5
- package/dist/{placeholder-d54Qr_7n.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-B5l_qwrA.mjs → fts-manager-Crzypjqu.mjs} +1 -1
- package/dist/hitl-Hw1RmWOq.mjs +677 -0
- package/dist/{hitl-requests-7NlzVeUA.mjs → hitl-requests-B4Vbcmaq.mjs} +2 -2
- package/dist/{hitl-route-helpers-k---_H3-.mjs → hitl-route-helpers-hEVzvP8l.mjs} +5 -4
- package/dist/import-Bh9biJfx.mjs +1354 -0
- package/dist/{index-CZiWCQDp.d.mts → index-D4y6NGiy.d.mts} +75 -3
- package/dist/index.d.mts +17 -16
- package/dist/index.mjs +80 -68
- package/dist/{jsonld-DZ67souc.d.mts → jsonld-Dq0gsnOH.d.mts} +8 -4
- package/dist/{load-D9OiGr2m.mjs → load-DmYeniXl.mjs} +1 -1
- package/dist/{loader--GOYux8M.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 +9 -7
- package/dist/{media-CbKyYukG.mjs → media-DMj0grzC.mjs} +3 -1
- package/dist/{media-allowlist-BYxJIcTO.mjs → media-allowlist-BlVCSzHx.mjs} +1 -1
- package/dist/media-url-lEKSrpr9.mjs +20 -0
- package/dist/{menus-BZbXf-ej.mjs → menus-TaW1gKnk.mjs} +19 -5
- package/dist/{menus-C7F0sCrC.mjs → menus-xvsnVZXw.mjs} +80 -15
- package/dist/{normalize-ByemhhfW.mjs → normalize-5ek_z7de.mjs} +8 -1
- package/dist/{oauth-authorization-DF-LCsIA.mjs → oauth-authorization-DiaGvRVz.mjs} +5 -5
- package/dist/{oauth-clients-Du-V0fEm.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-DzfqRREq.mjs → plugins-BolVa-tl.mjs} +831 -63
- package/dist/{transport-LSdZVXHF.mjs → portable-text-dA_UlJwW.mjs} +1 -134
- package/dist/{preview-C-3YTX2U.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-B4xV4rGa.d.mts → public-url-gsp3oUbu.d.mts} +1 -1
- package/dist/{query-Ds0EnMFX.mjs → query-CfRCdaL3.mjs} +281 -76
- package/dist/{query-CZ3TH_Uu.mjs → query-jaAmw8E1.mjs} +11 -6
- package/dist/{rate-limit-i0G3IAOX.mjs → rate-limit-ZLdyWoZF.mjs} +2 -2
- package/dist/{redirect-CEACczxo.mjs → redirect-BAjt4Z6b.mjs} +2 -2
- package/dist/{redirects-DYj1yPxs.mjs → redirects-BTdwpQtE.mjs} +47 -24
- package/dist/{redirects-ocRJmQHP.mjs → redirects-CA-xylPG.mjs} +19 -11
- package/dist/{registry-D7HACema.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-Qum4713s.mjs → review-requests-C9Ff11Vq.mjs} +1 -1
- package/dist/{review-requests-BW2NxY-l.mjs → review-requests-DUyEmtmG.mjs} +1 -1
- package/dist/{runner-09sTqtv0.d.mts → runner-1tC2tIRV.d.mts} +1 -1
- package/dist/runner-DB7CRfOF.mjs +6740 -0
- package/dist/{runtime-C4-2lSFg.d.mts → runtime-BOeiQsCv.d.mts} +1952 -1489
- package/dist/runtime.d.mts +10 -10
- package/dist/runtime.mjs +3 -3
- package/dist/schema-DXdYj4R3.mjs +8 -0
- package/dist/{search-Gdrqj582.mjs → search-DSaLgEFI.mjs} +5 -3
- package/dist/{secrets-CeGpBFV2.mjs → secrets-CDZo2k8L.mjs} +14 -11
- package/dist/{sections-BOjU13Y-.mjs → sections-PVVXHGfp.mjs} +2 -2
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +21 -18
- package/dist/seo/index.d.mts +1 -1
- package/dist/seo/index.mjs +3 -12
- package/dist/{seo-CLj8lS7Q.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-jGlhrICs.mjs → service-DiN4ZuPp.mjs} +2 -2
- package/dist/session-user-CAKImna3.mjs +22 -0
- package/dist/{settings-CUXOxzsT.mjs → settings-BbqgHWpU.mjs} +28 -55
- package/dist/{settings-DlBsT2VS.mjs → settings-i4VPP8bT.mjs} +2 -2
- package/dist/{setup-complete-BRrdPYjZ.mjs → setup-complete-B8fl-mjV.mjs} +1 -1
- package/dist/{site-activity-DONFrMBJ.mjs → site-activity-Dy3FROs0.mjs} +1 -1
- package/dist/{site-context-C8Az_P_I.mjs → site-context-DQiL8Fl5.mjs} +23 -652
- package/dist/{site-url-DIMD68go.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-D9Sw4wWM.mjs → taxonomies-9s-v03H-.mjs} +36 -29
- package/dist/taxonomies-DRiixp_E.mjs +443 -0
- package/dist/{taxonomy-B169Nm6B.mjs → taxonomy-Dvsw6BOs.mjs} +44 -9
- 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-CSgR9nQB.mjs → types-Dq1qT19x.mjs} +1 -1
- package/dist/ui/server-runtime.d.mts +15 -15
- package/dist/ui/server-runtime.mjs +24 -20
- package/dist/url-Cac7a9QZ.mjs +33 -0
- package/dist/{user-DTLoZs16.mjs → user-BIZPzCb9.mjs} +2 -2
- package/dist/{utils-B8hBJ9Oz.mjs → utils-CMDhr5Xd.mjs} +129 -7
- package/dist/{validate-DzjCdy6v.d.mts → validate-CZvb-BKB.d.mts} +10 -7
- package/dist/{validate-DWmPO6oj.mjs → validate-DNs0pTSc.mjs} +11 -6
- package/dist/version-BTvfRGc6.mjs +6 -0
- package/dist/{widgets-BpJ8EpPd.mjs → widgets-f0ibZUIq.mjs} +46 -43
- package/dist/{wordpress-slugs-DHNR9LpG.mjs → wordpress-slugs-BhHJX8XE.mjs} +1 -1
- package/dist/{zod-generator-K91-g665.mjs → zod-generator-B7TMjyFJ.mjs} +41 -13
- package/package.json +30 -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-4y93Yjuc.mjs +0 -51
- package/dist/import-4YBXbDkI.mjs +0 -684
- package/dist/runner-DzIpHGND.mjs +0 -2836
- package/dist/schema-Bsi-VpYv.mjs +0 -8
- package/dist/taxonomies-CZ-_DitR.mjs +0 -327
- package/dist/types-CuJOqHfM.d.mts +0 -758
- package/dist/version-C4gfn0PJ.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/{challenge-store-DFxX0_15.mjs → challenge-store-Bjlepa2E.mjs} +0 -0
- /package/dist/{components--pg6zBvu.mjs → components-Bclf98Be.mjs} +0 -0
- /package/dist/{context-types-r8oFvyOq.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-CSMffP6q.mjs → experimental-workflows-BMsUnIAw.mjs} +0 -0
- /package/dist/{mime-CbKsKDCB.mjs → mime-CA7Lgovc.mjs} +0 -0
- /package/dist/{mode-CZqCF9dZ.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-LsPjZlqD.mjs → options-DQPTH5n0.mjs} +0 -0
- /package/dist/{passkey-config-DzHQK90v.mjs → passkey-config-BUwu8BA3.mjs} +0 -0
- /package/dist/{patterns-DKAX6oqN.mjs → patterns-BhAvqO0S.mjs} +0 -0
- /package/dist/{provider-loader-DzUxejk7.mjs → provider-loader-D0w9dqjm.mjs} +0 -0
- /package/dist/{public-url-B_m9IwdV.mjs → public-url-BEz_sM9n.mjs} +0 -0
- /package/dist/{redirect-BjIBtDWY.mjs → redirect-wphRBv4y.mjs} +0 -0
- /package/dist/{request-cache-ho99schz.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-BqebcqBg.mjs → slugify-KSsVD_D3.mjs} +0 -0
- /package/dist/{ssrf-DiKqWd3N.mjs → ssrf-DWe8jwAp.mjs} +0 -0
- /package/dist/{tokens-SLmgowfd.mjs → tokens-1RK1n6ED.mjs} +0 -0
- /package/dist/{transaction-CFLhEOuH.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-CJ8DkL0q.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
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
import { c as stableStringify, d as HitlRequestRepository, s as buildStableActionHash, t as HitlRequestService } from "./hitl-Hw1RmWOq.mjs";
|
|
2
|
+
import { i as hasScope } from "./api-tokens-2r7OWi_I.mjs";
|
|
3
|
+
import { m as logSiteActivityStrict, p as logSiteActivitySafely } from "./activity-events-y6eT8UW6.mjs";
|
|
4
|
+
import { ulid } from "ulidx";
|
|
5
|
+
import { hasPermission } from "@dineway-ai/auth";
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
|
|
9
|
+
//#region src/plugins/mcp.ts
|
|
10
|
+
function createPluginMcpRegistry(plugins) {
|
|
11
|
+
const tools = [];
|
|
12
|
+
const resources = [];
|
|
13
|
+
const toolOwners = /* @__PURE__ */ new Map();
|
|
14
|
+
const resourceOwners = /* @__PURE__ */ new Map();
|
|
15
|
+
const resourceUriOwners = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const plugin of plugins) {
|
|
17
|
+
for (const tool of plugin.mcp.tools) {
|
|
18
|
+
assertUniqueContribution("tool", tool.name, plugin.id, toolOwners);
|
|
19
|
+
tools.push({
|
|
20
|
+
pluginId: plugin.id,
|
|
21
|
+
pluginVersion: plugin.version,
|
|
22
|
+
tool,
|
|
23
|
+
authorizeTarget: plugin.mcp.authorizeTarget
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
for (const resource of plugin.mcp.resources) {
|
|
27
|
+
assertUniqueContribution("resource", resource.name, plugin.id, resourceOwners);
|
|
28
|
+
assertUniqueContribution("resource URI", resource.uri, plugin.id, resourceUriOwners);
|
|
29
|
+
resources.push({
|
|
30
|
+
pluginId: plugin.id,
|
|
31
|
+
pluginVersion: plugin.version,
|
|
32
|
+
resource,
|
|
33
|
+
authorizeTarget: plugin.mcp.authorizeTarget
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
tools,
|
|
39
|
+
resources
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function createActivePluginMcpRegistry(configuredPlugins, enabledPluginIds) {
|
|
43
|
+
return createPluginMcpRegistry(configuredPlugins.filter((plugin) => enabledPluginIds.has(plugin.id)));
|
|
44
|
+
}
|
|
45
|
+
function registerPluginMcpRegistry(server, registry, options) {
|
|
46
|
+
for (const contribution of registry.tools) {
|
|
47
|
+
const { tool } = contribution;
|
|
48
|
+
server.registerTool(tool.name, {
|
|
49
|
+
title: tool.title,
|
|
50
|
+
description: tool.description,
|
|
51
|
+
inputSchema: tool.inputSchema,
|
|
52
|
+
outputSchema: tool.kind === "query" ? tool.outputSchema : void 0,
|
|
53
|
+
annotations: {
|
|
54
|
+
readOnlyHint: tool.kind === "query",
|
|
55
|
+
destructiveHint: tool.kind === "command" && tool.reversibility === "irreversible",
|
|
56
|
+
idempotentHint: tool.kind === "query" || tool.kind === "command"
|
|
57
|
+
}
|
|
58
|
+
}, async (input, requestExtra) => {
|
|
59
|
+
if (!isRecord$1(input)) throw new McpError(ErrorCode.InvalidParams, "Plugin MCP tool input must be an object");
|
|
60
|
+
const context = options.resolveContext({
|
|
61
|
+
id: contribution.pluginId,
|
|
62
|
+
version: contribution.pluginVersion
|
|
63
|
+
}, requestExtra);
|
|
64
|
+
const target = tool.resolveTarget ? await tool.resolveTarget(input, context) : void 0;
|
|
65
|
+
await authorizeContribution(tool.authorization, target, context, contribution.authorizeTarget, options);
|
|
66
|
+
if (tool.pii.output === "sensitive") await authorizeSensitiveOutput({
|
|
67
|
+
contributionType: "tool",
|
|
68
|
+
name: tool.name,
|
|
69
|
+
target,
|
|
70
|
+
context
|
|
71
|
+
}, options);
|
|
72
|
+
const output = tool.kind === "query" ? await tool.handler(input, context) : await executeCommand(contribution, input, context, target, requestExtra, options);
|
|
73
|
+
const content = [{
|
|
74
|
+
type: "text",
|
|
75
|
+
text: JSON.stringify(output, null, 2)
|
|
76
|
+
}];
|
|
77
|
+
return tool.kind === "query" && tool.outputSchema ? {
|
|
78
|
+
content,
|
|
79
|
+
structuredContent: output
|
|
80
|
+
} : { content };
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
for (const contribution of registry.resources) {
|
|
84
|
+
const { resource } = contribution;
|
|
85
|
+
server.registerResource(resource.name, resource.uri, {
|
|
86
|
+
title: resource.title,
|
|
87
|
+
description: resource.description,
|
|
88
|
+
mimeType: resource.mimeType
|
|
89
|
+
}, async (uri, requestExtra) => {
|
|
90
|
+
const context = options.resolveContext({
|
|
91
|
+
id: contribution.pluginId,
|
|
92
|
+
version: contribution.pluginVersion
|
|
93
|
+
}, requestExtra);
|
|
94
|
+
await authorizeContribution(resource.authorization, resource.target, context, contribution.authorizeTarget, options);
|
|
95
|
+
if (resource.pii.output === "sensitive") await authorizeSensitiveOutput({
|
|
96
|
+
contributionType: "resource",
|
|
97
|
+
name: resource.name,
|
|
98
|
+
target: resource.target,
|
|
99
|
+
context
|
|
100
|
+
}, options);
|
|
101
|
+
const result = await resource.handler(uri, context);
|
|
102
|
+
return { contents: [{
|
|
103
|
+
uri: uri.href,
|
|
104
|
+
mimeType: result.mimeType ?? resource.mimeType,
|
|
105
|
+
text: result.text
|
|
106
|
+
}] };
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function isRecord$1(value) {
|
|
111
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
112
|
+
}
|
|
113
|
+
function assertUniqueContribution(kind, name, pluginId, owners) {
|
|
114
|
+
const existingOwner = owners.get(name);
|
|
115
|
+
if (existingOwner) throw new Error(`Duplicate plugin MCP ${kind} "${name}" contributed by "${existingOwner}" and "${pluginId}".`);
|
|
116
|
+
owners.set(name, pluginId);
|
|
117
|
+
}
|
|
118
|
+
async function authorizeContribution(authorization, target, context, pluginAuthorizer, options) {
|
|
119
|
+
if (!hasPermission({ role: context.actor.role }, authorization.permission)) throw new McpError(ErrorCode.InvalidRequest, "Insufficient permissions for this operation");
|
|
120
|
+
const tokenScopes = context.actor.tokenScopes;
|
|
121
|
+
if (tokenScopes && !authorization.anyOfTokenScopes.some((scope) => hasScope([...tokenScopes], scope))) throw new McpError(ErrorCode.InvalidRequest, `Insufficient scope: requires one of ${authorization.anyOfTokenScopes.join(", ")}`);
|
|
122
|
+
if (authorization.restaurantPermission) {
|
|
123
|
+
if (!target || !pluginAuthorizer && !options.authorizeTarget) throw new McpError(ErrorCode.InvalidRequest, "Restaurant target authorization is not configured for this MCP contribution");
|
|
124
|
+
const request = {
|
|
125
|
+
restaurantPermission: authorization.restaurantPermission,
|
|
126
|
+
target,
|
|
127
|
+
context
|
|
128
|
+
};
|
|
129
|
+
try {
|
|
130
|
+
await pluginAuthorizer?.(request);
|
|
131
|
+
await options.authorizeTarget?.(request);
|
|
132
|
+
} catch {
|
|
133
|
+
throw new McpError(ErrorCode.InvalidRequest, "Restaurant target authorization denied for this operation");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async function authorizeSensitiveOutput(request, options) {
|
|
138
|
+
if (!options.authorizeSensitiveOutput) throw new McpError(ErrorCode.InvalidRequest, "Sensitive plugin MCP output requires an explicit core authorization policy");
|
|
139
|
+
await options.authorizeSensitiveOutput(request);
|
|
140
|
+
}
|
|
141
|
+
async function executeCommand(contribution, input, context, target, requestExtra, options) {
|
|
142
|
+
if (contribution.tool.kind !== "command") throw new Error(`MCP contribution "${contribution.tool.name}" is not a command.`);
|
|
143
|
+
if (!options.executeCommand) throw new McpError(ErrorCode.InvalidRequest, "Plugin MCP command execution requires the core reviewed execution boundary");
|
|
144
|
+
return options.executeCommand({
|
|
145
|
+
...contribution,
|
|
146
|
+
tool: contribution.tool
|
|
147
|
+
}, input, context, {
|
|
148
|
+
target,
|
|
149
|
+
review: parseReviewMetadata(requestExtra)
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function parseReviewMetadata(requestExtra) {
|
|
153
|
+
if (!isRecord$1(requestExtra) || !isRecord$1(requestExtra._meta)) return {};
|
|
154
|
+
const value = requestExtra._meta["dineway/review"];
|
|
155
|
+
if (value === void 0) return {};
|
|
156
|
+
if (!isRecord$1(value)) throw new McpError(ErrorCode.InvalidParams, "MCP metadata \"dineway/review\" must be an object");
|
|
157
|
+
return {
|
|
158
|
+
hitlRequestId: optionalNonEmptyString(value.hitl_request_id, "hitl_request_id"),
|
|
159
|
+
quickActionHash: optionalNonEmptyString(value.quick_action_hash, "quick_action_hash")
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function optionalNonEmptyString(value, name) {
|
|
163
|
+
if (value === void 0) return void 0;
|
|
164
|
+
if (typeof value !== "string" || value.trim().length === 0) throw new McpError(ErrorCode.InvalidParams, `MCP review metadata ${name} must be a string`);
|
|
165
|
+
return value;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/database/repositories/hitl-executions.ts
|
|
170
|
+
var HitlExecutionRepository = class {
|
|
171
|
+
constructor(db) {
|
|
172
|
+
this.db = db;
|
|
173
|
+
}
|
|
174
|
+
async claim(input) {
|
|
175
|
+
const id = ulid();
|
|
176
|
+
const now = input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
177
|
+
await this.db.insertInto("_dineway_hitl_executions").values(toInsertableExecution(id, input, now)).onConflict((conflict) => conflict.doNothing()).execute();
|
|
178
|
+
const inserted = await this.findById(id);
|
|
179
|
+
if (inserted) return {
|
|
180
|
+
claimed: true,
|
|
181
|
+
execution: inserted
|
|
182
|
+
};
|
|
183
|
+
const conflicts = await this.findConflicts(input);
|
|
184
|
+
const existing = conflicts[0];
|
|
185
|
+
if (conflicts.length !== 1 || !existing || !matchesClaim(existing, input)) throw new Error("HITL execution claim conflicts with a different reviewed action.");
|
|
186
|
+
return {
|
|
187
|
+
claimed: false,
|
|
188
|
+
execution: existing
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async findById(id) {
|
|
192
|
+
const row = await this.db.selectFrom("_dineway_hitl_executions").selectAll().where("id", "=", id).executeTakeFirst();
|
|
193
|
+
return row ? rowToExecution(row) : null;
|
|
194
|
+
}
|
|
195
|
+
async markSucceeded(id, result, completedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
196
|
+
return this.complete(id, "succeeded", result, null, completedAt);
|
|
197
|
+
}
|
|
198
|
+
async markFailed(id, errorCode, completedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
199
|
+
return this.complete(id, "failed", null, errorCode, completedAt);
|
|
200
|
+
}
|
|
201
|
+
async markIndeterminate(id, errorCode, completedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
202
|
+
return this.complete(id, "indeterminate", null, errorCode, completedAt);
|
|
203
|
+
}
|
|
204
|
+
async complete(id, status, result, errorCode, completedAt) {
|
|
205
|
+
const update = await this.db.updateTable("_dineway_hitl_executions").set({
|
|
206
|
+
status,
|
|
207
|
+
result_json: result ? JSON.stringify(result) : null,
|
|
208
|
+
error_code: errorCode,
|
|
209
|
+
updated_at: completedAt,
|
|
210
|
+
completed_at: completedAt
|
|
211
|
+
}).where("id", "=", id).where("status", "=", "claimed").executeTakeFirst();
|
|
212
|
+
if (Number(update.numUpdatedRows ?? 0) === 0) return null;
|
|
213
|
+
return this.findById(id);
|
|
214
|
+
}
|
|
215
|
+
async findConflicts(input) {
|
|
216
|
+
return (await this.db.selectFrom("_dineway_hitl_executions").selectAll().where((eb) => eb.or([
|
|
217
|
+
eb("action_hash", "=", input.actionHash),
|
|
218
|
+
eb("idempotency_key", "=", input.idempotencyKey),
|
|
219
|
+
...input.hitlRequestId ? [eb("hitl_request_id", "=", input.hitlRequestId)] : []
|
|
220
|
+
])).execute()).map(rowToExecution);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
function toInsertableExecution(id, input, now) {
|
|
224
|
+
return {
|
|
225
|
+
id,
|
|
226
|
+
hitl_request_id: input.hitlRequestId ?? null,
|
|
227
|
+
plugin_id: input.pluginId,
|
|
228
|
+
tool_name: input.toolName,
|
|
229
|
+
review_mode: input.reviewMode,
|
|
230
|
+
action_hash: input.actionHash,
|
|
231
|
+
idempotency_key: input.idempotencyKey,
|
|
232
|
+
status: "claimed",
|
|
233
|
+
actor_type: input.actorType,
|
|
234
|
+
actor_id: input.actorId,
|
|
235
|
+
scope: input.scope,
|
|
236
|
+
target_ref_type: input.targetRefType,
|
|
237
|
+
target_ref_id: input.targetRefId,
|
|
238
|
+
result_json: null,
|
|
239
|
+
error_code: null,
|
|
240
|
+
created_at: now,
|
|
241
|
+
updated_at: now,
|
|
242
|
+
completed_at: null
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function matchesClaim(execution, input) {
|
|
246
|
+
return execution.hitlRequestId === (input.hitlRequestId ?? null) && execution.pluginId === input.pluginId && execution.toolName === input.toolName && execution.reviewMode === input.reviewMode && execution.actionHash === input.actionHash && execution.idempotencyKey === input.idempotencyKey && execution.actorType === input.actorType && execution.actorId === input.actorId && execution.scope === input.scope && execution.targetRefType === input.targetRefType && execution.targetRefId === input.targetRefId;
|
|
247
|
+
}
|
|
248
|
+
function rowToExecution(row) {
|
|
249
|
+
return {
|
|
250
|
+
id: row.id,
|
|
251
|
+
hitlRequestId: row.hitl_request_id,
|
|
252
|
+
pluginId: row.plugin_id,
|
|
253
|
+
toolName: row.tool_name,
|
|
254
|
+
reviewMode: row.review_mode,
|
|
255
|
+
actionHash: row.action_hash,
|
|
256
|
+
idempotencyKey: row.idempotency_key,
|
|
257
|
+
status: row.status,
|
|
258
|
+
actorType: row.actor_type,
|
|
259
|
+
actorId: row.actor_id,
|
|
260
|
+
scope: row.scope,
|
|
261
|
+
targetRefType: row.target_ref_type,
|
|
262
|
+
targetRefId: row.target_ref_id,
|
|
263
|
+
result: parseNullableRecord(row.result_json),
|
|
264
|
+
errorCode: row.error_code,
|
|
265
|
+
createdAt: row.created_at,
|
|
266
|
+
updatedAt: row.updated_at,
|
|
267
|
+
completedAt: row.completed_at
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function parseNullableRecord(value) {
|
|
271
|
+
if (!value) return null;
|
|
272
|
+
try {
|
|
273
|
+
const parsed = JSON.parse(value);
|
|
274
|
+
return isRecord(parsed) ? parsed : null;
|
|
275
|
+
} catch {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function isRecord(value) {
|
|
280
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/plugins/mcp-reviewed-executor.ts
|
|
285
|
+
const REVIEW_METADATA_KEY = "dineway/review";
|
|
286
|
+
var PluginMcpIndeterminateError = class extends Error {
|
|
287
|
+
constructor(message, code = "PLUGIN_COMMAND_OUTCOME_INDETERMINATE") {
|
|
288
|
+
super(message);
|
|
289
|
+
this.code = code;
|
|
290
|
+
this.name = "PluginMcpIndeterminateError";
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
function createReviewedPluginMcpCommandExecutor() {
|
|
294
|
+
return async (command, input, context, request) => executeReviewedPluginMcpCommand(command, input, context, request);
|
|
295
|
+
}
|
|
296
|
+
async function executeReviewedPluginMcpCommand(command, input, context, request) {
|
|
297
|
+
const preview = await command.tool.preview(input, context);
|
|
298
|
+
validatePreview(preview, "Command preview");
|
|
299
|
+
if (request.target && stableStringify(request.target) !== stableStringify(preview.target)) throw invalidReview("Command preview target does not match the authorized target.");
|
|
300
|
+
const redactedPreview = command.tool.redactPreview ? await command.tool.redactPreview(preview, context) : preview;
|
|
301
|
+
validatePreview(redactedPreview, "Redacted command preview");
|
|
302
|
+
if (stableStringify(redactedPreview.target) !== stableStringify(preview.target)) throw invalidReview("Command preview redaction must not change the target.");
|
|
303
|
+
const fingerprint = await command.tool.actionFingerprint(input, preview, context);
|
|
304
|
+
const actionHash = await buildStableActionHash({
|
|
305
|
+
plugin: {
|
|
306
|
+
id: command.pluginId,
|
|
307
|
+
version: command.pluginVersion
|
|
308
|
+
},
|
|
309
|
+
tool: command.tool.name,
|
|
310
|
+
actor: {
|
|
311
|
+
type: context.actor.type,
|
|
312
|
+
id: context.actor.id
|
|
313
|
+
},
|
|
314
|
+
input,
|
|
315
|
+
target: preview.target,
|
|
316
|
+
preview,
|
|
317
|
+
fingerprint
|
|
318
|
+
});
|
|
319
|
+
const idempotencyKey = `${command.tool.idempotency.namespace ?? `${command.pluginId}:${command.tool.name}`}:${actionHash}`;
|
|
320
|
+
const reviewMode = command.tool.risk.level === "strong_confirmation" ? "strong" : "quick";
|
|
321
|
+
const scope = preview.target.scope;
|
|
322
|
+
let hitlRequestId = null;
|
|
323
|
+
if (reviewMode === "strong") {
|
|
324
|
+
const review = await resolveStrongReview({
|
|
325
|
+
command,
|
|
326
|
+
context,
|
|
327
|
+
request,
|
|
328
|
+
redactedPreview,
|
|
329
|
+
actionHash,
|
|
330
|
+
idempotencyKey,
|
|
331
|
+
scope
|
|
332
|
+
});
|
|
333
|
+
if (review.response) return review.response;
|
|
334
|
+
hitlRequestId = review.hitlRequestId;
|
|
335
|
+
} else if (request.review.quickActionHash !== actionHash) return {
|
|
336
|
+
status: "confirmation_required",
|
|
337
|
+
review_mode: "quick",
|
|
338
|
+
action_hash: actionHash,
|
|
339
|
+
preview: redactedPreview,
|
|
340
|
+
message: `Retry this tool with _meta["${REVIEW_METADATA_KEY}"].quick_action_hash set to the exact action_hash.`
|
|
341
|
+
};
|
|
342
|
+
const executions = new HitlExecutionRepository(context.db);
|
|
343
|
+
const claim = await executions.claim({
|
|
344
|
+
hitlRequestId,
|
|
345
|
+
pluginId: command.pluginId,
|
|
346
|
+
toolName: command.tool.name,
|
|
347
|
+
reviewMode,
|
|
348
|
+
actionHash,
|
|
349
|
+
idempotencyKey,
|
|
350
|
+
actorType: context.actor.type,
|
|
351
|
+
actorId: context.actor.id,
|
|
352
|
+
scope,
|
|
353
|
+
targetRefType: preview.target.type,
|
|
354
|
+
targetRefId: preview.target.id
|
|
355
|
+
});
|
|
356
|
+
if (!claim.claimed) return existingExecutionResponse(claim.execution);
|
|
357
|
+
const activityInput = {
|
|
358
|
+
actionType: `plugin.mcp.${command.tool.name}`,
|
|
359
|
+
subjectType: preview.target.type,
|
|
360
|
+
subjectId: preview.target.id,
|
|
361
|
+
relatedSubjectType: "plugin",
|
|
362
|
+
relatedSubjectId: command.pluginId,
|
|
363
|
+
sourceType: "mcp_tool",
|
|
364
|
+
sourceName: command.tool.name,
|
|
365
|
+
scope,
|
|
366
|
+
summary: redactedPreview.summary,
|
|
367
|
+
detail: {
|
|
368
|
+
executionId: claim.execution.id,
|
|
369
|
+
hitlRequestId,
|
|
370
|
+
actionHash,
|
|
371
|
+
reviewMode,
|
|
372
|
+
reversibility: command.tool.reversibility,
|
|
373
|
+
target: redactedPreview.target
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
const actorLocals = toActorLocals(context);
|
|
377
|
+
try {
|
|
378
|
+
if (command.tool.audit === "strict") await logSiteActivityStrict(context.db, actorLocals, {
|
|
379
|
+
...activityInput,
|
|
380
|
+
resultStatus: "pending"
|
|
381
|
+
});
|
|
382
|
+
else await logSiteActivitySafely(context.db, actorLocals, {
|
|
383
|
+
...activityInput,
|
|
384
|
+
resultStatus: "pending"
|
|
385
|
+
});
|
|
386
|
+
} catch {
|
|
387
|
+
await executions.markFailed(claim.execution.id, "STRICT_AUDIT_WRITE_FAILED");
|
|
388
|
+
throw invalidReview("The command was not executed because its required audit record failed.");
|
|
389
|
+
}
|
|
390
|
+
try {
|
|
391
|
+
const output = await command.tool.handler(input, {
|
|
392
|
+
...context,
|
|
393
|
+
reviewedExecution: {
|
|
394
|
+
id: claim.execution.id,
|
|
395
|
+
hitlRequestId,
|
|
396
|
+
actionHash,
|
|
397
|
+
idempotencyKey
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
const storedResult = command.tool.pii.output === "sensitive" ? {
|
|
401
|
+
status: "succeeded",
|
|
402
|
+
result_omitted: true
|
|
403
|
+
} : output;
|
|
404
|
+
if (!await executions.markSucceeded(claim.execution.id, storedResult)) throw new PluginMcpIndeterminateError("The command completed but its execution result could not be persisted.", "EXECUTION_RESULT_PERSIST_FAILED");
|
|
405
|
+
await logSiteActivitySafely(context.db, actorLocals, {
|
|
406
|
+
...activityInput,
|
|
407
|
+
resultStatus: "succeeded"
|
|
408
|
+
});
|
|
409
|
+
return output;
|
|
410
|
+
} catch (error) {
|
|
411
|
+
if (error instanceof PluginMcpIndeterminateError) {
|
|
412
|
+
await executions.markIndeterminate(claim.execution.id, error.code);
|
|
413
|
+
await logSiteActivitySafely(context.db, actorLocals, {
|
|
414
|
+
...activityInput,
|
|
415
|
+
resultStatus: "blocked",
|
|
416
|
+
detail: {
|
|
417
|
+
...activityInput.detail,
|
|
418
|
+
outcome: "indeterminate"
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
throw new McpError(ErrorCode.InternalError, "Command outcome is indeterminate; manual reconciliation is required.");
|
|
422
|
+
}
|
|
423
|
+
await executions.markFailed(claim.execution.id, "PLUGIN_COMMAND_FAILED");
|
|
424
|
+
await logSiteActivitySafely(context.db, actorLocals, {
|
|
425
|
+
...activityInput,
|
|
426
|
+
resultStatus: "failed"
|
|
427
|
+
});
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
async function resolveStrongReview(input) {
|
|
432
|
+
const repository = new HitlRequestRepository(input.context.db);
|
|
433
|
+
let request;
|
|
434
|
+
if (input.request.review.hitlRequestId) {
|
|
435
|
+
request = await repository.findById(input.request.review.hitlRequestId);
|
|
436
|
+
if (!request) throw invalidReview("The supplied HITL request does not exist.");
|
|
437
|
+
validateStrongReviewRequest(request, input);
|
|
438
|
+
} else {
|
|
439
|
+
request = await findMatchingReviewRequest(repository, input);
|
|
440
|
+
if (!request) request = await createReviewRequest(input);
|
|
441
|
+
return { response: approvalResponse(request, input.redactedPreview, input.actionHash) };
|
|
442
|
+
}
|
|
443
|
+
if (request.status === "pending") return { response: approvalResponse(request, input.redactedPreview, input.actionHash) };
|
|
444
|
+
if (request.status === "rejected") return { response: {
|
|
445
|
+
status: "approval_rejected",
|
|
446
|
+
review_mode: "strong",
|
|
447
|
+
hitl_request_id: request.id,
|
|
448
|
+
action_hash: input.actionHash
|
|
449
|
+
} };
|
|
450
|
+
if (request.resolvedByActorType !== "user" || !request.resolvedByActorId) throw invalidReview("Strong confirmation must be approved by an authenticated user.");
|
|
451
|
+
return { hitlRequestId: request.id };
|
|
452
|
+
}
|
|
453
|
+
async function findMatchingReviewRequest(repository, input) {
|
|
454
|
+
return (await repository.list({
|
|
455
|
+
scope: input.scope,
|
|
456
|
+
actionType: `plugin.mcp.${input.command.tool.name}`,
|
|
457
|
+
targetRefType: input.redactedPreview.target.type,
|
|
458
|
+
targetRefId: input.redactedPreview.target.id,
|
|
459
|
+
requestedByActorType: input.context.actor.type,
|
|
460
|
+
requestedByActorId: input.context.actor.id,
|
|
461
|
+
limit: 100
|
|
462
|
+
})).items.find((request) => request.metadata.actionHash === input.actionHash && request.metadata.idempotencyKey === input.idempotencyKey) ?? null;
|
|
463
|
+
}
|
|
464
|
+
async function createReviewRequest(input) {
|
|
465
|
+
return new HitlRequestService(input.context.db).create({
|
|
466
|
+
actorType: input.context.actor.type,
|
|
467
|
+
actorId: input.context.actor.id,
|
|
468
|
+
userRole: input.context.actor.role,
|
|
469
|
+
authMetadata: actorAuthMetadata(input.context)
|
|
470
|
+
}, {
|
|
471
|
+
scope: input.scope,
|
|
472
|
+
actionType: `plugin.mcp.${input.command.tool.name}`,
|
|
473
|
+
title: input.command.tool.title,
|
|
474
|
+
summary: input.redactedPreview.summary,
|
|
475
|
+
riskReason: input.command.tool.risk.reason,
|
|
476
|
+
reviewPayload: {
|
|
477
|
+
actionHash: input.actionHash,
|
|
478
|
+
idempotencyKey: input.idempotencyKey,
|
|
479
|
+
preview: input.redactedPreview
|
|
480
|
+
},
|
|
481
|
+
targetRefType: input.redactedPreview.target.type,
|
|
482
|
+
targetRefId: input.redactedPreview.target.id,
|
|
483
|
+
metadata: {
|
|
484
|
+
pluginId: input.command.pluginId,
|
|
485
|
+
toolName: input.command.tool.name,
|
|
486
|
+
actionHash: input.actionHash,
|
|
487
|
+
idempotencyKey: input.idempotencyKey,
|
|
488
|
+
reviewMode: "strong",
|
|
489
|
+
reversibility: input.command.tool.reversibility
|
|
490
|
+
},
|
|
491
|
+
priority: input.command.tool.reversibility === "irreversible" ? "high" : "normal"
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
function validateStrongReviewRequest(request, input) {
|
|
495
|
+
if (request.scope !== input.scope || request.actionType !== `plugin.mcp.${input.command.tool.name}` || request.targetRefType !== input.redactedPreview.target.type || request.targetRefId !== input.redactedPreview.target.id || request.requestedByActorType !== input.context.actor.type || request.requestedByActorId !== input.context.actor.id || request.metadata.pluginId !== input.command.pluginId || request.metadata.toolName !== input.command.tool.name || request.metadata.actionHash !== input.actionHash || request.metadata.idempotencyKey !== input.idempotencyKey || request.reviewPayload.actionHash !== input.actionHash || request.reviewPayload.idempotencyKey !== input.idempotencyKey) throw invalidReview("The supplied HITL approval is stale or belongs to another action.");
|
|
496
|
+
}
|
|
497
|
+
function approvalResponse(request, preview, actionHash) {
|
|
498
|
+
return {
|
|
499
|
+
status: "approval_required",
|
|
500
|
+
review_mode: "strong",
|
|
501
|
+
hitl_request_id: request.id,
|
|
502
|
+
hitl_status: request.status,
|
|
503
|
+
action_hash: actionHash,
|
|
504
|
+
preview,
|
|
505
|
+
message: `After human approval, retry this tool with _meta["${REVIEW_METADATA_KEY}"].hitl_request_id set to the HITL request id.`
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
function existingExecutionResponse(execution) {
|
|
509
|
+
if (execution.status === "succeeded") return execution.result ?? {
|
|
510
|
+
status: "succeeded",
|
|
511
|
+
result_omitted: true,
|
|
512
|
+
execution_id: execution.id
|
|
513
|
+
};
|
|
514
|
+
return {
|
|
515
|
+
status: execution.status === "claimed" ? "execution_in_progress" : execution.status === "indeterminate" ? "outcome_indeterminate" : "execution_failed",
|
|
516
|
+
execution_id: execution.id,
|
|
517
|
+
action_hash: execution.actionHash,
|
|
518
|
+
retry_allowed: false
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
function validatePreview(preview, label) {
|
|
522
|
+
if (!preview || typeof preview.summary !== "string" || preview.summary.trim().length === 0) throw invalidReview(`${label} requires a non-empty summary.`);
|
|
523
|
+
validateTarget(preview.target, label);
|
|
524
|
+
}
|
|
525
|
+
function validateTarget(target, label) {
|
|
526
|
+
if (!target || ![
|
|
527
|
+
"plugin",
|
|
528
|
+
"location",
|
|
529
|
+
"entity"
|
|
530
|
+
].includes(target.type) || typeof target.id !== "string" || target.id.trim().length === 0 || typeof target.scope !== "string" || target.scope.trim().length === 0 || target.locationId !== void 0 && (typeof target.locationId !== "string" || target.locationId.trim().length === 0)) throw invalidReview(`${label} contains an invalid target.`);
|
|
531
|
+
}
|
|
532
|
+
function actorAuthMetadata(context) {
|
|
533
|
+
return {
|
|
534
|
+
auth_method: context.actor.authMethod,
|
|
535
|
+
user_id: context.actor.userId,
|
|
536
|
+
token_scopes: context.actor.tokenScopes ?? []
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
function toActorLocals(context) {
|
|
540
|
+
const authToken = context.actor.authMethod === "api_token" || context.actor.authMethod === "oauth_token" ? {
|
|
541
|
+
type: context.actor.authMethod,
|
|
542
|
+
id: context.actor.authMethod === "api_token" ? context.actor.id : null
|
|
543
|
+
} : void 0;
|
|
544
|
+
return {
|
|
545
|
+
user: context.actor.userId ? { id: context.actor.userId } : null,
|
|
546
|
+
tokenScopes: context.actor.tokenScopes ? [...context.actor.tokenScopes] : void 0,
|
|
547
|
+
authToken
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
function invalidReview(message) {
|
|
551
|
+
return new McpError(ErrorCode.InvalidRequest, message);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
//#endregion
|
|
555
|
+
export { createActivePluginMcpRegistry as n, registerPluginMcpRegistry as r, createReviewedPluginMcpCommandExecutor as t };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/media/image-endpoint.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Portable helpers shared by image-endpoint modules.
|
|
4
|
+
*
|
|
5
|
+
* Dineway wraps Astro's image endpoint so source bytes for Dineway media can be
|
|
6
|
+
* read directly from the storage adapter instead of fetched over HTTP.
|
|
7
|
+
*/
|
|
8
|
+
declare const ALLOWED_TRANSFORM_FORMATS: readonly ["webp", "avif", "jpeg", "png"];
|
|
9
|
+
declare const DEFAULT_TRANSFORM_FORMAT: ImageTransformFormat;
|
|
10
|
+
declare const MAX_TRANSFORM_DIMENSION = 4000;
|
|
11
|
+
declare const IMMUTABLE_IMAGE_CACHE = "public, max-age=31536000, immutable";
|
|
12
|
+
type ImageTransformFormat = (typeof ALLOWED_TRANSFORM_FORMATS)[number];
|
|
13
|
+
interface ImageTransformOptions {
|
|
14
|
+
width?: number;
|
|
15
|
+
height?: number;
|
|
16
|
+
format: ImageTransformFormat;
|
|
17
|
+
quality?: number;
|
|
18
|
+
}
|
|
19
|
+
declare function originalMediaHeaders(contentType: string): Record<string, string>;
|
|
20
|
+
declare function isSafeTransformKey(key: string): boolean;
|
|
21
|
+
declare function matchInternalMediaKey(href: string | null | undefined): string | null;
|
|
22
|
+
declare function isTransformFormat(value: string): value is ImageTransformFormat;
|
|
23
|
+
type ParsedTransformParams = {
|
|
24
|
+
ok: true;
|
|
25
|
+
options: ImageTransformOptions;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
message: string;
|
|
29
|
+
};
|
|
30
|
+
declare function parseTransformParams(params: URLSearchParams): ParsedTransformParams;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { ALLOWED_TRANSFORM_FORMATS, DEFAULT_TRANSFORM_FORMAT, IMMUTABLE_IMAGE_CACHE, ImageTransformFormat, ImageTransformOptions, MAX_TRANSFORM_DIMENSION, ParsedTransformParams, isSafeTransformKey, isTransformFormat, matchInternalMediaKey, originalMediaHeaders, parseTransformParams };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { t as INTERNAL_MEDIA_PREFIX } from "../normalize-5ek_z7de.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/media/image-endpoint.ts
|
|
4
|
+
/**
|
|
5
|
+
* Portable helpers shared by image-endpoint modules.
|
|
6
|
+
*
|
|
7
|
+
* Dineway wraps Astro's image endpoint so source bytes for Dineway media can be
|
|
8
|
+
* read directly from the storage adapter instead of fetched over HTTP.
|
|
9
|
+
*/
|
|
10
|
+
const ALLOWED_TRANSFORM_FORMATS = [
|
|
11
|
+
"webp",
|
|
12
|
+
"avif",
|
|
13
|
+
"jpeg",
|
|
14
|
+
"png"
|
|
15
|
+
];
|
|
16
|
+
const DEFAULT_TRANSFORM_FORMAT = "webp";
|
|
17
|
+
const MAX_TRANSFORM_DIMENSION = 4e3;
|
|
18
|
+
const IMMUTABLE_IMAGE_CACHE = "public, max-age=31536000, immutable";
|
|
19
|
+
const SAFE_INLINE_IMAGE_TYPES = new Set([
|
|
20
|
+
"image/jpeg",
|
|
21
|
+
"image/png",
|
|
22
|
+
"image/gif",
|
|
23
|
+
"image/webp",
|
|
24
|
+
"image/avif",
|
|
25
|
+
"image/x-icon"
|
|
26
|
+
]);
|
|
27
|
+
function originalMediaHeaders(contentType) {
|
|
28
|
+
return {
|
|
29
|
+
"Content-Type": contentType,
|
|
30
|
+
"Cache-Control": IMMUTABLE_IMAGE_CACHE,
|
|
31
|
+
"X-Content-Type-Options": "nosniff",
|
|
32
|
+
"Content-Security-Policy": "sandbox; default-src 'none'; img-src 'self'; style-src 'unsafe-inline'",
|
|
33
|
+
"Content-Disposition": SAFE_INLINE_IMAGE_TYPES.has(contentType) ? "inline" : "attachment"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const SAFE_STORAGE_KEY_SEGMENT = /^[A-Za-z0-9._-]+$/;
|
|
37
|
+
const DECIMAL_DIGITS = /^\d+$/;
|
|
38
|
+
function isSafeTransformKey(key) {
|
|
39
|
+
const segments = key.split("/");
|
|
40
|
+
return segments.length > 0 && segments.every((segment) => segment !== "" && segment !== "." && segment !== ".." && SAFE_STORAGE_KEY_SEGMENT.test(segment));
|
|
41
|
+
}
|
|
42
|
+
function matchInternalMediaKey(href) {
|
|
43
|
+
if (!href) return null;
|
|
44
|
+
let pathname;
|
|
45
|
+
try {
|
|
46
|
+
pathname = new URL(href, "http://localhost").pathname;
|
|
47
|
+
} catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (!pathname.startsWith(INTERNAL_MEDIA_PREFIX)) return null;
|
|
51
|
+
const key = pathname.slice(INTERNAL_MEDIA_PREFIX.length);
|
|
52
|
+
if (!key || !isSafeTransformKey(key)) return null;
|
|
53
|
+
return key;
|
|
54
|
+
}
|
|
55
|
+
function isTransformFormat(value) {
|
|
56
|
+
return ALLOWED_TRANSFORM_FORMATS.includes(value);
|
|
57
|
+
}
|
|
58
|
+
function parseTransformParams(params) {
|
|
59
|
+
const width = parseDimension(params.get("w"));
|
|
60
|
+
if (width === null) return {
|
|
61
|
+
ok: false,
|
|
62
|
+
message: "Invalid 'w' (width)"
|
|
63
|
+
};
|
|
64
|
+
if (width === void 0) return {
|
|
65
|
+
ok: false,
|
|
66
|
+
message: "Missing 'w' (width)"
|
|
67
|
+
};
|
|
68
|
+
const height = parseDimension(params.get("h"));
|
|
69
|
+
if (height === null) return {
|
|
70
|
+
ok: false,
|
|
71
|
+
message: "Invalid 'h' (height)"
|
|
72
|
+
};
|
|
73
|
+
const formatRaw = params.get("f");
|
|
74
|
+
let format = DEFAULT_TRANSFORM_FORMAT;
|
|
75
|
+
if (formatRaw !== null) {
|
|
76
|
+
if (!isTransformFormat(formatRaw)) return {
|
|
77
|
+
ok: false,
|
|
78
|
+
message: `Unsupported 'f' (format): ${formatRaw}`
|
|
79
|
+
};
|
|
80
|
+
format = formatRaw;
|
|
81
|
+
}
|
|
82
|
+
const qualityRaw = params.get("q");
|
|
83
|
+
let quality;
|
|
84
|
+
if (qualityRaw !== null) {
|
|
85
|
+
const parsedQuality = Number(qualityRaw);
|
|
86
|
+
if (!Number.isInteger(parsedQuality) || parsedQuality < 1 || parsedQuality > 100) return {
|
|
87
|
+
ok: false,
|
|
88
|
+
message: "Invalid 'q' (quality), expected 1-100"
|
|
89
|
+
};
|
|
90
|
+
quality = parsedQuality;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
ok: true,
|
|
94
|
+
options: {
|
|
95
|
+
width,
|
|
96
|
+
height,
|
|
97
|
+
format,
|
|
98
|
+
quality
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function parseDimension(raw) {
|
|
103
|
+
if (raw === null) return void 0;
|
|
104
|
+
if (!DECIMAL_DIGITS.test(raw)) return null;
|
|
105
|
+
const parsed = Number(raw);
|
|
106
|
+
if (parsed < 1 || parsed > MAX_TRANSFORM_DIMENSION) return null;
|
|
107
|
+
return parsed;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
export { ALLOWED_TRANSFORM_FORMATS, DEFAULT_TRANSFORM_FORMAT, IMMUTABLE_IMAGE_CACHE, MAX_TRANSFORM_DIMENSION, isSafeTransformKey, isTransformFormat, matchInternalMediaKey, originalMediaHeaders, parseTransformParams };
|