emdash 0.7.0 → 0.9.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/{adapters-Di31kZ28.d.mts → adapters-DoNJiveC.d.mts} +1 -1
- package/dist/{adapters-Di31kZ28.d.mts.map → adapters-DoNJiveC.d.mts.map} +1 -1
- package/dist/{apply-5uslYdUu.mjs → apply-BzltprvY.mjs} +90 -139
- package/dist/apply-BzltprvY.mjs.map +1 -0
- package/dist/astro/index.d.mts +6 -6
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +194 -17
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +6 -7
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +34 -57
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +17 -12
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.d.mts.map +1 -1
- package/dist/astro/middleware/request-context.mjs +9 -6
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +301 -165
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/types.d.mts +34 -10
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{base64-MBPo9ozB.mjs → base64-BRICGH2l.mjs} +1 -1
- package/dist/{base64-MBPo9ozB.mjs.map → base64-BRICGH2l.mjs.map} +1 -1
- package/dist/{byline-C4OVd8b3.mjs → byline-BSaNL1w7.mjs} +5 -5
- package/dist/byline-BSaNL1w7.mjs.map +1 -0
- package/dist/bylines-CvJ3PYz2.mjs +113 -0
- package/dist/bylines-CvJ3PYz2.mjs.map +1 -0
- package/dist/cache-C6N_hhN7.mjs +65 -0
- package/dist/cache-C6N_hhN7.mjs.map +1 -0
- package/dist/{chunks-HGz06Soa.mjs → chunks-NBQVDOci.mjs} +8 -2
- package/dist/{chunks-HGz06Soa.mjs.map → chunks-NBQVDOci.mjs.map} +1 -1
- package/dist/cli/index.mjs +229 -31
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +3 -3
- package/dist/client/index.mjs.map +1 -1
- package/dist/{config-BXwuX8Bx.mjs → config-BI0V3ICQ.mjs} +1 -1
- package/dist/{config-BXwuX8Bx.mjs.map → config-BI0V3ICQ.mjs.map} +1 -1
- package/dist/{content-D7J5y73J.mjs → content-8lOYF0pr.mjs} +43 -28
- package/dist/content-8lOYF0pr.mjs.map +1 -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.d.mts.map +1 -1
- package/dist/db/libsql.mjs +7 -2
- package/dist/db/libsql.mjs.map +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.d.mts.map +1 -1
- package/dist/db/sqlite.mjs +8 -3
- package/dist/db/sqlite.mjs.map +1 -1
- package/dist/{db-errors-D0UT85nC.mjs → db-errors-WRezodiz.mjs} +1 -1
- package/dist/{db-errors-D0UT85nC.mjs.map → db-errors-WRezodiz.mjs.map} +1 -1
- package/dist/{default-CME5YdZ3.mjs → default-D8ksjWhO.mjs} +1 -1
- package/dist/{default-CME5YdZ3.mjs.map → default-D8ksjWhO.mjs.map} +1 -1
- package/dist/{dialect-helpers-DhTzaUxP.mjs → dialect-helpers-BKCvISIQ.mjs} +19 -2
- package/dist/dialect-helpers-BKCvISIQ.mjs.map +1 -0
- package/dist/{error-CiYn9yDu.mjs → error-D_-tqP-I.mjs} +1 -1
- package/dist/error-D_-tqP-I.mjs.map +1 -0
- package/dist/{index-De6_Xv3v.d.mts → index-BFRaVcD6.d.mts} +243 -40
- package/dist/index-BFRaVcD6.d.mts.map +1 -0
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +29 -25
- package/dist/{load-CBcmDIot.mjs → load-DDqMMvZL.mjs} +2 -2
- package/dist/{load-CBcmDIot.mjs.map → load-DDqMMvZL.mjs.map} +1 -1
- package/dist/{loader-DeiBJEMe.mjs → loader-CKLbBnhK.mjs} +32 -10
- package/dist/loader-CKLbBnhK.mjs.map +1 -0
- package/dist/{manifest-schema-V30qsMft.mjs → manifest-schema-DqWNC3lM.mjs} +45 -3
- package/dist/manifest-schema-DqWNC3lM.mjs.map +1 -0
- 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/media/local-runtime.mjs +3 -3
- package/dist/{media-DqHVh136.mjs → media-BW32b4gi.mjs} +4 -7
- package/dist/media-BW32b4gi.mjs.map +1 -0
- package/dist/{mode-CpNnGkPz.mjs → mode-ier8jbBk.mjs} +1 -1
- package/dist/mode-ier8jbBk.mjs.map +1 -0
- package/dist/options-BVp3UsTS.mjs +117 -0
- package/dist/options-BVp3UsTS.mjs.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{placeholder-tzpqGWII.d.mts → placeholder-BE4o_2dc.d.mts} +1 -1
- package/dist/{placeholder-tzpqGWII.d.mts.map → placeholder-BE4o_2dc.d.mts.map} +1 -1
- package/dist/{placeholder-C-fk5hYI.mjs → placeholder-CIJejMlK.mjs} +1 -1
- package/dist/placeholder-CIJejMlK.mjs.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.mjs +6 -5
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
- package/dist/public-url-DByxYjUw.mjs +51 -0
- package/dist/public-url-DByxYjUw.mjs.map +1 -0
- package/dist/{query-g4Ug-9j9.mjs → query-Cg9ZKRQ0.mjs} +114 -16
- package/dist/query-Cg9ZKRQ0.mjs.map +1 -0
- package/dist/{redirect-CN0Rt9Ob.mjs → redirect-BhUBKRc1.mjs} +13 -8
- package/dist/redirect-BhUBKRc1.mjs.map +1 -0
- package/dist/{registry-Ci3WxVAr.mjs → registry-Dw70ChxB.mjs} +69 -11
- package/dist/registry-Dw70ChxB.mjs.map +1 -0
- package/dist/{request-cache-DiR961CV.mjs → request-cache-B-bmkipQ.mjs} +1 -1
- package/dist/request-cache-B-bmkipQ.mjs.map +1 -0
- package/dist/runner-Bnoj7vjK.d.mts +44 -0
- package/dist/runner-Bnoj7vjK.d.mts.map +1 -0
- package/dist/{runner-tQ7BJ4T7.mjs → runner-C7ADox5q.mjs} +185 -55
- package/dist/{runner-tQ7BJ4T7.mjs.map → runner-C7ADox5q.mjs.map} +1 -1
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +4 -4
- package/dist/{search-B0effn3j.mjs → search-dOGEccMa.mjs} +341 -152
- package/dist/search-dOGEccMa.mjs.map +1 -0
- package/dist/secrets-CW3reAnU.mjs +314 -0
- package/dist/secrets-CW3reAnU.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +15 -14
- 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 +1 -1
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +4 -4
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{taxonomies-K2z0Uhnj.mjs → taxonomies-ZlRtD6AG.mjs} +14 -7
- package/dist/taxonomies-ZlRtD6AG.mjs.map +1 -0
- package/dist/{tokens-BFPFx3CA.mjs → tokens-D7zMmWi2.mjs} +2 -2
- package/dist/{tokens-BFPFx3CA.mjs.map → tokens-D7zMmWi2.mjs.map} +1 -1
- package/dist/{transport-BykRfpyy.mjs → transport-BeMCmin1.mjs} +6 -5
- package/dist/{transport-BykRfpyy.mjs.map → transport-BeMCmin1.mjs.map} +1 -1
- package/dist/{transport-H4Iwx7tC.d.mts → transport-DNEfeMaU.d.mts} +1 -1
- package/dist/{transport-H4Iwx7tC.d.mts.map → transport-DNEfeMaU.d.mts.map} +1 -1
- package/dist/types-4fVtCIm0.mjs +68 -0
- package/dist/types-4fVtCIm0.mjs.map +1 -0
- package/dist/{types-CnZYHyLW.d.mts → types-BSyXeCFW.d.mts} +24 -2
- package/dist/{types-CnZYHyLW.d.mts.map → types-BSyXeCFW.d.mts.map} +1 -1
- package/dist/{types-DgrIP0tF.d.mts → types-BuBIptGk.d.mts} +80 -106
- package/dist/types-BuBIptGk.d.mts.map +1 -0
- package/dist/{types-BH2L167P.mjs → types-CDbKp7ND.mjs} +1 -1
- package/dist/{types-BH2L167P.mjs.map → types-CDbKp7ND.mjs.map} +1 -1
- package/dist/{types-DDS4MxsT.mjs → types-CIOg5AR8.mjs} +1 -1
- package/dist/{types-DDS4MxsT.mjs.map → types-CIOg5AR8.mjs.map} +1 -1
- package/dist/{types-6CUZRrZP.d.mts → types-CJsYGpco.d.mts} +24 -2
- package/dist/{types-6CUZRrZP.d.mts.map → types-CJsYGpco.d.mts.map} +1 -1
- package/dist/types-CRxNbK-Z.mjs +68 -0
- package/dist/types-CRxNbK-Z.mjs.map +1 -0
- package/dist/{types-C2v0c34j.d.mts → types-CrtWgIvl.d.mts} +1 -1
- package/dist/{types-C2v0c34j.d.mts.map → types-CrtWgIvl.d.mts.map} +1 -1
- package/dist/{types-CFWjXmus.d.mts → types-M78DQ1lx.d.mts} +1 -1
- package/dist/{types-CFWjXmus.d.mts.map → types-M78DQ1lx.d.mts.map} +1 -1
- package/dist/{validate-CqsNItbt.mjs → validate-Baqf0slj.mjs} +3 -3
- package/dist/{validate-CqsNItbt.mjs.map → validate-Baqf0slj.mjs.map} +1 -1
- package/dist/{validate-kM8Pjuf7.d.mts → validate-BfQh_C_y.d.mts} +4 -4
- package/dist/{validate-kM8Pjuf7.d.mts.map → validate-BfQh_C_y.d.mts.map} +1 -1
- package/dist/validation-BfEI7tNe.mjs +144 -0
- package/dist/validation-BfEI7tNe.mjs.map +1 -0
- package/dist/version-DoxrVdYf.mjs +7 -0
- package/dist/{version-BnTKdfam.mjs.map → version-DoxrVdYf.mjs.map} +1 -1
- package/dist/zod-generator-CC0xNe_K.mjs +132 -0
- package/dist/zod-generator-CC0xNe_K.mjs.map +1 -0
- package/locals.d.ts +1 -6
- package/package.json +21 -7
- package/src/api/auth-storage.ts +37 -0
- package/src/api/error.ts +6 -0
- package/src/api/errors.ts +8 -0
- package/src/api/handlers/comments.ts +19 -4
- package/src/api/handlers/content.ts +151 -4
- package/src/api/handlers/device-flow.ts +5 -0
- package/src/api/handlers/index.ts +2 -0
- package/src/api/handlers/marketplace.ts +11 -4
- package/src/api/handlers/media.ts +8 -1
- package/src/api/handlers/menus.ts +160 -21
- package/src/api/handlers/oauth-authorization.ts +72 -33
- package/src/api/handlers/redirects.ts +16 -3
- package/src/api/handlers/revision.ts +23 -14
- package/src/api/handlers/sections.ts +8 -1
- package/src/api/handlers/taxonomies.ts +131 -22
- package/src/api/handlers/validation.ts +212 -0
- package/src/api/openapi/document.ts +4 -1
- package/src/api/public-url.ts +54 -5
- package/src/api/route-utils.ts +14 -0
- package/src/api/schemas/comments.ts +2 -2
- package/src/api/schemas/common.ts +1 -1
- package/src/api/schemas/content.ts +17 -0
- package/src/api/schemas/sections.ts +3 -3
- package/src/api/schemas/setup.ts +8 -0
- package/src/api/schemas/users.ts +1 -1
- package/src/api/schemas/widgets.ts +12 -10
- package/src/api/setup-complete.ts +40 -0
- package/src/api/types.ts +5 -1
- package/src/astro/integration/index.ts +30 -2
- package/src/astro/integration/routes.ts +28 -0
- package/src/astro/integration/runtime.ts +49 -1
- package/src/astro/integration/virtual-modules.ts +73 -2
- package/src/astro/integration/vite-config.ts +49 -13
- package/src/astro/middleware/auth.ts +34 -6
- package/src/astro/middleware/redirect.ts +29 -16
- package/src/astro/middleware/request-context.ts +15 -5
- package/src/astro/middleware.ts +41 -10
- package/src/astro/routes/PluginRegistry.tsx +10 -1
- package/src/astro/routes/api/auth/invite/complete.ts +6 -1
- package/src/astro/routes/api/auth/mode.ts +57 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +23 -3
- package/src/astro/routes/api/auth/oauth/[provider].ts +10 -4
- package/src/astro/routes/api/auth/passkey/register/verify.ts +6 -1
- package/src/astro/routes/api/auth/passkey/verify.ts +6 -1
- package/src/astro/routes/api/auth/signup/complete.ts +6 -1
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +34 -12
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +32 -2
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +4 -2
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +3 -2
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +8 -4
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id].ts +12 -0
- package/src/astro/routes/api/content/[collection]/index.ts +1 -9
- package/src/astro/routes/api/import/wordpress/execute.ts +3 -1
- package/src/astro/routes/api/import/wordpress/media.ts +2 -7
- package/src/astro/routes/api/import/wordpress/prepare.ts +9 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +3 -1
- package/src/astro/routes/api/manifest.ts +62 -45
- package/src/astro/routes/api/media/[id]/confirm.ts +10 -1
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +12 -3
- package/src/astro/routes/api/openapi.json.ts +27 -10
- package/src/astro/routes/api/redirects/404s/index.ts +10 -4
- package/src/astro/routes/api/redirects/404s/summary.ts +4 -2
- package/src/astro/routes/api/redirects/[id].ts +10 -4
- package/src/astro/routes/api/redirects/index.ts +7 -3
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +1 -1
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +0 -2
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +0 -1
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +0 -1
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -2
- package/src/astro/routes/api/schema/collections/index.ts +1 -1
- package/src/astro/routes/api/search/index.ts +10 -2
- package/src/astro/routes/api/sections/[slug].ts +10 -4
- package/src/astro/routes/api/sections/index.ts +7 -3
- package/src/astro/routes/api/settings/email.ts +4 -9
- package/src/astro/routes/api/setup/admin-verify.ts +6 -1
- package/src/astro/routes/api/setup/admin.ts +8 -2
- package/src/astro/routes/api/setup/index.ts +2 -2
- package/src/astro/routes/api/setup/status.ts +3 -1
- package/src/astro/routes/api/snapshot.ts +44 -18
- package/src/astro/routes/api/taxonomies/index.ts +0 -1
- package/src/astro/routes/api/themes/preview.ts +11 -5
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +4 -1
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +4 -1
- package/src/astro/routes/api/widget-areas/[name].ts +4 -1
- package/src/astro/routes/api/widget-areas/index.ts +4 -1
- package/src/astro/types.ts +32 -3
- package/src/auth/allowed-origins.ts +168 -0
- package/src/auth/mode.ts +15 -3
- package/src/auth/passkey-config.ts +35 -13
- package/src/auth/providers/github-admin.tsx +29 -0
- package/src/auth/providers/github.ts +31 -0
- package/src/auth/providers/google-admin.tsx +44 -0
- package/src/auth/providers/google.ts +31 -0
- package/src/auth/types.ts +114 -4
- package/src/bylines/index.ts +37 -88
- package/src/cli/commands/auth.ts +28 -6
- package/src/cli/commands/bundle-utils.ts +11 -2
- package/src/cli/commands/bundle.ts +31 -9
- package/src/cli/commands/content.ts +13 -0
- package/src/cli/commands/login.ts +8 -1
- package/src/cli/commands/publish.ts +24 -0
- package/src/cli/commands/secrets.ts +183 -0
- package/src/cli/credentials.ts +1 -1
- package/src/cli/index.ts +5 -1
- package/src/client/index.ts +4 -4
- package/src/client/transport.ts +17 -7
- package/src/components/Break.astro +2 -2
- package/src/components/EmDashHead.astro +18 -13
- package/src/components/EmDashImage.astro +7 -6
- package/src/components/Embed.astro +1 -1
- package/src/components/Gallery.astro +6 -4
- package/src/components/Image.astro +9 -4
- package/src/components/InlinePortableTextEditor.tsx +106 -19
- package/src/components/LiveSearch.astro +5 -14
- package/src/config/secrets.ts +528 -0
- package/src/database/dialect-helpers.ts +50 -0
- package/src/database/migrations/034_published_at_index.ts +1 -1
- package/src/database/migrations/035_bounded_404_log.ts +56 -39
- package/src/database/migrations/runner.ts +156 -23
- package/src/database/repositories/audit.ts +6 -8
- package/src/database/repositories/byline.ts +6 -8
- package/src/database/repositories/comment.ts +12 -16
- package/src/database/repositories/content.ts +76 -52
- package/src/database/repositories/index.ts +1 -1
- package/src/database/repositories/media.ts +10 -13
- package/src/database/repositories/plugin-storage.ts +4 -6
- package/src/database/repositories/redirect.ts +26 -19
- package/src/database/repositories/taxonomy.ts +40 -3
- package/src/database/repositories/types.ts +57 -8
- package/src/database/repositories/user.ts +6 -8
- package/src/db/libsql.ts +1 -3
- package/src/db/sqlite.ts +2 -5
- package/src/emdash-runtime.ts +388 -247
- package/src/index.ts +14 -1
- package/src/loader.ts +30 -6
- package/src/mcp/server.ts +781 -141
- package/src/media/normalize.ts +1 -1
- package/src/media/url.ts +78 -0
- package/src/page/site-identity.ts +58 -0
- package/src/plugins/adapt-sandbox-entry.ts +22 -10
- package/src/plugins/context.ts +13 -10
- package/src/plugins/define-plugin.ts +40 -12
- package/src/plugins/email-console.ts +10 -3
- package/src/plugins/hooks.ts +34 -19
- package/src/plugins/index.ts +9 -0
- package/src/plugins/manifest-schema.ts +49 -2
- package/src/plugins/types.ts +174 -13
- package/src/preview/urls.ts +23 -3
- package/src/query.ts +149 -6
- package/src/redirects/cache.ts +38 -18
- package/src/request-cache.ts +3 -0
- package/src/schema/registry.ts +97 -5
- package/src/schema/zod-generator.ts +27 -5
- package/src/search/fts-manager.ts +0 -2
- package/src/search/query.ts +111 -26
- package/src/search/types.ts +8 -1
- package/src/sections/index.ts +7 -9
- package/src/seed/apply.ts +2 -0
- package/src/settings/index.ts +80 -6
- package/src/settings/types.ts +23 -1
- package/src/storage/s3.ts +12 -6
- package/src/taxonomies/index.ts +11 -1
- package/src/virtual-modules.d.ts +21 -1
- package/src/widgets/index.ts +1 -1
- package/dist/apply-5uslYdUu.mjs.map +0 -1
- package/dist/byline-C4OVd8b3.mjs.map +0 -1
- package/dist/bylines-hPTW79hw.mjs +0 -157
- package/dist/bylines-hPTW79hw.mjs.map +0 -1
- package/dist/cache-BkKBuIvS.mjs +0 -56
- package/dist/cache-BkKBuIvS.mjs.map +0 -1
- package/dist/chunk-ClPoSABd.mjs +0 -21
- package/dist/content-D7J5y73J.mjs.map +0 -1
- package/dist/dialect-helpers-DhTzaUxP.mjs.map +0 -1
- package/dist/error-CiYn9yDu.mjs.map +0 -1
- package/dist/index-De6_Xv3v.d.mts.map +0 -1
- package/dist/loader-DeiBJEMe.mjs.map +0 -1
- package/dist/manifest-schema-V30qsMft.mjs.map +0 -1
- package/dist/media-DqHVh136.mjs.map +0 -1
- package/dist/mode-CpNnGkPz.mjs.map +0 -1
- package/dist/placeholder-C-fk5hYI.mjs.map +0 -1
- package/dist/query-g4Ug-9j9.mjs.map +0 -1
- package/dist/redirect-CN0Rt9Ob.mjs.map +0 -1
- package/dist/registry-Ci3WxVAr.mjs.map +0 -1
- package/dist/request-cache-DiR961CV.mjs.map +0 -1
- package/dist/runner-BR2xKwhn.d.mts +0 -34
- package/dist/runner-BR2xKwhn.d.mts.map +0 -1
- package/dist/search-B0effn3j.mjs.map +0 -1
- package/dist/taxonomies-K2z0Uhnj.mjs.map +0 -1
- package/dist/types-CMMN0pNg.mjs +0 -31
- package/dist/types-CMMN0pNg.mjs.map +0 -1
- package/dist/types-DgrIP0tF.d.mts.map +0 -1
- package/dist/version-BnTKdfam.mjs +0 -7
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import { n as validateJsonFieldName, r as validatePluginIdentifier, t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { a as slugify, r as RevisionRepository, t as ContentRepository } from "./content-
|
|
4
|
-
import { r as encodeBase64, t as decodeBase64 } from "./base64-
|
|
5
|
-
import { n as
|
|
6
|
-
import { t as MediaRepository } from "./media-
|
|
7
|
-
import { a as ssrfSafeFetch, i as resolveAndValidateExternalUrl, o as stripCredentialHeaders,
|
|
2
|
+
import { s as jsonExtractExpr } from "./dialect-helpers-BKCvISIQ.mjs";
|
|
3
|
+
import { a as slugify, r as RevisionRepository, t as ContentRepository } from "./content-8lOYF0pr.mjs";
|
|
4
|
+
import { r as encodeBase64, t as decodeBase64 } from "./base64-BRICGH2l.mjs";
|
|
5
|
+
import { i as encodeCursor, n as InvalidCursorError, r as decodeCursor, t as EmDashValidationError } from "./types-CRxNbK-Z.mjs";
|
|
6
|
+
import { t as MediaRepository } from "./media-BW32b4gi.mjs";
|
|
7
|
+
import { a as ssrfSafeFetch, i as resolveAndValidateExternalUrl, o as stripCredentialHeaders, r as SsrfError, s as validateExternalUrl } from "./apply-BzltprvY.mjs";
|
|
8
|
+
import { t as OptionsRepository } from "./options-BVp3UsTS.mjs";
|
|
8
9
|
import { t as withTransaction } from "./transaction-Cn2rjY78.mjs";
|
|
9
|
-
import { t as RedirectRepository } from "./redirect-
|
|
10
|
-
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-
|
|
11
|
-
import { t as BylineRepository } from "./byline-
|
|
12
|
-
import { r as isI18nEnabled } from "./config-
|
|
13
|
-
import { r as invalidateRedirectCache } from "./cache-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { n as
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
10
|
+
import { t as RedirectRepository } from "./redirect-BhUBKRc1.mjs";
|
|
11
|
+
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-NBQVDOci.mjs";
|
|
12
|
+
import { t as BylineRepository } from "./byline-BSaNL1w7.mjs";
|
|
13
|
+
import { r as isI18nEnabled } from "./config-BI0V3ICQ.mjs";
|
|
14
|
+
import { r as invalidateRedirectCache } from "./cache-C6N_hhN7.mjs";
|
|
15
|
+
import { t as isMissingTableError } from "./db-errors-WRezodiz.mjs";
|
|
16
|
+
import { r as hashString } from "./zod-generator-CC0xNe_K.mjs";
|
|
17
|
+
import { i as FTSManager, n as SchemaRegistry } from "./registry-Dw70ChxB.mjs";
|
|
18
|
+
import { r as getDb } from "./loader-CKLbBnhK.mjs";
|
|
19
|
+
import { n as requestCached } from "./request-cache-B-bmkipQ.mjs";
|
|
20
|
+
import { i as pluginManifestSchema } from "./manifest-schema-DqWNC3lM.mjs";
|
|
21
|
+
import { i as normalizeCapabilities } from "./types-4fVtCIm0.mjs";
|
|
22
|
+
import { t as generatePreviewToken } from "./tokens-D7zMmWi2.mjs";
|
|
19
23
|
import { sql } from "kysely";
|
|
20
24
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
21
25
|
import { ulid } from "ulidx";
|
|
@@ -78,7 +82,7 @@ var UserRepository = class UserRepository {
|
|
|
78
82
|
if (options.role !== void 0) query = query.where("role", "=", UserRepository.resolveRole(options.role));
|
|
79
83
|
if (options.cursor) {
|
|
80
84
|
const decoded = decodeCursor(options.cursor);
|
|
81
|
-
|
|
85
|
+
query = query.where((eb) => eb.or([eb("created_at", "<", decoded.orderValue), eb.and([eb("created_at", "=", decoded.orderValue), eb("id", "<", decoded.id)])]));
|
|
82
86
|
}
|
|
83
87
|
const rows = await query.execute();
|
|
84
88
|
const items = rows.slice(0, limit).map((row) => this.rowToUser(row));
|
|
@@ -228,7 +232,7 @@ var CommentRepository = class CommentRepository {
|
|
|
228
232
|
if (options.status) query = query.where("status", "=", options.status);
|
|
229
233
|
if (options.cursor) {
|
|
230
234
|
const decoded = decodeCursor(options.cursor);
|
|
231
|
-
|
|
235
|
+
query = query.where((eb) => eb.or([eb("created_at", ">", decoded.orderValue), eb.and([eb("created_at", "=", decoded.orderValue), eb("id", ">", decoded.id)])]));
|
|
232
236
|
}
|
|
233
237
|
query = query.orderBy("created_at", "asc").orderBy("id", "asc").limit(limit + 1);
|
|
234
238
|
const rows = await query.execute();
|
|
@@ -259,7 +263,7 @@ var CommentRepository = class CommentRepository {
|
|
|
259
263
|
}
|
|
260
264
|
if (options.cursor) {
|
|
261
265
|
const decoded = decodeCursor(options.cursor);
|
|
262
|
-
|
|
266
|
+
query = query.where((eb) => eb.or([eb("created_at", "<", decoded.orderValue), eb.and([eb("created_at", "=", decoded.orderValue), eb("id", "<", decoded.id)])]));
|
|
263
267
|
}
|
|
264
268
|
query = query.orderBy("created_at", "desc").orderBy("id", "desc").limit(limit + 1);
|
|
265
269
|
const rows = await query.execute();
|
|
@@ -683,7 +687,7 @@ var PluginStorageRepository = class {
|
|
|
683
687
|
}
|
|
684
688
|
if (cursor) {
|
|
685
689
|
const decoded = decodeCursor(cursor);
|
|
686
|
-
|
|
690
|
+
query = query.where(({ eb }) => eb(sql`(created_at, id)`, ">", sql`(${decoded.orderValue}, ${decoded.id})`));
|
|
687
691
|
}
|
|
688
692
|
if (Object.keys(orderBy).length > 0) for (const [field, direction] of Object.entries(orderBy)) {
|
|
689
693
|
const extract = jsonExtract(this.db, field);
|
|
@@ -976,6 +980,16 @@ function validateRev(rev, item) {
|
|
|
976
980
|
//#endregion
|
|
977
981
|
//#region src/api/handlers/content.ts
|
|
978
982
|
/**
|
|
983
|
+
* Narrow a caught error to one carrying a structured `apiError` discriminant.
|
|
984
|
+
* Used by transaction callbacks that want to surface a specific error code
|
|
985
|
+
* through the standard Error throwing path.
|
|
986
|
+
*/
|
|
987
|
+
function hasApiError(error) {
|
|
988
|
+
if (!(error instanceof Error) || !("apiError" in error)) return false;
|
|
989
|
+
const { apiError } = error;
|
|
990
|
+
return typeof apiError === "object" && apiError !== null && "code" in apiError && typeof apiError.code === "string";
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
979
993
|
* Extract a slug source (title or name) from content data.
|
|
980
994
|
* Returns null if no suitable string field is found.
|
|
981
995
|
*/
|
|
@@ -1125,6 +1139,27 @@ async function handleContentList(db, collection, params) {
|
|
|
1125
1139
|
}
|
|
1126
1140
|
};
|
|
1127
1141
|
} catch (error) {
|
|
1142
|
+
if (error instanceof InvalidCursorError) return {
|
|
1143
|
+
success: false,
|
|
1144
|
+
error: {
|
|
1145
|
+
code: "INVALID_CURSOR",
|
|
1146
|
+
message: error.message
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1149
|
+
if (isMissingTableError(error)) return {
|
|
1150
|
+
success: false,
|
|
1151
|
+
error: {
|
|
1152
|
+
code: "COLLECTION_NOT_FOUND",
|
|
1153
|
+
message: `Collection '${collection}' not found`
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
if (error instanceof EmDashValidationError) return {
|
|
1157
|
+
success: false,
|
|
1158
|
+
error: {
|
|
1159
|
+
code: "VALIDATION_ERROR",
|
|
1160
|
+
message: error.message
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1128
1163
|
console.error("Content list error:", error);
|
|
1129
1164
|
return {
|
|
1130
1165
|
success: false,
|
|
@@ -1255,6 +1290,37 @@ async function handleContentCreate(db, collection, body) {
|
|
|
1255
1290
|
}
|
|
1256
1291
|
};
|
|
1257
1292
|
} catch (error) {
|
|
1293
|
+
if (isMissingTableError(error)) return {
|
|
1294
|
+
success: false,
|
|
1295
|
+
error: {
|
|
1296
|
+
code: "COLLECTION_NOT_FOUND",
|
|
1297
|
+
message: `Collection '${collection}' not found`
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
if (error instanceof EmDashValidationError) return {
|
|
1301
|
+
success: false,
|
|
1302
|
+
error: {
|
|
1303
|
+
code: "VALIDATION_ERROR",
|
|
1304
|
+
message: error.message
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
const message = error instanceof Error ? error.message.toLowerCase() : "";
|
|
1308
|
+
if (message.includes("unique constraint failed") || message.includes("duplicate key")) {
|
|
1309
|
+
if (message.includes("slug")) return {
|
|
1310
|
+
success: false,
|
|
1311
|
+
error: {
|
|
1312
|
+
code: "SLUG_CONFLICT",
|
|
1313
|
+
message: `Slug '${body.slug ?? "(auto-generated)"}' already exists in collection '${collection}'`
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
return {
|
|
1317
|
+
success: false,
|
|
1318
|
+
error: {
|
|
1319
|
+
code: "CONFLICT",
|
|
1320
|
+
message: "Unique constraint violation"
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1258
1324
|
console.error("Content create error:", error);
|
|
1259
1325
|
return {
|
|
1260
1326
|
success: false,
|
|
@@ -1324,13 +1390,41 @@ async function handleContentUpdate(db, collection, id, body) {
|
|
|
1324
1390
|
}
|
|
1325
1391
|
};
|
|
1326
1392
|
} catch (error) {
|
|
1327
|
-
if (error
|
|
1328
|
-
|
|
1393
|
+
if (hasApiError(error)) return {
|
|
1394
|
+
success: false,
|
|
1395
|
+
error: {
|
|
1396
|
+
code: error.apiError.code,
|
|
1397
|
+
message: error.message
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
if (isMissingTableError(error)) return {
|
|
1401
|
+
success: false,
|
|
1402
|
+
error: {
|
|
1403
|
+
code: "COLLECTION_NOT_FOUND",
|
|
1404
|
+
message: `Collection '${collection}' not found`
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
if (error instanceof EmDashValidationError) return {
|
|
1408
|
+
success: false,
|
|
1409
|
+
error: {
|
|
1410
|
+
code: "VALIDATION_ERROR",
|
|
1411
|
+
message: error.message
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
const message = error instanceof Error ? error.message.toLowerCase() : "";
|
|
1415
|
+
if (message.includes("unique constraint failed") || message.includes("duplicate key")) {
|
|
1416
|
+
if (message.includes("slug")) return {
|
|
1417
|
+
success: false,
|
|
1418
|
+
error: {
|
|
1419
|
+
code: "SLUG_CONFLICT",
|
|
1420
|
+
message: `Slug '${body.slug ?? id}' already exists in collection '${collection}'`
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1329
1423
|
return {
|
|
1330
1424
|
success: false,
|
|
1331
1425
|
error: {
|
|
1332
|
-
code,
|
|
1333
|
-
message:
|
|
1426
|
+
code: "CONFLICT",
|
|
1427
|
+
message: "Unique constraint violation"
|
|
1334
1428
|
}
|
|
1335
1429
|
};
|
|
1336
1430
|
}
|
|
@@ -1519,6 +1613,13 @@ async function handleContentListTrashed(db, collection, options = {}) {
|
|
|
1519
1613
|
}
|
|
1520
1614
|
};
|
|
1521
1615
|
} catch (error) {
|
|
1616
|
+
if (error instanceof InvalidCursorError) return {
|
|
1617
|
+
success: false,
|
|
1618
|
+
error: {
|
|
1619
|
+
code: "INVALID_CURSOR",
|
|
1620
|
+
message: error.message
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1522
1623
|
console.error("Content list trashed error:", error);
|
|
1523
1624
|
return {
|
|
1524
1625
|
success: false,
|
|
@@ -1598,6 +1699,13 @@ async function handleContentUnschedule(db, collection, id) {
|
|
|
1598
1699
|
data: { item }
|
|
1599
1700
|
};
|
|
1600
1701
|
} catch (error) {
|
|
1702
|
+
if (error instanceof EmDashValidationError) return {
|
|
1703
|
+
success: false,
|
|
1704
|
+
error: {
|
|
1705
|
+
code: "VALIDATION_ERROR",
|
|
1706
|
+
message: error.message
|
|
1707
|
+
}
|
|
1708
|
+
};
|
|
1601
1709
|
console.error("Content unschedule error:", error);
|
|
1602
1710
|
return {
|
|
1603
1711
|
success: false,
|
|
@@ -1615,12 +1723,12 @@ async function handleContentUnschedule(db, collection, id) {
|
|
|
1615
1723
|
* (syncDataColumns, slug sync, status/revision update) that must
|
|
1616
1724
|
* be atomic to prevent FTS shadow table corruption on crash.
|
|
1617
1725
|
*/
|
|
1618
|
-
async function handleContentPublish(db, collection, id) {
|
|
1726
|
+
async function handleContentPublish(db, collection, id, options = {}) {
|
|
1619
1727
|
try {
|
|
1620
1728
|
const item = await withTransaction(db, async (trx) => {
|
|
1621
1729
|
const repo = new ContentRepository(trx);
|
|
1622
1730
|
const resolvedId = await resolveId(repo, collection, id) ?? id;
|
|
1623
|
-
return repo.publish(collection, resolvedId);
|
|
1731
|
+
return repo.publish(collection, resolvedId, options.publishedAt);
|
|
1624
1732
|
});
|
|
1625
1733
|
await hydrateSeo(db, collection, item, await collectionHasSeo(db, collection));
|
|
1626
1734
|
return {
|
|
@@ -1628,6 +1736,13 @@ async function handleContentPublish(db, collection, id) {
|
|
|
1628
1736
|
data: { item }
|
|
1629
1737
|
};
|
|
1630
1738
|
} catch (error) {
|
|
1739
|
+
if (error instanceof EmDashValidationError) return {
|
|
1740
|
+
success: false,
|
|
1741
|
+
error: {
|
|
1742
|
+
code: "VALIDATION_ERROR",
|
|
1743
|
+
message: error.message
|
|
1744
|
+
}
|
|
1745
|
+
};
|
|
1631
1746
|
console.error("Content publish error:", error);
|
|
1632
1747
|
return {
|
|
1633
1748
|
success: false,
|
|
@@ -1657,6 +1772,13 @@ async function handleContentUnpublish(db, collection, id) {
|
|
|
1657
1772
|
data: { item }
|
|
1658
1773
|
};
|
|
1659
1774
|
} catch (error) {
|
|
1775
|
+
if (error instanceof EmDashValidationError) return {
|
|
1776
|
+
success: false,
|
|
1777
|
+
error: {
|
|
1778
|
+
code: "VALIDATION_ERROR",
|
|
1779
|
+
message: error.message
|
|
1780
|
+
}
|
|
1781
|
+
};
|
|
1660
1782
|
console.error("Content unpublish error:", error);
|
|
1661
1783
|
return {
|
|
1662
1784
|
success: false,
|
|
@@ -1841,37 +1963,6 @@ async function syncNonTranslatableFields(trx, collectionSlug, updatedItemId, tra
|
|
|
1841
1963
|
`.execute(trx);
|
|
1842
1964
|
}
|
|
1843
1965
|
|
|
1844
|
-
//#endregion
|
|
1845
|
-
//#region src/utils/hash.ts
|
|
1846
|
-
/**
|
|
1847
|
-
* SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
|
|
1848
|
-
* For cache invalidation / ETags — not for security.
|
|
1849
|
-
*/
|
|
1850
|
-
async function hashString(content) {
|
|
1851
|
-
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(content));
|
|
1852
|
-
return Array.from(new Uint8Array(buf).slice(0, 8), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
1853
|
-
}
|
|
1854
|
-
/**
|
|
1855
|
-
* Compute content hash using Web Crypto API
|
|
1856
|
-
*
|
|
1857
|
-
* Uses SHA-1 which is the fastest option in SubtleCrypto.
|
|
1858
|
-
* SHA-1 is cryptographically weak but fine for content deduplication
|
|
1859
|
-
* where we only need to detect identical files, not resist attacks.
|
|
1860
|
-
*
|
|
1861
|
-
* Returns hex string prefixed with "sha1:" for future-proofing
|
|
1862
|
-
*/
|
|
1863
|
-
async function computeContentHash(content) {
|
|
1864
|
-
let buf;
|
|
1865
|
-
if (content instanceof ArrayBuffer) buf = content;
|
|
1866
|
-
else {
|
|
1867
|
-
buf = new ArrayBuffer(content.byteLength);
|
|
1868
|
-
new Uint8Array(buf).set(content);
|
|
1869
|
-
}
|
|
1870
|
-
const hashBuffer = await crypto.subtle.digest("SHA-1", buf);
|
|
1871
|
-
const hashArray = new Uint8Array(hashBuffer);
|
|
1872
|
-
return `sha1:${Array.from(hashArray, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
1966
|
//#endregion
|
|
1876
1967
|
//#region src/api/handlers/manifest.ts
|
|
1877
1968
|
/**
|
|
@@ -2050,9 +2141,7 @@ async function handleRevisionGet(db, revisionId) {
|
|
|
2050
2141
|
*/
|
|
2051
2142
|
async function handleRevisionRestore(db, revisionId, callerUserId) {
|
|
2052
2143
|
try {
|
|
2053
|
-
const
|
|
2054
|
-
const contentRepo = new ContentRepository(db);
|
|
2055
|
-
const revision = await revisionRepo.findById(revisionId);
|
|
2144
|
+
const revision = await new RevisionRepository(db).findById(revisionId);
|
|
2056
2145
|
if (!revision) return {
|
|
2057
2146
|
success: false,
|
|
2058
2147
|
error: {
|
|
@@ -2061,17 +2150,22 @@ async function handleRevisionRestore(db, revisionId, callerUserId) {
|
|
|
2061
2150
|
}
|
|
2062
2151
|
};
|
|
2063
2152
|
const { _slug, ...fieldData } = revision.data;
|
|
2064
|
-
const item = await
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2153
|
+
const item = await withTransaction(db, async (trx) => {
|
|
2154
|
+
const trxContentRepo = new ContentRepository(trx);
|
|
2155
|
+
const trxRevisionRepo = new RevisionRepository(trx);
|
|
2156
|
+
const updated = await trxContentRepo.update(revision.collection, revision.entryId, {
|
|
2157
|
+
data: fieldData,
|
|
2158
|
+
slug: typeof _slug === "string" ? _slug : void 0
|
|
2159
|
+
});
|
|
2160
|
+
await trxRevisionRepo.create({
|
|
2161
|
+
collection: revision.collection,
|
|
2162
|
+
entryId: revision.entryId,
|
|
2163
|
+
data: revision.data,
|
|
2164
|
+
authorId: callerUserId
|
|
2165
|
+
});
|
|
2166
|
+
return updated;
|
|
2073
2167
|
});
|
|
2074
|
-
|
|
2168
|
+
new RevisionRepository(db).pruneOldRevisions(revision.collection, revision.entryId, 50).catch(() => {});
|
|
2075
2169
|
return {
|
|
2076
2170
|
success: true,
|
|
2077
2171
|
data: { item }
|
|
@@ -2106,7 +2200,14 @@ async function handleMediaList(db, params) {
|
|
|
2106
2200
|
nextCursor: result.nextCursor
|
|
2107
2201
|
}
|
|
2108
2202
|
};
|
|
2109
|
-
} catch {
|
|
2203
|
+
} catch (error) {
|
|
2204
|
+
if (error instanceof InvalidCursorError) return {
|
|
2205
|
+
success: false,
|
|
2206
|
+
error: {
|
|
2207
|
+
code: "INVALID_CURSOR",
|
|
2208
|
+
message: error.message
|
|
2209
|
+
}
|
|
2210
|
+
};
|
|
2110
2211
|
return {
|
|
2111
2212
|
success: false,
|
|
2112
2213
|
error: {
|
|
@@ -2436,7 +2537,7 @@ async function getSectionsWithDb(db, options = {}) {
|
|
|
2436
2537
|
query = query.orderBy("title", "asc").orderBy("id", "asc");
|
|
2437
2538
|
if (options.cursor) {
|
|
2438
2539
|
const decoded = decodeCursor(options.cursor);
|
|
2439
|
-
|
|
2540
|
+
query = query.where((eb) => eb.or([eb("title", ">", decoded.orderValue), eb.and([eb("title", "=", decoded.orderValue), eb("id", ">", decoded.id)])]));
|
|
2440
2541
|
}
|
|
2441
2542
|
query = query.limit(limit + 1);
|
|
2442
2543
|
const rows = await query.$castTo().execute();
|
|
@@ -2542,7 +2643,7 @@ const VALID_ROLE_LEVELS = new Set([
|
|
|
2542
2643
|
const roleLevel = z$1.coerce.number().int().refine((n) => VALID_ROLE_LEVELS.has(n), { message: "Invalid role level. Must be 10, 20, 30, 40, or 50" });
|
|
2543
2644
|
/** Pagination query params — cursor-based */
|
|
2544
2645
|
const cursorPaginationQuery = z$1.object({
|
|
2545
|
-
cursor: z$1.string().optional().meta({ description: "Opaque cursor for pagination" }),
|
|
2646
|
+
cursor: z$1.string().max(2048).optional().meta({ description: "Opaque cursor for pagination" }),
|
|
2546
2647
|
limit: z$1.coerce.number().int().min(1).max(100).optional().default(50).meta({ description: "Maximum number of items to return (1-100, default 50)" })
|
|
2547
2648
|
}).meta({ id: "CursorPaginationQuery" });
|
|
2548
2649
|
/** Pagination query params — offset-based */
|
|
@@ -2672,6 +2773,10 @@ const contentScheduleBody = z$1.object({ scheduledAt: z$1.string().min(1, "sched
|
|
|
2672
2773
|
description: "ISO 8601 datetime for scheduled publishing",
|
|
2673
2774
|
example: "2025-06-15T09:00:00Z"
|
|
2674
2775
|
}) }).meta({ id: "ContentScheduleBody" });
|
|
2776
|
+
const contentPublishBody = z$1.object({ publishedAt: z$1.iso.datetime({
|
|
2777
|
+
offset: true,
|
|
2778
|
+
message: "must be an ISO 8601 datetime"
|
|
2779
|
+
}).optional().meta({ description: "Optional ISO 8601 datetime to backdate the publish (e.g. when migrating content). Requires content:publish_any permission. Without this, existing published_at is preserved on re-publish." }) }).meta({ id: "ContentPublishBody" });
|
|
2675
2780
|
const contentPreviewUrlBody = z$1.object({
|
|
2676
2781
|
expiresIn: z$1.union([z$1.string(), z$1.number()]).optional(),
|
|
2677
2782
|
pathPattern: z$1.string().optional()
|
|
@@ -3013,8 +3118,8 @@ const commentListQuery = z$1.object({
|
|
|
3013
3118
|
]).optional(),
|
|
3014
3119
|
collection: z$1.string().optional(),
|
|
3015
3120
|
search: z$1.string().optional(),
|
|
3016
|
-
limit: z$1.coerce.number().int().min(1).max(100).optional(),
|
|
3017
|
-
cursor: z$1.string().optional()
|
|
3121
|
+
limit: z$1.coerce.number().int().min(1).max(100).optional().default(50),
|
|
3122
|
+
cursor: z$1.string().max(2048).optional()
|
|
3018
3123
|
}).meta({ id: "CommentListQuery" });
|
|
3019
3124
|
const commentStatusValues = z$1.enum([
|
|
3020
3125
|
"pending",
|
|
@@ -3313,8 +3418,8 @@ const sectionSource = z$1.enum([
|
|
|
3313
3418
|
const sectionsListQuery = z$1.object({
|
|
3314
3419
|
source: sectionSource.optional(),
|
|
3315
3420
|
search: z$1.string().optional(),
|
|
3316
|
-
limit: z$1.coerce.number().int().min(1).max(100).optional(),
|
|
3317
|
-
cursor: z$1.string().optional()
|
|
3421
|
+
limit: z$1.coerce.number().int().min(1).max(100).optional().default(50),
|
|
3422
|
+
cursor: z$1.string().max(2048).optional()
|
|
3318
3423
|
}).meta({ id: "SectionsListQuery" });
|
|
3319
3424
|
const createSectionBody = z$1.object({
|
|
3320
3425
|
slug: z$1.string().min(1),
|
|
@@ -3323,7 +3428,7 @@ const createSectionBody = z$1.object({
|
|
|
3323
3428
|
keywords: z$1.array(z$1.string()).optional(),
|
|
3324
3429
|
content: z$1.array(z$1.record(z$1.string(), z$1.unknown())),
|
|
3325
3430
|
previewMediaId: z$1.string().optional(),
|
|
3326
|
-
source:
|
|
3431
|
+
source: z$1.enum(["user", "import"]).optional(),
|
|
3327
3432
|
themeId: z$1.string().optional()
|
|
3328
3433
|
}).meta({ id: "CreateSectionBody" });
|
|
3329
3434
|
const updateSectionBody = z$1.object({
|
|
@@ -3498,13 +3603,15 @@ const setupAdminBody = z$1.object({
|
|
|
3498
3603
|
name: z$1.string().optional()
|
|
3499
3604
|
});
|
|
3500
3605
|
const setupAdminVerifyBody = z$1.object({ credential: registrationCredential });
|
|
3606
|
+
const atprotoLoginBody = z$1.object({ handle: z$1.string().trim().min(1) });
|
|
3607
|
+
const setupAtprotoAdminBody = z$1.object({ handle: z$1.string().trim().min(1) });
|
|
3501
3608
|
|
|
3502
3609
|
//#endregion
|
|
3503
3610
|
//#region src/api/schemas/users.ts
|
|
3504
3611
|
const usersListQuery = z$1.object({
|
|
3505
3612
|
search: z$1.string().optional(),
|
|
3506
3613
|
role: z$1.string().optional(),
|
|
3507
|
-
cursor: z$1.string().optional(),
|
|
3614
|
+
cursor: z$1.string().max(2048).optional(),
|
|
3508
3615
|
limit: z$1.coerce.number().int().min(1).max(100).optional().default(50)
|
|
3509
3616
|
}).meta({ id: "UsersListQuery" });
|
|
3510
3617
|
const userUpdateBody = z$1.object({
|
|
@@ -3601,18 +3708,15 @@ const widgetAreaSchema = z$1.object({
|
|
|
3601
3708
|
}).meta({ id: "WidgetArea" });
|
|
3602
3709
|
const widgetSchema = z$1.object({
|
|
3603
3710
|
id: z$1.string(),
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
component_props: z$1.string().nullable(),
|
|
3611
|
-
sort_order: z$1.number().int(),
|
|
3612
|
-
created_at: z$1.string(),
|
|
3613
|
-
updated_at: z$1.string()
|
|
3711
|
+
type: widgetType,
|
|
3712
|
+
title: z$1.string().optional(),
|
|
3713
|
+
content: z$1.array(z$1.record(z$1.string(), z$1.unknown())).optional(),
|
|
3714
|
+
menuName: z$1.string().optional(),
|
|
3715
|
+
componentId: z$1.string().optional(),
|
|
3716
|
+
componentProps: z$1.record(z$1.string(), z$1.unknown()).optional()
|
|
3614
3717
|
}).meta({ id: "Widget" });
|
|
3615
3718
|
const widgetAreaWithWidgetsSchema = widgetAreaSchema.extend({ widgets: z$1.array(widgetSchema) }).meta({ id: "WidgetAreaWithWidgets" });
|
|
3719
|
+
const widgetAreaWithWidgetsAndCountSchema = widgetAreaWithWidgetsSchema.extend({ widgetCount: z$1.number().int() }).meta({ id: "WidgetAreaWithWidgetsAndCount" });
|
|
3616
3720
|
|
|
3617
3721
|
//#endregion
|
|
3618
3722
|
//#region src/api/schemas/redirects.ts
|
|
@@ -4897,6 +5001,20 @@ function buildNavMenus(navMenuItemPosts, menuTermsBySlug) {
|
|
|
4897
5001
|
|
|
4898
5002
|
//#endregion
|
|
4899
5003
|
//#region src/plugins/define-plugin.ts
|
|
5004
|
+
/**
|
|
5005
|
+
* definePlugin() Helper
|
|
5006
|
+
*
|
|
5007
|
+
* Creates a properly typed and normalized plugin definition.
|
|
5008
|
+
* Supports two formats:
|
|
5009
|
+
*
|
|
5010
|
+
* 1. **Native format** -- full PluginDefinition with id, version, capabilities, etc.
|
|
5011
|
+
* Returns a ResolvedPlugin.
|
|
5012
|
+
*
|
|
5013
|
+
* 2. **Standard format** -- just { hooks, routes }. No id/version/capabilities.
|
|
5014
|
+
* Returns the same object (identity function for type inference).
|
|
5015
|
+
* Metadata comes from the descriptor at config time.
|
|
5016
|
+
*
|
|
5017
|
+
*/
|
|
4900
5018
|
const SIMPLE_ID = /^[a-z0-9-]+$/;
|
|
4901
5019
|
const SCOPED_ID = /^@[a-z0-9-]+\/[a-z0-9-]+$/;
|
|
4902
5020
|
const SEMVER_PATTERN = /^\d+\.\d+\.\d+/;
|
|
@@ -4916,6 +5034,17 @@ function defineNativePlugin(definition) {
|
|
|
4916
5034
|
if (!SIMPLE_ID.test(id) && !SCOPED_ID.test(id)) throw new Error(`Invalid plugin id "${id}". Must be lowercase alphanumeric with dashes (e.g., "my-plugin" or "@scope/my-plugin").`);
|
|
4917
5035
|
if (!SEMVER_PATTERN.test(version)) throw new Error(`Invalid plugin version "${version}". Must be semver format (e.g., "1.0.0").`);
|
|
4918
5036
|
const validCapabilities = new Set([
|
|
5037
|
+
"network:request",
|
|
5038
|
+
"network:request:unrestricted",
|
|
5039
|
+
"content:read",
|
|
5040
|
+
"content:write",
|
|
5041
|
+
"media:read",
|
|
5042
|
+
"media:write",
|
|
5043
|
+
"users:read",
|
|
5044
|
+
"email:send",
|
|
5045
|
+
"hooks.email-transport:register",
|
|
5046
|
+
"hooks.email-events:register",
|
|
5047
|
+
"hooks.page-fragments:register",
|
|
4919
5048
|
"network:fetch",
|
|
4920
5049
|
"network:fetch:any",
|
|
4921
5050
|
"read:content",
|
|
@@ -4923,16 +5052,16 @@ function defineNativePlugin(definition) {
|
|
|
4923
5052
|
"read:media",
|
|
4924
5053
|
"write:media",
|
|
4925
5054
|
"read:users",
|
|
4926
|
-
"email:send",
|
|
4927
5055
|
"email:provide",
|
|
4928
5056
|
"email:intercept",
|
|
4929
5057
|
"page:inject"
|
|
4930
5058
|
]);
|
|
4931
5059
|
for (const cap of capabilities) if (!validCapabilities.has(cap)) throw new Error(`Invalid capability "${cap}" in plugin "${id}".`);
|
|
4932
|
-
const
|
|
4933
|
-
|
|
4934
|
-
if (
|
|
4935
|
-
if (
|
|
5060
|
+
const canonical = normalizeCapabilities(capabilities);
|
|
5061
|
+
const normalizedCapabilities = [...canonical];
|
|
5062
|
+
if (canonical.includes("content:write") && !canonical.includes("content:read")) normalizedCapabilities.push("content:read");
|
|
5063
|
+
if (canonical.includes("media:write") && !canonical.includes("media:read")) normalizedCapabilities.push("media:read");
|
|
5064
|
+
if (canonical.includes("network:request:unrestricted") && !canonical.includes("network:request")) normalizedCapabilities.push("network:request");
|
|
4936
5065
|
return {
|
|
4937
5066
|
id,
|
|
4938
5067
|
version,
|
|
@@ -5943,16 +6072,16 @@ var PluginContextFactory = class {
|
|
|
5943
6072
|
const log = createLogAccess(plugin.id);
|
|
5944
6073
|
const storage = createStorageAccess(this.db, plugin.id, plugin.storage);
|
|
5945
6074
|
let content;
|
|
5946
|
-
if (capabilities.has("write
|
|
5947
|
-
else if (capabilities.has("read
|
|
6075
|
+
if (capabilities.has("content:write")) content = createContentAccessWithWrite(this.db);
|
|
6076
|
+
else if (capabilities.has("content:read")) content = createContentAccess(this.db);
|
|
5948
6077
|
let media;
|
|
5949
|
-
if (capabilities.has("write
|
|
5950
|
-
else if (capabilities.has("read
|
|
6078
|
+
if (capabilities.has("media:write") && this.getUploadUrl) media = createMediaAccessWithWrite(this.db, this.getUploadUrl, this.storage);
|
|
6079
|
+
else if (capabilities.has("media:read")) media = createMediaAccess(this.db);
|
|
5951
6080
|
let http;
|
|
5952
|
-
if (capabilities.has("network:
|
|
5953
|
-
else if (capabilities.has("network:
|
|
6081
|
+
if (capabilities.has("network:request:unrestricted")) http = createUnrestrictedHttpAccess(plugin.id);
|
|
6082
|
+
else if (capabilities.has("network:request")) http = createHttpAccess(plugin.id, plugin.allowedHosts);
|
|
5954
6083
|
let users;
|
|
5955
|
-
if (capabilities.has("read
|
|
6084
|
+
if (capabilities.has("users:read")) users = createUserAccess(this.db);
|
|
5956
6085
|
let cron;
|
|
5957
6086
|
if (this.cronReschedule) cron = new CronAccessImpl(this.db, plugin.id, this.cronReschedule);
|
|
5958
6087
|
let email;
|
|
@@ -6098,22 +6227,22 @@ var HookPipeline = class HookPipeline {
|
|
|
6098
6227
|
* capability will have that hook silently skipped at registration time.
|
|
6099
6228
|
*/
|
|
6100
6229
|
static HOOK_REQUIRED_CAPABILITY = new Map([
|
|
6101
|
-
["email:beforeSend", "email:
|
|
6102
|
-
["email:afterSend", "email:
|
|
6103
|
-
["email:deliver", "email:
|
|
6104
|
-
["content:beforeSave", "write
|
|
6105
|
-
["content:afterSave", "read
|
|
6106
|
-
["content:beforeDelete", "read
|
|
6107
|
-
["content:afterDelete", "read
|
|
6108
|
-
["content:afterPublish", "read
|
|
6109
|
-
["content:afterUnpublish", "read
|
|
6110
|
-
["media:beforeUpload", "write
|
|
6111
|
-
["media:afterUpload", "read
|
|
6112
|
-
["comment:beforeCreate", "read
|
|
6113
|
-
["comment:moderate", "read
|
|
6114
|
-
["comment:afterCreate", "read
|
|
6115
|
-
["comment:afterModerate", "read
|
|
6116
|
-
["page:fragments", "page:
|
|
6230
|
+
["email:beforeSend", "hooks.email-events:register"],
|
|
6231
|
+
["email:afterSend", "hooks.email-events:register"],
|
|
6232
|
+
["email:deliver", "hooks.email-transport:register"],
|
|
6233
|
+
["content:beforeSave", "content:write"],
|
|
6234
|
+
["content:afterSave", "content:read"],
|
|
6235
|
+
["content:beforeDelete", "content:read"],
|
|
6236
|
+
["content:afterDelete", "content:read"],
|
|
6237
|
+
["content:afterPublish", "content:read"],
|
|
6238
|
+
["content:afterUnpublish", "content:read"],
|
|
6239
|
+
["media:beforeUpload", "media:write"],
|
|
6240
|
+
["media:afterUpload", "media:read"],
|
|
6241
|
+
["comment:beforeCreate", "users:read"],
|
|
6242
|
+
["comment:moderate", "users:read"],
|
|
6243
|
+
["comment:afterCreate", "users:read"],
|
|
6244
|
+
["comment:afterModerate", "users:read"],
|
|
6245
|
+
["page:fragments", "hooks.page-fragments:register"]
|
|
6117
6246
|
]);
|
|
6118
6247
|
/**
|
|
6119
6248
|
* Register a single plugin's hook by name
|
|
@@ -6815,6 +6944,15 @@ var HookPipeline = class HookPipeline {
|
|
|
6815
6944
|
return (this.hooks.get(hookName) ?? []).filter((h) => h.exclusive).map((h) => ({ pluginId: h.pluginId }));
|
|
6816
6945
|
}
|
|
6817
6946
|
/**
|
|
6947
|
+
* Get all plugins that registered a non-exclusive handler for a given
|
|
6948
|
+
* hook (e.g. `email:beforeSend`, `email:afterSend`), preserving priority
|
|
6949
|
+
* order. Partitions with `getExclusiveHookProviders()`, which returns
|
|
6950
|
+
* plugins whose registration is marked `exclusive: true`.
|
|
6951
|
+
*/
|
|
6952
|
+
getHookProviders(hookName) {
|
|
6953
|
+
return (this.hooks.get(hookName) ?? []).filter((h) => !h.exclusive).map((h) => ({ pluginId: h.pluginId }));
|
|
6954
|
+
}
|
|
6955
|
+
/**
|
|
6818
6956
|
* Invoke an exclusive hook — dispatch only to the selected provider.
|
|
6819
6957
|
* Returns null if no provider is selected or if the selected hook
|
|
6820
6958
|
* is not found in the pipeline.
|
|
@@ -7058,8 +7196,15 @@ const MAX_STORED_EMAILS = 100;
|
|
|
7058
7196
|
* instances (the runtime and the route handler may load separate copies
|
|
7059
7197
|
* of this module, but globalThis is always the same object).
|
|
7060
7198
|
*/
|
|
7061
|
-
const GLOBAL_KEY = "
|
|
7062
|
-
const
|
|
7199
|
+
const GLOBAL_KEY = Symbol.for("emdash:dev-emails");
|
|
7200
|
+
const g = globalThis;
|
|
7201
|
+
const storedEmails = (() => {
|
|
7202
|
+
const existing = g[GLOBAL_KEY];
|
|
7203
|
+
if (existing) return existing;
|
|
7204
|
+
const fresh = [];
|
|
7205
|
+
g[GLOBAL_KEY] = fresh;
|
|
7206
|
+
return fresh;
|
|
7207
|
+
})();
|
|
7063
7208
|
/**
|
|
7064
7209
|
* The email:deliver handler for the dev console provider.
|
|
7065
7210
|
* Logs to console and stores in memory.
|
|
@@ -7696,18 +7841,6 @@ function createNoopSandboxRunner(_options) {
|
|
|
7696
7841
|
return new NoopSandboxRunner();
|
|
7697
7842
|
}
|
|
7698
7843
|
|
|
7699
|
-
//#endregion
|
|
7700
|
-
//#region src/plugins/types.ts
|
|
7701
|
-
/**
|
|
7702
|
-
* Check if a value is a StandardPluginDefinition (has hooks/routes but no id/version).
|
|
7703
|
-
*/
|
|
7704
|
-
function isStandardPluginDefinition(value) {
|
|
7705
|
-
if (typeof value !== "object" || value === null) return false;
|
|
7706
|
-
const hasPluginShape = "hooks" in value || "routes" in value;
|
|
7707
|
-
const hasNativeShape = "id" in value && "version" in value;
|
|
7708
|
-
return hasPluginShape && !hasNativeShape;
|
|
7709
|
-
}
|
|
7710
|
-
|
|
7711
7844
|
//#endregion
|
|
7712
7845
|
//#region src/import/sections.ts
|
|
7713
7846
|
/**
|
|
@@ -8631,6 +8764,7 @@ registerSource(wxrSource);
|
|
|
8631
8764
|
*
|
|
8632
8765
|
* Creates preview URLs that include a signed token for accessing draft content.
|
|
8633
8766
|
*/
|
|
8767
|
+
const REPEATED_SLASHES = /\/{2,}/g;
|
|
8634
8768
|
/**
|
|
8635
8769
|
* Generate a preview URL for content
|
|
8636
8770
|
*
|
|
@@ -8665,13 +8799,15 @@ registerSource(wxrSource);
|
|
|
8665
8799
|
* ```
|
|
8666
8800
|
*/
|
|
8667
8801
|
async function getPreviewUrl(options) {
|
|
8668
|
-
const { collection, id, secret, expiresIn = "1h", baseUrl, pathPattern = "/{collection}/{id}" } = options;
|
|
8802
|
+
const { collection, id, secret, expiresIn = "1h", baseUrl, pathPattern = "/{collection}/{id}", locale = "" } = options;
|
|
8669
8803
|
const token = await generatePreviewToken({
|
|
8670
8804
|
contentId: `${collection}:${id}`,
|
|
8671
8805
|
expiresIn,
|
|
8672
8806
|
secret
|
|
8673
8807
|
});
|
|
8674
|
-
|
|
8808
|
+
let path = pathPattern.replace("{collection}", collection).replace("{id}", id).replace("{locale}", locale);
|
|
8809
|
+
path = path.replace(REPEATED_SLASHES, "/");
|
|
8810
|
+
if (path.length > 1 && path.endsWith("/")) path = path.slice(0, -1);
|
|
8675
8811
|
const url = new URL(path, baseUrl || "http://placeholder");
|
|
8676
8812
|
url.searchParams.set("_preview", token);
|
|
8677
8813
|
if (!baseUrl) return `${url.pathname}${url.search}`;
|
|
@@ -9186,6 +9322,22 @@ const WHITESPACE_SPLIT_PATTERN = /\s+/;
|
|
|
9186
9322
|
const FTS_OPERATORS_PATTERN = /\b(AND|OR|NOT|NEAR)\b/i;
|
|
9187
9323
|
const DOUBLE_QUOTE_PATTERN = /"/g;
|
|
9188
9324
|
/**
|
|
9325
|
+
* Detect FTS5 query syntax errors. Match specifically on the SQLite FTS5
|
|
9326
|
+
* error fingerprints rather than a broad "fts5" / "syntax error" filter
|
|
9327
|
+
* (which would also swallow internal table-corruption errors). The two
|
|
9328
|
+
* fingerprints we care about are:
|
|
9329
|
+
*
|
|
9330
|
+
* - "fts5: syntax error near …" — unbalanced quotes, stray operators,
|
|
9331
|
+
* other malformed user input
|
|
9332
|
+
* - "unknown special query: …" — bare special tokens like `^*` that
|
|
9333
|
+
* parse but don't resolve to a real FTS5 directive
|
|
9334
|
+
*/
|
|
9335
|
+
function isFts5SyntaxError(error) {
|
|
9336
|
+
if (!(error instanceof Error)) return false;
|
|
9337
|
+
const message = error.message.toLowerCase();
|
|
9338
|
+
return message.includes("fts5: syntax error") || message.includes("unknown special query");
|
|
9339
|
+
}
|
|
9340
|
+
/**
|
|
9189
9341
|
* Search across multiple collections
|
|
9190
9342
|
*
|
|
9191
9343
|
* Public API that auto-injects the database.
|
|
@@ -9282,7 +9434,9 @@ async function searchSingleCollection(db, collection, query, options, weights) {
|
|
|
9282
9434
|
bm25Args = weightValues.join(", ");
|
|
9283
9435
|
}
|
|
9284
9436
|
const bm25Expr = bm25Args ? `bm25("${ftsTable}", ${bm25Args})` : `bm25("${ftsTable}")`;
|
|
9285
|
-
|
|
9437
|
+
let results;
|
|
9438
|
+
try {
|
|
9439
|
+
results = await sql`
|
|
9286
9440
|
SELECT
|
|
9287
9441
|
c.id,
|
|
9288
9442
|
c.slug,
|
|
@@ -9298,16 +9452,45 @@ async function searchSingleCollection(db, collection, query, options, weights) {
|
|
|
9298
9452
|
${locale ? sql`AND c.locale = ${locale}` : sql``}
|
|
9299
9453
|
ORDER BY score
|
|
9300
9454
|
LIMIT ${limit}
|
|
9301
|
-
`.execute(db)
|
|
9455
|
+
`.execute(db);
|
|
9456
|
+
} catch (error) {
|
|
9457
|
+
if (isFts5SyntaxError(error)) return [];
|
|
9458
|
+
throw error;
|
|
9459
|
+
}
|
|
9460
|
+
return results.rows.map((row) => ({
|
|
9302
9461
|
collection,
|
|
9303
9462
|
id: row.id,
|
|
9304
9463
|
slug: row.slug,
|
|
9305
9464
|
locale: row.locale,
|
|
9306
9465
|
title: row.title ?? void 0,
|
|
9307
|
-
snippet: row.snippet,
|
|
9466
|
+
snippet: row.snippet === null ? void 0 : sanitizeSnippet(row.snippet),
|
|
9308
9467
|
score: Math.abs(row.score)
|
|
9309
9468
|
}));
|
|
9310
9469
|
}
|
|
9470
|
+
const SNIPPET_AMP_RE = /&/g;
|
|
9471
|
+
const SNIPPET_LT_RE = /</g;
|
|
9472
|
+
const SNIPPET_GT_RE = />/g;
|
|
9473
|
+
const SNIPPET_QUOT_RE = /"/g;
|
|
9474
|
+
const SNIPPET_APOS_RE = /'/g;
|
|
9475
|
+
/**
|
|
9476
|
+
* Make an FTS5 snippet safe to render with `set:html` / `innerHTML`.
|
|
9477
|
+
*
|
|
9478
|
+
* SQLite's `snippet()` function splices literal `<mark>` and `</mark>`
|
|
9479
|
+
* markers around matched terms but does not escape the surrounding
|
|
9480
|
+
* source text. Posts that legitimately contain `<`, `>`, `&`, `"` or
|
|
9481
|
+
* `'` would render as broken markup, and a `<script>` literal in a
|
|
9482
|
+
* title (or any other indexed field) would execute when displayed.
|
|
9483
|
+
*
|
|
9484
|
+
* The fix: HTML-escape the whole string, which turns the markers into
|
|
9485
|
+
* `<mark>` / `</mark>`. Then restore those two patterns to
|
|
9486
|
+
* their original tag form. The result is "the indexed text with all
|
|
9487
|
+
* HTML metacharacters escaped, plus a small set of literal `<mark>`
|
|
9488
|
+
* highlight tags around matched terms" — which matches the API's
|
|
9489
|
+
* documented contract.
|
|
9490
|
+
*/
|
|
9491
|
+
function sanitizeSnippet(snippet) {
|
|
9492
|
+
return snippet.replace(SNIPPET_AMP_RE, "&").replace(SNIPPET_LT_RE, "<").replace(SNIPPET_GT_RE, ">").replace(SNIPPET_QUOT_RE, """).replace(SNIPPET_APOS_RE, "'").replaceAll("<mark>", "<mark>").replaceAll("</mark>", "</mark>");
|
|
9493
|
+
}
|
|
9311
9494
|
/**
|
|
9312
9495
|
* Get search suggestions for autocomplete
|
|
9313
9496
|
*
|
|
@@ -9331,20 +9514,26 @@ async function getSuggestions(db, query, options = {}) {
|
|
|
9331
9514
|
const contentTable = ftsManager.getContentTableName(collection);
|
|
9332
9515
|
const prefixQuery = escapeQuery(query);
|
|
9333
9516
|
if (!prefixQuery) continue;
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
|
|
9342
|
-
|
|
9343
|
-
|
|
9344
|
-
|
|
9345
|
-
|
|
9346
|
-
|
|
9347
|
-
|
|
9517
|
+
let results;
|
|
9518
|
+
try {
|
|
9519
|
+
results = await sql`
|
|
9520
|
+
SELECT
|
|
9521
|
+
c.id,
|
|
9522
|
+
c.title
|
|
9523
|
+
FROM "${sql.raw(ftsTable)}" f
|
|
9524
|
+
JOIN "${sql.raw(contentTable)}" c ON f.id = c.id
|
|
9525
|
+
WHERE "${sql.raw(ftsTable)}" MATCH ${prefixQuery}
|
|
9526
|
+
AND c.status = 'published'
|
|
9527
|
+
AND c.deleted_at IS NULL
|
|
9528
|
+
AND c.title IS NOT NULL
|
|
9529
|
+
${locale ? sql`AND c.locale = ${locale}` : sql``}
|
|
9530
|
+
ORDER BY bm25("${sql.raw(ftsTable)}")
|
|
9531
|
+
LIMIT ${limit}
|
|
9532
|
+
`.execute(db);
|
|
9533
|
+
} catch (error) {
|
|
9534
|
+
if (isFts5SyntaxError(error)) continue;
|
|
9535
|
+
throw error;
|
|
9536
|
+
}
|
|
9348
9537
|
for (const row of results.rows) suggestions.push({
|
|
9349
9538
|
collection,
|
|
9350
9539
|
id: row.id,
|
|
@@ -9490,5 +9679,5 @@ function extractSearchableFields(entry, fields) {
|
|
|
9490
9679
|
}
|
|
9491
9680
|
|
|
9492
9681
|
//#endregion
|
|
9493
|
-
export {
|
|
9494
|
-
//# sourceMappingURL=search-
|
|
9682
|
+
export { isSafeHref as $, NoopSandboxRunner as A, handleContentTranslations as At, HookPipeline as B, getAllSources as C, handleContentGetIncludingTrashed as Ct, probeUrl as D, handleContentPublish as Dt, getUrlSources as E, handleContentPermanentDelete as Et, PluginRouteError as F, portableText as Ft, sanitizeHeadersForSandbox as G, resolveExclusiveHooks as H, PluginRouteRegistry as I, reference as It, parseWxr as J, getTrustedProxyHeaders as K, DEV_CONSOLE_EMAIL_PLUGIN_ID as L, image as Lt, createNoopSandboxRunner as M, handleContentUnschedule as Mt, PluginManager as N, handleContentUpdate as Nt, registerSource as O, handleContentRestore as Ot, createPluginManager as P, validateRev as Pt, prosemirrorToPortableText as Q, devConsoleEmailDeliver as R, clearSources as S, handleContentGet as St, getSource as T, handleContentListTrashed as Tt, CronExecutor as U, createHookPipeline as V, extractRequestMeta as W, after as X, parseWxrString as Y, portableTextToProsemirror as Z, buildPreviewUrl as _, handleContentCountTrashed as _t, search as a, getCollectionInfo as at, parseWxrDate as b, handleContentDiscardDraft as bt, getWidgetArea as c, handleMediaGet as ct, getMenu as d, handleRevisionGet as dt, sanitizeHref as et, getMenus as f, handleRevisionList as ft, isPreviewRequest as g, handleContentCountScheduled as gt, getPreviewToken as h, handleContentCompare as ht, getSuggestions as i, PluginStateRepository as it, SandboxNotAvailableError as j, handleContentUnpublish as jt, importReusableBlocksAsSections as k, handleContentSchedule as kt, getWidgetAreas as l, handleMediaList as lt, getComments as m, generateManifest as mt, extractSearchableFields as n, getSection as nt, searchCollection as o, handleMediaCreate as ot, getCommentCount as p, handleRevisionRestore as pt, definePlugin as q, getSearchStats as r, getSections as rt, searchWithDb as s, handleMediaDelete as st, extractPlainText as t, loadBundleFromR2 as tt, getWidgetComponents as u, handleMediaUpdate as ut, getPreviewUrl as v, handleContentCreate as vt, getFileSources as w, handleContentList as wt, wxrSource as x, handleContentDuplicate as xt, wordpressRestSource as y, handleContentDelete as yt, EmailPipeline as z };
|
|
9683
|
+
//# sourceMappingURL=search-dOGEccMa.mjs.map
|