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
|
@@ -1,292 +1,59 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { i as __exportAll } from "./runner-DMnlIkh4.mjs";
|
|
2
|
+
import { n as getI18nConfig } from "./config-CVssduLe.mjs";
|
|
3
|
+
import { r as RevisionRepository, t as ContentRepository } from "./content-C7G4QXkK.mjs";
|
|
3
4
|
import { t as MediaRepository } from "./media-D8FbNsl0.mjs";
|
|
4
|
-
import { t as
|
|
5
|
-
import { t as
|
|
6
|
-
import { t as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
5
|
+
import { t as TaxonomyRepository } from "./taxonomy-DSxx2K2L.mjs";
|
|
6
|
+
import { t as OptionsRepository } from "./options-nPxWnrya.mjs";
|
|
7
|
+
import { t as withTransaction } from "./transaction-D44LBXvU.mjs";
|
|
8
|
+
import { t as RedirectRepository } from "./redirect-C5H7VGIX.mjs";
|
|
9
|
+
import { t as BylineRepository } from "./byline-C3vnhIpU.mjs";
|
|
10
|
+
import { i as FTSManager, n as SchemaRegistry } from "./registry-Beb7wxFc.mjs";
|
|
11
|
+
import { r as getDb } from "./loader-Bx2_9-5e.mjs";
|
|
12
|
+
import { n as requestCached, t as peekRequestCache } from "./request-cache-C-tIpYIw.mjs";
|
|
13
|
+
import { t as validateSeed } from "./validate-CBIbxM3L.mjs";
|
|
12
14
|
import { ulid } from "ulidx";
|
|
13
15
|
import { imageSize } from "image-size";
|
|
14
16
|
import mime from "mime/lite";
|
|
15
17
|
|
|
16
|
-
//#region src/
|
|
18
|
+
//#region src/settings/index.ts
|
|
19
|
+
/** Prefix for site settings in the options table */
|
|
20
|
+
const SETTINGS_PREFIX = "site:";
|
|
21
|
+
const SITE_SETTINGS_CACHE_KEY = Symbol.for("emdash:site-settings");
|
|
22
|
+
const g = globalThis;
|
|
23
|
+
const holder = g[SITE_SETTINGS_CACHE_KEY] ?? (() => {
|
|
24
|
+
const h = {
|
|
25
|
+
version: 0,
|
|
26
|
+
cached: null,
|
|
27
|
+
cachedVersion: -1
|
|
28
|
+
};
|
|
29
|
+
g[SITE_SETTINGS_CACHE_KEY] = h;
|
|
30
|
+
return h;
|
|
31
|
+
})();
|
|
17
32
|
/**
|
|
18
|
-
*
|
|
33
|
+
* Bump the isolate-wide site-settings cache version, forcing the next
|
|
34
|
+
* `getSiteSettings()` to re-query the database.
|
|
19
35
|
*
|
|
20
|
-
*
|
|
36
|
+
* Called from every `site:*` write path. Other isolates still serve their
|
|
37
|
+
* own cached copy until they expire — staleness bounded by isolate lifetime.
|
|
21
38
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Create a new taxonomy term
|
|
28
|
-
*/
|
|
29
|
-
async create(input) {
|
|
30
|
-
const id = ulid();
|
|
31
|
-
const parentId = input.parentId === void 0 || input.parentId === "" ? null : input.parentId;
|
|
32
|
-
const row = {
|
|
33
|
-
id,
|
|
34
|
-
name: input.name,
|
|
35
|
-
slug: input.slug,
|
|
36
|
-
label: input.label,
|
|
37
|
-
parent_id: parentId,
|
|
38
|
-
data: input.data ? JSON.stringify(input.data) : null
|
|
39
|
-
};
|
|
40
|
-
await this.db.insertInto("taxonomies").values(row).execute();
|
|
41
|
-
const taxonomy = await this.findById(id);
|
|
42
|
-
if (!taxonomy) throw new Error("Failed to create taxonomy");
|
|
43
|
-
return taxonomy;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Find taxonomy by ID
|
|
47
|
-
*/
|
|
48
|
-
async findById(id) {
|
|
49
|
-
const row = await this.db.selectFrom("taxonomies").selectAll().where("id", "=", id).executeTakeFirst();
|
|
50
|
-
return row ? this.rowToTaxonomy(row) : null;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Find taxonomy by name and slug (unique constraint)
|
|
54
|
-
*/
|
|
55
|
-
async findBySlug(name, slug) {
|
|
56
|
-
const row = await this.db.selectFrom("taxonomies").selectAll().where("name", "=", name).where("slug", "=", slug).executeTakeFirst();
|
|
57
|
-
return row ? this.rowToTaxonomy(row) : null;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Get all terms for a taxonomy (e.g., all categories)
|
|
61
|
-
*/
|
|
62
|
-
async findByName(name, options = {}) {
|
|
63
|
-
let query = this.db.selectFrom("taxonomies").selectAll().where("name", "=", name).orderBy("label", "asc").orderBy("id", "asc");
|
|
64
|
-
if (options.parentId !== void 0) if (options.parentId === null) query = query.where("parent_id", "is", null);
|
|
65
|
-
else query = query.where("parent_id", "=", options.parentId);
|
|
66
|
-
return (await query.execute()).map((row) => this.rowToTaxonomy(row));
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Get children of a taxonomy term
|
|
70
|
-
*/
|
|
71
|
-
async findChildren(parentId) {
|
|
72
|
-
return (await this.db.selectFrom("taxonomies").selectAll().where("parent_id", "=", parentId).orderBy("label", "asc").orderBy("id", "asc").execute()).map((row) => this.rowToTaxonomy(row));
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Update a taxonomy term
|
|
76
|
-
*/
|
|
77
|
-
async update(id, input) {
|
|
78
|
-
if (!await this.findById(id)) return null;
|
|
79
|
-
const updates = {};
|
|
80
|
-
if (input.slug !== void 0) updates.slug = input.slug;
|
|
81
|
-
if (input.label !== void 0) updates.label = input.label;
|
|
82
|
-
if (input.parentId !== void 0) updates.parent_id = input.parentId === "" ? null : input.parentId;
|
|
83
|
-
if (input.data !== void 0) updates.data = JSON.stringify(input.data);
|
|
84
|
-
if (Object.keys(updates).length > 0) await this.db.updateTable("taxonomies").set(updates).where("id", "=", id).execute();
|
|
85
|
-
return this.findById(id);
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Delete a taxonomy term
|
|
89
|
-
*/
|
|
90
|
-
async delete(id) {
|
|
91
|
-
await this.db.deleteFrom("content_taxonomies").where("taxonomy_id", "=", id).execute();
|
|
92
|
-
return ((await this.db.deleteFrom("taxonomies").where("id", "=", id).executeTakeFirst()).numDeletedRows ?? 0) > 0;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Attach a taxonomy term to a content entry
|
|
96
|
-
*/
|
|
97
|
-
async attachToEntry(collection, entryId, taxonomyId) {
|
|
98
|
-
const row = {
|
|
99
|
-
collection,
|
|
100
|
-
entry_id: entryId,
|
|
101
|
-
taxonomy_id: taxonomyId
|
|
102
|
-
};
|
|
103
|
-
await this.db.insertInto("content_taxonomies").values(row).onConflict((oc) => oc.doNothing()).execute();
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Detach a taxonomy term from a content entry
|
|
107
|
-
*/
|
|
108
|
-
async detachFromEntry(collection, entryId, taxonomyId) {
|
|
109
|
-
await this.db.deleteFrom("content_taxonomies").where("collection", "=", collection).where("entry_id", "=", entryId).where("taxonomy_id", "=", taxonomyId).execute();
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Get all taxonomy terms for a content entry
|
|
113
|
-
*/
|
|
114
|
-
async getTermsForEntry(collection, entryId, taxonomyName) {
|
|
115
|
-
let query = this.db.selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id").selectAll("taxonomies").where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "=", entryId);
|
|
116
|
-
if (taxonomyName) query = query.where("taxonomies.name", "=", taxonomyName);
|
|
117
|
-
return (await query.execute()).map((row) => this.rowToTaxonomy(row));
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Set all taxonomy terms for a content entry (replaces existing)
|
|
121
|
-
* Uses batch operations to avoid N+1 queries.
|
|
122
|
-
*/
|
|
123
|
-
async setTermsForEntry(collection, entryId, taxonomyName, taxonomyIds) {
|
|
124
|
-
const current = await this.getTermsForEntry(collection, entryId, taxonomyName);
|
|
125
|
-
const currentIds = new Set(current.map((t) => t.id));
|
|
126
|
-
const newIds = new Set(taxonomyIds);
|
|
127
|
-
const toRemove = current.filter((t) => !newIds.has(t.id)).map((t) => t.id);
|
|
128
|
-
if (toRemove.length > 0) await this.db.deleteFrom("content_taxonomies").where("collection", "=", collection).where("entry_id", "=", entryId).where("taxonomy_id", "in", toRemove).execute();
|
|
129
|
-
const toAdd = taxonomyIds.filter((id) => !currentIds.has(id));
|
|
130
|
-
if (toAdd.length > 0) await this.db.insertInto("content_taxonomies").values(toAdd.map((taxonomy_id) => ({
|
|
131
|
-
collection,
|
|
132
|
-
entry_id: entryId,
|
|
133
|
-
taxonomy_id
|
|
134
|
-
}))).onConflict((oc) => oc.doNothing()).execute();
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Remove all taxonomy associations for an entry (use when entry is deleted)
|
|
138
|
-
*/
|
|
139
|
-
async clearEntryTerms(collection, entryId) {
|
|
140
|
-
const result = await this.db.deleteFrom("content_taxonomies").where("collection", "=", collection).where("entry_id", "=", entryId).executeTakeFirst();
|
|
141
|
-
return Number(result.numDeletedRows ?? 0);
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Count entries that have a specific taxonomy term
|
|
145
|
-
*/
|
|
146
|
-
async countEntriesWithTerm(taxonomyId) {
|
|
147
|
-
const result = await this.db.selectFrom("content_taxonomies").select((eb) => eb.fn.count("entry_id").as("count")).where("taxonomy_id", "=", taxonomyId).executeTakeFirst();
|
|
148
|
-
return Number(result?.count || 0);
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Convert database row to Taxonomy object
|
|
152
|
-
*/
|
|
153
|
-
rowToTaxonomy(row) {
|
|
154
|
-
return {
|
|
155
|
-
id: row.id,
|
|
156
|
-
name: row.name,
|
|
157
|
-
slug: row.slug,
|
|
158
|
-
label: row.label,
|
|
159
|
-
parentId: row.parent_id,
|
|
160
|
-
data: row.data ? JSON.parse(row.data) : null
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
//#endregion
|
|
166
|
-
//#region src/database/repositories/options.ts
|
|
167
|
-
function escapeLike(value) {
|
|
168
|
-
return value.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_");
|
|
39
|
+
function invalidateSiteSettingsCache() {
|
|
40
|
+
holder.version++;
|
|
41
|
+
holder.cached = null;
|
|
42
|
+
holder.cachedVersion = -1;
|
|
169
43
|
}
|
|
170
44
|
/**
|
|
171
|
-
* Options repository for key-value settings storage
|
|
172
|
-
*
|
|
173
|
-
* Used for site settings, plugin configuration, and other arbitrary key-value data.
|
|
174
|
-
* Values are stored as JSON for flexibility.
|
|
175
|
-
*/
|
|
176
|
-
var OptionsRepository = class {
|
|
177
|
-
constructor(db) {
|
|
178
|
-
this.db = db;
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Get an option value
|
|
182
|
-
*/
|
|
183
|
-
async get(name) {
|
|
184
|
-
const row = await this.db.selectFrom("options").select("value").where("name", "=", name).executeTakeFirst();
|
|
185
|
-
if (!row) return null;
|
|
186
|
-
return JSON.parse(row.value);
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Get an option value with a default
|
|
190
|
-
*/
|
|
191
|
-
async getOrDefault(name, defaultValue) {
|
|
192
|
-
return await this.get(name) ?? defaultValue;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Set an option value (creates or updates)
|
|
196
|
-
*/
|
|
197
|
-
async set(name, value) {
|
|
198
|
-
const row = {
|
|
199
|
-
name,
|
|
200
|
-
value: JSON.stringify(value)
|
|
201
|
-
};
|
|
202
|
-
await this.db.insertInto("options").values(row).onConflict((oc) => oc.column("name").doUpdateSet({ value: row.value })).execute();
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Set an option value only if no row with that name exists. Atomic at the
|
|
206
|
-
* database level via INSERT ... ON CONFLICT DO NOTHING, so concurrent
|
|
207
|
-
* callers can't race past the check.
|
|
208
|
-
*
|
|
209
|
-
* Returns true when the row was inserted, false when a row already
|
|
210
|
-
* existed (regardless of its value — even an empty string or null).
|
|
211
|
-
*/
|
|
212
|
-
async setIfAbsent(name, value) {
|
|
213
|
-
const row = {
|
|
214
|
-
name,
|
|
215
|
-
value: JSON.stringify(value)
|
|
216
|
-
};
|
|
217
|
-
return ((await this.db.insertInto("options").values(row).onConflict((oc) => oc.column("name").doNothing()).executeTakeFirst()).numInsertedOrUpdatedRows ?? 0n) > 0n;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Delete an option
|
|
221
|
-
*/
|
|
222
|
-
async delete(name) {
|
|
223
|
-
return ((await this.db.deleteFrom("options").where("name", "=", name).executeTakeFirst()).numDeletedRows ?? 0) > 0;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Check if an option exists
|
|
227
|
-
*/
|
|
228
|
-
async exists(name) {
|
|
229
|
-
return !!await this.db.selectFrom("options").select("name").where("name", "=", name).executeTakeFirst();
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Get multiple options at once
|
|
233
|
-
*/
|
|
234
|
-
async getMany(names) {
|
|
235
|
-
if (names.length === 0) return /* @__PURE__ */ new Map();
|
|
236
|
-
const rows = await this.db.selectFrom("options").select(["name", "value"]).where("name", "in", names).execute();
|
|
237
|
-
const result = /* @__PURE__ */ new Map();
|
|
238
|
-
for (const row of rows) result.set(row.name, JSON.parse(row.value));
|
|
239
|
-
return result;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Set multiple options at once
|
|
243
|
-
*/
|
|
244
|
-
async setMany(options) {
|
|
245
|
-
const entries = Object.entries(options);
|
|
246
|
-
if (entries.length === 0) return;
|
|
247
|
-
for (const [name, value] of entries) await this.set(name, value);
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Get all options (use sparingly)
|
|
251
|
-
*/
|
|
252
|
-
async getAll() {
|
|
253
|
-
const rows = await this.db.selectFrom("options").select(["name", "value"]).execute();
|
|
254
|
-
const result = /* @__PURE__ */ new Map();
|
|
255
|
-
for (const row of rows) result.set(row.name, JSON.parse(row.value));
|
|
256
|
-
return result;
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Get all options matching a prefix
|
|
260
|
-
*/
|
|
261
|
-
async getByPrefix(prefix) {
|
|
262
|
-
const pattern = `${escapeLike(prefix)}%`;
|
|
263
|
-
const rows = await this.db.selectFrom("options").select(["name", "value"]).where(sql`name LIKE ${pattern} ESCAPE '\\'`).execute();
|
|
264
|
-
const result = /* @__PURE__ */ new Map();
|
|
265
|
-
for (const row of rows) result.set(row.name, JSON.parse(row.value));
|
|
266
|
-
return result;
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Delete all options matching a prefix
|
|
270
|
-
*/
|
|
271
|
-
async deleteByPrefix(prefix) {
|
|
272
|
-
const pattern = `${escapeLike(prefix)}%`;
|
|
273
|
-
const result = await this.db.deleteFrom("options").where(sql`name LIKE ${pattern} ESCAPE '\\'`).executeTakeFirst();
|
|
274
|
-
return Number(result.numDeletedRows ?? 0);
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
//#endregion
|
|
279
|
-
//#region src/settings/index.ts
|
|
280
|
-
/** Prefix for site settings in the options table */
|
|
281
|
-
const SETTINGS_PREFIX = "site:";
|
|
282
|
-
/**
|
|
283
45
|
* Type guard for MediaReference values
|
|
284
46
|
*/
|
|
285
47
|
function isMediaReference(value) {
|
|
286
48
|
return typeof value === "object" && value !== null && "mediaId" in value;
|
|
287
49
|
}
|
|
288
50
|
/**
|
|
289
|
-
* Resolve a media reference to include the full URL
|
|
51
|
+
* Resolve a media reference to include the full URL plus content metadata.
|
|
52
|
+
*
|
|
53
|
+
* Pulls `mimeType` and intrinsic dimensions from the media row so callers
|
|
54
|
+
* can emit correct head tags (e.g. `<link rel="icon" type="image/svg+xml">`,
|
|
55
|
+
* which Chromium requires when the URL has no `.svg` extension) without
|
|
56
|
+
* a second round-trip to the media table.
|
|
290
57
|
*/
|
|
291
58
|
async function resolveMediaReference(mediaRef, db, _storage) {
|
|
292
59
|
if (!mediaRef?.mediaId) return mediaRef;
|
|
@@ -294,7 +61,10 @@ async function resolveMediaReference(mediaRef, db, _storage) {
|
|
|
294
61
|
const media = await new MediaRepository(db).findById(mediaRef.mediaId);
|
|
295
62
|
if (media) return {
|
|
296
63
|
...mediaRef,
|
|
297
|
-
url: `/_emdash/api/media/file/${media.storageKey}
|
|
64
|
+
url: `/_emdash/api/media/file/${media.storageKey}`,
|
|
65
|
+
contentType: media.mimeType,
|
|
66
|
+
...media.width !== null ? { width: media.width } : {},
|
|
67
|
+
...media.height !== null ? { height: media.height } : {}
|
|
298
68
|
};
|
|
299
69
|
} catch {}
|
|
300
70
|
return mediaRef;
|
|
@@ -352,8 +122,21 @@ async function getSiteSettingWithDb(key, db, storage = null) {
|
|
|
352
122
|
* ```
|
|
353
123
|
*/
|
|
354
124
|
function getSiteSettings() {
|
|
355
|
-
return requestCached("siteSettings",
|
|
356
|
-
|
|
125
|
+
return requestCached("siteSettings", () => {
|
|
126
|
+
const versionAtCall = holder.version;
|
|
127
|
+
if (holder.cached && holder.cachedVersion === versionAtCall) return holder.cached;
|
|
128
|
+
const fetchPromise = (async () => {
|
|
129
|
+
return getSiteSettingsWithDb(await getDb());
|
|
130
|
+
})().catch((error) => {
|
|
131
|
+
if (holder.cached === fetchPromise) {
|
|
132
|
+
holder.cached = null;
|
|
133
|
+
holder.cachedVersion = -1;
|
|
134
|
+
}
|
|
135
|
+
throw error;
|
|
136
|
+
});
|
|
137
|
+
holder.cached = fetchPromise;
|
|
138
|
+
holder.cachedVersion = versionAtCall;
|
|
139
|
+
return fetchPromise;
|
|
357
140
|
});
|
|
358
141
|
}
|
|
359
142
|
/**
|
|
@@ -400,7 +183,11 @@ async function setSiteSettings(settings, db) {
|
|
|
400
183
|
const options = new OptionsRepository(db);
|
|
401
184
|
const updates = {};
|
|
402
185
|
for (const [key, value] of Object.entries(settings)) if (value !== void 0) updates[`${SETTINGS_PREFIX}${key}`] = value;
|
|
403
|
-
|
|
186
|
+
try {
|
|
187
|
+
await options.setMany(updates);
|
|
188
|
+
} finally {
|
|
189
|
+
invalidateSiteSettingsCache();
|
|
190
|
+
}
|
|
404
191
|
}
|
|
405
192
|
/**
|
|
406
193
|
* Get a single plugin setting by key.
|
|
@@ -945,49 +732,78 @@ async function applySeed(db, seed, options = {}) {
|
|
|
945
732
|
}
|
|
946
733
|
}
|
|
947
734
|
}
|
|
948
|
-
if (seed.taxonomies)
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
735
|
+
if (seed.taxonomies) {
|
|
736
|
+
const defSeedIdMap = /* @__PURE__ */ new Map();
|
|
737
|
+
const termSeedIdMap = /* @__PURE__ */ new Map();
|
|
738
|
+
const fallbackLocale = getI18nConfig()?.defaultLocale ?? "en";
|
|
739
|
+
for (const taxonomy of seed.taxonomies) {
|
|
740
|
+
const defLocale = taxonomy.locale ?? fallbackLocale;
|
|
741
|
+
const existingDef = await db.selectFrom("_emdash_taxonomy_defs").selectAll().where("name", "=", taxonomy.name).where("locale", "=", defLocale).executeTakeFirst();
|
|
742
|
+
let defId;
|
|
743
|
+
let defTranslationGroup;
|
|
744
|
+
if (existingDef) {
|
|
745
|
+
defId = existingDef.id;
|
|
746
|
+
defTranslationGroup = existingDef.translation_group ?? existingDef.id;
|
|
747
|
+
if (onConflict === "error") throw new Error(`Conflict: taxonomy "${taxonomy.name}" (${defLocale}) already exists`);
|
|
748
|
+
if (onConflict === "update") await db.updateTable("_emdash_taxonomy_defs").set({
|
|
749
|
+
label: taxonomy.label,
|
|
750
|
+
label_singular: taxonomy.labelSingular ?? null,
|
|
751
|
+
hierarchical: taxonomy.hierarchical ? 1 : 0,
|
|
752
|
+
collections: JSON.stringify(taxonomy.collections)
|
|
753
|
+
}).where("id", "=", existingDef.id).execute();
|
|
754
|
+
} else {
|
|
755
|
+
defId = ulid();
|
|
756
|
+
defTranslationGroup = defId;
|
|
757
|
+
if (taxonomy.translationOf) {
|
|
758
|
+
const source = defSeedIdMap.get(taxonomy.translationOf);
|
|
759
|
+
if (source) defTranslationGroup = source.translationGroup;
|
|
760
|
+
else console.warn(`taxonomy "${taxonomy.name}" (${defLocale}): translationOf "${taxonomy.translationOf}" not found yet; minting a fresh group.`);
|
|
761
|
+
}
|
|
762
|
+
await db.insertInto("_emdash_taxonomy_defs").values({
|
|
763
|
+
id: defId,
|
|
764
|
+
name: taxonomy.name,
|
|
765
|
+
label: taxonomy.label,
|
|
766
|
+
label_singular: taxonomy.labelSingular ?? null,
|
|
767
|
+
hierarchical: taxonomy.hierarchical ? 1 : 0,
|
|
768
|
+
collections: JSON.stringify(taxonomy.collections),
|
|
769
|
+
locale: defLocale,
|
|
770
|
+
translation_group: defTranslationGroup
|
|
771
|
+
}).execute();
|
|
772
|
+
result.taxonomies.created++;
|
|
773
|
+
}
|
|
774
|
+
if (taxonomy.id) defSeedIdMap.set(taxonomy.id, {
|
|
775
|
+
id: defId,
|
|
776
|
+
translationGroup: defTranslationGroup
|
|
777
|
+
});
|
|
778
|
+
if (taxonomy.terms && taxonomy.terms.length > 0) {
|
|
779
|
+
const termRepo = new TaxonomyRepository(db);
|
|
780
|
+
if (taxonomy.hierarchical) await applyHierarchicalTerms(termRepo, taxonomy.name, defLocale, taxonomy.terms, termSeedIdMap, result, onConflict);
|
|
781
|
+
else for (const term of taxonomy.terms) {
|
|
782
|
+
const termLocale = term.locale ?? defLocale;
|
|
783
|
+
const existing = await termRepo.findBySlug(taxonomy.name, term.slug, termLocale);
|
|
784
|
+
if (existing) {
|
|
785
|
+
if (onConflict === "error") throw new Error(`Conflict: taxonomy term "${term.slug}" in "${taxonomy.name}" (${termLocale}) already exists`);
|
|
786
|
+
if (onConflict === "update") {
|
|
787
|
+
await termRepo.update(existing.id, {
|
|
788
|
+
label: term.label,
|
|
789
|
+
data: term.description ? { description: term.description } : {}
|
|
790
|
+
});
|
|
791
|
+
result.taxonomies.terms++;
|
|
792
|
+
}
|
|
793
|
+
if (term.id) termSeedIdMap.set(term.id, existing.id);
|
|
794
|
+
} else {
|
|
795
|
+
const translationOf = term.translationOf ? termSeedIdMap.get(term.translationOf) : void 0;
|
|
796
|
+
const created = await termRepo.create({
|
|
797
|
+
name: taxonomy.name,
|
|
798
|
+
slug: term.slug,
|
|
978
799
|
label: term.label,
|
|
979
|
-
data: term.description ? { description: term.description } :
|
|
800
|
+
data: term.description ? { description: term.description } : void 0,
|
|
801
|
+
locale: termLocale,
|
|
802
|
+
translationOf
|
|
980
803
|
});
|
|
804
|
+
if (term.id) termSeedIdMap.set(term.id, created.id);
|
|
981
805
|
result.taxonomies.terms++;
|
|
982
806
|
}
|
|
983
|
-
} else {
|
|
984
|
-
await termRepo.create({
|
|
985
|
-
name: taxonomy.name,
|
|
986
|
-
slug: term.slug,
|
|
987
|
-
label: term.label,
|
|
988
|
-
data: term.description ? { description: term.description } : void 0
|
|
989
|
-
});
|
|
990
|
-
result.taxonomies.terms++;
|
|
991
807
|
}
|
|
992
808
|
}
|
|
993
809
|
}
|
|
@@ -1090,25 +906,44 @@ async function applySeed(db, seed, options = {}) {
|
|
|
1090
906
|
result.content.created++;
|
|
1091
907
|
}
|
|
1092
908
|
}
|
|
1093
|
-
if (seed.menus)
|
|
1094
|
-
const
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
await db.
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
909
|
+
if (seed.menus) {
|
|
910
|
+
const menuSeedIdMap = /* @__PURE__ */ new Map();
|
|
911
|
+
const fallbackLocale = getI18nConfig()?.defaultLocale ?? "en";
|
|
912
|
+
for (const menu of seed.menus) {
|
|
913
|
+
const locale = menu.locale ?? fallbackLocale;
|
|
914
|
+
const existingMenu = await db.selectFrom("_emdash_menus").selectAll().where("name", "=", menu.name).where("locale", "=", locale).executeTakeFirst();
|
|
915
|
+
let menuId;
|
|
916
|
+
let translationGroup;
|
|
917
|
+
if (existingMenu) {
|
|
918
|
+
menuId = existingMenu.id;
|
|
919
|
+
translationGroup = existingMenu.translation_group ?? existingMenu.id;
|
|
920
|
+
await db.deleteFrom("_emdash_menu_items").where("menu_id", "=", menuId).execute();
|
|
921
|
+
} else {
|
|
922
|
+
menuId = ulid();
|
|
923
|
+
translationGroup = menuId;
|
|
924
|
+
if (menu.translationOf) {
|
|
925
|
+
const source = menuSeedIdMap.get(menu.translationOf);
|
|
926
|
+
if (source) translationGroup = source.translationGroup;
|
|
927
|
+
else console.warn(`menu "${menu.name}" (${locale}): translationOf "${menu.translationOf}" not found yet; minting a fresh group.`);
|
|
928
|
+
}
|
|
929
|
+
await db.insertInto("_emdash_menus").values({
|
|
930
|
+
id: menuId,
|
|
931
|
+
name: menu.name,
|
|
932
|
+
label: menu.label,
|
|
933
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
934
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
935
|
+
locale,
|
|
936
|
+
translation_group: translationGroup
|
|
937
|
+
}).execute();
|
|
938
|
+
result.menus.created++;
|
|
939
|
+
}
|
|
940
|
+
if (menu.id) menuSeedIdMap.set(menu.id, {
|
|
1102
941
|
id: menuId,
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
}).execute();
|
|
1108
|
-
result.menus.created++;
|
|
942
|
+
translationGroup
|
|
943
|
+
});
|
|
944
|
+
const itemCount = await applyMenuItems(db, menuId, locale, menu.items, null, 0, seedIdMap);
|
|
945
|
+
result.menus.items += itemCount;
|
|
1109
946
|
}
|
|
1110
|
-
const itemCount = await applyMenuItems(db, menuId, menu.items, null, 0, seedIdMap);
|
|
1111
|
-
result.menus.items += itemCount;
|
|
1112
947
|
}
|
|
1113
948
|
if (seed.redirects) {
|
|
1114
949
|
const redirectRepo = new RedirectRepository(db);
|
|
@@ -1207,9 +1042,9 @@ async function applySeed(db, seed, options = {}) {
|
|
|
1207
1042
|
}
|
|
1208
1043
|
}
|
|
1209
1044
|
}
|
|
1210
|
-
const { invalidateBylineCache } = await import("./bylines-
|
|
1211
|
-
const { invalidateRedirectCache } = await import("./cache-
|
|
1212
|
-
const { invalidateUrlPatternCache } = await import("./query-
|
|
1045
|
+
const { invalidateBylineCache } = await import("./bylines-esI7ioa9.mjs").then((n) => n.t);
|
|
1046
|
+
const { invalidateRedirectCache } = await import("./cache-fTzxgMFJ.mjs").then((n) => n.t);
|
|
1047
|
+
const { invalidateUrlPatternCache } = await import("./query-Bo-msrmu.mjs").then((n) => n.o);
|
|
1213
1048
|
invalidateBylineCache();
|
|
1214
1049
|
invalidateRedirectCache();
|
|
1215
1050
|
invalidateUrlPatternCache();
|
|
@@ -1218,17 +1053,22 @@ async function applySeed(db, seed, options = {}) {
|
|
|
1218
1053
|
/**
|
|
1219
1054
|
* Apply hierarchical taxonomy terms (parents before children)
|
|
1220
1055
|
*/
|
|
1221
|
-
async function applyHierarchicalTerms(termRepo, taxonomyName, terms, result, onConflict = "skip") {
|
|
1056
|
+
async function applyHierarchicalTerms(termRepo, taxonomyName, defLocale, terms, termSeedIdMap, result, onConflict = "skip") {
|
|
1222
1057
|
const slugToId = /* @__PURE__ */ new Map();
|
|
1223
1058
|
let remaining = [...terms];
|
|
1224
1059
|
let maxPasses = 10;
|
|
1225
1060
|
while (remaining.length > 0 && maxPasses > 0) {
|
|
1226
1061
|
const processedThisPass = [];
|
|
1227
|
-
for (const term of remaining)
|
|
1228
|
-
const
|
|
1229
|
-
const
|
|
1062
|
+
for (const term of remaining) {
|
|
1063
|
+
const termLocale = term.locale ?? defLocale;
|
|
1064
|
+
const parentReady = !term.parent || slugToId.has(`${termLocale}::${term.parent}`);
|
|
1065
|
+
const translationReady = !term.translationOf || termSeedIdMap.has(term.translationOf);
|
|
1066
|
+
if (!parentReady || !translationReady) continue;
|
|
1067
|
+
const parentId = term.parent ? slugToId.get(`${termLocale}::${term.parent}`) : void 0;
|
|
1068
|
+
const translationOf = term.translationOf ? termSeedIdMap.get(term.translationOf) : void 0;
|
|
1069
|
+
const existing = await termRepo.findBySlug(taxonomyName, term.slug, termLocale);
|
|
1230
1070
|
if (existing) {
|
|
1231
|
-
if (onConflict === "error") throw new Error(`Conflict: taxonomy term "${term.slug}" in "${taxonomyName}" already exists`);
|
|
1071
|
+
if (onConflict === "error") throw new Error(`Conflict: taxonomy term "${term.slug}" in "${taxonomyName}" (${termLocale}) already exists`);
|
|
1232
1072
|
if (onConflict === "update") {
|
|
1233
1073
|
await termRepo.update(existing.id, {
|
|
1234
1074
|
label: term.label,
|
|
@@ -1237,24 +1077,28 @@ async function applyHierarchicalTerms(termRepo, taxonomyName, terms, result, onC
|
|
|
1237
1077
|
});
|
|
1238
1078
|
result.taxonomies.terms++;
|
|
1239
1079
|
}
|
|
1240
|
-
slugToId.set(term.slug
|
|
1080
|
+
slugToId.set(`${termLocale}::${term.slug}`, existing.id);
|
|
1081
|
+
if (term.id) termSeedIdMap.set(term.id, existing.id);
|
|
1241
1082
|
} else {
|
|
1242
1083
|
const created = await termRepo.create({
|
|
1243
1084
|
name: taxonomyName,
|
|
1244
1085
|
slug: term.slug,
|
|
1245
1086
|
label: term.label,
|
|
1246
1087
|
parentId,
|
|
1247
|
-
data: term.description ? { description: term.description } : void 0
|
|
1088
|
+
data: term.description ? { description: term.description } : void 0,
|
|
1089
|
+
locale: termLocale,
|
|
1090
|
+
translationOf
|
|
1248
1091
|
});
|
|
1249
|
-
slugToId.set(term.slug
|
|
1092
|
+
slugToId.set(`${termLocale}::${term.slug}`, created.id);
|
|
1093
|
+
if (term.id) termSeedIdMap.set(term.id, created.id);
|
|
1250
1094
|
result.taxonomies.terms++;
|
|
1251
1095
|
}
|
|
1252
|
-
processedThisPass.push(term.slug);
|
|
1096
|
+
processedThisPass.push(term.slug + "::" + termLocale);
|
|
1253
1097
|
}
|
|
1254
|
-
remaining = remaining.filter((t) => !processedThisPass.includes(t.slug));
|
|
1098
|
+
remaining = remaining.filter((t) => !processedThisPass.includes(t.slug + "::" + (t.locale ?? defLocale)));
|
|
1255
1099
|
maxPasses--;
|
|
1256
1100
|
}
|
|
1257
|
-
if (remaining.length > 0) console.warn(`Could not process ${remaining.length} terms due to missing parents`);
|
|
1101
|
+
if (remaining.length > 0) console.warn(`Could not process ${remaining.length} terms due to missing parents/translations`);
|
|
1258
1102
|
}
|
|
1259
1103
|
/**
|
|
1260
1104
|
* Apply byline credits to a content entry.
|
|
@@ -1284,7 +1128,7 @@ async function applyContentTaxonomies(db, collectionSlug, contentId, entry, isUp
|
|
|
1284
1128
|
if (isUpdate) await db.deleteFrom("content_taxonomies").where("collection", "=", collectionSlug).where("entry_id", "=", contentId).execute();
|
|
1285
1129
|
if (!entry.taxonomies) {
|
|
1286
1130
|
if (isUpdate) {
|
|
1287
|
-
const { invalidateTermCache } = await import("./taxonomies-
|
|
1131
|
+
const { invalidateTermCache } = await import("./taxonomies-CTtewrSQ.mjs").then((n) => n.u);
|
|
1288
1132
|
invalidateTermCache();
|
|
1289
1133
|
}
|
|
1290
1134
|
return;
|
|
@@ -1296,13 +1140,19 @@ async function applyContentTaxonomies(db, collectionSlug, contentId, entry, isUp
|
|
|
1296
1140
|
if (term) await termRepo.attachToEntry(collectionSlug, contentId, term.id);
|
|
1297
1141
|
}
|
|
1298
1142
|
}
|
|
1299
|
-
const { invalidateTermCache } = await import("./taxonomies-
|
|
1143
|
+
const { invalidateTermCache } = await import("./taxonomies-CTtewrSQ.mjs").then((n) => n.u);
|
|
1300
1144
|
invalidateTermCache();
|
|
1301
1145
|
}
|
|
1302
1146
|
/**
|
|
1303
|
-
* Apply menu items recursively
|
|
1147
|
+
* Apply menu items recursively.
|
|
1148
|
+
*
|
|
1149
|
+
* Each item gets a fresh `translation_group` (= its own id). The seed format's
|
|
1150
|
+
* `SeedMenuItem` has no `id`/`translationOf` fields, so we can't express the
|
|
1151
|
+
* cross-locale "same nav entry" link here — items diverge across locales on
|
|
1152
|
+
* re-apply. Runtime navigation still resolves correctly because `reference_id`
|
|
1153
|
+
* already holds the content's translation_group.
|
|
1304
1154
|
*/
|
|
1305
|
-
async function applyMenuItems(db, menuId, items, parentId, startOrder, seedIdMap) {
|
|
1155
|
+
async function applyMenuItems(db, menuId, locale, items, parentId, startOrder, seedIdMap) {
|
|
1306
1156
|
let count = 0;
|
|
1307
1157
|
let order = startOrder;
|
|
1308
1158
|
for (const item of items) {
|
|
@@ -1328,12 +1178,14 @@ async function applyMenuItems(db, menuId, items, parentId, startOrder, seedIdMap
|
|
|
1328
1178
|
title_attr: item.titleAttr ?? null,
|
|
1329
1179
|
target: item.target ?? null,
|
|
1330
1180
|
css_classes: item.cssClasses ?? null,
|
|
1331
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1181
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1182
|
+
locale,
|
|
1183
|
+
translation_group: itemId
|
|
1332
1184
|
}).execute();
|
|
1333
1185
|
count++;
|
|
1334
1186
|
order++;
|
|
1335
1187
|
if (item.children && item.children.length > 0) {
|
|
1336
|
-
const childCount = await applyMenuItems(db, menuId, item.children, itemId, 0, seedIdMap);
|
|
1188
|
+
const childCount = await applyMenuItems(db, menuId, locale, item.children, itemId, 0, seedIdMap);
|
|
1337
1189
|
count += childCount;
|
|
1338
1190
|
}
|
|
1339
1191
|
}
|
|
@@ -1524,5 +1376,5 @@ function getImageDimensions(buffer) {
|
|
|
1524
1376
|
}
|
|
1525
1377
|
|
|
1526
1378
|
//#endregion
|
|
1527
|
-
export { ssrfSafeFetch as a, getPluginSetting as c, getSiteSettings as d, setSiteSettings as f, resolveAndValidateExternalUrl as i, getPluginSettings as l,
|
|
1528
|
-
//# sourceMappingURL=apply-
|
|
1379
|
+
export { ssrfSafeFetch as a, getPluginSetting as c, getSiteSettings as d, setSiteSettings as f, resolveAndValidateExternalUrl as i, getPluginSettings as l, apply_exports as n, stripCredentialHeaders as o, SsrfError as r, validateExternalUrl as s, applySeed as t, getSiteSetting as u };
|
|
1380
|
+
//# sourceMappingURL=apply-UsrFuO7l.mjs.map
|