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
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* GET /_emdash/api/search?q=query&collections=posts,pages&limit=20
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { hasPermission } from "@emdash-cms/auth";
|
|
7
8
|
import type { APIRoute } from "astro";
|
|
8
9
|
|
|
9
10
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
@@ -23,7 +24,7 @@ export const prerender = false;
|
|
|
23
24
|
* - limit: Maximum results (optional, defaults to 20)
|
|
24
25
|
*/
|
|
25
26
|
export const GET: APIRoute = async ({ url, locals }) => {
|
|
26
|
-
const { emdash } = locals;
|
|
27
|
+
const { emdash, user } = locals;
|
|
27
28
|
|
|
28
29
|
if (!emdash?.db) {
|
|
29
30
|
return apiError("NOT_CONFIGURED", "EmDash not configured", 500);
|
|
@@ -36,6 +37,13 @@ export const GET: APIRoute = async ({ url, locals }) => {
|
|
|
36
37
|
? query.collections.split(",").map((c: string) => c.trim())
|
|
37
38
|
: undefined;
|
|
38
39
|
|
|
40
|
+
// Only users with content:read_drafts may search non-published statuses.
|
|
41
|
+
// Anonymous and subscriber requests are forced to "published".
|
|
42
|
+
const status =
|
|
43
|
+
query.status && query.status !== "published" && hasPermission(user, "content:read_drafts")
|
|
44
|
+
? query.status
|
|
45
|
+
: "published";
|
|
46
|
+
|
|
39
47
|
try {
|
|
40
48
|
// Verify FTS indexes are healthy on first use. At most once per worker
|
|
41
49
|
// lifetime; no-op after that. Moved off the cold-start hot path to
|
|
@@ -44,7 +52,7 @@ export const GET: APIRoute = async ({ url, locals }) => {
|
|
|
44
52
|
|
|
45
53
|
const result = await searchWithDb(emdash.db, query.q, {
|
|
46
54
|
collections,
|
|
47
|
-
status
|
|
55
|
+
status,
|
|
48
56
|
locale: query.locale,
|
|
49
57
|
limit: query.limit,
|
|
50
58
|
});
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type { APIRoute } from "astro";
|
|
10
10
|
|
|
11
11
|
import { requirePerm } from "#api/authorize.js";
|
|
12
|
-
import { apiError, handleError, unwrapResult } from "#api/error.js";
|
|
12
|
+
import { apiError, handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
13
13
|
import {
|
|
14
14
|
handleSectionDelete,
|
|
15
15
|
handleSectionGet,
|
|
@@ -22,7 +22,9 @@ export const prerender = false;
|
|
|
22
22
|
|
|
23
23
|
export const GET: APIRoute = async ({ params, locals }) => {
|
|
24
24
|
const { emdash, user } = locals;
|
|
25
|
-
const
|
|
25
|
+
const dbErr = requireDb(emdash?.db);
|
|
26
|
+
if (dbErr) return dbErr;
|
|
27
|
+
const db = emdash!.db;
|
|
26
28
|
const { slug } = params;
|
|
27
29
|
|
|
28
30
|
const denied = requirePerm(user, "sections:read");
|
|
@@ -42,7 +44,9 @@ export const GET: APIRoute = async ({ params, locals }) => {
|
|
|
42
44
|
|
|
43
45
|
export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
44
46
|
const { emdash, user } = locals;
|
|
45
|
-
const
|
|
47
|
+
const dbErr = requireDb(emdash?.db);
|
|
48
|
+
if (dbErr) return dbErr;
|
|
49
|
+
const db = emdash!.db;
|
|
46
50
|
const { slug } = params;
|
|
47
51
|
|
|
48
52
|
const denied = requirePerm(user, "sections:manage");
|
|
@@ -65,7 +69,9 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
65
69
|
|
|
66
70
|
export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
67
71
|
const { emdash, user } = locals;
|
|
68
|
-
const
|
|
72
|
+
const dbErr = requireDb(emdash?.db);
|
|
73
|
+
if (dbErr) return dbErr;
|
|
74
|
+
const db = emdash!.db;
|
|
69
75
|
const { slug } = params;
|
|
70
76
|
|
|
71
77
|
const denied = requirePerm(user, "sections:manage");
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { APIRoute } from "astro";
|
|
9
9
|
|
|
10
10
|
import { requirePerm } from "#api/authorize.js";
|
|
11
|
-
import { handleError, unwrapResult } from "#api/error.js";
|
|
11
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
12
12
|
import { handleSectionCreate, handleSectionList } from "#api/handlers/sections.js";
|
|
13
13
|
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
14
14
|
import { createSectionBody, sectionsListQuery } from "#api/schemas.js";
|
|
@@ -17,7 +17,9 @@ export const prerender = false;
|
|
|
17
17
|
|
|
18
18
|
export const GET: APIRoute = async ({ url, locals }) => {
|
|
19
19
|
const { emdash, user } = locals;
|
|
20
|
-
const
|
|
20
|
+
const dbErr = requireDb(emdash?.db);
|
|
21
|
+
if (dbErr) return dbErr;
|
|
22
|
+
const db = emdash!.db;
|
|
21
23
|
|
|
22
24
|
const denied = requirePerm(user, "sections:read");
|
|
23
25
|
if (denied) return denied;
|
|
@@ -35,7 +37,9 @@ export const GET: APIRoute = async ({ url, locals }) => {
|
|
|
35
37
|
|
|
36
38
|
export const POST: APIRoute = async ({ request, locals }) => {
|
|
37
39
|
const { emdash, user } = locals;
|
|
38
|
-
const
|
|
40
|
+
const dbErr = requireDb(emdash?.db);
|
|
41
|
+
if (dbErr) return dbErr;
|
|
42
|
+
const db = emdash!.db;
|
|
39
43
|
|
|
40
44
|
const denied = requirePerm(user, "sections:manage");
|
|
41
45
|
if (denied) return denied;
|
|
@@ -49,20 +49,15 @@ export const GET: APIRoute = async ({ locals }) => {
|
|
|
49
49
|
`emdash:exclusive_hook:${EMAIL_DELIVER_HOOK}`,
|
|
50
50
|
);
|
|
51
51
|
|
|
52
|
-
// Get middleware hooks (beforeSend / afterSend)
|
|
52
|
+
// Get middleware hooks (beforeSend / afterSend). These are non-exclusive —
|
|
53
|
+
// many plugins can subscribe — so we enumerate non-exclusive providers.
|
|
53
54
|
const beforeSendPlugins = pipeline
|
|
54
|
-
.
|
|
55
|
+
.getHookProviders(EMAIL_BEFORE_SEND_HOOK)
|
|
55
56
|
.map((p) => p.pluginId);
|
|
56
57
|
const afterSendPlugins = pipeline
|
|
57
|
-
.
|
|
58
|
+
.getHookProviders(EMAIL_AFTER_SEND_HOOK)
|
|
58
59
|
.map((p) => p.pluginId);
|
|
59
60
|
|
|
60
|
-
// Note: beforeSend/afterSend are NOT exclusive hooks, but getExclusiveHookProviders
|
|
61
|
-
// only finds exclusive ones. We need all hooks for those names.
|
|
62
|
-
// For now, report what we can from the exclusive hook system.
|
|
63
|
-
// Middleware is non-exclusive so we'd need a different query.
|
|
64
|
-
// TODO: Add getHookProviders() for non-exclusive hooks to the pipeline.
|
|
65
|
-
|
|
66
61
|
return apiSuccess({
|
|
67
62
|
available: emdash.email?.isAvailable() ?? false,
|
|
68
63
|
providers: providers.map((p) => ({
|
|
@@ -16,6 +16,7 @@ import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
|
16
16
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
17
17
|
import { getPublicOrigin } from "#api/public-url.js";
|
|
18
18
|
import { setupAdminVerifyBody } from "#api/schemas.js";
|
|
19
|
+
import { getConfiguredAllowedOrigins, validateAllowedOrigins } from "#auth/allowed-origins.js";
|
|
19
20
|
import { createChallengeStore } from "#auth/challenge-store.js";
|
|
20
21
|
import { getPasskeyConfig } from "#auth/passkey-config.js";
|
|
21
22
|
import { SETUP_NONCE_COOKIE } from "#auth/setup-nonce.js";
|
|
@@ -83,7 +84,11 @@ export const POST: APIRoute = async ({ cookies, request, locals }) => {
|
|
|
83
84
|
const url = new URL(request.url);
|
|
84
85
|
const siteName = (await options.get<string>("emdash:site_title")) ?? undefined;
|
|
85
86
|
const siteUrl = getPublicOrigin(url, emdash?.config);
|
|
86
|
-
const
|
|
87
|
+
const allowedOrigins = validateAllowedOrigins(
|
|
88
|
+
siteUrl,
|
|
89
|
+
getConfiguredAllowedOrigins(emdash?.config),
|
|
90
|
+
);
|
|
91
|
+
const passkeyConfig = getPasskeyConfig(url, siteName, siteUrl, allowedOrigins);
|
|
87
92
|
|
|
88
93
|
// Verify the registration response
|
|
89
94
|
const challengeStore = createChallengeStore(emdash.db);
|
|
@@ -49,6 +49,10 @@ export const POST: APIRoute = async ({ cookies, request, locals }) => {
|
|
|
49
49
|
const body = await parseBody(request, setupAdminBody);
|
|
50
50
|
if (isParseError(body)) return body;
|
|
51
51
|
|
|
52
|
+
// Preserve title/tagline from step 1 by reading existing setup state
|
|
53
|
+
// before we overwrite it below.
|
|
54
|
+
const existingState = await options.get<Record<string, unknown>>("emdash:setup_state");
|
|
55
|
+
|
|
52
56
|
// Mint a fresh session nonce. This binds the follow-up
|
|
53
57
|
// /setup/admin/verify call to the same browser that made this
|
|
54
58
|
// request, so an unauthenticated attacker on another host cannot
|
|
@@ -81,9 +85,11 @@ export const POST: APIRoute = async ({ cookies, request, locals }) => {
|
|
|
81
85
|
challengeStore,
|
|
82
86
|
);
|
|
83
87
|
|
|
84
|
-
// Store the nonce alongside the rest of the setup state
|
|
85
|
-
//
|
|
88
|
+
// Store the nonce alongside the rest of the setup state, preserving
|
|
89
|
+
// title/tagline from step 1. The verify endpoint will constant-time
|
|
90
|
+
// compare the nonce with the incoming cookie.
|
|
86
91
|
await options.set("emdash:setup_state", {
|
|
92
|
+
...existingState,
|
|
87
93
|
step: "admin",
|
|
88
94
|
email: body.email.toLowerCase(),
|
|
89
95
|
name: body.name || null,
|
|
@@ -81,7 +81,7 @@ export const POST: APIRoute = async ({ request, url, locals }) => {
|
|
|
81
81
|
|
|
82
82
|
// 5. Store setup state
|
|
83
83
|
// In external auth mode, mark setup complete immediately (first user to login becomes admin)
|
|
84
|
-
//
|
|
84
|
+
// Otherwise, setup_complete is set after admin user is created (passkey or auth provider)
|
|
85
85
|
const authMode = getAuthMode(emdash.config);
|
|
86
86
|
const useExternalAuth = authMode.type === "external";
|
|
87
87
|
|
|
@@ -105,7 +105,7 @@ export const POST: APIRoute = async ({ request, url, locals }) => {
|
|
|
105
105
|
await options.set("emdash:site_tagline", body.tagline);
|
|
106
106
|
}
|
|
107
107
|
} else {
|
|
108
|
-
// Passkey mode: store state for next step (admin creation)
|
|
108
|
+
// Passkey/provider mode: store state for next step (admin creation)
|
|
109
109
|
await options.set("emdash:setup_state", {
|
|
110
110
|
step: "site_complete",
|
|
111
111
|
title: body.title,
|
|
@@ -91,7 +91,7 @@ export const GET: APIRoute = async ({ locals }) => {
|
|
|
91
91
|
const authMode = getAuthMode(emdash.config);
|
|
92
92
|
const useExternalAuth = authMode.type === "external";
|
|
93
93
|
|
|
94
|
-
// In external auth mode, setup is complete if flag is set (no users required initially)
|
|
94
|
+
// In external auth mode (not atproto), setup is complete if flag is set (no users required initially)
|
|
95
95
|
if (useExternalAuth && isComplete) {
|
|
96
96
|
return apiSuccess({
|
|
97
97
|
needsSetup: false,
|
|
@@ -106,6 +106,8 @@ export const GET: APIRoute = async ({ locals }) => {
|
|
|
106
106
|
description: seed.meta?.description || "",
|
|
107
107
|
collections: seed.collections?.length || 0,
|
|
108
108
|
hasContent: !!(seed.content && Object.keys(seed.content).length > 0),
|
|
109
|
+
title: seed.settings?.title,
|
|
110
|
+
tagline: seed.settings?.tagline,
|
|
109
111
|
}
|
|
110
112
|
: null;
|
|
111
113
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - Excludes auth/user/session/token tables
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import type { User } from "@emdash-cms/auth";
|
|
10
11
|
import type { APIRoute } from "astro";
|
|
11
12
|
|
|
12
13
|
import { requirePerm } from "#api/authorize.js";
|
|
@@ -17,11 +18,31 @@ import {
|
|
|
17
18
|
verifyPreviewSignature,
|
|
18
19
|
} from "#api/handlers/snapshot.js";
|
|
19
20
|
import { getPublicOrigin } from "#api/public-url.js";
|
|
21
|
+
import { resolveSecretsCached } from "#config/secrets.js";
|
|
20
22
|
|
|
21
23
|
export const prerender = false;
|
|
22
24
|
|
|
23
|
-
export const GET: APIRoute = async ({ request, locals, url }) => {
|
|
24
|
-
const { emdash
|
|
25
|
+
export const GET: APIRoute = async ({ request, locals, url, session }) => {
|
|
26
|
+
const { emdash } = locals;
|
|
27
|
+
// This route is in PUBLIC_API_EXACT (for preview-signature callers with no session),
|
|
28
|
+
// so auth middleware skips user resolution. Manually resolve the session user here
|
|
29
|
+
// to support session-authenticated admin users alongside preview-signature auth.
|
|
30
|
+
let user: User | undefined = (locals as { user?: User }).user;
|
|
31
|
+
if (!user && session && emdash?.db) {
|
|
32
|
+
try {
|
|
33
|
+
const { createKyselyAdapter } = await import("@emdash-cms/auth/adapters/kysely");
|
|
34
|
+
const sessionUser = await session.get("user");
|
|
35
|
+
if (sessionUser?.id) {
|
|
36
|
+
const adapter = createKyselyAdapter(emdash.db);
|
|
37
|
+
const resolved = await adapter.getUserById(sessionUser.id);
|
|
38
|
+
if (resolved && !resolved.disabled) {
|
|
39
|
+
user = resolved;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
// Session resolution failed, continue to preview-signature check
|
|
44
|
+
}
|
|
45
|
+
}
|
|
25
46
|
|
|
26
47
|
if (!emdash?.db) {
|
|
27
48
|
return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500);
|
|
@@ -32,24 +53,29 @@ export const GET: APIRoute = async ({ request, locals, url }) => {
|
|
|
32
53
|
let authorized = false;
|
|
33
54
|
|
|
34
55
|
if (previewSig) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
// Resolves env override or DB-stored value. Always non-empty after
|
|
57
|
+
// resolution, so the signature path is never silently disabled.
|
|
58
|
+
// Note: a signing process without access to this database (e.g. a
|
|
59
|
+
// remote preview Worker) must set the same `EMDASH_PREVIEW_SECRET`
|
|
60
|
+
// env var on both sides.
|
|
61
|
+
const { previewSecret: secret, previewSecretSource } = await resolveSecretsCached(emdash.db);
|
|
62
|
+
const parsed = parsePreviewSignatureHeader(previewSig);
|
|
63
|
+
if (!parsed) {
|
|
64
|
+
console.warn("[snapshot] Failed to parse X-Preview-Signature header");
|
|
40
65
|
} else {
|
|
41
|
-
|
|
42
|
-
if (!
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
authorized = await verifyPreviewSignature(parsed.source, parsed.exp, parsed.sig, secret);
|
|
67
|
+
if (!authorized) {
|
|
68
|
+
const fields: Record<string, unknown> = {
|
|
69
|
+
source: parsed.source,
|
|
70
|
+
exp: parsed.exp,
|
|
71
|
+
expired: parsed.exp < Date.now() / 1000,
|
|
72
|
+
secretSource: previewSecretSource,
|
|
73
|
+
};
|
|
74
|
+
if (previewSecretSource === "db") {
|
|
75
|
+
fields.hint =
|
|
76
|
+
"Set EMDASH_PREVIEW_SECRET in both this process and the signing process to share secrets across deployments";
|
|
52
77
|
}
|
|
78
|
+
console.warn("[snapshot] Preview signature verification failed", fields);
|
|
53
79
|
}
|
|
54
80
|
}
|
|
55
81
|
}
|
|
@@ -52,7 +52,6 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
52
52
|
if (isParseError(body)) return body;
|
|
53
53
|
|
|
54
54
|
const result = await handleTaxonomyCreate(emdash.db, body);
|
|
55
|
-
if (result.success) emdash.invalidateManifest();
|
|
56
55
|
return unwrapResult(result, 201);
|
|
57
56
|
} catch (error) {
|
|
58
57
|
return handleError(error, "Failed to create taxonomy", "TAXONOMY_CREATE_ERROR");
|
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
* POST /_emdash/api/themes/preview
|
|
5
5
|
*
|
|
6
6
|
* Generates a signed preview URL for the "Try with my data" feature.
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* Uses the resolved preview secret: env override (`EMDASH_PREVIEW_SECRET`)
|
|
9
|
+
* wins, otherwise an auto-generated stable per-site value persisted in the
|
|
10
|
+
* options table is used. Processes that share the same database converge on
|
|
11
|
+
* the same auto-generated value; only set `EMDASH_PREVIEW_SECRET` in both
|
|
12
|
+
* processes when the verifying side runs without access to the EmDash DB
|
|
13
|
+
* (e.g. a remote preview Worker).
|
|
8
14
|
*/
|
|
9
15
|
|
|
10
16
|
import type { APIRoute } from "astro";
|
|
@@ -12,6 +18,7 @@ import type { APIRoute } from "astro";
|
|
|
12
18
|
import { requirePerm } from "#api/authorize.js";
|
|
13
19
|
import { apiError, apiSuccess } from "#api/error.js";
|
|
14
20
|
import { getPublicOrigin } from "#api/public-url.js";
|
|
21
|
+
import { resolveSecretsCached } from "#config/secrets.js";
|
|
15
22
|
|
|
16
23
|
export const prerender = false;
|
|
17
24
|
|
|
@@ -25,10 +32,9 @@ export const POST: APIRoute = async ({ request, url, locals }) => {
|
|
|
25
32
|
const denied = requirePerm(user, "plugins:read");
|
|
26
33
|
if (denied) return denied;
|
|
27
34
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
35
|
+
// Always non-empty after resolution; env override wins, otherwise a
|
|
36
|
+
// stable DB-stored value is used.
|
|
37
|
+
const { previewSecret: secret } = await resolveSecretsCached(emdash.db);
|
|
32
38
|
|
|
33
39
|
let body: { previewUrl: string };
|
|
34
40
|
try {
|
|
@@ -11,6 +11,8 @@ import { requirePerm } from "#api/authorize.js";
|
|
|
11
11
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
12
12
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
13
13
|
import { updateWidgetBody } from "#api/schemas.js";
|
|
14
|
+
import { rowToWidget } from "#widgets/index.js";
|
|
15
|
+
import type { WidgetRow } from "#widgets/types.js";
|
|
14
16
|
|
|
15
17
|
export const prerender = false;
|
|
16
18
|
|
|
@@ -73,10 +75,11 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
73
75
|
const widget = await db
|
|
74
76
|
.selectFrom("_emdash_widgets")
|
|
75
77
|
.selectAll()
|
|
78
|
+
.$castTo<WidgetRow>()
|
|
76
79
|
.where("id", "=", id)
|
|
77
80
|
.executeTakeFirstOrThrow();
|
|
78
81
|
|
|
79
|
-
return apiSuccess(widget);
|
|
82
|
+
return apiSuccess(rowToWidget(widget));
|
|
80
83
|
} catch (error) {
|
|
81
84
|
return handleError(error, "Failed to update widget", "WIDGET_UPDATE_ERROR");
|
|
82
85
|
}
|
|
@@ -11,6 +11,8 @@ import { requirePerm } from "#api/authorize.js";
|
|
|
11
11
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
12
12
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
13
13
|
import { createWidgetBody } from "#api/schemas.js";
|
|
14
|
+
import { rowToWidget } from "#widgets/index.js";
|
|
15
|
+
import type { WidgetRow } from "#widgets/types.js";
|
|
14
16
|
|
|
15
17
|
export const prerender = false;
|
|
16
18
|
|
|
@@ -70,10 +72,11 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
70
72
|
const widget = await db
|
|
71
73
|
.selectFrom("_emdash_widgets")
|
|
72
74
|
.selectAll()
|
|
75
|
+
.$castTo<WidgetRow>()
|
|
73
76
|
.where("id", "=", id)
|
|
74
77
|
.executeTakeFirstOrThrow();
|
|
75
78
|
|
|
76
|
-
return apiSuccess(widget, 201);
|
|
79
|
+
return apiSuccess(rowToWidget(widget), 201);
|
|
77
80
|
} catch (error) {
|
|
78
81
|
return handleError(error, "Failed to create widget", "WIDGET_CREATE_ERROR");
|
|
79
82
|
}
|
|
@@ -9,6 +9,8 @@ import type { APIRoute } from "astro";
|
|
|
9
9
|
|
|
10
10
|
import { requirePerm } from "#api/authorize.js";
|
|
11
11
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
12
|
+
import { rowToWidget } from "#widgets/index.js";
|
|
13
|
+
import type { WidgetRow } from "#widgets/types.js";
|
|
12
14
|
|
|
13
15
|
export const prerender = false;
|
|
14
16
|
|
|
@@ -40,13 +42,14 @@ export const GET: APIRoute = async ({ params, locals }) => {
|
|
|
40
42
|
const widgets = await db
|
|
41
43
|
.selectFrom("_emdash_widgets")
|
|
42
44
|
.selectAll()
|
|
45
|
+
.$castTo<WidgetRow>()
|
|
43
46
|
.where("area_id", "=", area.id)
|
|
44
47
|
.orderBy("sort_order", "asc")
|
|
45
48
|
.execute();
|
|
46
49
|
|
|
47
50
|
return apiSuccess({
|
|
48
51
|
...area,
|
|
49
|
-
widgets,
|
|
52
|
+
widgets: widgets.map((row) => rowToWidget(row)),
|
|
50
53
|
});
|
|
51
54
|
} catch (error) {
|
|
52
55
|
return handleError(error, "Failed to fetch widget area", "WIDGET_AREA_GET_ERROR");
|
|
@@ -12,6 +12,8 @@ import { requirePerm } from "#api/authorize.js";
|
|
|
12
12
|
import { apiError, apiSuccess, handleError } from "#api/error.js";
|
|
13
13
|
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
14
|
import { createWidgetAreaBody } from "#api/schemas.js";
|
|
15
|
+
import { rowToWidget } from "#widgets/index.js";
|
|
16
|
+
import type { WidgetRow } from "#widgets/types.js";
|
|
15
17
|
|
|
16
18
|
export const prerender = false;
|
|
17
19
|
|
|
@@ -35,13 +37,14 @@ export const GET: APIRoute = async ({ locals }) => {
|
|
|
35
37
|
const widgets = await db
|
|
36
38
|
.selectFrom("_emdash_widgets")
|
|
37
39
|
.selectAll()
|
|
40
|
+
.$castTo<WidgetRow>()
|
|
38
41
|
.where("area_id", "=", area.id)
|
|
39
42
|
.orderBy("sort_order", "asc")
|
|
40
43
|
.execute();
|
|
41
44
|
|
|
42
45
|
return {
|
|
43
46
|
...area,
|
|
44
|
-
widgets,
|
|
47
|
+
widgets: widgets.map((row) => rowToWidget(row)),
|
|
45
48
|
widgetCount: widgets.length,
|
|
46
49
|
};
|
|
47
50
|
}),
|
package/src/astro/types.ts
CHANGED
|
@@ -228,6 +228,15 @@ export interface EmDashHandlers {
|
|
|
228
228
|
slug?: string;
|
|
229
229
|
status?: string;
|
|
230
230
|
authorId?: string | null;
|
|
231
|
+
bylines?: Array<{ bylineId: string; roleLabel?: string | null }>;
|
|
232
|
+
seo?: {
|
|
233
|
+
title?: string | null;
|
|
234
|
+
description?: string | null;
|
|
235
|
+
image?: string | null;
|
|
236
|
+
canonical?: string | null;
|
|
237
|
+
noIndex?: boolean;
|
|
238
|
+
};
|
|
239
|
+
publishedAt?: string | null;
|
|
231
240
|
_rev?: string;
|
|
232
241
|
},
|
|
233
242
|
) => Promise<HandlerResponse>;
|
|
@@ -255,7 +264,11 @@ export interface EmDashHandlers {
|
|
|
255
264
|
) => Promise<HandlerResponse>;
|
|
256
265
|
|
|
257
266
|
// Publishing & Scheduling handlers
|
|
258
|
-
handleContentPublish: (
|
|
267
|
+
handleContentPublish: (
|
|
268
|
+
collection: string,
|
|
269
|
+
id: string,
|
|
270
|
+
options?: { publishedAt?: string },
|
|
271
|
+
) => Promise<HandlerResponse>;
|
|
259
272
|
|
|
260
273
|
handleContentUnpublish: (collection: string, id: string) => Promise<HandlerResponse>;
|
|
261
274
|
|
|
@@ -348,6 +361,7 @@ export interface EmDashHandlers {
|
|
|
348
361
|
// Direct access to storage and database for advanced use cases
|
|
349
362
|
storage: import("../index.js").Storage | null;
|
|
350
363
|
db: Kysely<import("../index.js").Database>;
|
|
364
|
+
getPublicMediaUrl?: (storageKey: string) => string;
|
|
351
365
|
|
|
352
366
|
// Hook pipeline for plugin integrations
|
|
353
367
|
hooks: import("../plugins/hooks.js").HookPipeline;
|
|
@@ -361,8 +375,15 @@ export interface EmDashHandlers {
|
|
|
361
375
|
// Configuration (for checking database type, auth mode, etc.)
|
|
362
376
|
config: import("./integration/runtime.js").EmDashConfig;
|
|
363
377
|
|
|
364
|
-
//
|
|
365
|
-
|
|
378
|
+
// Build the admin manifest from the live database. Only used by admin
|
|
379
|
+
// routes; logged-out requests don't need it. Per-request, deduplicated
|
|
380
|
+
// by `requestCached`.
|
|
381
|
+
getManifest: () => Promise<EmDashManifest>;
|
|
382
|
+
|
|
383
|
+
// Clear the cached URL patterns used by `resolveEmDashPath`. Call after
|
|
384
|
+
// any schema mutation that creates/updates/deletes a collection's
|
|
385
|
+
// `urlPattern` so public routing picks up the change immediately.
|
|
386
|
+
invalidateUrlPatternCache: () => void;
|
|
366
387
|
|
|
367
388
|
// Sandbox runner (for marketplace plugin install/update)
|
|
368
389
|
getSandboxRunner: () => import("../plugins/sandbox/types.js").SandboxRunner | null;
|
|
@@ -380,4 +401,12 @@ export interface EmDashHandlers {
|
|
|
380
401
|
collectPageFragments: (
|
|
381
402
|
page: import("../plugins/types.js").PublicPageContext,
|
|
382
403
|
) => Promise<import("../plugins/types.js").PageFragmentContribution[]>;
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Lazy search index health check. Search routes call this before
|
|
407
|
+
* querying so a crash-corrupted index gets repaired on first use
|
|
408
|
+
* rather than stalling cold start. Optional because it's only
|
|
409
|
+
* meaningful when an FTS5-capable runtime is wired in.
|
|
410
|
+
*/
|
|
411
|
+
ensureSearchHealthy?: () => Promise<void>;
|
|
383
412
|
}
|