emdash 0.8.0 → 0.10.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-BKSf3T9R.d.mts → adapters-BktHA7EO.d.mts} +1 -1
- package/dist/{adapters-BKSf3T9R.d.mts.map → adapters-BktHA7EO.d.mts.map} +1 -1
- package/dist/{apply-x0eMK1lX.mjs → apply-UsrFuO7l.mjs} +207 -355
- package/dist/apply-UsrFuO7l.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 +118 -4
- 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 +14 -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 +15 -10
- 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 +8 -5
- 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 +70 -121
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/types.d.mts +25 -10
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{byline-Chbr2GoP.mjs → byline-C3vnhIpU.mjs} +4 -4
- package/dist/{byline-Chbr2GoP.mjs.map → byline-C3vnhIpU.mjs.map} +1 -1
- package/dist/bylines-esI7ioa9.mjs +113 -0
- package/dist/bylines-esI7ioa9.mjs.map +1 -0
- package/dist/cache-fTzxgMFJ.mjs +65 -0
- package/dist/cache-fTzxgMFJ.mjs.map +1 -0
- package/dist/{chunks-HGz06Soa.mjs → chunks-Da2-b-oA.mjs} +8 -2
- package/dist/{chunks-HGz06Soa.mjs.map → chunks-Da2-b-oA.mjs.map} +1 -1
- package/dist/cli/index.mjs +456 -90
- 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-CVssduLe.mjs} +1 -1
- package/dist/{config-BXwuX8Bx.mjs.map → config-CVssduLe.mjs.map} +1 -1
- package/dist/{content-BcQPYxdV.mjs → content-C7G4QXkK.mjs} +42 -14
- package/dist/content-C7G4QXkK.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-l1Qh2RPR.mjs → db-errors-B7P2pSCn.mjs} +1 -1
- package/dist/{db-errors-l1Qh2RPR.mjs.map → db-errors-B7P2pSCn.mjs.map} +1 -1
- package/dist/{default-DCVqE5ib.mjs → default-pHuz9WF6.mjs} +1 -1
- package/dist/{default-DCVqE5ib.mjs.map → default-pHuz9WF6.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-zG5T1UGA.mjs → error-DqnRMM5z.mjs} +1 -1
- package/dist/{error-zG5T1UGA.mjs.map → error-DqnRMM5z.mjs.map} +1 -1
- package/dist/{index-DIb-CzNx.d.mts → index-DjPMOfO0.d.mts} +162 -87
- package/dist/index-DjPMOfO0.d.mts.map +1 -0
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +27 -24
- package/dist/{load-CyEoextb.mjs → load-sXRuM7Us.mjs} +2 -2
- package/dist/{load-CyEoextb.mjs.map → load-sXRuM7Us.mjs.map} +1 -1
- package/dist/{loader-CndGj8kM.mjs → loader-Bx2_9-5e.mjs} +53 -8
- package/dist/loader-Bx2_9-5e.mjs.map +1 -0
- package/dist/{manifest-schema-DH9xhc6t.mjs → manifest-schema-CXAbd1vH.mjs} +33 -3
- package/dist/manifest-schema-CXAbd1vH.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/{mode-BnAOqItE.mjs → mode-YhqNVef_.mjs} +1 -1
- package/dist/{mode-BnAOqItE.mjs.map → mode-YhqNVef_.mjs.map} +1 -1
- package/dist/options-nPxWnrya.mjs +117 -0
- package/dist/options-nPxWnrya.mjs.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{patterns-CrCYkMBb.mjs → patterns-DsUZ4uxI.mjs} +1 -1
- package/dist/{patterns-CrCYkMBb.mjs.map → patterns-DsUZ4uxI.mjs.map} +1 -1
- package/dist/{placeholder-D29tWZ7o.d.mts → placeholder-CDPtkelt.d.mts} +1 -1
- package/dist/{placeholder-D29tWZ7o.d.mts.map → placeholder-CDPtkelt.d.mts.map} +1 -1
- package/dist/{placeholder-C-fk5hYI.mjs → placeholder-Ci0RLeCk.mjs} +1 -1
- package/dist/{placeholder-C-fk5hYI.mjs.map → placeholder-Ci0RLeCk.mjs.map} +1 -1
- 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-B1AxbbbQ.mjs +51 -0
- package/dist/public-url-B1AxbbbQ.mjs.map +1 -0
- package/dist/{query-fqEdLFms.mjs → query-Bo-msrmu.mjs} +114 -16
- package/dist/query-Bo-msrmu.mjs.map +1 -0
- package/dist/{redirect-D_pshWdf.mjs → redirect-C5H7VGIX.mjs} +11 -6
- package/dist/redirect-C5H7VGIX.mjs.map +1 -0
- package/dist/{registry-C3Mr0ODu.mjs → registry-Beb7wxFc.mjs} +39 -5
- package/dist/registry-Beb7wxFc.mjs.map +1 -0
- package/dist/{request-cache-Ci7f5pBb.mjs → request-cache-C-tIpYIw.mjs} +1 -1
- package/dist/{request-cache-Ci7f5pBb.mjs.map → request-cache-C-tIpYIw.mjs.map} +1 -1
- package/dist/runner-Clwe4Mme.d.mts +44 -0
- package/dist/runner-Clwe4Mme.d.mts.map +1 -0
- package/dist/{runner-tQ7BJ4T7.mjs → runner-DMnlIkh4.mjs} +616 -191
- package/dist/runner-DMnlIkh4.mjs.map +1 -0
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +2 -2
- package/dist/{search-BoZYFuUk.mjs → search-DkN-BqsS.mjs} +270 -152
- package/dist/search-DkN-BqsS.mjs.map +1 -0
- package/dist/secrets-CZ8rxLX3.mjs +314 -0
- package/dist/secrets-CZ8rxLX3.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +13 -11
- 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.mjs +1 -1
- package/dist/taxonomies-CTtewrSQ.mjs +407 -0
- package/dist/taxonomies-CTtewrSQ.mjs.map +1 -0
- package/dist/taxonomy-DSxx2K2L.mjs +218 -0
- package/dist/taxonomy-DSxx2K2L.mjs.map +1 -0
- package/dist/{tokens-D9vnZqYS.mjs → tokens-CyRDPVW2.mjs} +1 -1
- package/dist/{tokens-D9vnZqYS.mjs.map → tokens-CyRDPVW2.mjs.map} +1 -1
- package/dist/{transaction-Cn2rjY78.mjs → transaction-D44LBXvU.mjs} +1 -1
- package/dist/{transaction-Cn2rjY78.mjs.map → transaction-D44LBXvU.mjs.map} +1 -1
- package/dist/{transport-CUnEL3Vs.d.mts → transport-DX_5rpsq.d.mts} +1 -1
- package/dist/{transport-CUnEL3Vs.d.mts.map → transport-DX_5rpsq.d.mts.map} +1 -1
- package/dist/{transport-C9ugt2Nr.mjs → transport-xpzIjCIB.mjs} +6 -5
- package/dist/{transport-C9ugt2Nr.mjs.map → transport-xpzIjCIB.mjs.map} +1 -1
- package/dist/{types-BrA0xf5I.d.mts → types-B_CXXnzh.d.mts} +1 -1
- package/dist/{types-BrA0xf5I.d.mts.map → types-B_CXXnzh.d.mts.map} +1 -1
- package/dist/{types-DIMwPFub.d.mts → types-C-aFbqmA.d.mts} +1 -1
- package/dist/{types-DIMwPFub.d.mts.map → types-C-aFbqmA.d.mts.map} +1 -1
- package/dist/types-CoO6mpV3.mjs +68 -0
- package/dist/types-CoO6mpV3.mjs.map +1 -0
- package/dist/{types-i36XcA_X.d.mts → types-D19uBYWn.d.mts} +83 -7
- package/dist/types-D19uBYWn.d.mts.map +1 -0
- package/dist/{types-BmPPSUEx.d.mts → types-Dl1fgFjn.d.mts} +24 -2
- package/dist/{types-BmPPSUEx.d.mts.map → types-Dl1fgFjn.d.mts.map} +1 -1
- package/dist/{types-CS8FIX7L.d.mts → types-Dtx1mSMX.d.mts} +9 -1
- package/dist/types-Dtx1mSMX.d.mts.map +1 -0
- package/dist/{types-Bm1dn-q3.mjs → types-Eg829jj9.mjs} +1 -1
- package/dist/{types-Bm1dn-q3.mjs.map → types-Eg829jj9.mjs.map} +1 -1
- package/dist/{types-CgqmmMJB.mjs → types-K-EkEQCI.mjs} +1 -1
- package/dist/{types-CgqmmMJB.mjs.map → types-K-EkEQCI.mjs.map} +1 -1
- package/dist/{validate-CxVsLehf.mjs → validate-CBIbxM3L.mjs} +14 -10
- package/dist/validate-CBIbxM3L.mjs.map +1 -0
- package/dist/{validate-DHxmpFJt.d.mts → validate-DHGwADqO.d.mts} +18 -5
- package/dist/validate-DHGwADqO.d.mts.map +1 -0
- package/dist/{validation-C-ZpN2GI.mjs → validation-B1NYiEos.mjs} +6 -6
- package/dist/{validation-C-ZpN2GI.mjs.map → validation-B1NYiEos.mjs.map} +1 -1
- package/dist/version-CMD42IRC.mjs +7 -0
- package/dist/{version-Bbq8TCrz.mjs.map → version-CMD42IRC.mjs.map} +1 -1
- package/dist/{zod-generator-CpwccCIv.mjs → zod-generator-BNJDQBSZ.mjs} +11 -6
- package/dist/{zod-generator-CpwccCIv.mjs.map → zod-generator-BNJDQBSZ.mjs.map} +1 -1
- package/locals.d.ts +1 -6
- package/package.json +9 -8
- package/src/api/handlers/comments.ts +6 -4
- package/src/api/handlers/content.ts +40 -1
- package/src/api/handlers/dashboard.ts +29 -36
- package/src/api/handlers/device-flow.ts +5 -0
- package/src/api/handlers/marketplace.ts +11 -4
- package/src/api/handlers/menus.ts +256 -75
- package/src/api/handlers/oauth-authorization.ts +72 -33
- package/src/api/handlers/revision.ts +23 -14
- package/src/api/handlers/taxonomies.ts +273 -100
- package/src/api/public-url.ts +48 -2
- package/src/api/schemas/comments.ts +2 -2
- package/src/api/schemas/common.ts +7 -0
- package/src/api/schemas/content.ts +17 -0
- package/src/api/schemas/menus.ts +23 -0
- package/src/api/schemas/sections.ts +3 -3
- package/src/api/schemas/taxonomies.ts +39 -0
- package/src/api/schemas/users.ts +1 -1
- package/src/api/types.ts +5 -1
- package/src/astro/integration/index.ts +17 -0
- package/src/astro/integration/routes.ts +10 -0
- package/src/astro/integration/runtime.ts +30 -0
- package/src/astro/integration/virtual-modules.ts +32 -2
- package/src/astro/integration/vite-config.ts +6 -1
- package/src/astro/middleware/auth.ts +13 -6
- package/src/astro/middleware/redirect.ts +29 -16
- package/src/astro/middleware/request-context.ts +15 -5
- package/src/astro/middleware.ts +23 -9
- package/src/astro/routes/api/auth/invite/complete.ts +6 -1
- 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]/permanent.ts +1 -1
- 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].ts +12 -0
- package/src/astro/routes/api/import/wordpress/execute.ts +3 -1
- package/src/astro/routes/api/import/wordpress/prepare.ts +7 -8
- package/src/astro/routes/api/import/wordpress/rewrite-url-helpers.ts +196 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +9 -177
- 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/menus/[name]/items.ts +16 -6
- package/src/astro/routes/api/menus/[name]/reorder.ts +8 -3
- package/src/astro/routes/api/menus/[name]/translations.ts +82 -0
- package/src/astro/routes/api/menus/[name].ts +19 -10
- package/src/astro/routes/api/menus/index.ts +9 -6
- 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/setup/admin-verify.ts +6 -1
- package/src/astro/routes/api/snapshot.ts +44 -18
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +89 -0
- package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +22 -22
- package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +11 -14
- package/src/astro/routes/api/taxonomies/index.ts +9 -7
- package/src/astro/routes/api/themes/preview.ts +11 -5
- package/src/astro/types.ts +23 -3
- package/src/auth/allowed-origins.ts +168 -0
- package/src/auth/passkey-config.ts +35 -13
- 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 +28 -8
- package/src/cli/commands/content.ts +13 -0
- package/src/cli/commands/export-seed.ts +82 -21
- package/src/cli/commands/login.ts +8 -1
- package/src/cli/commands/plugin-init.ts +216 -90
- 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/Embed.astro +1 -1
- package/src/components/Gallery.astro +1 -1
- package/src/components/Image.astro +1 -1
- package/src/components/InlinePortableTextEditor.tsx +104 -18
- 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/036_i18n_menus_and_taxonomies.ts +477 -0
- package/src/database/migrations/runner.ts +158 -23
- package/src/database/repositories/content.ts +47 -12
- package/src/database/repositories/redirect.ts +14 -3
- package/src/database/repositories/taxonomy.ts +212 -82
- package/src/database/types.ts +10 -2
- package/src/db/libsql.ts +1 -3
- package/src/db/sqlite.ts +2 -5
- package/src/emdash-runtime.ts +84 -159
- package/src/i18n/resolve.ts +37 -0
- package/src/index.ts +9 -0
- package/src/loader.ts +73 -3
- package/src/mcp/server.ts +180 -54
- package/src/menus/index.ts +143 -124
- package/src/menus/types.ts +15 -1
- 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/hooks.ts +23 -19
- package/src/plugins/index.ts +9 -0
- package/src/plugins/manifest-schema.ts +37 -2
- package/src/plugins/types.ts +151 -11
- package/src/preview/urls.ts +23 -3
- package/src/query.ts +148 -5
- package/src/redirects/cache.ts +38 -18
- package/src/schema/registry.ts +56 -0
- package/src/schema/zod-generator.ts +39 -7
- package/src/seed/apply.ts +142 -54
- package/src/seed/types.ts +14 -1
- package/src/seed/validate.ts +27 -13
- package/src/settings/index.ts +80 -6
- package/src/settings/types.ts +23 -1
- package/src/taxonomies/index.ts +237 -210
- package/src/taxonomies/types.ts +10 -0
- package/dist/apply-x0eMK1lX.mjs.map +0 -1
- package/dist/bylines-CRNsVG88.mjs +0 -157
- package/dist/bylines-CRNsVG88.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-BcQPYxdV.mjs.map +0 -1
- package/dist/dialect-helpers-DhTzaUxP.mjs.map +0 -1
- package/dist/index-DIb-CzNx.d.mts.map +0 -1
- package/dist/loader-CndGj8kM.mjs.map +0 -1
- package/dist/manifest-schema-DH9xhc6t.mjs.map +0 -1
- package/dist/query-fqEdLFms.mjs.map +0 -1
- package/dist/redirect-D_pshWdf.mjs.map +0 -1
- package/dist/registry-C3Mr0ODu.mjs.map +0 -1
- package/dist/runner-OURCaApa.d.mts +0 -34
- package/dist/runner-OURCaApa.d.mts.map +0 -1
- package/dist/runner-tQ7BJ4T7.mjs.map +0 -1
- package/dist/search-BoZYFuUk.mjs.map +0 -1
- package/dist/taxonomies-B4IAshV8.mjs +0 -308
- package/dist/taxonomies-B4IAshV8.mjs.map +0 -1
- package/dist/types-CS8FIX7L.d.mts.map +0 -1
- package/dist/types-i36XcA_X.d.mts.map +0 -1
- package/dist/validate-CxVsLehf.mjs.map +0 -1
- package/dist/validate-DHxmpFJt.d.mts.map +0 -1
- package/dist/version-Bbq8TCrz.mjs +0 -7
|
@@ -9,8 +9,8 @@ import type { APIRoute } from "astro";
|
|
|
9
9
|
import { requirePerm } from "#api/authorize.js";
|
|
10
10
|
import { handleError, unwrapResult } from "#api/error.js";
|
|
11
11
|
import { handleMenuItemReorder } from "#api/handlers/menus.js";
|
|
12
|
-
import { isParseError, parseBody } from "#api/parse.js";
|
|
13
|
-
import { reorderMenuItemsBody } from "#api/schemas.js";
|
|
12
|
+
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
13
|
+
import { localeFilterQuery, reorderMenuItemsBody } from "#api/schemas.js";
|
|
14
14
|
|
|
15
15
|
export const prerender = false;
|
|
16
16
|
|
|
@@ -21,11 +21,16 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
21
21
|
const denied = requirePerm(user, "menus:manage");
|
|
22
22
|
if (denied) return denied;
|
|
23
23
|
|
|
24
|
+
const localeQ = parseQuery(new URL(request.url), localeFilterQuery);
|
|
25
|
+
if (isParseError(localeQ)) return localeQ;
|
|
26
|
+
|
|
24
27
|
try {
|
|
25
28
|
const body = await parseBody(request, reorderMenuItemsBody);
|
|
26
29
|
if (isParseError(body)) return body;
|
|
27
30
|
|
|
28
|
-
const result = await handleMenuItemReorder(emdash.db, name, body.items
|
|
31
|
+
const result = await handleMenuItemReorder(emdash.db, name, body.items, {
|
|
32
|
+
locale: localeQ.locale,
|
|
33
|
+
});
|
|
29
34
|
return unwrapResult(result);
|
|
30
35
|
} catch (error) {
|
|
31
36
|
return handleError(error, "Failed to reorder menu items", "MENU_REORDER_ERROR");
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Menu translation endpoints
|
|
3
|
+
*
|
|
4
|
+
* GET /_emdash/api/menus/:name/translations — list translations for a menu (uses any locale row)
|
|
5
|
+
* POST /_emdash/api/menus/:name/translations — create a new locale translation (body: { locale, label })
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { APIRoute } from "astro";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
|
|
11
|
+
import { requirePerm } from "#api/authorize.js";
|
|
12
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
13
|
+
import { handleMenuCreate, handleMenuGet, handleMenuTranslations } from "#api/handlers/menus.js";
|
|
14
|
+
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
15
|
+
import { localeFilterQuery } from "#api/schemas.js";
|
|
16
|
+
|
|
17
|
+
export const prerender = false;
|
|
18
|
+
|
|
19
|
+
const createTranslationBody = z
|
|
20
|
+
.object({
|
|
21
|
+
locale: z.string().min(1),
|
|
22
|
+
label: z.string().min(1).optional(),
|
|
23
|
+
})
|
|
24
|
+
.meta({ id: "CreateMenuTranslationBody" });
|
|
25
|
+
|
|
26
|
+
export const GET: APIRoute = async ({ params, request, locals }) => {
|
|
27
|
+
const { emdash, user } = locals;
|
|
28
|
+
const name = params.name!;
|
|
29
|
+
|
|
30
|
+
const dbErr = requireDb(emdash?.db);
|
|
31
|
+
if (dbErr) return dbErr;
|
|
32
|
+
|
|
33
|
+
const denied = requirePerm(user, "menus:read");
|
|
34
|
+
if (denied) return denied;
|
|
35
|
+
|
|
36
|
+
const localeQ = parseQuery(new URL(request.url), localeFilterQuery);
|
|
37
|
+
if (isParseError(localeQ)) return localeQ;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
// Look up any menu row matching the name so we can get its translation_group.
|
|
41
|
+
const anchor = await handleMenuGet(emdash.db, name, { locale: localeQ.locale });
|
|
42
|
+
if (!anchor.success) return unwrapResult(anchor);
|
|
43
|
+
const result = await handleMenuTranslations(emdash.db, anchor.data.id);
|
|
44
|
+
return unwrapResult(result);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
return handleError(error, "Failed to fetch menu translations", "MENU_TRANSLATIONS_ERROR");
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
51
|
+
const { emdash, user } = locals;
|
|
52
|
+
const name = params.name!;
|
|
53
|
+
|
|
54
|
+
const dbErr = requireDb(emdash?.db);
|
|
55
|
+
if (dbErr) return dbErr;
|
|
56
|
+
|
|
57
|
+
const denied = requirePerm(user, "menus:manage");
|
|
58
|
+
if (denied) return denied;
|
|
59
|
+
|
|
60
|
+
const localeQ = parseQuery(new URL(request.url), localeFilterQuery);
|
|
61
|
+
if (isParseError(localeQ)) return localeQ;
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const body = await parseBody(request, createTranslationBody);
|
|
65
|
+
if (isParseError(body)) return body;
|
|
66
|
+
|
|
67
|
+
// Resolve the source menu (either by explicit locale in query, or the
|
|
68
|
+
// first matching row). Its id becomes the `translationOf` for the new row.
|
|
69
|
+
const source = await handleMenuGet(emdash.db, name, { locale: localeQ.locale });
|
|
70
|
+
if (!source.success) return unwrapResult(source);
|
|
71
|
+
|
|
72
|
+
const result = await handleMenuCreate(emdash.db, {
|
|
73
|
+
name,
|
|
74
|
+
label: body.label ?? source.data.label,
|
|
75
|
+
locale: body.locale,
|
|
76
|
+
translationOf: source.data.id,
|
|
77
|
+
});
|
|
78
|
+
return unwrapResult(result, 201);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
return handleError(error, "Failed to create menu translation", "MENU_TRANSLATION_CREATE_ERROR");
|
|
81
|
+
}
|
|
82
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Single menu endpoint
|
|
3
3
|
*
|
|
4
|
-
* GET /_emdash/api/menus/:name
|
|
5
|
-
* PUT /_emdash/api/menus/:name
|
|
6
|
-
* DELETE /_emdash/api/menus/:name
|
|
4
|
+
* GET /_emdash/api/menus/:name[?locale=xx]
|
|
5
|
+
* PUT /_emdash/api/menus/:name[?locale=xx]
|
|
6
|
+
* DELETE /_emdash/api/menus/:name[?locale=xx]
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { APIRoute } from "astro";
|
|
@@ -11,20 +11,23 @@ import type { APIRoute } from "astro";
|
|
|
11
11
|
import { requirePerm } from "#api/authorize.js";
|
|
12
12
|
import { handleError, unwrapResult } from "#api/error.js";
|
|
13
13
|
import { handleMenuDelete, handleMenuGet, handleMenuUpdate } from "#api/handlers/menus.js";
|
|
14
|
-
import { isParseError, parseBody } from "#api/parse.js";
|
|
15
|
-
import { updateMenuBody } from "#api/schemas.js";
|
|
14
|
+
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
15
|
+
import { localeFilterQuery, updateMenuBody } from "#api/schemas.js";
|
|
16
16
|
|
|
17
17
|
export const prerender = false;
|
|
18
18
|
|
|
19
|
-
export const GET: APIRoute = async ({ params, locals }) => {
|
|
19
|
+
export const GET: APIRoute = async ({ params, request, locals }) => {
|
|
20
20
|
const { emdash, user } = locals;
|
|
21
21
|
const name = params.name!;
|
|
22
22
|
|
|
23
23
|
const denied = requirePerm(user, "menus:read");
|
|
24
24
|
if (denied) return denied;
|
|
25
25
|
|
|
26
|
+
const query = parseQuery(new URL(request.url), localeFilterQuery);
|
|
27
|
+
if (isParseError(query)) return query;
|
|
28
|
+
|
|
26
29
|
try {
|
|
27
|
-
const result = await handleMenuGet(emdash.db, name);
|
|
30
|
+
const result = await handleMenuGet(emdash.db, name, { locale: query.locale });
|
|
28
31
|
return unwrapResult(result);
|
|
29
32
|
} catch (error) {
|
|
30
33
|
return handleError(error, "Failed to fetch menu", "MENU_GET_ERROR");
|
|
@@ -38,26 +41,32 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
38
41
|
const denied = requirePerm(user, "menus:manage");
|
|
39
42
|
if (denied) return denied;
|
|
40
43
|
|
|
44
|
+
const query = parseQuery(new URL(request.url), localeFilterQuery);
|
|
45
|
+
if (isParseError(query)) return query;
|
|
46
|
+
|
|
41
47
|
try {
|
|
42
48
|
const body = await parseBody(request, updateMenuBody);
|
|
43
49
|
if (isParseError(body)) return body;
|
|
44
50
|
|
|
45
|
-
const result = await handleMenuUpdate(emdash.db, name, body);
|
|
51
|
+
const result = await handleMenuUpdate(emdash.db, name, { ...body, locale: query.locale });
|
|
46
52
|
return unwrapResult(result);
|
|
47
53
|
} catch (error) {
|
|
48
54
|
return handleError(error, "Failed to update menu", "MENU_UPDATE_ERROR");
|
|
49
55
|
}
|
|
50
56
|
};
|
|
51
57
|
|
|
52
|
-
export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
58
|
+
export const DELETE: APIRoute = async ({ params, request, locals }) => {
|
|
53
59
|
const { emdash, user } = locals;
|
|
54
60
|
const name = params.name!;
|
|
55
61
|
|
|
56
62
|
const denied = requirePerm(user, "menus:manage");
|
|
57
63
|
if (denied) return denied;
|
|
58
64
|
|
|
65
|
+
const query = parseQuery(new URL(request.url), localeFilterQuery);
|
|
66
|
+
if (isParseError(query)) return query;
|
|
67
|
+
|
|
59
68
|
try {
|
|
60
|
-
const result = await handleMenuDelete(emdash.db, name);
|
|
69
|
+
const result = await handleMenuDelete(emdash.db, name, { locale: query.locale });
|
|
61
70
|
return unwrapResult(result);
|
|
62
71
|
} catch (error) {
|
|
63
72
|
return handleError(error, "Failed to delete menu", "MENU_DELETE_ERROR");
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Menus list and create endpoints
|
|
3
3
|
*
|
|
4
|
-
* GET /_emdash/api/menus - List
|
|
5
|
-
* POST /_emdash/api/menus
|
|
4
|
+
* GET /_emdash/api/menus[?locale=xx] - List menus (optionally filtered by locale)
|
|
5
|
+
* POST /_emdash/api/menus - Create menu (body may include locale & translationOf)
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { APIRoute } from "astro";
|
|
@@ -10,19 +10,22 @@ import type { APIRoute } from "astro";
|
|
|
10
10
|
import { requirePerm } from "#api/authorize.js";
|
|
11
11
|
import { handleError, unwrapResult } from "#api/error.js";
|
|
12
12
|
import { handleMenuCreate, handleMenuList } from "#api/handlers/menus.js";
|
|
13
|
-
import { isParseError, parseBody } from "#api/parse.js";
|
|
14
|
-
import { createMenuBody } from "#api/schemas.js";
|
|
13
|
+
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
14
|
+
import { createMenuBody, localeFilterQuery } from "#api/schemas.js";
|
|
15
15
|
|
|
16
16
|
export const prerender = false;
|
|
17
17
|
|
|
18
|
-
export const GET: APIRoute = async ({ locals }) => {
|
|
18
|
+
export const GET: APIRoute = async ({ request, locals }) => {
|
|
19
19
|
const { emdash, user } = locals;
|
|
20
20
|
|
|
21
21
|
const denied = requirePerm(user, "menus:read");
|
|
22
22
|
if (denied) return denied;
|
|
23
23
|
|
|
24
|
+
const query = parseQuery(new URL(request.url), localeFilterQuery);
|
|
25
|
+
if (isParseError(query)) return query;
|
|
26
|
+
|
|
24
27
|
try {
|
|
25
|
-
const result = await handleMenuList(emdash.db);
|
|
28
|
+
const result = await handleMenuList(emdash.db, { locale: query.locale });
|
|
26
29
|
return unwrapResult(result);
|
|
27
30
|
} catch (error) {
|
|
28
31
|
return handleError(error, "Failed to fetch menus", "MENU_LIST_ERROR");
|
|
@@ -9,33 +9,50 @@
|
|
|
9
9
|
|
|
10
10
|
import type { APIRoute } from "astro";
|
|
11
11
|
|
|
12
|
+
import { handleError } from "../../../api/error.js";
|
|
12
13
|
import { generateOpenApiDocument } from "../../../api/openapi/index.js";
|
|
13
14
|
|
|
14
15
|
export const prerender = false;
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
// Use globalThis with Symbol.for to survive Vite's SSR module duplication
|
|
18
|
+
const OPENAPI_CACHE_KEY = Symbol.for("emdash.openapi.cachedSpec");
|
|
19
|
+
|
|
20
|
+
function getCachedSpec(): string | null {
|
|
21
|
+
const val = (globalThis as Record<symbol, unknown>)[OPENAPI_CACHE_KEY];
|
|
22
|
+
return typeof val === "string" ? val : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function setCachedSpec(spec: string): void {
|
|
26
|
+
(globalThis as Record<symbol, unknown>)[OPENAPI_CACHE_KEY] = spec;
|
|
27
|
+
}
|
|
17
28
|
|
|
18
29
|
export const GET: APIRoute = async ({ locals }) => {
|
|
19
30
|
const { emdash } = locals;
|
|
20
|
-
|
|
31
|
+
|
|
32
|
+
let spec = getCachedSpec();
|
|
33
|
+
if (!spec && emdash) {
|
|
21
34
|
try {
|
|
22
35
|
const doc = generateOpenApiDocument({ maxUploadSize: emdash.config.maxUploadSize });
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{ status: 500, headers: { "Content-Type": "application/json" } },
|
|
28
|
-
);
|
|
36
|
+
spec = JSON.stringify(doc);
|
|
37
|
+
setCachedSpec(spec);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return handleError(error, "Failed to generate OpenAPI document", "OPENAPI_ERROR");
|
|
29
40
|
}
|
|
30
41
|
}
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
if (!spec) {
|
|
44
|
+
try {
|
|
45
|
+
spec = JSON.stringify(generateOpenApiDocument());
|
|
46
|
+
} catch (error) {
|
|
47
|
+
return handleError(error, "Failed to generate OpenAPI document", "OPENAPI_ERROR");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
33
50
|
|
|
34
51
|
return new Response(spec, {
|
|
35
52
|
status: 200,
|
|
36
53
|
headers: {
|
|
37
54
|
"Content-Type": "application/json",
|
|
38
|
-
"Cache-Control": "
|
|
55
|
+
"Cache-Control": "private, no-store",
|
|
39
56
|
"Access-Control-Allow-Origin": "*",
|
|
40
57
|
},
|
|
41
58
|
});
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type { APIRoute } from "astro";
|
|
10
10
|
|
|
11
11
|
import { requirePerm } from "#api/authorize.js";
|
|
12
|
-
import { handleError, unwrapResult } from "#api/error.js";
|
|
12
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
13
13
|
import {
|
|
14
14
|
handleNotFoundClear,
|
|
15
15
|
handleNotFoundList,
|
|
@@ -22,7 +22,9 @@ export const prerender = false;
|
|
|
22
22
|
|
|
23
23
|
export const GET: APIRoute = async ({ url, 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
|
|
|
27
29
|
const denied = requirePerm(user, "redirects:read");
|
|
28
30
|
if (denied) return denied;
|
|
@@ -40,7 +42,9 @@ export const GET: APIRoute = async ({ url, locals }) => {
|
|
|
40
42
|
|
|
41
43
|
export const DELETE: APIRoute = async ({ locals }) => {
|
|
42
44
|
const { emdash, user } = locals;
|
|
43
|
-
const
|
|
45
|
+
const dbErr = requireDb(emdash?.db);
|
|
46
|
+
if (dbErr) return dbErr;
|
|
47
|
+
const db = emdash!.db;
|
|
44
48
|
|
|
45
49
|
const denied = requirePerm(user, "redirects:manage");
|
|
46
50
|
if (denied) return denied;
|
|
@@ -55,7 +59,9 @@ export const DELETE: APIRoute = async ({ locals }) => {
|
|
|
55
59
|
|
|
56
60
|
export const POST: APIRoute = async ({ request, locals }) => {
|
|
57
61
|
const { emdash, user } = locals;
|
|
58
|
-
const
|
|
62
|
+
const dbErr = requireDb(emdash?.db);
|
|
63
|
+
if (dbErr) return dbErr;
|
|
64
|
+
const db = emdash!.db;
|
|
59
65
|
|
|
60
66
|
const denied = requirePerm(user, "redirects:manage");
|
|
61
67
|
if (denied) return denied;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import type { APIRoute } from "astro";
|
|
8
8
|
|
|
9
9
|
import { requirePerm } from "#api/authorize.js";
|
|
10
|
-
import { handleError, unwrapResult } from "#api/error.js";
|
|
10
|
+
import { handleError, requireDb, unwrapResult } from "#api/error.js";
|
|
11
11
|
import { handleNotFoundSummary } from "#api/handlers/redirects.js";
|
|
12
12
|
import { isParseError, parseQuery } from "#api/parse.js";
|
|
13
13
|
import { notFoundSummaryQuery } from "#api/schemas.js";
|
|
@@ -16,7 +16,9 @@ export const prerender = false;
|
|
|
16
16
|
|
|
17
17
|
export const GET: APIRoute = async ({ url, locals }) => {
|
|
18
18
|
const { emdash, user } = locals;
|
|
19
|
-
const
|
|
19
|
+
const dbErr = requireDb(emdash?.db);
|
|
20
|
+
if (dbErr) return dbErr;
|
|
21
|
+
const db = emdash!.db;
|
|
20
22
|
|
|
21
23
|
const denied = requirePerm(user, "redirects:read");
|
|
22
24
|
if (denied) return denied;
|
|
@@ -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
|
handleRedirectDelete,
|
|
15
15
|
handleRedirectGet,
|
|
@@ -23,7 +23,9 @@ export const prerender = false;
|
|
|
23
23
|
|
|
24
24
|
export const GET: APIRoute = async ({ params, locals }) => {
|
|
25
25
|
const { emdash, user } = locals;
|
|
26
|
-
const
|
|
26
|
+
const dbErr = requireDb(emdash?.db);
|
|
27
|
+
if (dbErr) return dbErr;
|
|
28
|
+
const db = emdash!.db;
|
|
27
29
|
const { id } = params;
|
|
28
30
|
|
|
29
31
|
const denied = requirePerm(user, "redirects:read");
|
|
@@ -43,7 +45,9 @@ export const GET: APIRoute = async ({ params, locals }) => {
|
|
|
43
45
|
|
|
44
46
|
export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
45
47
|
const { emdash, user } = locals;
|
|
46
|
-
const
|
|
48
|
+
const dbErr = requireDb(emdash?.db);
|
|
49
|
+
if (dbErr) return dbErr;
|
|
50
|
+
const db = emdash!.db;
|
|
47
51
|
const { id } = params;
|
|
48
52
|
|
|
49
53
|
const denied = requirePerm(user, "redirects:manage");
|
|
@@ -67,7 +71,9 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
67
71
|
|
|
68
72
|
export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
69
73
|
const { emdash, user } = locals;
|
|
70
|
-
const
|
|
74
|
+
const dbErr = requireDb(emdash?.db);
|
|
75
|
+
if (dbErr) return dbErr;
|
|
76
|
+
const db = emdash!.db;
|
|
71
77
|
const { id } = params;
|
|
72
78
|
|
|
73
79
|
const denied = requirePerm(user, "redirects: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 { handleRedirectCreate, handleRedirectList } from "#api/handlers/redirects.js";
|
|
13
13
|
import { isParseError, parseBody, parseQuery } from "#api/parse.js";
|
|
14
14
|
import { createRedirectBody, redirectsListQuery } from "#api/schemas.js";
|
|
@@ -18,7 +18,9 @@ export const prerender = false;
|
|
|
18
18
|
|
|
19
19
|
export const GET: APIRoute = async ({ url, locals }) => {
|
|
20
20
|
const { emdash, user } = locals;
|
|
21
|
-
const
|
|
21
|
+
const dbErr = requireDb(emdash?.db);
|
|
22
|
+
if (dbErr) return dbErr;
|
|
23
|
+
const db = emdash!.db;
|
|
22
24
|
|
|
23
25
|
const denied = requirePerm(user, "redirects:read");
|
|
24
26
|
if (denied) return denied;
|
|
@@ -36,7 +38,9 @@ export const GET: APIRoute = async ({ url, locals }) => {
|
|
|
36
38
|
|
|
37
39
|
export const POST: APIRoute = async ({ request, locals }) => {
|
|
38
40
|
const { emdash, user } = locals;
|
|
39
|
-
const
|
|
41
|
+
const dbErr = requireDb(emdash?.db);
|
|
42
|
+
if (dbErr) return dbErr;
|
|
43
|
+
const db = emdash!.db;
|
|
40
44
|
|
|
41
45
|
const denied = requirePerm(user, "redirects:manage");
|
|
42
46
|
if (denied) return denied;
|
|
@@ -16,7 +16,7 @@ export const GET: APIRoute = async ({ params, locals }) => {
|
|
|
16
16
|
const { emdash, user } = locals;
|
|
17
17
|
const revisionId = params.revisionId!;
|
|
18
18
|
|
|
19
|
-
const denied = requirePerm(user, "content:
|
|
19
|
+
const denied = requirePerm(user, "content:read_drafts");
|
|
20
20
|
if (denied) return denied;
|
|
21
21
|
|
|
22
22
|
if (!emdash?.handleRevisionGet) {
|
|
@@ -57,7 +57,6 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
57
57
|
fieldSlug,
|
|
58
58
|
body as UpdateFieldInput,
|
|
59
59
|
);
|
|
60
|
-
if (result.success) emdash!.invalidateManifest();
|
|
61
60
|
return unwrapResult(result);
|
|
62
61
|
};
|
|
63
62
|
|
|
@@ -73,6 +72,5 @@ export const DELETE: APIRoute = async ({ params, locals }) => {
|
|
|
73
72
|
if (denied) return denied;
|
|
74
73
|
|
|
75
74
|
const result = await handleSchemaFieldDelete(emdash!.db, collectionSlug, fieldSlug);
|
|
76
|
-
if (result.success) emdash!.invalidateManifest();
|
|
77
75
|
return unwrapResult(result);
|
|
78
76
|
};
|
|
@@ -28,6 +28,5 @@ export const POST: APIRoute = async ({ params, request, locals }) => {
|
|
|
28
28
|
if (isParseError(body)) return body;
|
|
29
29
|
|
|
30
30
|
const result = await handleSchemaFieldReorder(emdash!.db, collectionSlug, body.fieldSlugs);
|
|
31
|
-
if (result.success) emdash!.invalidateManifest();
|
|
32
31
|
return unwrapResult(result);
|
|
33
32
|
};
|
|
@@ -59,7 +59,7 @@ export const PUT: APIRoute = async ({ params, request, locals }) => {
|
|
|
59
59
|
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- parseBody validates via Zod
|
|
60
60
|
body as UpdateCollectionInput,
|
|
61
61
|
);
|
|
62
|
-
emdash!.
|
|
62
|
+
emdash!.invalidateUrlPatternCache();
|
|
63
63
|
return unwrapResult(result);
|
|
64
64
|
};
|
|
65
65
|
|
|
@@ -77,6 +77,6 @@ export const DELETE: APIRoute = async ({ params, url, locals }) => {
|
|
|
77
77
|
const result = await handleSchemaCollectionDelete(emdash!.db, slug, {
|
|
78
78
|
force,
|
|
79
79
|
});
|
|
80
|
-
emdash!.
|
|
80
|
+
emdash!.invalidateUrlPatternCache();
|
|
81
81
|
return unwrapResult(result);
|
|
82
82
|
};
|
|
@@ -43,6 +43,6 @@ export const POST: APIRoute = async ({ request, locals }) => {
|
|
|
43
43
|
|
|
44
44
|
// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- Zod schema output narrowed to CreateCollectionInput
|
|
45
45
|
const result = await handleSchemaCollectionCreate(emdash!.db, body as CreateCollectionInput);
|
|
46
|
-
emdash!.
|
|
46
|
+
emdash!.invalidateUrlPatternCache();
|
|
47
47
|
return unwrapResult(result, 201);
|
|
48
48
|
};
|
|
@@ -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;
|
|
@@ -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);
|