dineway 0.1.3 → 0.1.5
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/README.md +6 -3
- package/dist/{apply-CAPvMfoU.mjs → apply-iVSqz2qs.mjs} +132 -39
- package/dist/astro/index.d.mts +18 -9
- package/dist/astro/index.mjs +238 -16
- package/dist/astro/middleware/auth.d.mts +16 -5
- package/dist/astro/middleware/auth.mjs +74 -37
- package/dist/astro/middleware/redirect.mjs +24 -8
- package/dist/astro/middleware/request-context.mjs +18 -5
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.mjs +411 -169
- package/dist/astro/types.d.mts +25 -8
- package/dist/{byline-DeWCMU_i.mjs → byline-OhH2dlRu.mjs} +6 -21
- package/dist/{bylines-DyqBV9EQ.mjs → bylines-BGpD9_hy.mjs} +16 -6
- package/dist/cache-BdSY-gQN.mjs +42 -0
- package/dist/chunks--4F8ddV4.mjs +18 -0
- package/dist/cli/index.mjs +935 -15
- package/dist/client/external-auth-headers.d.mts +1 -1
- package/dist/client/index.d.mts +11 -3
- package/dist/client/index.mjs +4 -3
- package/dist/{connection-C9pxzuag.mjs → connection-BCNICDWN.mjs} +22 -5
- package/dist/{content-zSgdNmnt.mjs → content-DWi4d0rT.mjs} +41 -2
- package/dist/database/instrumentation.d.mts +34 -0
- package/dist/database/instrumentation.mjs +53 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/libsql.mjs +11 -5
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.mjs +7 -1
- package/dist/db-errors-CEqD7qH9.mjs +23 -0
- package/dist/{default-WYlzADZL.mjs → default-VjJyuuG9.mjs} +2 -0
- package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +3 -0
- package/dist/{error-DrxtnGPg.mjs → error-BmL6QipT.mjs} +7 -3
- package/dist/{index-C-jx21qs.d.mts → index-yvc6E_17.d.mts} +157 -30
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +24 -22
- package/dist/{loader-qKmo0wAY.mjs → loader-sMG4TZ-u.mjs} +9 -3
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +1 -1
- package/dist/media/local-runtime.d.mts +7 -7
- package/dist/page/index.d.mts +10 -2
- package/dist/page/index.mjs +22 -1
- package/dist/patterns-CrCYkMBb.mjs +92 -0
- package/dist/{placeholder-bOx1xCTY.d.mts → placeholder--wOi4TbO.d.mts} +1 -1
- package/dist/{placeholder-B3knXwNc.mjs → placeholder-Cp8g5Emj.mjs} +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
- package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
- package/dist/{query-BiaPl_g2.mjs → query-kDmwCsHh.mjs} +118 -50
- package/dist/{redirect-JPqLAbxa.mjs → redirect-DnEWAkVg.mjs} +43 -99
- package/dist/{registry-DSd1GWB8.mjs → registry-C0zjeB9P.mjs} +191 -123
- package/dist/request-cache-Dk5qPSOx.mjs +66 -0
- package/dist/request-context.d.mts +4 -16
- package/dist/{runner-B5l1JfOj.d.mts → runner-CFI6B6J2.d.mts} +1 -1
- package/dist/{runner-BGUGywgG.mjs → runner-DWZm2KQm.mjs} +589 -137
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +2 -2
- package/dist/{search-BNruJHDL.mjs → search-ByRGV2pq.mjs} +570 -424
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +11 -10
- package/dist/seo/index.d.mts +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +11 -3
- package/dist/storage/s3.mjs +78 -15
- package/dist/taxonomies-1s5PaS_8.mjs +266 -0
- package/dist/transaction-Cn2rjY78.mjs +27 -0
- package/dist/{types-BgQeVaPj.d.mts → types-BuMDPy5C.d.mts} +52 -3
- package/dist/{types-DuNbGKjF.mjs → types-COeOq9nK.mjs} +6 -1
- package/dist/{types-ju-_ORz7.d.mts → types-CWbdtiux.d.mts} +13 -5
- package/dist/{types-D38djUXv.d.mts → types-Cj0KMIZV.d.mts} +16 -3
- package/dist/{types-DkvMXalq.d.mts → types-DOrVigru.d.mts} +159 -0
- package/dist/{validate-CXnRKfJK.mjs → validate-BZ5wnLLp.mjs} +2 -1
- package/dist/{validate-DVKJJ-M_.d.mts → validate-IPf8n4Fj.d.mts} +4 -51
- package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +10 -10
- package/dist/version-BKXPsfmJ.mjs +6 -0
- package/package.json +53 -39
- package/src/astro/routes/PluginRegistry.tsx +21 -0
- package/src/astro/routes/admin.astro +99 -0
- package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
- package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
- package/src/astro/routes/api/admin/api-tokens/[id].ts +44 -0
- package/src/astro/routes/api/admin/api-tokens/index.ts +90 -0
- package/src/astro/routes/api/admin/briefing.ts +76 -0
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +90 -0
- package/src/astro/routes/api/admin/bylines/index.ts +74 -0
- package/src/astro/routes/api/admin/comments/[id]/status.ts +120 -0
- package/src/astro/routes/api/admin/comments/[id].ts +64 -0
- package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
- package/src/astro/routes/api/admin/comments/counts.ts +30 -0
- package/src/astro/routes/api/admin/comments/index.ts +46 -0
- package/src/astro/routes/api/admin/context/[id]/history.ts +35 -0
- package/src/astro/routes/api/admin/context/[id]/index.ts +35 -0
- package/src/astro/routes/api/admin/context/[id]/review.ts +57 -0
- package/src/astro/routes/api/admin/context/[id]/supersede.ts +58 -0
- package/src/astro/routes/api/admin/context/diff.ts +35 -0
- package/src/astro/routes/api/admin/context/index.ts +69 -0
- package/src/astro/routes/api/admin/context/stale.ts +35 -0
- package/src/astro/routes/api/admin/hitl-requests/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/hitl-requests/[id]/resolve.ts +54 -0
- package/src/astro/routes/api/admin/hitl-requests/index.ts +38 -0
- package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +132 -0
- package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
- package/src/astro/routes/api/admin/oauth-clients/[id].ts +137 -0
- package/src/astro/routes/api/admin/oauth-clients/index.ts +95 -0
- package/src/astro/routes/api/admin/plugins/[id]/disable.ts +91 -0
- package/src/astro/routes/api/admin/plugins/[id]/enable.ts +91 -0
- package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +98 -0
- package/src/astro/routes/api/admin/plugins/[id]/update.ts +154 -0
- package/src/astro/routes/api/admin/plugins/index.ts +32 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +62 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +135 -0
- package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
- package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
- package/src/astro/routes/api/admin/review-requests/[id]/index.ts +35 -0
- package/src/astro/routes/api/admin/review-requests/[id]/resolve.ts +52 -0
- package/src/astro/routes/api/admin/review-requests/index.ts +35 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
- package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +62 -0
- package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
- package/src/astro/routes/api/admin/users/[id]/disable.ts +72 -0
- package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
- package/src/astro/routes/api/admin/users/[id]/index.ts +166 -0
- package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
- package/src/astro/routes/api/admin/users/index.ts +66 -0
- package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
- package/src/astro/routes/api/auth/invite/accept.ts +52 -0
- package/src/astro/routes/api/auth/invite/complete.ts +86 -0
- package/src/astro/routes/api/auth/invite/index.ts +99 -0
- package/src/astro/routes/api/auth/invite/register-options.ts +73 -0
- package/src/astro/routes/api/auth/logout.ts +40 -0
- package/src/astro/routes/api/auth/magic-link/send.ts +90 -0
- package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
- package/src/astro/routes/api/auth/me.ts +60 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +221 -0
- package/src/astro/routes/api/auth/oauth/[provider].ts +120 -0
- package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
- package/src/astro/routes/api/auth/passkey/index.ts +54 -0
- package/src/astro/routes/api/auth/passkey/options.ts +85 -0
- package/src/astro/routes/api/auth/passkey/register/options.ts +88 -0
- package/src/astro/routes/api/auth/passkey/register/verify.ts +119 -0
- package/src/astro/routes/api/auth/passkey/verify.ts +72 -0
- package/src/astro/routes/api/auth/signup/complete.ts +87 -0
- package/src/astro/routes/api/auth/signup/request.ts +89 -0
- package/src/astro/routes/api/auth/signup/verify.ts +53 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +310 -0
- package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +68 -0
- package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +77 -0
- package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +42 -0
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +100 -0
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +64 -0
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
- package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +129 -0
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +143 -0
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +50 -0
- package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +69 -0
- package/src/astro/routes/api/content/[collection]/[id].ts +173 -0
- package/src/astro/routes/api/content/[collection]/index.ts +103 -0
- package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
- package/src/astro/routes/api/dashboard.ts +32 -0
- package/src/astro/routes/api/dev/emails.ts +36 -0
- package/src/astro/routes/api/health.ts +54 -0
- package/src/astro/routes/api/import/probe.ts +47 -0
- package/src/astro/routes/api/import/wordpress/analyze.ts +523 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +330 -0
- package/src/astro/routes/api/import/wordpress/media.ts +338 -0
- package/src/astro/routes/api/import/wordpress/prepare.ts +212 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +425 -0
- package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
- package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +399 -0
- package/src/astro/routes/api/manifest.ts +75 -0
- package/src/astro/routes/api/mcp.ts +125 -0
- package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
- package/src/astro/routes/api/media/[id].ts +145 -0
- package/src/astro/routes/api/media/file/[...key].ts +79 -0
- package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +91 -0
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
- package/src/astro/routes/api/media/providers/index.ts +30 -0
- package/src/astro/routes/api/media/upload-url.ts +146 -0
- package/src/astro/routes/api/media.ts +204 -0
- package/src/astro/routes/api/menus/[name]/items.ts +206 -0
- package/src/astro/routes/api/menus/[name]/reorder.ts +79 -0
- package/src/astro/routes/api/menus/[name].ts +145 -0
- package/src/astro/routes/api/menus/index.ts +91 -0
- package/src/astro/routes/api/oauth/authorize.ts +430 -0
- package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
- package/src/astro/routes/api/oauth/device/code.ts +56 -0
- package/src/astro/routes/api/oauth/device/token.ts +70 -0
- package/src/astro/routes/api/oauth/register.ts +182 -0
- package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
- package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
- package/src/astro/routes/api/oauth/token.ts +195 -0
- package/src/astro/routes/api/openapi.json.ts +33 -0
- package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +109 -0
- package/src/astro/routes/api/redirects/404s/index.ts +72 -0
- package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
- package/src/astro/routes/api/redirects/[id].ts +183 -0
- package/src/astro/routes/api/redirects/index.ts +100 -0
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
- package/src/astro/routes/api/revisions/[revisionId]/restore.ts +62 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +104 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +67 -0
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +45 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +107 -0
- package/src/astro/routes/api/schema/collections/index.ts +61 -0
- package/src/astro/routes/api/schema/index.ts +109 -0
- package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
- package/src/astro/routes/api/schema/orphans/index.ts +26 -0
- package/src/astro/routes/api/search/enable.ts +64 -0
- package/src/astro/routes/api/search/index.ts +52 -0
- package/src/astro/routes/api/search/rebuild.ts +72 -0
- package/src/astro/routes/api/search/stats.ts +35 -0
- package/src/astro/routes/api/search/suggest.ts +50 -0
- package/src/astro/routes/api/sections/[slug].ts +203 -0
- package/src/astro/routes/api/sections/index.ts +107 -0
- package/src/astro/routes/api/settings/email.ts +150 -0
- package/src/astro/routes/api/settings.ts +116 -0
- package/src/astro/routes/api/setup/admin-verify.ts +122 -0
- package/src/astro/routes/api/setup/admin.ts +104 -0
- package/src/astro/routes/api/setup/dev-bypass.ts +200 -0
- package/src/astro/routes/api/setup/dev-reset.ts +40 -0
- package/src/astro/routes/api/setup/index.ts +128 -0
- package/src/astro/routes/api/setup/status.ts +122 -0
- package/src/astro/routes/api/snapshot.ts +76 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +232 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +131 -0
- package/src/astro/routes/api/taxonomies/index.ts +114 -0
- package/src/astro/routes/api/themes/preview.ts +78 -0
- package/src/astro/routes/api/typegen.ts +114 -0
- package/src/astro/routes/api/well-known/auth.ts +71 -0
- package/src/astro/routes/api/well-known/oauth-authorization-server.ts +48 -0
- package/src/astro/routes/api/well-known/oauth-protected-resource.ts +39 -0
- package/src/astro/routes/api/widget-areas/[name]/reorder.ts +114 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +213 -0
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +126 -0
- package/src/astro/routes/api/widget-areas/[name].ts +135 -0
- package/src/astro/routes/api/widget-areas/index.ts +149 -0
- package/src/astro/routes/api/widget-components.ts +22 -0
- package/src/astro/routes/robots.txt.ts +81 -0
- package/src/astro/routes/sitemap-[collection].xml.ts +104 -0
- package/src/astro/routes/sitemap.xml.ts +92 -0
- package/src/components/Break.astro +45 -0
- package/src/components/Button.astro +71 -0
- package/src/components/Buttons.astro +49 -0
- package/src/components/Code.astro +59 -0
- package/src/components/Columns.astro +59 -0
- package/src/components/CommentForm.astro +315 -0
- package/src/components/Comments.astro +232 -0
- package/src/components/Cover.astro +128 -0
- package/src/components/DinewayBodyEnd.astro +32 -0
- package/src/components/DinewayBodyStart.astro +32 -0
- package/src/components/DinewayHead.astro +61 -0
- package/src/components/DinewayImage.astro +178 -0
- package/src/components/DinewayMedia.astro +167 -0
- package/src/components/Embed.astro +128 -0
- package/src/components/File.astro +122 -0
- package/src/components/Gallery.astro +93 -0
- package/src/components/HtmlBlock.astro +33 -0
- package/src/components/Image.astro +178 -0
- package/src/components/InlineEditor.astro +27 -0
- package/src/components/InlinePortableTextEditor.tsx +1937 -0
- package/src/components/LiveSearch.astro +614 -0
- package/src/components/PortableText.astro +51 -0
- package/src/components/Pullquote.astro +51 -0
- package/src/components/Table.astro +135 -0
- package/src/components/WidgetArea.astro +22 -0
- package/src/components/WidgetRenderer.astro +72 -0
- package/src/components/index.ts +106 -0
- package/src/components/marks/Link.astro +31 -0
- package/src/components/marks/StrikeThrough.astro +7 -0
- package/src/components/marks/Subscript.astro +7 -0
- package/src/components/marks/Superscript.astro +7 -0
- package/src/components/marks/Underline.astro +7 -0
- package/src/components/marks.ts +19 -0
- package/src/components/widgets/Archives.astro +65 -0
- package/src/components/widgets/Categories.astro +35 -0
- package/src/components/widgets/RecentPosts.astro +51 -0
- package/src/components/widgets/Search.astro +18 -0
- package/src/components/widgets/Tags.astro +38 -0
- package/src/ui.ts +75 -0
- package/LICENSE +0 -9
- /package/dist/{adapters-BlzWJG82.d.mts → adapters-C2ypTrZZ.d.mts} +0 -0
- /package/dist/{config-Cq8H0SfX.mjs → config-BXwuX8Bx.mjs} +0 -0
- /package/dist/{load-C6FCD1FU.mjs → load-Coc9HpHH.mjs} +0 -0
- /package/dist/{manifest-schema-CTSEyIJ3.mjs → manifest-schema-D1MSVnoI.mjs} +0 -0
- /package/dist/{mode-BlyYtIFO.mjs → mode-47goXBBK.mjs} +0 -0
- /package/dist/{tokens-4vgYuXsZ.mjs → tokens-CJz9ubV6.mjs} +0 -0
- /package/dist/{transport-C5FYnid7.mjs → transport-DB5eDN4x.mjs} +0 -0
- /package/dist/{transport-gIL-e43D.d.mts → transport-Wge_IzKl.d.mts} +0 -0
- /package/dist/{types-CLLdsG3g.d.mts → types-BzcUjoqg.d.mts} +0 -0
- /package/dist/{types-DShnjzb6.mjs → types-griIBQOQ.mjs} +0 -0
|
@@ -1,24 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { n as validateJsonFieldName, r as validatePluginIdentifier, t as validateIdentifier } from "./validate-
|
|
4
|
-
import {
|
|
1
|
+
import { runWithContext } from "./request-context.mjs";
|
|
2
|
+
import { n as createDatabase } from "./connection-BCNICDWN.mjs";
|
|
3
|
+
import { n as validateJsonFieldName, r as validatePluginIdentifier, t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
4
|
+
import { o as jsonExtractExpr } from "./dialect-helpers-DhTzaUxP.mjs";
|
|
5
|
+
import { a as slugify, r as RevisionRepository, t as ContentRepository } from "./content-DWi4d0rT.mjs";
|
|
5
6
|
import { r as encodeBase64, t as decodeBase64 } from "./base64-F8-DUraK.mjs";
|
|
6
7
|
import { n as decodeCursor, r as encodeCursor, t as DinewayValidationError } from "./types-BawVha09.mjs";
|
|
7
8
|
import { t as MediaRepository } from "./media-DMTr80Gv.mjs";
|
|
8
|
-
import { a as
|
|
9
|
-
import {
|
|
10
|
-
import { t as RedirectRepository } from "./redirect-
|
|
11
|
-
import { n as
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { i as
|
|
16
|
-
import {
|
|
9
|
+
import { a as ssrfSafeFetch, i as resolveAndValidateExternalUrl, o as stripCredentialHeaders, p as OptionsRepository, r as SsrfError, s as validateExternalUrl } from "./apply-iVSqz2qs.mjs";
|
|
10
|
+
import { t as withTransaction } from "./transaction-Cn2rjY78.mjs";
|
|
11
|
+
import { t as RedirectRepository } from "./redirect-DnEWAkVg.mjs";
|
|
12
|
+
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks--4F8ddV4.mjs";
|
|
13
|
+
import { t as BylineRepository } from "./byline-OhH2dlRu.mjs";
|
|
14
|
+
import { r as isI18nEnabled } from "./config-BXwuX8Bx.mjs";
|
|
15
|
+
import { i as invalidateRedirectCache } from "./cache-BdSY-gQN.mjs";
|
|
16
|
+
import { i as FTSManager, n as SchemaRegistry } from "./registry-C0zjeB9P.mjs";
|
|
17
|
+
import { n as getDb } from "./loader-sMG4TZ-u.mjs";
|
|
18
|
+
import { n as requestCached } from "./request-cache-Dk5qPSOx.mjs";
|
|
19
|
+
import { n as VERSION, t as COMMIT } from "./version-BKXPsfmJ.mjs";
|
|
20
|
+
import { i as pluginManifestSchema } from "./manifest-schema-D1MSVnoI.mjs";
|
|
21
|
+
import { t as generatePreviewToken } from "./tokens-CJz9ubV6.mjs";
|
|
17
22
|
import BetterSqlite3 from "better-sqlite3";
|
|
18
23
|
import { sql } from "kysely";
|
|
24
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
19
25
|
import { ulid } from "ulidx";
|
|
20
26
|
import { z } from "astro/zod";
|
|
21
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
22
27
|
import { z as z$1 } from "zod";
|
|
23
28
|
import { createGzipDecoder, unpackTar } from "modern-tar";
|
|
24
29
|
import { createHash } from "node:crypto";
|
|
@@ -995,6 +1000,13 @@ const SEO_DEFAULTS = {
|
|
|
995
1000
|
canonical: null,
|
|
996
1001
|
noIndex: false
|
|
997
1002
|
};
|
|
1003
|
+
var ContentUpdateApiError = class extends Error {
|
|
1004
|
+
constructor(code, message) {
|
|
1005
|
+
super(message);
|
|
1006
|
+
this.code = code;
|
|
1007
|
+
this.name = "ContentUpdateApiError";
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
998
1010
|
/**
|
|
999
1011
|
* Check if a collection has SEO enabled.
|
|
1000
1012
|
*/
|
|
@@ -1285,34 +1297,18 @@ async function handleContentUpdate(db, collection, id, body) {
|
|
|
1285
1297
|
message: `Collection "${collection}" does not have SEO enabled. Remove the seo field or enable SEO on this collection.`
|
|
1286
1298
|
}
|
|
1287
1299
|
};
|
|
1288
|
-
const
|
|
1289
|
-
const resolvedId = await resolveId(repo, collection, id) ?? id;
|
|
1290
|
-
if (body._rev) {
|
|
1291
|
-
const existing = await repo.findById(collection, resolvedId);
|
|
1292
|
-
if (!existing) return {
|
|
1293
|
-
success: false,
|
|
1294
|
-
error: {
|
|
1295
|
-
code: "NOT_FOUND",
|
|
1296
|
-
message: `Content item not found: ${id}`
|
|
1297
|
-
}
|
|
1298
|
-
};
|
|
1299
|
-
const revCheck = validateRev(body._rev, existing);
|
|
1300
|
-
if (!revCheck.valid) return {
|
|
1301
|
-
success: false,
|
|
1302
|
-
error: {
|
|
1303
|
-
code: "CONFLICT",
|
|
1304
|
-
message: revCheck.message
|
|
1305
|
-
}
|
|
1306
|
-
};
|
|
1307
|
-
}
|
|
1300
|
+
const resolvedId = await resolveId(new ContentRepository(db), collection, id) ?? id;
|
|
1308
1301
|
const item = await withTransaction(db, async (trx) => {
|
|
1309
1302
|
const trxRepo = new ContentRepository(trx);
|
|
1310
1303
|
const bylineRepo = new BylineRepository(trx);
|
|
1311
|
-
|
|
1312
|
-
if (body.
|
|
1313
|
-
|
|
1314
|
-
|
|
1304
|
+
const existing = body._rev || body.slug ? await trxRepo.findById(collection, resolvedId) : null;
|
|
1305
|
+
if (body._rev) {
|
|
1306
|
+
if (!existing) throw new ContentUpdateApiError("NOT_FOUND", `Content item not found: ${id}`);
|
|
1307
|
+
const revCheck = validateRev(body._rev, existing);
|
|
1308
|
+
if (!revCheck.valid) throw new ContentUpdateApiError("CONFLICT", revCheck.message);
|
|
1315
1309
|
}
|
|
1310
|
+
let oldSlug;
|
|
1311
|
+
if (body.slug && existing?.slug && existing.slug !== body.slug) oldSlug = existing.slug;
|
|
1316
1312
|
const updated = await trxRepo.update(collection, resolvedId, {
|
|
1317
1313
|
data: body.data,
|
|
1318
1314
|
slug: body.slug,
|
|
@@ -1326,6 +1322,7 @@ async function handleContentUpdate(db, collection, id, body) {
|
|
|
1326
1322
|
if (oldSlug && body.slug) {
|
|
1327
1323
|
const collectionRow = await trx.selectFrom("_dineway_collections").select("url_pattern").where("slug", "=", collection).executeTakeFirst();
|
|
1328
1324
|
await new RedirectRepository(trx).createAutoRedirect(collection, oldSlug, body.slug, resolvedId, collectionRow?.url_pattern ?? null);
|
|
1325
|
+
invalidateRedirectCache();
|
|
1329
1326
|
}
|
|
1330
1327
|
if (isI18nEnabled() && body.data && updated.translationGroup) await syncNonTranslatableFields(trx, collection, updated.id, updated.translationGroup, body.data);
|
|
1331
1328
|
if (body.seo && hasSeo) updated.seo = await new SeoRepository(trx).upsert(collection, resolvedId, body.seo);
|
|
@@ -1341,6 +1338,13 @@ async function handleContentUpdate(db, collection, id, body) {
|
|
|
1341
1338
|
}
|
|
1342
1339
|
};
|
|
1343
1340
|
} catch (error) {
|
|
1341
|
+
if (error instanceof ContentUpdateApiError) return {
|
|
1342
|
+
success: false,
|
|
1343
|
+
error: {
|
|
1344
|
+
code: error.code,
|
|
1345
|
+
message: error.message
|
|
1346
|
+
}
|
|
1347
|
+
};
|
|
1344
1348
|
console.error("Content update error:", error);
|
|
1345
1349
|
return {
|
|
1346
1350
|
success: false,
|
|
@@ -1473,6 +1477,7 @@ async function handleContentPermanentDelete(db, collection, id) {
|
|
|
1473
1477
|
if (wasDeleted) {
|
|
1474
1478
|
await new SeoRepository(trx).delete(collection, resolvedId);
|
|
1475
1479
|
await new CommentRepository(trx).deleteByContent(collection, resolvedId);
|
|
1480
|
+
await new RevisionRepository(trx).deleteByEntry(collection, resolvedId);
|
|
1476
1481
|
}
|
|
1477
1482
|
return wasDeleted;
|
|
1478
1483
|
})) return {
|
|
@@ -1847,6 +1852,151 @@ async function syncNonTranslatableFields(trx, collectionSlug, updatedItemId, tra
|
|
|
1847
1852
|
`.execute(trx);
|
|
1848
1853
|
}
|
|
1849
1854
|
|
|
1855
|
+
//#endregion
|
|
1856
|
+
//#region src/plugins/state.ts
|
|
1857
|
+
function toPluginStatus(value) {
|
|
1858
|
+
if (value === "active") return "active";
|
|
1859
|
+
return "inactive";
|
|
1860
|
+
}
|
|
1861
|
+
function toPluginSource(value) {
|
|
1862
|
+
if (value === "marketplace") return "marketplace";
|
|
1863
|
+
return "config";
|
|
1864
|
+
}
|
|
1865
|
+
/**
|
|
1866
|
+
* Repository for plugin state in the database
|
|
1867
|
+
*/
|
|
1868
|
+
var PluginStateRepository = class {
|
|
1869
|
+
constructor(db) {
|
|
1870
|
+
this.db = db;
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Get state for a specific plugin
|
|
1874
|
+
*/
|
|
1875
|
+
async get(pluginId) {
|
|
1876
|
+
const row = await this.db.selectFrom("_plugin_state").selectAll().where("plugin_id", "=", pluginId).executeTakeFirst();
|
|
1877
|
+
if (!row) return null;
|
|
1878
|
+
return {
|
|
1879
|
+
pluginId: row.plugin_id,
|
|
1880
|
+
status: toPluginStatus(row.status),
|
|
1881
|
+
version: row.version,
|
|
1882
|
+
installedAt: new Date(row.installed_at),
|
|
1883
|
+
activatedAt: row.activated_at ? new Date(row.activated_at) : null,
|
|
1884
|
+
deactivatedAt: row.deactivated_at ? new Date(row.deactivated_at) : null,
|
|
1885
|
+
source: toPluginSource(row.source),
|
|
1886
|
+
marketplaceVersion: row.marketplace_version ?? null,
|
|
1887
|
+
displayName: row.display_name ?? null,
|
|
1888
|
+
description: row.description ?? null
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
/**
|
|
1892
|
+
* Get all plugin states
|
|
1893
|
+
*/
|
|
1894
|
+
async getAll() {
|
|
1895
|
+
return (await this.db.selectFrom("_plugin_state").selectAll().execute()).map((row) => ({
|
|
1896
|
+
pluginId: row.plugin_id,
|
|
1897
|
+
status: toPluginStatus(row.status),
|
|
1898
|
+
version: row.version,
|
|
1899
|
+
installedAt: new Date(row.installed_at),
|
|
1900
|
+
activatedAt: row.activated_at ? new Date(row.activated_at) : null,
|
|
1901
|
+
deactivatedAt: row.deactivated_at ? new Date(row.deactivated_at) : null,
|
|
1902
|
+
source: toPluginSource(row.source),
|
|
1903
|
+
marketplaceVersion: row.marketplace_version ?? null,
|
|
1904
|
+
displayName: row.display_name ?? null,
|
|
1905
|
+
description: row.description ?? null
|
|
1906
|
+
}));
|
|
1907
|
+
}
|
|
1908
|
+
/**
|
|
1909
|
+
* Get all marketplace-installed plugin states
|
|
1910
|
+
*/
|
|
1911
|
+
async getMarketplacePlugins() {
|
|
1912
|
+
return (await this.db.selectFrom("_plugin_state").selectAll().where("source", "=", "marketplace").execute()).map((row) => ({
|
|
1913
|
+
pluginId: row.plugin_id,
|
|
1914
|
+
status: toPluginStatus(row.status),
|
|
1915
|
+
version: row.version,
|
|
1916
|
+
installedAt: new Date(row.installed_at),
|
|
1917
|
+
activatedAt: row.activated_at ? new Date(row.activated_at) : null,
|
|
1918
|
+
deactivatedAt: row.deactivated_at ? new Date(row.deactivated_at) : null,
|
|
1919
|
+
source: toPluginSource(row.source),
|
|
1920
|
+
marketplaceVersion: row.marketplace_version ?? null,
|
|
1921
|
+
displayName: row.display_name ?? null,
|
|
1922
|
+
description: row.description ?? null
|
|
1923
|
+
}));
|
|
1924
|
+
}
|
|
1925
|
+
/**
|
|
1926
|
+
* Create or update plugin state
|
|
1927
|
+
*/
|
|
1928
|
+
async upsert(pluginId, version, status, opts) {
|
|
1929
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1930
|
+
const existing = await this.get(pluginId);
|
|
1931
|
+
if (existing) {
|
|
1932
|
+
const updates = {
|
|
1933
|
+
status,
|
|
1934
|
+
version
|
|
1935
|
+
};
|
|
1936
|
+
if (status === "active" && existing.status !== "active") updates.activated_at = now;
|
|
1937
|
+
else if (status === "inactive" && existing.status !== "inactive") updates.deactivated_at = now;
|
|
1938
|
+
if (opts?.source) updates.source = opts.source;
|
|
1939
|
+
if (opts?.marketplaceVersion !== void 0) updates.marketplace_version = opts.marketplaceVersion;
|
|
1940
|
+
if (opts?.displayName !== void 0) updates.display_name = opts.displayName;
|
|
1941
|
+
if (opts?.description !== void 0) updates.description = opts.description;
|
|
1942
|
+
await this.db.updateTable("_plugin_state").set(updates).where("plugin_id", "=", pluginId).execute();
|
|
1943
|
+
} else await this.db.insertInto("_plugin_state").values({
|
|
1944
|
+
plugin_id: pluginId,
|
|
1945
|
+
status,
|
|
1946
|
+
version,
|
|
1947
|
+
installed_at: now,
|
|
1948
|
+
activated_at: status === "active" ? now : null,
|
|
1949
|
+
deactivated_at: null,
|
|
1950
|
+
data: null,
|
|
1951
|
+
source: opts?.source ?? "config",
|
|
1952
|
+
marketplace_version: opts?.marketplaceVersion ?? null,
|
|
1953
|
+
display_name: opts?.displayName ?? null,
|
|
1954
|
+
description: opts?.description ?? null
|
|
1955
|
+
}).execute();
|
|
1956
|
+
return await this.get(pluginId);
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* Enable a plugin
|
|
1960
|
+
*/
|
|
1961
|
+
async enable(pluginId, version) {
|
|
1962
|
+
return this.upsert(pluginId, version, "active");
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Disable a plugin
|
|
1966
|
+
*/
|
|
1967
|
+
async disable(pluginId, version) {
|
|
1968
|
+
return this.upsert(pluginId, version, "inactive");
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Delete plugin state
|
|
1972
|
+
*/
|
|
1973
|
+
async delete(pluginId) {
|
|
1974
|
+
return ((await this.db.deleteFrom("_plugin_state").where("plugin_id", "=", pluginId).executeTakeFirst()).numDeletedRows ?? 0) > 0;
|
|
1975
|
+
}
|
|
1976
|
+
};
|
|
1977
|
+
|
|
1978
|
+
//#endregion
|
|
1979
|
+
//#region src/site-context/context-types.ts
|
|
1980
|
+
const SITE_CONTEXT_TYPES = [
|
|
1981
|
+
"brand_voice",
|
|
1982
|
+
"seo_strategy",
|
|
1983
|
+
"audience",
|
|
1984
|
+
"content_guideline",
|
|
1985
|
+
"forbidden_terms",
|
|
1986
|
+
"editorial_policy",
|
|
1987
|
+
"migration_note",
|
|
1988
|
+
"plugin_note",
|
|
1989
|
+
"agent_reasoning",
|
|
1990
|
+
"decision",
|
|
1991
|
+
"risk",
|
|
1992
|
+
"content_gap",
|
|
1993
|
+
"style_exception"
|
|
1994
|
+
];
|
|
1995
|
+
const SITE_CONTEXT_TYPE_SET = new Set(SITE_CONTEXT_TYPES);
|
|
1996
|
+
function isSiteContextType(value) {
|
|
1997
|
+
return SITE_CONTEXT_TYPE_SET.has(value);
|
|
1998
|
+
}
|
|
1999
|
+
|
|
1850
2000
|
//#endregion
|
|
1851
2001
|
//#region src/utils/hash.ts
|
|
1852
2002
|
/**
|
|
@@ -1901,7 +2051,8 @@ async function generateManifest(collections, plugins = {}) {
|
|
|
1901
2051
|
};
|
|
1902
2052
|
}
|
|
1903
2053
|
return {
|
|
1904
|
-
version:
|
|
2054
|
+
version: VERSION,
|
|
2055
|
+
commit: COMMIT,
|
|
1905
2056
|
hash: await hashString(JSON.stringify(manifestCollections)),
|
|
1906
2057
|
collections: manifestCollections,
|
|
1907
2058
|
plugins
|
|
@@ -2238,7 +2389,9 @@ async function handleMediaDelete(db, id) {
|
|
|
2238
2389
|
* ```
|
|
2239
2390
|
*/
|
|
2240
2391
|
async function getCollectionInfo(slug) {
|
|
2241
|
-
return
|
|
2392
|
+
return requestCached(`collection-info:${slug}`, async () => {
|
|
2393
|
+
return getCollectionInfoWithDb(await getDb(), slug);
|
|
2394
|
+
});
|
|
2242
2395
|
}
|
|
2243
2396
|
/**
|
|
2244
2397
|
* Get collection metadata with an explicit db handle.
|
|
@@ -2250,129 +2403,6 @@ async function getCollectionInfoWithDb(db, slug) {
|
|
|
2250
2403
|
return new SchemaRegistry(db).getCollection(slug);
|
|
2251
2404
|
}
|
|
2252
2405
|
|
|
2253
|
-
//#endregion
|
|
2254
|
-
//#region src/plugins/state.ts
|
|
2255
|
-
function toPluginStatus(value) {
|
|
2256
|
-
if (value === "active") return "active";
|
|
2257
|
-
return "inactive";
|
|
2258
|
-
}
|
|
2259
|
-
function toPluginSource(value) {
|
|
2260
|
-
if (value === "marketplace") return "marketplace";
|
|
2261
|
-
return "config";
|
|
2262
|
-
}
|
|
2263
|
-
/**
|
|
2264
|
-
* Repository for plugin state in the database
|
|
2265
|
-
*/
|
|
2266
|
-
var PluginStateRepository = class {
|
|
2267
|
-
constructor(db) {
|
|
2268
|
-
this.db = db;
|
|
2269
|
-
}
|
|
2270
|
-
/**
|
|
2271
|
-
* Get state for a specific plugin
|
|
2272
|
-
*/
|
|
2273
|
-
async get(pluginId) {
|
|
2274
|
-
const row = await this.db.selectFrom("_plugin_state").selectAll().where("plugin_id", "=", pluginId).executeTakeFirst();
|
|
2275
|
-
if (!row) return null;
|
|
2276
|
-
return {
|
|
2277
|
-
pluginId: row.plugin_id,
|
|
2278
|
-
status: toPluginStatus(row.status),
|
|
2279
|
-
version: row.version,
|
|
2280
|
-
installedAt: new Date(row.installed_at),
|
|
2281
|
-
activatedAt: row.activated_at ? new Date(row.activated_at) : null,
|
|
2282
|
-
deactivatedAt: row.deactivated_at ? new Date(row.deactivated_at) : null,
|
|
2283
|
-
source: toPluginSource(row.source),
|
|
2284
|
-
marketplaceVersion: row.marketplace_version ?? null,
|
|
2285
|
-
displayName: row.display_name ?? null,
|
|
2286
|
-
description: row.description ?? null
|
|
2287
|
-
};
|
|
2288
|
-
}
|
|
2289
|
-
/**
|
|
2290
|
-
* Get all plugin states
|
|
2291
|
-
*/
|
|
2292
|
-
async getAll() {
|
|
2293
|
-
return (await this.db.selectFrom("_plugin_state").selectAll().execute()).map((row) => ({
|
|
2294
|
-
pluginId: row.plugin_id,
|
|
2295
|
-
status: toPluginStatus(row.status),
|
|
2296
|
-
version: row.version,
|
|
2297
|
-
installedAt: new Date(row.installed_at),
|
|
2298
|
-
activatedAt: row.activated_at ? new Date(row.activated_at) : null,
|
|
2299
|
-
deactivatedAt: row.deactivated_at ? new Date(row.deactivated_at) : null,
|
|
2300
|
-
source: toPluginSource(row.source),
|
|
2301
|
-
marketplaceVersion: row.marketplace_version ?? null,
|
|
2302
|
-
displayName: row.display_name ?? null,
|
|
2303
|
-
description: row.description ?? null
|
|
2304
|
-
}));
|
|
2305
|
-
}
|
|
2306
|
-
/**
|
|
2307
|
-
* Get all marketplace-installed plugin states
|
|
2308
|
-
*/
|
|
2309
|
-
async getMarketplacePlugins() {
|
|
2310
|
-
return (await this.db.selectFrom("_plugin_state").selectAll().where("source", "=", "marketplace").execute()).map((row) => ({
|
|
2311
|
-
pluginId: row.plugin_id,
|
|
2312
|
-
status: toPluginStatus(row.status),
|
|
2313
|
-
version: row.version,
|
|
2314
|
-
installedAt: new Date(row.installed_at),
|
|
2315
|
-
activatedAt: row.activated_at ? new Date(row.activated_at) : null,
|
|
2316
|
-
deactivatedAt: row.deactivated_at ? new Date(row.deactivated_at) : null,
|
|
2317
|
-
source: toPluginSource(row.source),
|
|
2318
|
-
marketplaceVersion: row.marketplace_version ?? null,
|
|
2319
|
-
displayName: row.display_name ?? null,
|
|
2320
|
-
description: row.description ?? null
|
|
2321
|
-
}));
|
|
2322
|
-
}
|
|
2323
|
-
/**
|
|
2324
|
-
* Create or update plugin state
|
|
2325
|
-
*/
|
|
2326
|
-
async upsert(pluginId, version, status, opts) {
|
|
2327
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2328
|
-
const existing = await this.get(pluginId);
|
|
2329
|
-
if (existing) {
|
|
2330
|
-
const updates = {
|
|
2331
|
-
status,
|
|
2332
|
-
version
|
|
2333
|
-
};
|
|
2334
|
-
if (status === "active" && existing.status !== "active") updates.activated_at = now;
|
|
2335
|
-
else if (status === "inactive" && existing.status !== "inactive") updates.deactivated_at = now;
|
|
2336
|
-
if (opts?.source) updates.source = opts.source;
|
|
2337
|
-
if (opts?.marketplaceVersion !== void 0) updates.marketplace_version = opts.marketplaceVersion;
|
|
2338
|
-
if (opts?.displayName !== void 0) updates.display_name = opts.displayName;
|
|
2339
|
-
if (opts?.description !== void 0) updates.description = opts.description;
|
|
2340
|
-
await this.db.updateTable("_plugin_state").set(updates).where("plugin_id", "=", pluginId).execute();
|
|
2341
|
-
} else await this.db.insertInto("_plugin_state").values({
|
|
2342
|
-
plugin_id: pluginId,
|
|
2343
|
-
status,
|
|
2344
|
-
version,
|
|
2345
|
-
installed_at: now,
|
|
2346
|
-
activated_at: status === "active" ? now : null,
|
|
2347
|
-
deactivated_at: null,
|
|
2348
|
-
data: null,
|
|
2349
|
-
source: opts?.source ?? "config",
|
|
2350
|
-
marketplace_version: opts?.marketplaceVersion ?? null,
|
|
2351
|
-
display_name: opts?.displayName ?? null,
|
|
2352
|
-
description: opts?.description ?? null
|
|
2353
|
-
}).execute();
|
|
2354
|
-
return await this.get(pluginId);
|
|
2355
|
-
}
|
|
2356
|
-
/**
|
|
2357
|
-
* Enable a plugin
|
|
2358
|
-
*/
|
|
2359
|
-
async enable(pluginId, version) {
|
|
2360
|
-
return this.upsert(pluginId, version, "active");
|
|
2361
|
-
}
|
|
2362
|
-
/**
|
|
2363
|
-
* Disable a plugin
|
|
2364
|
-
*/
|
|
2365
|
-
async disable(pluginId, version) {
|
|
2366
|
-
return this.upsert(pluginId, version, "inactive");
|
|
2367
|
-
}
|
|
2368
|
-
/**
|
|
2369
|
-
* Delete plugin state
|
|
2370
|
-
*/
|
|
2371
|
-
async delete(pluginId) {
|
|
2372
|
-
return ((await this.db.deleteFrom("_plugin_state").where("plugin_id", "=", pluginId).executeTakeFirst()).numDeletedRows ?? 0) > 0;
|
|
2373
|
-
}
|
|
2374
|
-
};
|
|
2375
|
-
|
|
2376
2406
|
//#endregion
|
|
2377
2407
|
//#region src/sections/index.ts
|
|
2378
2408
|
/**
|
|
@@ -2693,7 +2723,7 @@ const contentListQuery = cursorPaginationQuery.extend({
|
|
|
2693
2723
|
const contentCreateBody = z$1.object({
|
|
2694
2724
|
data: z$1.record(z$1.string(), z$1.unknown()),
|
|
2695
2725
|
slug: z$1.string().nullish(),
|
|
2696
|
-
status: z$1.
|
|
2726
|
+
status: z$1.enum(["draft"]).optional(),
|
|
2697
2727
|
bylines: z$1.array(contentBylineInputSchema).optional(),
|
|
2698
2728
|
locale: localeCode.optional(),
|
|
2699
2729
|
translationOf: z$1.string().optional(),
|
|
@@ -2702,7 +2732,7 @@ const contentCreateBody = z$1.object({
|
|
|
2702
2732
|
const contentUpdateBody = z$1.object({
|
|
2703
2733
|
data: z$1.record(z$1.string(), z$1.unknown()).optional(),
|
|
2704
2734
|
slug: z$1.string().nullish(),
|
|
2705
|
-
status: z$1.
|
|
2735
|
+
status: z$1.enum(["draft"]).optional(),
|
|
2706
2736
|
authorId: z$1.string().nullish(),
|
|
2707
2737
|
bylines: z$1.array(contentBylineInputSchema).optional(),
|
|
2708
2738
|
_rev: z$1.string().optional().meta({ description: "Opaque revision token for optimistic concurrency" }),
|
|
@@ -2713,6 +2743,10 @@ const contentScheduleBody = z$1.object({ scheduledAt: z$1.string().min(1, "sched
|
|
|
2713
2743
|
description: "ISO 8601 datetime for scheduled publishing",
|
|
2714
2744
|
example: "2025-06-15T09:00:00Z"
|
|
2715
2745
|
}) }).meta({ id: "ContentScheduleBody" });
|
|
2746
|
+
const contentPublishBody = z$1.object({
|
|
2747
|
+
reviewRequestId: z$1.string().optional().meta({ description: "Approved review request ID for token-authenticated publish execution." }),
|
|
2748
|
+
review_request_id: z$1.string().optional().meta({ description: "Snake-case alias for reviewRequestId." })
|
|
2749
|
+
}).meta({ id: "ContentPublishBody" });
|
|
2716
2750
|
const contentPreviewUrlBody = z$1.object({
|
|
2717
2751
|
expiresIn: z$1.union([z$1.string(), z$1.number()]).optional(),
|
|
2718
2752
|
pathPattern: z$1.string().optional()
|
|
@@ -2805,14 +2839,8 @@ const mediaUpdateBody = z$1.object({
|
|
|
2805
2839
|
width: z$1.number().int().positive().optional(),
|
|
2806
2840
|
height: z$1.number().int().positive().optional()
|
|
2807
2841
|
}).meta({ id: "MediaUpdateBody" });
|
|
2808
|
-
/**
|
|
2809
|
-
const
|
|
2810
|
-
const mediaUploadUrlBody = z$1.object({
|
|
2811
|
-
filename: z$1.string().min(1, "filename is required"),
|
|
2812
|
-
contentType: z$1.string().min(1, "contentType is required"),
|
|
2813
|
-
size: z$1.number().int().positive().max(MAX_UPLOAD_SIZE, `File size must not exceed ${MAX_UPLOAD_SIZE / 1024 / 1024}MB`),
|
|
2814
|
-
contentHash: z$1.string().optional()
|
|
2815
|
-
}).meta({ id: "MediaUploadUrlBody" });
|
|
2842
|
+
/** Default maximum allowed file upload size (50 MB). */
|
|
2843
|
+
const DEFAULT_MAX_UPLOAD_SIZE = 50 * 1024 * 1024;
|
|
2816
2844
|
const mediaConfirmBody = z$1.object({
|
|
2817
2845
|
size: z$1.number().int().positive().optional(),
|
|
2818
2846
|
width: z$1.number().int().positive().optional(),
|
|
@@ -2875,9 +2903,11 @@ const collectionSupportValues = z$1.enum([
|
|
|
2875
2903
|
"search"
|
|
2876
2904
|
]);
|
|
2877
2905
|
const collectionSourcePattern = /^(template:.+|import:.+|manual|discovered|seed)$/;
|
|
2906
|
+
const urlPatternSchema = z$1.string().refine((value) => !value || value.includes("{slug}"), "URL pattern must include a {slug} placeholder");
|
|
2878
2907
|
const fieldTypeValues = z$1.enum([
|
|
2879
2908
|
"string",
|
|
2880
2909
|
"text",
|
|
2910
|
+
"url",
|
|
2881
2911
|
"number",
|
|
2882
2912
|
"integer",
|
|
2883
2913
|
"boolean",
|
|
@@ -2897,6 +2927,7 @@ const repeaterSubFieldSchema = z$1.object({
|
|
|
2897
2927
|
type: z$1.enum([
|
|
2898
2928
|
"string",
|
|
2899
2929
|
"text",
|
|
2930
|
+
"url",
|
|
2900
2931
|
"number",
|
|
2901
2932
|
"integer",
|
|
2902
2933
|
"boolean",
|
|
@@ -2928,7 +2959,7 @@ const createCollectionBody = z$1.object({
|
|
|
2928
2959
|
icon: z$1.string().optional(),
|
|
2929
2960
|
supports: z$1.array(collectionSupportValues).optional(),
|
|
2930
2961
|
source: z$1.string().regex(collectionSourcePattern).optional(),
|
|
2931
|
-
urlPattern:
|
|
2962
|
+
urlPattern: urlPatternSchema.optional(),
|
|
2932
2963
|
hasSeo: z$1.boolean().optional()
|
|
2933
2964
|
}).meta({ id: "CreateCollectionBody" });
|
|
2934
2965
|
const updateCollectionBody = z$1.object({
|
|
@@ -2937,7 +2968,7 @@ const updateCollectionBody = z$1.object({
|
|
|
2937
2968
|
description: z$1.string().optional(),
|
|
2938
2969
|
icon: z$1.string().optional(),
|
|
2939
2970
|
supports: z$1.array(collectionSupportValues).optional(),
|
|
2940
|
-
urlPattern:
|
|
2971
|
+
urlPattern: urlPatternSchema.nullish(),
|
|
2941
2972
|
hasSeo: z$1.boolean().optional(),
|
|
2942
2973
|
commentsEnabled: z$1.boolean().optional(),
|
|
2943
2974
|
commentsModeration: z$1.enum([
|
|
@@ -3115,6 +3146,148 @@ const commentCountsResponseSchema = z$1.object({
|
|
|
3115
3146
|
}).meta({ id: "CommentCountsResponse" });
|
|
3116
3147
|
const commentBulkResponseSchema = z$1.object({ affected: z$1.number().int() }).meta({ id: "CommentBulkResponse" });
|
|
3117
3148
|
|
|
3149
|
+
//#endregion
|
|
3150
|
+
//#region src/api/schemas/context.ts
|
|
3151
|
+
const csvList = z$1.string().optional().transform((value) => value?.split(",").map((item) => item.trim()).filter((item) => item.length > 0));
|
|
3152
|
+
const contextTypesQuery$1 = z$1.string().optional().transform((value, ctx) => {
|
|
3153
|
+
if (!value) return void 0;
|
|
3154
|
+
const types = value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
3155
|
+
const invalid = types.find((type) => !isSiteContextType(type));
|
|
3156
|
+
if (invalid) {
|
|
3157
|
+
ctx.addIssue({
|
|
3158
|
+
code: "custom",
|
|
3159
|
+
message: `Invalid context type: ${invalid}`
|
|
3160
|
+
});
|
|
3161
|
+
return z$1.NEVER;
|
|
3162
|
+
}
|
|
3163
|
+
return types;
|
|
3164
|
+
});
|
|
3165
|
+
const optionalBooleanQuery$1 = z$1.enum(["true", "false"]).optional().transform((value) => value === void 0 ? void 0 : value === "true");
|
|
3166
|
+
const contextEntryListQuery = z$1.object({
|
|
3167
|
+
q: z$1.string().optional(),
|
|
3168
|
+
scope: z$1.string().optional(),
|
|
3169
|
+
includeInherited: optionalBooleanQuery$1,
|
|
3170
|
+
contextTypes: contextTypesQuery$1,
|
|
3171
|
+
tags: csvList,
|
|
3172
|
+
createdByActorType: z$1.enum([
|
|
3173
|
+
"user",
|
|
3174
|
+
"api_token",
|
|
3175
|
+
"system"
|
|
3176
|
+
]).optional(),
|
|
3177
|
+
createdByActorId: z$1.string().optional(),
|
|
3178
|
+
currentOnly: optionalBooleanQuery$1,
|
|
3179
|
+
limit: z$1.coerce.number().int().min(1).max(100).optional(),
|
|
3180
|
+
cursor: z$1.string().optional()
|
|
3181
|
+
}).meta({ id: "ContextEntryListQuery" });
|
|
3182
|
+
const contextEntryStaleQuery = contextEntryListQuery.omit({
|
|
3183
|
+
q: true,
|
|
3184
|
+
currentOnly: true
|
|
3185
|
+
}).extend({ now: z$1.string().optional() }).meta({ id: "ContextEntryStaleQuery" });
|
|
3186
|
+
const contextEntryDiffQuery = z$1.object({
|
|
3187
|
+
since: z$1.string().min(1),
|
|
3188
|
+
scope: z$1.string().optional(),
|
|
3189
|
+
includeInherited: optionalBooleanQuery$1,
|
|
3190
|
+
now: z$1.string().optional()
|
|
3191
|
+
}).meta({ id: "ContextEntryDiffQuery" });
|
|
3192
|
+
const contextEntryCreateBody = z$1.object({
|
|
3193
|
+
scope: z$1.string().min(1),
|
|
3194
|
+
contextType: z$1.enum(SITE_CONTEXT_TYPES),
|
|
3195
|
+
title: z$1.string().min(1).max(200),
|
|
3196
|
+
body: z$1.string().min(1).max(2e4),
|
|
3197
|
+
tags: z$1.array(z$1.string()).max(50).optional(),
|
|
3198
|
+
policyKey: z$1.string().max(200).nullable().optional(),
|
|
3199
|
+
sourceActivityId: z$1.string().nullable().optional(),
|
|
3200
|
+
validUntil: z$1.string().nullable().optional()
|
|
3201
|
+
}).meta({ id: "ContextEntryCreateBody" });
|
|
3202
|
+
const contextEntrySupersedeBody = z$1.object({
|
|
3203
|
+
scope: z$1.string().min(1).optional(),
|
|
3204
|
+
contextType: z$1.enum(SITE_CONTEXT_TYPES).optional(),
|
|
3205
|
+
title: z$1.string().min(1).max(200),
|
|
3206
|
+
body: z$1.string().min(1).max(2e4),
|
|
3207
|
+
tags: z$1.array(z$1.string()).max(50).optional(),
|
|
3208
|
+
policyKey: z$1.string().max(200).nullable().optional(),
|
|
3209
|
+
sourceActivityId: z$1.string().nullable().optional(),
|
|
3210
|
+
validUntil: z$1.string().nullable().optional()
|
|
3211
|
+
}).meta({ id: "ContextEntrySupersedeBody" });
|
|
3212
|
+
const contextEntryReviewBody = z$1.object({
|
|
3213
|
+
reviewNote: z$1.string().max(5e3).nullable().optional(),
|
|
3214
|
+
validUntil: z$1.string().nullable().optional()
|
|
3215
|
+
}).meta({ id: "ContextEntryReviewBody" });
|
|
3216
|
+
|
|
3217
|
+
//#endregion
|
|
3218
|
+
//#region src/api/schemas/briefing.ts
|
|
3219
|
+
const optionalBooleanQuery = z$1.enum(["true", "false"]).optional().transform((value) => value === void 0 ? void 0 : value === "true");
|
|
3220
|
+
const contextTypesQuery = z$1.string().optional().transform((value, ctx) => {
|
|
3221
|
+
if (!value) return void 0;
|
|
3222
|
+
const types = value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
3223
|
+
const invalid = types.find((type) => !isSiteContextType(type));
|
|
3224
|
+
if (invalid) {
|
|
3225
|
+
ctx.addIssue({
|
|
3226
|
+
code: "custom",
|
|
3227
|
+
message: `Invalid context type: ${invalid}`
|
|
3228
|
+
});
|
|
3229
|
+
return z$1.NEVER;
|
|
3230
|
+
}
|
|
3231
|
+
return types;
|
|
3232
|
+
});
|
|
3233
|
+
const siteBriefingQuery = z$1.object({
|
|
3234
|
+
scope: z$1.string().optional(),
|
|
3235
|
+
since: z$1.string().optional(),
|
|
3236
|
+
contextTypes: contextTypesQuery,
|
|
3237
|
+
includeStale: optionalBooleanQuery,
|
|
3238
|
+
tokenBudget: z$1.coerce.number().int().min(1).max(1e5).optional(),
|
|
3239
|
+
activityLimit: z$1.coerce.number().int().min(1).max(100).optional()
|
|
3240
|
+
}).meta({ id: "SiteBriefingQuery" });
|
|
3241
|
+
|
|
3242
|
+
//#endregion
|
|
3243
|
+
//#region src/api/schemas/hitl-requests.ts
|
|
3244
|
+
const optionalStatus$1 = z$1.enum([
|
|
3245
|
+
"pending",
|
|
3246
|
+
"approved",
|
|
3247
|
+
"rejected"
|
|
3248
|
+
]).optional();
|
|
3249
|
+
const optionalPriority = z$1.enum([
|
|
3250
|
+
"low",
|
|
3251
|
+
"normal",
|
|
3252
|
+
"high",
|
|
3253
|
+
"urgent"
|
|
3254
|
+
]).optional();
|
|
3255
|
+
const hitlRequestListQuery = z$1.object({
|
|
3256
|
+
status: optionalStatus$1,
|
|
3257
|
+
priority: optionalPriority,
|
|
3258
|
+
actionType: z$1.string().optional(),
|
|
3259
|
+
scope: z$1.string().optional(),
|
|
3260
|
+
targetRefType: z$1.string().optional(),
|
|
3261
|
+
targetRefId: z$1.string().optional(),
|
|
3262
|
+
limit: z$1.coerce.number().int().min(1).max(100).optional(),
|
|
3263
|
+
cursor: z$1.string().optional()
|
|
3264
|
+
}).meta({ id: "HitlRequestListQuery" });
|
|
3265
|
+
const hitlRequestResolveBody = z$1.object({
|
|
3266
|
+
decision: z$1.enum(["approved", "rejected"]),
|
|
3267
|
+
reviewNote: z$1.string().max(5e3).nullable().optional()
|
|
3268
|
+
}).meta({ id: "HitlRequestResolveBody" });
|
|
3269
|
+
|
|
3270
|
+
//#endregion
|
|
3271
|
+
//#region src/api/schemas/review-requests.ts
|
|
3272
|
+
const optionalStatus = z$1.enum([
|
|
3273
|
+
"pending",
|
|
3274
|
+
"approved",
|
|
3275
|
+
"rejected"
|
|
3276
|
+
]).optional();
|
|
3277
|
+
const reviewRequestListQuery = z$1.object({
|
|
3278
|
+
status: optionalStatus,
|
|
3279
|
+
collection: z$1.string().optional(),
|
|
3280
|
+
entryId: z$1.string().optional(),
|
|
3281
|
+
scope: z$1.string().optional(),
|
|
3282
|
+
actionType: z$1.string().optional(),
|
|
3283
|
+
limit: z$1.coerce.number().int().min(1).max(100).optional(),
|
|
3284
|
+
cursor: z$1.string().optional()
|
|
3285
|
+
}).meta({ id: "ReviewRequestListQuery" });
|
|
3286
|
+
const reviewRequestResolveBody = z$1.object({
|
|
3287
|
+
decision: z$1.enum(["approved", "rejected"]),
|
|
3288
|
+
reviewNote: z$1.string().max(5e3).nullable().optional()
|
|
3289
|
+
}).meta({ id: "ReviewRequestResolveBody" });
|
|
3290
|
+
|
|
3118
3291
|
//#endregion
|
|
3119
3292
|
//#region src/api/schemas/auth.ts
|
|
3120
3293
|
const authenticatorTransport$1 = z$1.enum([
|
|
@@ -3164,6 +3337,10 @@ const inviteCompleteBody = z$1.object({
|
|
|
3164
3337
|
credential: registrationCredential$1,
|
|
3165
3338
|
name: z$1.string().optional()
|
|
3166
3339
|
}).meta({ id: "InviteCompleteBody" });
|
|
3340
|
+
const inviteRegisterOptionsBody = z$1.object({
|
|
3341
|
+
token: z$1.string().min(1),
|
|
3342
|
+
name: z$1.string().optional()
|
|
3343
|
+
}).meta({ id: "InviteRegisterOptionsBody" });
|
|
3167
3344
|
const magicLinkSendBody = z$1.object({ email: z$1.string().email() }).meta({ id: "MagicLinkSendBody" });
|
|
3168
3345
|
const passkeyOptionsBody = z$1.object({ email: z$1.string().email().optional() }).meta({ id: "PasskeyOptionsBody" });
|
|
3169
3346
|
const passkeyVerifyBody = z$1.object({ credential: authenticationCredential }).meta({ id: "PasskeyVerifyBody" });
|
|
@@ -3400,6 +3577,7 @@ const mediaReference = z$1.object({
|
|
|
3400
3577
|
mediaId: z$1.string(),
|
|
3401
3578
|
alt: z$1.string().optional()
|
|
3402
3579
|
});
|
|
3580
|
+
const resolvedMediaReference = mediaReference.extend({ url: z$1.string().optional() });
|
|
3403
3581
|
const socialSettings = z$1.object({
|
|
3404
3582
|
twitter: z$1.string().optional(),
|
|
3405
3583
|
github: z$1.string().optional(),
|
|
@@ -3430,8 +3608,8 @@ const settingsUpdateBody = z$1.object({
|
|
|
3430
3608
|
const siteSettingsSchema = z$1.object({
|
|
3431
3609
|
title: z$1.string().optional(),
|
|
3432
3610
|
tagline: z$1.string().optional(),
|
|
3433
|
-
logo:
|
|
3434
|
-
favicon:
|
|
3611
|
+
logo: resolvedMediaReference.optional(),
|
|
3612
|
+
favicon: resolvedMediaReference.optional(),
|
|
3435
3613
|
url: z$1.string().optional(),
|
|
3436
3614
|
postsPerPage: z$1.number().int().optional(),
|
|
3437
3615
|
dateFormat: z$1.string().optional(),
|
|
@@ -3713,7 +3891,8 @@ const redirectSchema = z$1.object({
|
|
|
3713
3891
|
}).meta({ id: "Redirect" });
|
|
3714
3892
|
const redirectListResponseSchema = z$1.object({
|
|
3715
3893
|
items: z$1.array(redirectSchema),
|
|
3716
|
-
nextCursor: z$1.string().optional()
|
|
3894
|
+
nextCursor: z$1.string().optional(),
|
|
3895
|
+
loopRedirectIds: z$1.array(z$1.string()).optional()
|
|
3717
3896
|
}).meta({ id: "RedirectListResponse" });
|
|
3718
3897
|
const notFoundEntrySchema = z$1.object({
|
|
3719
3898
|
id: z$1.string(),
|
|
@@ -4270,6 +4449,14 @@ function convertCodeBlock(block) {
|
|
|
4270
4449
|
};
|
|
4271
4450
|
}
|
|
4272
4451
|
|
|
4452
|
+
//#endregion
|
|
4453
|
+
//#region src/after.ts
|
|
4454
|
+
function after(fn) {
|
|
4455
|
+
Promise.resolve().then(fn).catch((error) => {
|
|
4456
|
+
console.error("[dineway] deferred task failed:", error);
|
|
4457
|
+
});
|
|
4458
|
+
}
|
|
4459
|
+
|
|
4273
4460
|
//#endregion
|
|
4274
4461
|
//#region src/preview/sidecar-client.ts
|
|
4275
4462
|
/**
|
|
@@ -5744,6 +5931,35 @@ function resolveHook(hook, pluginId) {
|
|
|
5744
5931
|
};
|
|
5745
5932
|
}
|
|
5746
5933
|
|
|
5934
|
+
//#endregion
|
|
5935
|
+
//#region src/auth/trusted-proxy.ts
|
|
5936
|
+
/**
|
|
5937
|
+
* RFC 7230 token characters for HTTP header names.
|
|
5938
|
+
* Invalid names throw when passed to `Headers.get()`.
|
|
5939
|
+
*/
|
|
5940
|
+
const HEADER_NAME_PATTERN = /^[!#$%&'*+\-.^_`|~0-9a-z]+$/;
|
|
5941
|
+
/** Cache for the env-derived value. `null` means "not yet parsed". */
|
|
5942
|
+
let envCache = null;
|
|
5943
|
+
function normalizeTrustedHeaders(names) {
|
|
5944
|
+
return names.map((name) => name.trim().toLowerCase()).filter((name) => name.length > 0 && HEADER_NAME_PATTERN.test(name));
|
|
5945
|
+
}
|
|
5946
|
+
function getEnvTrustedHeaders() {
|
|
5947
|
+
if (envCache !== null) return envCache;
|
|
5948
|
+
let raw;
|
|
5949
|
+
try {
|
|
5950
|
+
const importMetaEnv = import.meta.env;
|
|
5951
|
+
raw = (typeof process !== "undefined" ? process.env?.DINEWAY_TRUSTED_PROXY_HEADERS : void 0) || importMetaEnv?.DINEWAY_TRUSTED_PROXY_HEADERS;
|
|
5952
|
+
} catch {
|
|
5953
|
+
raw = void 0;
|
|
5954
|
+
}
|
|
5955
|
+
envCache = raw ? normalizeTrustedHeaders(raw.split(",")) : [];
|
|
5956
|
+
return envCache;
|
|
5957
|
+
}
|
|
5958
|
+
function getTrustedProxyHeaders(config) {
|
|
5959
|
+
if (config?.trustedProxyHeaders !== void 0) return normalizeTrustedHeaders(config.trustedProxyHeaders);
|
|
5960
|
+
return getEnvTrustedHeaders();
|
|
5961
|
+
}
|
|
5962
|
+
|
|
5747
5963
|
//#endregion
|
|
5748
5964
|
//#region src/plugins/request-meta.ts
|
|
5749
5965
|
/**
|
|
@@ -5765,6 +5981,18 @@ function parseFirstForwardedIp(header) {
|
|
|
5765
5981
|
return IP_PATTERN.test(trimmed) ? trimmed : null;
|
|
5766
5982
|
}
|
|
5767
5983
|
/**
|
|
5984
|
+
* Read an IP from an operator-declared trusted header. Forwarded-for style
|
|
5985
|
+
* headers are parsed as comma-separated lists and the first entry is used.
|
|
5986
|
+
*/
|
|
5987
|
+
function readIpFromHeader(headers, name) {
|
|
5988
|
+
const value = headers.get(name);
|
|
5989
|
+
if (!value) return null;
|
|
5990
|
+
if (name.endsWith("forwarded-for")) return parseFirstForwardedIp(value);
|
|
5991
|
+
const trimmed = value.trim();
|
|
5992
|
+
if (!trimmed) return null;
|
|
5993
|
+
return IP_PATTERN.test(trimmed) ? trimmed : null;
|
|
5994
|
+
}
|
|
5995
|
+
/**
|
|
5768
5996
|
* Get the runtime-provided `cf` object from the request, if present.
|
|
5769
5997
|
*/
|
|
5770
5998
|
function getCfObject(request) {
|
|
@@ -5793,13 +6021,15 @@ function extractGeo(cf) {
|
|
|
5793
6021
|
* 1. `CF-Connecting-IP` header — only trusted when a `cf` object is
|
|
5794
6022
|
* present on the request (proving the request came through a trusted
|
|
5795
6023
|
* edge/runtime that strips or overwrites client-supplied values).
|
|
5796
|
-
* 2. `X-Forwarded-For` header (first entry) —
|
|
5797
|
-
*
|
|
5798
|
-
* 3.
|
|
6024
|
+
* 2. `X-Forwarded-For` header (first entry) — trusted only with runtime
|
|
6025
|
+
* edge metadata.
|
|
6026
|
+
* 3. Operator-declared trusted proxy headers, tried in order.
|
|
6027
|
+
* 4. `null`
|
|
5799
6028
|
*/
|
|
5800
|
-
function extractRequestMeta(request) {
|
|
6029
|
+
function extractRequestMeta(request, configOrTrustedHeaders) {
|
|
5801
6030
|
const headers = request.headers;
|
|
5802
6031
|
const cf = getCfObject(request);
|
|
6032
|
+
const trustedHeaders = resolveTrustedHeaders(configOrTrustedHeaders);
|
|
5803
6033
|
let ip = null;
|
|
5804
6034
|
if (cf) {
|
|
5805
6035
|
const cfIp = headers.get("cf-connecting-ip")?.trim();
|
|
@@ -5809,6 +6039,13 @@ function extractRequestMeta(request) {
|
|
|
5809
6039
|
const xff = headers.get("x-forwarded-for");
|
|
5810
6040
|
ip = xff ? parseFirstForwardedIp(xff) : null;
|
|
5811
6041
|
}
|
|
6042
|
+
if (!ip) for (const name of trustedHeaders) {
|
|
6043
|
+
const value = readIpFromHeader(headers, name);
|
|
6044
|
+
if (value) {
|
|
6045
|
+
ip = value;
|
|
6046
|
+
break;
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
5812
6049
|
const userAgent = headers.get("user-agent")?.trim() || null;
|
|
5813
6050
|
const referer = headers.get("referer")?.trim() || null;
|
|
5814
6051
|
const geo = extractGeo(cf);
|
|
@@ -5819,6 +6056,10 @@ function extractRequestMeta(request) {
|
|
|
5819
6056
|
geo
|
|
5820
6057
|
};
|
|
5821
6058
|
}
|
|
6059
|
+
function resolveTrustedHeaders(value) {
|
|
6060
|
+
if (Array.isArray(value)) return normalizeTrustedHeaders(value);
|
|
6061
|
+
return getTrustedProxyHeaders(value);
|
|
6062
|
+
}
|
|
5822
6063
|
/**
|
|
5823
6064
|
* Headers that must never cross the RPC boundary to sandboxed plugins.
|
|
5824
6065
|
* Session tokens, auth credentials, and infrastructure headers are stripped
|
|
@@ -5858,6 +6099,7 @@ function sanitizeHeadersForSandbox(headers) {
|
|
|
5858
6099
|
*/
|
|
5859
6100
|
/** Stale lock threshold in minutes */
|
|
5860
6101
|
const STALE_LOCK_MINUTES = 10;
|
|
6102
|
+
const MAX_ONESHOT_RETRIES = 5;
|
|
5861
6103
|
/**
|
|
5862
6104
|
* Executes overdue cron tasks.
|
|
5863
6105
|
*
|
|
@@ -5918,12 +6160,30 @@ var CronExecutor = class {
|
|
|
5918
6160
|
hookFailed = true;
|
|
5919
6161
|
console.error(`[cron] Hook failed for ${task.plugin_id}:${task.task_name}:`, error);
|
|
5920
6162
|
}
|
|
5921
|
-
if (task.is_oneshot) if (hookFailed)
|
|
6163
|
+
if (task.is_oneshot) if (hookFailed) {
|
|
6164
|
+
const retryMeta = parsedData?.__dineway != null && typeof parsedData.__dineway === "object" ? parsedData.__dineway : void 0;
|
|
6165
|
+
const rawRetryCount = retryMeta?.retryCount;
|
|
6166
|
+
const retryCount = typeof rawRetryCount === "number" && Number.isFinite(rawRetryCount) && rawRetryCount > 0 ? Math.floor(rawRetryCount) : 0;
|
|
6167
|
+
if (retryCount >= MAX_ONESHOT_RETRIES) {
|
|
6168
|
+
console.error(`[cron] One-shot task ${task.plugin_id}:${task.task_name} exceeded ${MAX_ONESHOT_RETRIES} retries, removing`);
|
|
6169
|
+
await sql`
|
|
6170
|
+
DELETE FROM _dineway_cron_tasks WHERE id = ${task.id}
|
|
6171
|
+
`.execute(this.db);
|
|
6172
|
+
} else {
|
|
6173
|
+
const backoffMs = 6e4 * Math.pow(2, retryCount);
|
|
6174
|
+
await sql`
|
|
5922
6175
|
UPDATE _dineway_cron_tasks
|
|
5923
|
-
SET status = 'idle', locked_at = NULL, next_run_at = ${new Date(Date.now() +
|
|
6176
|
+
SET status = 'idle', locked_at = NULL, next_run_at = ${new Date(Date.now() + backoffMs).toISOString()}, data = ${JSON.stringify({
|
|
6177
|
+
...parsedData,
|
|
6178
|
+
__dineway: {
|
|
6179
|
+
...retryMeta,
|
|
6180
|
+
retryCount: retryCount + 1
|
|
6181
|
+
}
|
|
6182
|
+
})}
|
|
5924
6183
|
WHERE id = ${task.id}
|
|
5925
6184
|
`.execute(this.db);
|
|
5926
|
-
|
|
6185
|
+
}
|
|
6186
|
+
} else await sql`
|
|
5927
6187
|
DELETE FROM _dineway_cron_tasks WHERE id = ${task.id}
|
|
5928
6188
|
`.execute(this.db);
|
|
5929
6189
|
else await sql`
|
|
@@ -6174,6 +6434,19 @@ async function assertSeoEnabled(seoRepo, collection, seo) {
|
|
|
6174
6434
|
if (seo !== void 0 && !hasSeo) throw new Error(`Collection "${collection}" does not have SEO enabled. Remove the seo field or enable SEO on this collection.`);
|
|
6175
6435
|
return hasSeo;
|
|
6176
6436
|
}
|
|
6437
|
+
function toPluginContentItem(item) {
|
|
6438
|
+
return {
|
|
6439
|
+
id: item.id,
|
|
6440
|
+
type: item.type,
|
|
6441
|
+
slug: item.slug,
|
|
6442
|
+
status: item.status,
|
|
6443
|
+
data: item.data,
|
|
6444
|
+
createdAt: item.createdAt,
|
|
6445
|
+
updatedAt: item.updatedAt,
|
|
6446
|
+
publishedAt: item.publishedAt,
|
|
6447
|
+
locale: item.locale
|
|
6448
|
+
};
|
|
6449
|
+
}
|
|
6177
6450
|
/**
|
|
6178
6451
|
* Create read-only content access
|
|
6179
6452
|
*/
|
|
@@ -6184,13 +6457,7 @@ function createContentAccess(db) {
|
|
|
6184
6457
|
async get(collection, id) {
|
|
6185
6458
|
const item = await contentRepo.findById(collection, id);
|
|
6186
6459
|
if (!item) return null;
|
|
6187
|
-
const result =
|
|
6188
|
-
id: item.id,
|
|
6189
|
-
type: item.type,
|
|
6190
|
-
data: item.data,
|
|
6191
|
-
createdAt: item.createdAt,
|
|
6192
|
-
updatedAt: item.updatedAt
|
|
6193
|
-
};
|
|
6460
|
+
const result = toPluginContentItem(item);
|
|
6194
6461
|
if (await seoRepo.isEnabled(collection)) result.seo = await seoRepo.get(collection, item.id);
|
|
6195
6462
|
return result;
|
|
6196
6463
|
},
|
|
@@ -6206,15 +6473,10 @@ function createContentAccess(db) {
|
|
|
6206
6473
|
const result = await contentRepo.findMany(collection, {
|
|
6207
6474
|
limit: options?.limit ?? 50,
|
|
6208
6475
|
cursor: options?.cursor,
|
|
6209
|
-
orderBy
|
|
6476
|
+
orderBy,
|
|
6477
|
+
where: options?.where
|
|
6210
6478
|
});
|
|
6211
|
-
const items = result.items.map(
|
|
6212
|
-
id: item.id,
|
|
6213
|
-
type: item.type,
|
|
6214
|
-
data: item.data,
|
|
6215
|
-
createdAt: item.createdAt,
|
|
6216
|
-
updatedAt: item.updatedAt
|
|
6217
|
-
}));
|
|
6479
|
+
const items = result.items.map(toPluginContentItem);
|
|
6218
6480
|
if (items.length > 0 && await seoRepo.isEnabled(collection)) {
|
|
6219
6481
|
const seoMap = await seoRepo.getMany(collection, items.map((i) => i.id));
|
|
6220
6482
|
for (const item of items) {
|
|
@@ -6252,13 +6514,7 @@ function createContentAccessWithWrite(db) {
|
|
|
6252
6514
|
type: collection,
|
|
6253
6515
|
data: fields
|
|
6254
6516
|
});
|
|
6255
|
-
const result =
|
|
6256
|
-
id: item.id,
|
|
6257
|
-
type: item.type,
|
|
6258
|
-
data: item.data,
|
|
6259
|
-
createdAt: item.createdAt,
|
|
6260
|
-
updatedAt: item.updatedAt
|
|
6261
|
-
};
|
|
6517
|
+
const result = toPluginContentItem(item);
|
|
6262
6518
|
if (hasSeo) result.seo = seo !== void 0 ? await trxSeoRepo.upsert(collection, item.id, seo) : await trxSeoRepo.get(collection, item.id);
|
|
6263
6519
|
return result;
|
|
6264
6520
|
});
|
|
@@ -6274,13 +6530,7 @@ function createContentAccessWithWrite(db) {
|
|
|
6274
6530
|
if (!existing) throw new Error("Content not found");
|
|
6275
6531
|
return existing;
|
|
6276
6532
|
})();
|
|
6277
|
-
const result =
|
|
6278
|
-
id: item.id,
|
|
6279
|
-
type: item.type,
|
|
6280
|
-
data: item.data,
|
|
6281
|
-
createdAt: item.createdAt,
|
|
6282
|
-
updatedAt: item.updatedAt
|
|
6283
|
-
};
|
|
6533
|
+
const result = toPluginContentItem(item);
|
|
6284
6534
|
if (hasSeo) result.seo = seo !== void 0 ? await trxSeoRepo.upsert(collection, item.id, seo) : await trxSeoRepo.get(collection, item.id);
|
|
6285
6535
|
return result;
|
|
6286
6536
|
});
|
|
@@ -6340,17 +6590,18 @@ function createMediaAccessWithWrite(db, getUploadUrlFn, storage) {
|
|
|
6340
6590
|
getUploadUrl: getUploadUrlFn,
|
|
6341
6591
|
async upload(filename, contentType, bytes) {
|
|
6342
6592
|
if (!storage) throw new Error("Media upload() requires a storage backend. Configure storage in PluginContextFactoryOptions.");
|
|
6343
|
-
const
|
|
6593
|
+
const keyPrefix = ulid();
|
|
6344
6594
|
const basename = filename.split("/").pop() ?? filename;
|
|
6345
6595
|
const dotIdx = basename.lastIndexOf(".");
|
|
6346
|
-
const storageKey = `${
|
|
6596
|
+
const storageKey = `${keyPrefix}${dotIdx > 0 ? basename.slice(dotIdx).toLowerCase() : ""}`;
|
|
6347
6597
|
await storage.upload({
|
|
6348
6598
|
key: storageKey,
|
|
6349
6599
|
body: new Uint8Array(bytes),
|
|
6350
6600
|
contentType
|
|
6351
6601
|
});
|
|
6602
|
+
let media;
|
|
6352
6603
|
try {
|
|
6353
|
-
await mediaRepo.create({
|
|
6604
|
+
media = await mediaRepo.create({
|
|
6354
6605
|
filename: basename,
|
|
6355
6606
|
mimeType: contentType,
|
|
6356
6607
|
size: bytes.byteLength,
|
|
@@ -6364,7 +6615,7 @@ function createMediaAccessWithWrite(db, getUploadUrlFn, storage) {
|
|
|
6364
6615
|
throw error;
|
|
6365
6616
|
}
|
|
6366
6617
|
return {
|
|
6367
|
-
mediaId,
|
|
6618
|
+
mediaId: media.id,
|
|
6368
6619
|
storageKey,
|
|
6369
6620
|
url: `/_dineway/api/media/file/${storageKey}`
|
|
6370
6621
|
};
|
|
@@ -6779,6 +7030,8 @@ var HookPipeline = class HookPipeline {
|
|
|
6779
7030
|
while (remaining.length > 0) {
|
|
6780
7031
|
const ready = remaining.filter((hook) => hook.dependencies.every((dep) => sorted.some((s) => s.pluginId === dep)));
|
|
6781
7032
|
if (ready.length === 0) {
|
|
7033
|
+
const pluginIds = remaining.map((hook) => hook.pluginId).join(", ");
|
|
7034
|
+
console.warn(`[hooks] Hook dependency cycle or missing dependency detected among plugins: ${pluginIds}. Falling back to priority order.`);
|
|
6782
7035
|
remaining.sort((a, b) => a.priority - b.priority);
|
|
6783
7036
|
sorted.push(...remaining);
|
|
6784
7037
|
break;
|
|
@@ -6794,7 +7047,15 @@ var HookPipeline = class HookPipeline {
|
|
|
6794
7047
|
* Execute a hook with timeout
|
|
6795
7048
|
*/
|
|
6796
7049
|
async executeWithTimeout(fn, timeout) {
|
|
6797
|
-
|
|
7050
|
+
let timer;
|
|
7051
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
7052
|
+
timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Hook timeout after ${timeout}ms`)), timeout);
|
|
7053
|
+
});
|
|
7054
|
+
try {
|
|
7055
|
+
return await Promise.race([fn(), timeoutPromise]);
|
|
7056
|
+
} finally {
|
|
7057
|
+
if (timer) clearTimeout(timer);
|
|
7058
|
+
}
|
|
6798
7059
|
}
|
|
6799
7060
|
/**
|
|
6800
7061
|
* Run plugin:install hooks
|
|
@@ -6956,7 +7217,8 @@ var HookPipeline = class HookPipeline {
|
|
|
6956
7217
|
const { handler } = hook;
|
|
6957
7218
|
const event = {
|
|
6958
7219
|
id,
|
|
6959
|
-
collection
|
|
7220
|
+
collection,
|
|
7221
|
+
permanent: false
|
|
6960
7222
|
};
|
|
6961
7223
|
const ctx = this.getContext(hook.pluginId);
|
|
6962
7224
|
const start = Date.now();
|
|
@@ -6987,14 +7249,15 @@ var HookPipeline = class HookPipeline {
|
|
|
6987
7249
|
/**
|
|
6988
7250
|
* Run content:afterDelete hooks
|
|
6989
7251
|
*/
|
|
6990
|
-
async runContentAfterDelete(id, collection) {
|
|
7252
|
+
async runContentAfterDelete(id, collection, permanent) {
|
|
6991
7253
|
const hooks = this.getTypedHooks("content:afterDelete");
|
|
6992
7254
|
const results = [];
|
|
6993
7255
|
for (const hook of hooks) {
|
|
6994
7256
|
const { handler } = hook;
|
|
6995
7257
|
const event = {
|
|
6996
7258
|
id,
|
|
6997
|
-
collection
|
|
7259
|
+
collection,
|
|
7260
|
+
permanent
|
|
6998
7261
|
};
|
|
6999
7262
|
const ctx = this.getContext(hook.pluginId);
|
|
7000
7263
|
const start = Date.now();
|
|
@@ -7709,9 +7972,11 @@ async function devConsoleEmailDeliver(event, _ctx) {
|
|
|
7709
7972
|
var PluginRouteHandler = class {
|
|
7710
7973
|
contextFactory;
|
|
7711
7974
|
plugin;
|
|
7975
|
+
trustedProxyHeaders;
|
|
7712
7976
|
constructor(plugin, factoryOptions) {
|
|
7713
7977
|
this.plugin = plugin;
|
|
7714
7978
|
this.contextFactory = new PluginContextFactory(factoryOptions);
|
|
7979
|
+
this.trustedProxyHeaders = factoryOptions.trustedProxyHeaders ?? [];
|
|
7715
7980
|
}
|
|
7716
7981
|
/**
|
|
7717
7982
|
* Invoke a route by name
|
|
@@ -7744,7 +8009,7 @@ var PluginRouteHandler = class {
|
|
|
7744
8009
|
...this.contextFactory.createContext(this.plugin),
|
|
7745
8010
|
input: validatedInput,
|
|
7746
8011
|
request: options.request,
|
|
7747
|
-
requestMeta: extractRequestMeta(options.request)
|
|
8012
|
+
requestMeta: extractRequestMeta(options.request, this.trustedProxyHeaders)
|
|
7748
8013
|
};
|
|
7749
8014
|
try {
|
|
7750
8015
|
return {
|
|
@@ -7762,11 +8027,12 @@ var PluginRouteHandler = class {
|
|
|
7762
8027
|
},
|
|
7763
8028
|
status: error.status
|
|
7764
8029
|
};
|
|
8030
|
+
console.error(`[plugin:${this.plugin.id}] Route handler failed:`, error);
|
|
7765
8031
|
return {
|
|
7766
8032
|
success: false,
|
|
7767
8033
|
error: {
|
|
7768
8034
|
code: "INTERNAL_ERROR",
|
|
7769
|
-
message:
|
|
8035
|
+
message: "An internal error occurred"
|
|
7770
8036
|
},
|
|
7771
8037
|
status: 500
|
|
7772
8038
|
};
|
|
@@ -7922,7 +8188,8 @@ var PluginManager = class {
|
|
|
7922
8188
|
this.factoryOptions = {
|
|
7923
8189
|
db: options.db,
|
|
7924
8190
|
storage: options.storage,
|
|
7925
|
-
getUploadUrl: options.getUploadUrl
|
|
8191
|
+
getUploadUrl: options.getUploadUrl,
|
|
8192
|
+
trustedProxyHeaders: options.trustedProxyHeaders
|
|
7926
8193
|
};
|
|
7927
8194
|
}
|
|
7928
8195
|
/**
|
|
@@ -8051,9 +8318,9 @@ var PluginManager = class {
|
|
|
8051
8318
|
/**
|
|
8052
8319
|
* Run content:afterDelete hooks across all active plugins
|
|
8053
8320
|
*/
|
|
8054
|
-
async runContentAfterDelete(id, collection) {
|
|
8321
|
+
async runContentAfterDelete(id, collection, permanent) {
|
|
8055
8322
|
this.ensureInitialized();
|
|
8056
|
-
return this.hookPipeline.runContentAfterDelete(id, collection);
|
|
8323
|
+
return this.hookPipeline.runContentAfterDelete(id, collection, permanent);
|
|
8057
8324
|
}
|
|
8058
8325
|
/**
|
|
8059
8326
|
* Run content:afterPublish hooks across all active plugins
|
|
@@ -8834,11 +9101,19 @@ function isQueryOptions(value) {
|
|
|
8834
9101
|
}
|
|
8835
9102
|
function isContentListOptions(value) {
|
|
8836
9103
|
if (!isRecord(value)) return false;
|
|
9104
|
+
if ("where" in value && value.where !== void 0 && !isContentListWhere(value.where)) return false;
|
|
8837
9105
|
if ("limit" in value && value.limit !== void 0 && typeof value.limit !== "number") return false;
|
|
8838
9106
|
if ("cursor" in value && value.cursor !== void 0 && typeof value.cursor !== "string") return false;
|
|
8839
9107
|
if ("orderBy" in value && value.orderBy !== void 0 && !isOrderByRecord(value.orderBy)) return false;
|
|
8840
9108
|
return true;
|
|
8841
9109
|
}
|
|
9110
|
+
function isContentListWhere(value) {
|
|
9111
|
+
if (!isRecord(value)) return false;
|
|
9112
|
+
return Object.entries(value).every(([key, item]) => {
|
|
9113
|
+
if (key !== "status" && key !== "locale") return false;
|
|
9114
|
+
return item === void 0 || typeof item === "string";
|
|
9115
|
+
});
|
|
9116
|
+
}
|
|
8842
9117
|
function isContentWriteInput(value) {
|
|
8843
9118
|
return isRecord(value);
|
|
8844
9119
|
}
|
|
@@ -9232,7 +9507,7 @@ async function probeUrl(url) {
|
|
|
9232
9507
|
let normalizedUrl = url.trim();
|
|
9233
9508
|
if (!normalizedUrl.startsWith("http")) normalizedUrl = `https://${normalizedUrl}`;
|
|
9234
9509
|
normalizedUrl = normalizedUrl.replace(TRAILING_SLASHES_PATTERN, "");
|
|
9235
|
-
|
|
9510
|
+
await resolveAndValidateExternalUrl(normalizedUrl);
|
|
9236
9511
|
const results = [];
|
|
9237
9512
|
const probePromises = getUrlSources().map(async (source) => {
|
|
9238
9513
|
try {
|
|
@@ -10228,8 +10503,10 @@ async function getCommentCountWithDb(db, collection, contentId) {
|
|
|
10228
10503
|
* }
|
|
10229
10504
|
* ```
|
|
10230
10505
|
*/
|
|
10231
|
-
|
|
10232
|
-
return
|
|
10506
|
+
function getMenu(name) {
|
|
10507
|
+
return requestCached(`menu:${name}`, async () => {
|
|
10508
|
+
return getMenuWithDb(name, await getDb());
|
|
10509
|
+
});
|
|
10233
10510
|
}
|
|
10234
10511
|
/**
|
|
10235
10512
|
* Get menu by name with resolved URLs (with explicit db)
|
|
@@ -10369,6 +10646,7 @@ function interpolateUrlPattern(pattern, slug, id) {
|
|
|
10369
10646
|
async function resolveContentUrl(collection, entryId, db, urlPatterns) {
|
|
10370
10647
|
if (!entryId) return null;
|
|
10371
10648
|
try {
|
|
10649
|
+
validateIdentifier(collection, "menu item collection");
|
|
10372
10650
|
const row = (await sql`
|
|
10373
10651
|
SELECT slug FROM ${sql.ref(`ec_${collection}`)} WHERE id = ${entryId} LIMIT 1
|
|
10374
10652
|
`.execute(db)).rows[0];
|
|
@@ -10395,179 +10673,6 @@ async function resolveTaxonomyUrl(taxonomyId, db) {
|
|
|
10395
10673
|
return `/${taxonomy.name}/${taxonomy.slug}`;
|
|
10396
10674
|
}
|
|
10397
10675
|
|
|
10398
|
-
//#endregion
|
|
10399
|
-
//#region src/taxonomies/index.ts
|
|
10400
|
-
/**
|
|
10401
|
-
* Runtime API for taxonomies
|
|
10402
|
-
*
|
|
10403
|
-
* Provides functions to query taxonomy definitions and terms.
|
|
10404
|
-
*/
|
|
10405
|
-
/**
|
|
10406
|
-
* Get all taxonomy definitions
|
|
10407
|
-
*/
|
|
10408
|
-
async function getTaxonomyDefs() {
|
|
10409
|
-
return (await (await getDb()).selectFrom("_dineway_taxonomy_defs").selectAll().execute()).map((row) => ({
|
|
10410
|
-
id: row.id,
|
|
10411
|
-
name: row.name,
|
|
10412
|
-
label: row.label,
|
|
10413
|
-
labelSingular: row.label_singular ?? void 0,
|
|
10414
|
-
hierarchical: row.hierarchical === 1,
|
|
10415
|
-
collections: row.collections ? JSON.parse(row.collections) : []
|
|
10416
|
-
}));
|
|
10417
|
-
}
|
|
10418
|
-
/**
|
|
10419
|
-
* Get a single taxonomy definition by name
|
|
10420
|
-
*/
|
|
10421
|
-
async function getTaxonomyDef(name) {
|
|
10422
|
-
const row = await (await getDb()).selectFrom("_dineway_taxonomy_defs").selectAll().where("name", "=", name).executeTakeFirst();
|
|
10423
|
-
if (!row) return null;
|
|
10424
|
-
return {
|
|
10425
|
-
id: row.id,
|
|
10426
|
-
name: row.name,
|
|
10427
|
-
label: row.label,
|
|
10428
|
-
labelSingular: row.label_singular ?? void 0,
|
|
10429
|
-
hierarchical: row.hierarchical === 1,
|
|
10430
|
-
collections: row.collections ? JSON.parse(row.collections) : []
|
|
10431
|
-
};
|
|
10432
|
-
}
|
|
10433
|
-
/**
|
|
10434
|
-
* Get all terms for a taxonomy (as tree for hierarchical, flat for tags)
|
|
10435
|
-
*/
|
|
10436
|
-
async function getTaxonomyTerms(taxonomyName) {
|
|
10437
|
-
const db = await getDb();
|
|
10438
|
-
const def = await getTaxonomyDef(taxonomyName);
|
|
10439
|
-
if (!def) return [];
|
|
10440
|
-
const rows = await db.selectFrom("taxonomies").selectAll().where("name", "=", taxonomyName).orderBy("label", "asc").execute();
|
|
10441
|
-
const countsResult = await db.selectFrom("content_taxonomies").select(["taxonomy_id"]).select((eb) => eb.fn.count("entry_id").as("count")).groupBy("taxonomy_id").execute();
|
|
10442
|
-
const counts = /* @__PURE__ */ new Map();
|
|
10443
|
-
for (const row of countsResult) counts.set(row.taxonomy_id, row.count);
|
|
10444
|
-
const flatTerms = rows.map((row) => ({
|
|
10445
|
-
id: row.id,
|
|
10446
|
-
name: row.name,
|
|
10447
|
-
slug: row.slug,
|
|
10448
|
-
label: row.label,
|
|
10449
|
-
parent_id: row.parent_id,
|
|
10450
|
-
data: row.data
|
|
10451
|
-
}));
|
|
10452
|
-
if (def.hierarchical) return buildTree(flatTerms, counts);
|
|
10453
|
-
return flatTerms.map((term) => ({
|
|
10454
|
-
id: term.id,
|
|
10455
|
-
name: term.name,
|
|
10456
|
-
slug: term.slug,
|
|
10457
|
-
label: term.label,
|
|
10458
|
-
children: [],
|
|
10459
|
-
count: counts.get(term.id) ?? 0
|
|
10460
|
-
}));
|
|
10461
|
-
}
|
|
10462
|
-
/**
|
|
10463
|
-
* Get a single term by taxonomy and slug
|
|
10464
|
-
*/
|
|
10465
|
-
async function getTerm(taxonomyName, slug) {
|
|
10466
|
-
const db = await getDb();
|
|
10467
|
-
const row = await db.selectFrom("taxonomies").selectAll().where("name", "=", taxonomyName).where("slug", "=", slug).executeTakeFirst();
|
|
10468
|
-
if (!row) return null;
|
|
10469
|
-
const count = (await db.selectFrom("content_taxonomies").select((eb) => eb.fn.count("entry_id").as("count")).where("taxonomy_id", "=", row.id).executeTakeFirst())?.count ?? 0;
|
|
10470
|
-
const children = (await db.selectFrom("taxonomies").selectAll().where("parent_id", "=", row.id).orderBy("label", "asc").execute()).map((child) => ({
|
|
10471
|
-
id: child.id,
|
|
10472
|
-
name: child.name,
|
|
10473
|
-
slug: child.slug,
|
|
10474
|
-
label: child.label,
|
|
10475
|
-
parentId: child.parent_id ?? void 0,
|
|
10476
|
-
children: []
|
|
10477
|
-
}));
|
|
10478
|
-
return {
|
|
10479
|
-
id: row.id,
|
|
10480
|
-
name: row.name,
|
|
10481
|
-
slug: row.slug,
|
|
10482
|
-
label: row.label,
|
|
10483
|
-
parentId: row.parent_id ?? void 0,
|
|
10484
|
-
description: row.data ? JSON.parse(row.data).description : void 0,
|
|
10485
|
-
children,
|
|
10486
|
-
count
|
|
10487
|
-
};
|
|
10488
|
-
}
|
|
10489
|
-
/**
|
|
10490
|
-
* Get terms assigned to an entry
|
|
10491
|
-
*/
|
|
10492
|
-
async function getEntryTerms(collection, entryId, taxonomyName) {
|
|
10493
|
-
let query = (await getDb()).selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id").selectAll("taxonomies").where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "=", entryId);
|
|
10494
|
-
if (taxonomyName) query = query.where("taxonomies.name", "=", taxonomyName);
|
|
10495
|
-
return (await query.execute()).map((row) => ({
|
|
10496
|
-
id: row.id,
|
|
10497
|
-
name: row.name,
|
|
10498
|
-
slug: row.slug,
|
|
10499
|
-
label: row.label,
|
|
10500
|
-
parentId: row.parent_id ?? void 0,
|
|
10501
|
-
children: []
|
|
10502
|
-
}));
|
|
10503
|
-
}
|
|
10504
|
-
/**
|
|
10505
|
-
* Get terms for multiple entries in a single query (batched API)
|
|
10506
|
-
*
|
|
10507
|
-
* This is more efficient than calling getEntryTerms for each entry
|
|
10508
|
-
* when you need terms for a list of entries.
|
|
10509
|
-
*
|
|
10510
|
-
* @param collection - The collection type (e.g., "posts")
|
|
10511
|
-
* @param entryIds - Array of entry IDs
|
|
10512
|
-
* @param taxonomyName - The taxonomy name (e.g., "categories")
|
|
10513
|
-
* @returns Map from entry ID to array of terms
|
|
10514
|
-
*/
|
|
10515
|
-
async function getTermsForEntries(collection, entryIds, taxonomyName) {
|
|
10516
|
-
const result = /* @__PURE__ */ new Map();
|
|
10517
|
-
for (const id of entryIds) result.set(id, []);
|
|
10518
|
-
if (entryIds.length === 0) return result;
|
|
10519
|
-
const rows = await (await getDb()).selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id").select([
|
|
10520
|
-
"content_taxonomies.entry_id",
|
|
10521
|
-
"taxonomies.id",
|
|
10522
|
-
"taxonomies.name",
|
|
10523
|
-
"taxonomies.slug",
|
|
10524
|
-
"taxonomies.label",
|
|
10525
|
-
"taxonomies.parent_id"
|
|
10526
|
-
]).where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "in", entryIds).where("taxonomies.name", "=", taxonomyName).execute();
|
|
10527
|
-
for (const row of rows) {
|
|
10528
|
-
const entryId = row.entry_id;
|
|
10529
|
-
const term = {
|
|
10530
|
-
id: row.id,
|
|
10531
|
-
name: row.name,
|
|
10532
|
-
slug: row.slug,
|
|
10533
|
-
label: row.label,
|
|
10534
|
-
parentId: row.parent_id ?? void 0,
|
|
10535
|
-
children: []
|
|
10536
|
-
};
|
|
10537
|
-
const terms = result.get(entryId);
|
|
10538
|
-
if (terms) terms.push(term);
|
|
10539
|
-
}
|
|
10540
|
-
return result;
|
|
10541
|
-
}
|
|
10542
|
-
/**
|
|
10543
|
-
* Get entries by term (wraps getDinewayCollection)
|
|
10544
|
-
*/
|
|
10545
|
-
async function getEntriesByTerm(collection, taxonomyName, termSlug) {
|
|
10546
|
-
const { getDinewayCollection } = await import("./query-BiaPl_g2.mjs").then((n) => n.a);
|
|
10547
|
-
const { entries } = await getDinewayCollection(collection, { where: { [taxonomyName]: termSlug } });
|
|
10548
|
-
return entries;
|
|
10549
|
-
}
|
|
10550
|
-
/**
|
|
10551
|
-
* Build tree structure from flat terms
|
|
10552
|
-
*/
|
|
10553
|
-
function buildTree(flatTerms, counts) {
|
|
10554
|
-
const map = /* @__PURE__ */ new Map();
|
|
10555
|
-
const roots = [];
|
|
10556
|
-
for (const term of flatTerms) map.set(term.id, {
|
|
10557
|
-
id: term.id,
|
|
10558
|
-
name: term.name,
|
|
10559
|
-
slug: term.slug,
|
|
10560
|
-
label: term.label,
|
|
10561
|
-
parentId: term.parent_id ?? void 0,
|
|
10562
|
-
description: term.data ? JSON.parse(term.data).description : void 0,
|
|
10563
|
-
children: [],
|
|
10564
|
-
count: counts.get(term.id) ?? 0
|
|
10565
|
-
});
|
|
10566
|
-
for (const term of map.values()) if (term.parentId && map.has(term.parentId)) map.get(term.parentId).children.push(term);
|
|
10567
|
-
else roots.push(term);
|
|
10568
|
-
return roots;
|
|
10569
|
-
}
|
|
10570
|
-
|
|
10571
10676
|
//#endregion
|
|
10572
10677
|
//#region src/widgets/components.ts
|
|
10573
10678
|
/**
|
|
@@ -10680,18 +10785,52 @@ function getWidgetComponents$1() {
|
|
|
10680
10785
|
* Get a widget area by name, with all its widgets
|
|
10681
10786
|
*/
|
|
10682
10787
|
async function getWidgetArea(name) {
|
|
10683
|
-
const
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10788
|
+
const rows = await (await getDb()).selectFrom("_dineway_widget_areas as a").leftJoin("_dineway_widgets as w", "w.area_id", "a.id").select([
|
|
10789
|
+
"a.id as a_id",
|
|
10790
|
+
"a.name as a_name",
|
|
10791
|
+
"a.label as a_label",
|
|
10792
|
+
"a.description as a_description",
|
|
10793
|
+
"w.id as w_id",
|
|
10794
|
+
"w.type as w_type",
|
|
10795
|
+
"w.title as w_title",
|
|
10796
|
+
"w.content as w_content",
|
|
10797
|
+
"w.menu_name as w_menu_name",
|
|
10798
|
+
"w.component_id as w_component_id",
|
|
10799
|
+
"w.component_props as w_component_props",
|
|
10800
|
+
"w.area_id as w_area_id",
|
|
10801
|
+
"w.sort_order as w_sort_order",
|
|
10802
|
+
"w.created_at as w_created_at"
|
|
10803
|
+
]).where("a.name", "=", name).orderBy("w.sort_order", "asc").execute();
|
|
10804
|
+
const first = rows[0];
|
|
10805
|
+
if (!first) return null;
|
|
10806
|
+
const widgets = [];
|
|
10807
|
+
for (const row of rows) {
|
|
10808
|
+
if (!row.w_id || !isWidgetType(row.w_type) || !row.w_area_id || row.w_sort_order === null || !row.w_created_at) continue;
|
|
10809
|
+
const widgetRow = {
|
|
10810
|
+
id: row.w_id,
|
|
10811
|
+
type: row.w_type,
|
|
10812
|
+
title: row.w_title,
|
|
10813
|
+
content: row.w_content,
|
|
10814
|
+
menu_name: row.w_menu_name,
|
|
10815
|
+
component_id: row.w_component_id,
|
|
10816
|
+
component_props: row.w_component_props,
|
|
10817
|
+
area_id: row.w_area_id,
|
|
10818
|
+
sort_order: row.w_sort_order,
|
|
10819
|
+
created_at: row.w_created_at
|
|
10820
|
+
};
|
|
10821
|
+
widgets.push(rowToWidget(widgetRow));
|
|
10822
|
+
}
|
|
10687
10823
|
return {
|
|
10688
|
-
id:
|
|
10689
|
-
name:
|
|
10690
|
-
label:
|
|
10691
|
-
description:
|
|
10824
|
+
id: first.a_id,
|
|
10825
|
+
name: first.a_name,
|
|
10826
|
+
label: first.a_label,
|
|
10827
|
+
description: first.a_description ?? void 0,
|
|
10692
10828
|
widgets
|
|
10693
10829
|
};
|
|
10694
10830
|
}
|
|
10831
|
+
function isWidgetType(value) {
|
|
10832
|
+
return value === "content" || value === "menu" || value === "component";
|
|
10833
|
+
}
|
|
10695
10834
|
/**
|
|
10696
10835
|
* Get all widget areas with their widgets
|
|
10697
10836
|
*/
|
|
@@ -10746,6 +10885,9 @@ function rowToWidget(row) {
|
|
|
10746
10885
|
const WHITESPACE_SPLIT_PATTERN = /\s+/;
|
|
10747
10886
|
const FTS_OPERATORS_PATTERN = /\b(AND|OR|NOT|NEAR)\b/i;
|
|
10748
10887
|
const DOUBLE_QUOTE_PATTERN = /"/g;
|
|
10888
|
+
function searchResultDisplayColumn(searchableFields) {
|
|
10889
|
+
return searchableFields.includes("title") ? "title" : "slug";
|
|
10890
|
+
}
|
|
10749
10891
|
/**
|
|
10750
10892
|
* Search across multiple collections
|
|
10751
10893
|
*
|
|
@@ -10836,6 +10978,8 @@ async function searchSingleCollection(db, collection, query, options, weights) {
|
|
|
10836
10978
|
const escapedQuery = escapeQuery(query);
|
|
10837
10979
|
if (!escapedQuery) return [];
|
|
10838
10980
|
const searchableFields = await ftsManager.getSearchableFields(collection);
|
|
10981
|
+
const displayColumn = searchResultDisplayColumn(searchableFields);
|
|
10982
|
+
const displayColumnSql = sql`c.${sql.ref(displayColumn)}`;
|
|
10839
10983
|
let bm25Args = "";
|
|
10840
10984
|
if (weights && searchableFields.length > 0) {
|
|
10841
10985
|
const weightValues = ["0", "0"];
|
|
@@ -10844,13 +10988,13 @@ async function searchSingleCollection(db, collection, query, options, weights) {
|
|
|
10844
10988
|
}
|
|
10845
10989
|
const bm25Expr = bm25Args ? `bm25("${ftsTable}", ${bm25Args})` : `bm25("${ftsTable}")`;
|
|
10846
10990
|
return (await sql`
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
|
|
10852
|
-
|
|
10853
|
-
|
|
10991
|
+
SELECT
|
|
10992
|
+
c.id,
|
|
10993
|
+
c.slug,
|
|
10994
|
+
c.locale,
|
|
10995
|
+
${displayColumnSql} as title,
|
|
10996
|
+
snippet("${sql.raw(ftsTable)}", 2, '<mark>', '</mark>', '...', 32) as snippet,
|
|
10997
|
+
${sql.raw(bm25Expr)} as score
|
|
10854
10998
|
FROM "${sql.raw(ftsTable)}" f
|
|
10855
10999
|
JOIN "${sql.raw(contentTable)}" c ON f.id = c.id
|
|
10856
11000
|
WHERE "${sql.raw(ftsTable)}" MATCH ${escapedQuery}
|
|
@@ -10890,18 +11034,20 @@ async function getSuggestions(db, query, options = {}) {
|
|
|
10890
11034
|
validateIdentifier(collection, "collection slug");
|
|
10891
11035
|
const ftsTable = ftsManager.getFtsTableName(collection);
|
|
10892
11036
|
const contentTable = ftsManager.getContentTableName(collection);
|
|
10893
|
-
const
|
|
10894
|
-
|
|
11037
|
+
const displayColumn = searchResultDisplayColumn(await ftsManager.getSearchableFields(collection));
|
|
11038
|
+
const displayColumnSql = sql`c.${sql.ref(displayColumn)}`;
|
|
11039
|
+
const prefixQuery = escapeQuery(query);
|
|
11040
|
+
if (!prefixQuery) continue;
|
|
10895
11041
|
const results = await sql`
|
|
10896
|
-
SELECT
|
|
11042
|
+
SELECT
|
|
10897
11043
|
c.id,
|
|
10898
|
-
|
|
11044
|
+
${displayColumnSql} as title
|
|
10899
11045
|
FROM "${sql.raw(ftsTable)}" f
|
|
10900
11046
|
JOIN "${sql.raw(contentTable)}" c ON f.id = c.id
|
|
10901
11047
|
WHERE "${sql.raw(ftsTable)}" MATCH ${prefixQuery}
|
|
10902
11048
|
AND c.status = 'published'
|
|
10903
11049
|
AND c.deleted_at IS NULL
|
|
10904
|
-
AND
|
|
11050
|
+
AND ${displayColumnSql} IS NOT NULL
|
|
10905
11051
|
${locale ? sql`AND c.locale = ${locale}` : sql``}
|
|
10906
11052
|
ORDER BY bm25("${sql.raw(ftsTable)}")
|
|
10907
11053
|
LIMIT ${limit}
|
|
@@ -11051,4 +11197,4 @@ function extractSearchableFields(entry, fields) {
|
|
|
11051
11197
|
}
|
|
11052
11198
|
|
|
11053
11199
|
//#endregion
|
|
11054
|
-
export {
|
|
11200
|
+
export { createFilePreviewMiddleware as $, validateRev as $t, isStandardPluginDefinition as A, generateManifest as At, DEV_CONSOLE_EMAIL_PLUGIN_ID as B, handleContentDuplicate as Bt, getAllSources as C, handleMediaDelete as Ct, probeUrl as D, handleRevisionGet as Dt, getUrlSources as E, handleMediaUpdate as Et, createNoopSandboxRunner as F, handleContentCountScheduled as Ft, resolveExclusiveHooks as G, handleContentPermanentDelete as Gt, EmailPipeline as H, handleContentGetIncludingTrashed as Ht, PluginManager as I, handleContentCountTrashed as It, sanitizeHeadersForSandbox as J, handleContentSchedule as Jt, CronExecutor as K, handleContentPublish as Kt, createPluginManager as L, handleContentCreate as Lt, createNodeSandboxRunner as M, hashString as Mt, NoopSandboxRunner as N, PluginStateRepository as Nt, registerSource as O, handleRevisionList as Ot, SandboxNotAvailableError as P, handleContentCompare as Pt, parseWxrString as Q, handleContentUpdate as Qt, PluginRouteError as R, handleContentDelete as Rt, clearSources as S, handleMediaCreate as St, getSource as T, handleMediaList as Tt, HookPipeline as U, handleContentList as Ut, devConsoleEmailDeliver as V, handleContentGet as Vt, createHookPipeline as W, handleContentListTrashed as Wt, definePlugin as X, handleContentUnpublish as Xt, getTrustedProxyHeaders as Y, handleContentTranslations as Yt, parseWxr as Z, handleContentUnschedule as Zt, buildPreviewUrl as _, sanitizeHref as _t, search as a, SessionDatabaseLimitError as at, parseWxrDate as b, getSections as bt, getWidgetArea as c, buildPreviewSignatureHeader as ct, getMenu as d, signPreviewUrl as dt, portableText as en, renderPreviewToolbar as et, getMenus as f, verifyPreviewSignature as ft, isPreviewRequest as g, isSafeHref as gt, getPreviewToken as h, prosemirrorToPortableText as ht, getSuggestions as i, FileSessionDatabaseFactory as it, NodeSandboxRunner as j, computeContentHash as jt, importReusableBlocksAsSections as k, handleRevisionRestore as kt, getWidgetAreas as l, defaultPreviewSidecarClient as lt, getComments as m, portableTextToProsemirror as mt, extractSearchableFields as n, image as nn, dropSessionDatabaseTables as nt, searchCollection as o, isBlockedInPreview as ot, getCommentCount as p, after as pt, extractRequestMeta as q, handleContentRestore as qt, getSearchStats as r, getAppliedSnapshotMeta as rt, searchWithDb as s, renderPreviewLoadingPage as st, extractPlainText as t, reference as tn, applySnapshotToDatabase as tt, getWidgetComponents as u, parsePreviewSignatureHeader as ut, getPreviewUrl as v, createPluginBundleStore as vt, getFileSources as w, handleMediaGet as wt, wxrSource as x, getCollectionInfo as xt, wordpressRestSource as y, getSection as yt, PluginRouteRegistry as z, handleContentDiscardDraft as zt };
|