emdash 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapters-Di31kZ28.d.mts → adapters-DoNJiveC.d.mts} +1 -1
- package/dist/{adapters-Di31kZ28.d.mts.map → adapters-DoNJiveC.d.mts.map} +1 -1
- package/dist/{apply-5uslYdUu.mjs → apply-BzltprvY.mjs} +90 -139
- package/dist/apply-BzltprvY.mjs.map +1 -0
- package/dist/astro/index.d.mts +6 -6
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +194 -17
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +6 -7
- package/dist/astro/middleware/auth.d.mts.map +1 -1
- package/dist/astro/middleware/auth.mjs +34 -57
- package/dist/astro/middleware/auth.mjs.map +1 -1
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +17 -12
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.d.mts.map +1 -1
- package/dist/astro/middleware/request-context.mjs +9 -6
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +301 -165
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/types.d.mts +34 -10
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{base64-MBPo9ozB.mjs → base64-BRICGH2l.mjs} +1 -1
- package/dist/{base64-MBPo9ozB.mjs.map → base64-BRICGH2l.mjs.map} +1 -1
- package/dist/{byline-C4OVd8b3.mjs → byline-BSaNL1w7.mjs} +5 -5
- package/dist/byline-BSaNL1w7.mjs.map +1 -0
- package/dist/bylines-CvJ3PYz2.mjs +113 -0
- package/dist/bylines-CvJ3PYz2.mjs.map +1 -0
- package/dist/cache-C6N_hhN7.mjs +65 -0
- package/dist/cache-C6N_hhN7.mjs.map +1 -0
- package/dist/{chunks-HGz06Soa.mjs → chunks-NBQVDOci.mjs} +8 -2
- package/dist/{chunks-HGz06Soa.mjs.map → chunks-NBQVDOci.mjs.map} +1 -1
- package/dist/cli/index.mjs +229 -31
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +3 -3
- package/dist/client/index.mjs.map +1 -1
- package/dist/{config-BXwuX8Bx.mjs → config-BI0V3ICQ.mjs} +1 -1
- package/dist/{config-BXwuX8Bx.mjs.map → config-BI0V3ICQ.mjs.map} +1 -1
- package/dist/{content-D7J5y73J.mjs → content-8lOYF0pr.mjs} +43 -28
- package/dist/content-8lOYF0pr.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/libsql.d.mts.map +1 -1
- package/dist/db/libsql.mjs +7 -2
- package/dist/db/libsql.mjs.map +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/db/sqlite.d.mts.map +1 -1
- package/dist/db/sqlite.mjs +8 -3
- package/dist/db/sqlite.mjs.map +1 -1
- package/dist/{db-errors-D0UT85nC.mjs → db-errors-WRezodiz.mjs} +1 -1
- package/dist/{db-errors-D0UT85nC.mjs.map → db-errors-WRezodiz.mjs.map} +1 -1
- package/dist/{default-CME5YdZ3.mjs → default-D8ksjWhO.mjs} +1 -1
- package/dist/{default-CME5YdZ3.mjs.map → default-D8ksjWhO.mjs.map} +1 -1
- package/dist/{dialect-helpers-DhTzaUxP.mjs → dialect-helpers-BKCvISIQ.mjs} +19 -2
- package/dist/dialect-helpers-BKCvISIQ.mjs.map +1 -0
- package/dist/{error-CiYn9yDu.mjs → error-D_-tqP-I.mjs} +1 -1
- package/dist/error-D_-tqP-I.mjs.map +1 -0
- package/dist/{index-De6_Xv3v.d.mts → index-BFRaVcD6.d.mts} +243 -40
- package/dist/index-BFRaVcD6.d.mts.map +1 -0
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +29 -25
- package/dist/{load-CBcmDIot.mjs → load-DDqMMvZL.mjs} +2 -2
- package/dist/{load-CBcmDIot.mjs.map → load-DDqMMvZL.mjs.map} +1 -1
- package/dist/{loader-DeiBJEMe.mjs → loader-CKLbBnhK.mjs} +32 -10
- package/dist/loader-CKLbBnhK.mjs.map +1 -0
- package/dist/{manifest-schema-V30qsMft.mjs → manifest-schema-DqWNC3lM.mjs} +45 -3
- package/dist/manifest-schema-DqWNC3lM.mjs.map +1 -0
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +1 -1
- package/dist/media/local-runtime.d.mts +7 -7
- package/dist/media/local-runtime.mjs +3 -3
- package/dist/{media-DqHVh136.mjs → media-BW32b4gi.mjs} +4 -7
- package/dist/media-BW32b4gi.mjs.map +1 -0
- package/dist/{mode-CpNnGkPz.mjs → mode-ier8jbBk.mjs} +1 -1
- package/dist/mode-ier8jbBk.mjs.map +1 -0
- package/dist/options-BVp3UsTS.mjs +117 -0
- package/dist/options-BVp3UsTS.mjs.map +1 -0
- package/dist/page/index.d.mts +2 -2
- package/dist/{placeholder-tzpqGWII.d.mts → placeholder-BE4o_2dc.d.mts} +1 -1
- package/dist/{placeholder-tzpqGWII.d.mts.map → placeholder-BE4o_2dc.d.mts.map} +1 -1
- package/dist/{placeholder-C-fk5hYI.mjs → placeholder-CIJejMlK.mjs} +1 -1
- package/dist/placeholder-CIJejMlK.mjs.map +1 -0
- package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
- package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
- package/dist/plugins/adapt-sandbox-entry.mjs +6 -5
- package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
- package/dist/public-url-DByxYjUw.mjs +51 -0
- package/dist/public-url-DByxYjUw.mjs.map +1 -0
- package/dist/{query-g4Ug-9j9.mjs → query-Cg9ZKRQ0.mjs} +114 -16
- package/dist/query-Cg9ZKRQ0.mjs.map +1 -0
- package/dist/{redirect-CN0Rt9Ob.mjs → redirect-BhUBKRc1.mjs} +13 -8
- package/dist/redirect-BhUBKRc1.mjs.map +1 -0
- package/dist/{registry-Ci3WxVAr.mjs → registry-Dw70ChxB.mjs} +69 -11
- package/dist/registry-Dw70ChxB.mjs.map +1 -0
- package/dist/{request-cache-DiR961CV.mjs → request-cache-B-bmkipQ.mjs} +1 -1
- package/dist/request-cache-B-bmkipQ.mjs.map +1 -0
- package/dist/runner-Bnoj7vjK.d.mts +44 -0
- package/dist/runner-Bnoj7vjK.d.mts.map +1 -0
- package/dist/{runner-tQ7BJ4T7.mjs → runner-C7ADox5q.mjs} +185 -55
- package/dist/{runner-tQ7BJ4T7.mjs.map → runner-C7ADox5q.mjs.map} +1 -1
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +4 -4
- package/dist/{search-B0effn3j.mjs → search-dOGEccMa.mjs} +341 -152
- package/dist/search-dOGEccMa.mjs.map +1 -0
- package/dist/secrets-CW3reAnU.mjs +314 -0
- package/dist/secrets-CW3reAnU.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +15 -14
- package/dist/seo/index.d.mts +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +1 -1
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +4 -4
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{taxonomies-K2z0Uhnj.mjs → taxonomies-ZlRtD6AG.mjs} +14 -7
- package/dist/taxonomies-ZlRtD6AG.mjs.map +1 -0
- package/dist/{tokens-BFPFx3CA.mjs → tokens-D7zMmWi2.mjs} +2 -2
- package/dist/{tokens-BFPFx3CA.mjs.map → tokens-D7zMmWi2.mjs.map} +1 -1
- package/dist/{transport-BykRfpyy.mjs → transport-BeMCmin1.mjs} +6 -5
- package/dist/{transport-BykRfpyy.mjs.map → transport-BeMCmin1.mjs.map} +1 -1
- package/dist/{transport-H4Iwx7tC.d.mts → transport-DNEfeMaU.d.mts} +1 -1
- package/dist/{transport-H4Iwx7tC.d.mts.map → transport-DNEfeMaU.d.mts.map} +1 -1
- package/dist/types-4fVtCIm0.mjs +68 -0
- package/dist/types-4fVtCIm0.mjs.map +1 -0
- package/dist/{types-CnZYHyLW.d.mts → types-BSyXeCFW.d.mts} +24 -2
- package/dist/{types-CnZYHyLW.d.mts.map → types-BSyXeCFW.d.mts.map} +1 -1
- package/dist/{types-DgrIP0tF.d.mts → types-BuBIptGk.d.mts} +80 -106
- package/dist/types-BuBIptGk.d.mts.map +1 -0
- package/dist/{types-BH2L167P.mjs → types-CDbKp7ND.mjs} +1 -1
- package/dist/{types-BH2L167P.mjs.map → types-CDbKp7ND.mjs.map} +1 -1
- package/dist/{types-DDS4MxsT.mjs → types-CIOg5AR8.mjs} +1 -1
- package/dist/{types-DDS4MxsT.mjs.map → types-CIOg5AR8.mjs.map} +1 -1
- package/dist/{types-6CUZRrZP.d.mts → types-CJsYGpco.d.mts} +24 -2
- package/dist/{types-6CUZRrZP.d.mts.map → types-CJsYGpco.d.mts.map} +1 -1
- package/dist/types-CRxNbK-Z.mjs +68 -0
- package/dist/types-CRxNbK-Z.mjs.map +1 -0
- package/dist/{types-C2v0c34j.d.mts → types-CrtWgIvl.d.mts} +1 -1
- package/dist/{types-C2v0c34j.d.mts.map → types-CrtWgIvl.d.mts.map} +1 -1
- package/dist/{types-CFWjXmus.d.mts → types-M78DQ1lx.d.mts} +1 -1
- package/dist/{types-CFWjXmus.d.mts.map → types-M78DQ1lx.d.mts.map} +1 -1
- package/dist/{validate-CqsNItbt.mjs → validate-Baqf0slj.mjs} +3 -3
- package/dist/{validate-CqsNItbt.mjs.map → validate-Baqf0slj.mjs.map} +1 -1
- package/dist/{validate-kM8Pjuf7.d.mts → validate-BfQh_C_y.d.mts} +4 -4
- package/dist/{validate-kM8Pjuf7.d.mts.map → validate-BfQh_C_y.d.mts.map} +1 -1
- package/dist/validation-BfEI7tNe.mjs +144 -0
- package/dist/validation-BfEI7tNe.mjs.map +1 -0
- package/dist/version-DoxrVdYf.mjs +7 -0
- package/dist/{version-BnTKdfam.mjs.map → version-DoxrVdYf.mjs.map} +1 -1
- package/dist/zod-generator-CC0xNe_K.mjs +132 -0
- package/dist/zod-generator-CC0xNe_K.mjs.map +1 -0
- package/locals.d.ts +1 -6
- package/package.json +21 -7
- package/src/api/auth-storage.ts +37 -0
- package/src/api/error.ts +6 -0
- package/src/api/errors.ts +8 -0
- package/src/api/handlers/comments.ts +19 -4
- package/src/api/handlers/content.ts +151 -4
- package/src/api/handlers/device-flow.ts +5 -0
- package/src/api/handlers/index.ts +2 -0
- package/src/api/handlers/marketplace.ts +11 -4
- package/src/api/handlers/media.ts +8 -1
- package/src/api/handlers/menus.ts +160 -21
- package/src/api/handlers/oauth-authorization.ts +72 -33
- package/src/api/handlers/redirects.ts +16 -3
- package/src/api/handlers/revision.ts +23 -14
- package/src/api/handlers/sections.ts +8 -1
- package/src/api/handlers/taxonomies.ts +131 -22
- package/src/api/handlers/validation.ts +212 -0
- package/src/api/openapi/document.ts +4 -1
- package/src/api/public-url.ts +54 -5
- package/src/api/route-utils.ts +14 -0
- package/src/api/schemas/comments.ts +2 -2
- package/src/api/schemas/common.ts +1 -1
- package/src/api/schemas/content.ts +17 -0
- package/src/api/schemas/sections.ts +3 -3
- package/src/api/schemas/setup.ts +8 -0
- package/src/api/schemas/users.ts +1 -1
- package/src/api/schemas/widgets.ts +12 -10
- package/src/api/setup-complete.ts +40 -0
- package/src/api/types.ts +5 -1
- package/src/astro/integration/index.ts +30 -2
- package/src/astro/integration/routes.ts +28 -0
- package/src/astro/integration/runtime.ts +49 -1
- package/src/astro/integration/virtual-modules.ts +73 -2
- package/src/astro/integration/vite-config.ts +49 -13
- package/src/astro/middleware/auth.ts +34 -6
- package/src/astro/middleware/redirect.ts +29 -16
- package/src/astro/middleware/request-context.ts +15 -5
- package/src/astro/middleware.ts +41 -10
- package/src/astro/routes/PluginRegistry.tsx +10 -1
- package/src/astro/routes/api/auth/invite/complete.ts +6 -1
- package/src/astro/routes/api/auth/mode.ts +57 -0
- package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +23 -3
- package/src/astro/routes/api/auth/oauth/[provider].ts +10 -4
- package/src/astro/routes/api/auth/passkey/register/verify.ts +6 -1
- package/src/astro/routes/api/auth/passkey/verify.ts +6 -1
- package/src/astro/routes/api/auth/signup/complete.ts +6 -1
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -2
- package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
- package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +34 -12
- package/src/astro/routes/api/content/[collection]/[id]/publish.ts +32 -2
- package/src/astro/routes/api/content/[collection]/[id]/restore.ts +4 -2
- package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +3 -2
- package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +8 -4
- package/src/astro/routes/api/content/[collection]/[id]/translations.ts +1 -1
- package/src/astro/routes/api/content/[collection]/[id].ts +12 -0
- package/src/astro/routes/api/content/[collection]/index.ts +1 -9
- package/src/astro/routes/api/import/wordpress/execute.ts +3 -1
- package/src/astro/routes/api/import/wordpress/media.ts +2 -7
- package/src/astro/routes/api/import/wordpress/prepare.ts +9 -0
- package/src/astro/routes/api/import/wordpress-plugin/execute.ts +3 -1
- package/src/astro/routes/api/manifest.ts +62 -45
- package/src/astro/routes/api/media/[id]/confirm.ts +10 -1
- package/src/astro/routes/api/media/providers/[providerId]/index.ts +12 -3
- package/src/astro/routes/api/openapi.json.ts +27 -10
- package/src/astro/routes/api/redirects/404s/index.ts +10 -4
- package/src/astro/routes/api/redirects/404s/summary.ts +4 -2
- package/src/astro/routes/api/redirects/[id].ts +10 -4
- package/src/astro/routes/api/redirects/index.ts +7 -3
- package/src/astro/routes/api/revisions/[revisionId]/index.ts +1 -1
- package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +0 -2
- package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +0 -1
- package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +0 -1
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -2
- package/src/astro/routes/api/schema/collections/index.ts +1 -1
- package/src/astro/routes/api/search/index.ts +10 -2
- package/src/astro/routes/api/sections/[slug].ts +10 -4
- package/src/astro/routes/api/sections/index.ts +7 -3
- package/src/astro/routes/api/settings/email.ts +4 -9
- package/src/astro/routes/api/setup/admin-verify.ts +6 -1
- package/src/astro/routes/api/setup/admin.ts +8 -2
- package/src/astro/routes/api/setup/index.ts +2 -2
- package/src/astro/routes/api/setup/status.ts +3 -1
- package/src/astro/routes/api/snapshot.ts +44 -18
- package/src/astro/routes/api/taxonomies/index.ts +0 -1
- package/src/astro/routes/api/themes/preview.ts +11 -5
- package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +4 -1
- package/src/astro/routes/api/widget-areas/[name]/widgets.ts +4 -1
- package/src/astro/routes/api/widget-areas/[name].ts +4 -1
- package/src/astro/routes/api/widget-areas/index.ts +4 -1
- package/src/astro/types.ts +32 -3
- package/src/auth/allowed-origins.ts +168 -0
- package/src/auth/mode.ts +15 -3
- package/src/auth/passkey-config.ts +35 -13
- package/src/auth/providers/github-admin.tsx +29 -0
- package/src/auth/providers/github.ts +31 -0
- package/src/auth/providers/google-admin.tsx +44 -0
- package/src/auth/providers/google.ts +31 -0
- package/src/auth/types.ts +114 -4
- package/src/bylines/index.ts +37 -88
- package/src/cli/commands/auth.ts +28 -6
- package/src/cli/commands/bundle-utils.ts +11 -2
- package/src/cli/commands/bundle.ts +31 -9
- package/src/cli/commands/content.ts +13 -0
- package/src/cli/commands/login.ts +8 -1
- package/src/cli/commands/publish.ts +24 -0
- package/src/cli/commands/secrets.ts +183 -0
- package/src/cli/credentials.ts +1 -1
- package/src/cli/index.ts +5 -1
- package/src/client/index.ts +4 -4
- package/src/client/transport.ts +17 -7
- package/src/components/Break.astro +2 -2
- package/src/components/EmDashHead.astro +18 -13
- package/src/components/EmDashImage.astro +7 -6
- package/src/components/Embed.astro +1 -1
- package/src/components/Gallery.astro +6 -4
- package/src/components/Image.astro +9 -4
- package/src/components/InlinePortableTextEditor.tsx +106 -19
- package/src/components/LiveSearch.astro +5 -14
- package/src/config/secrets.ts +528 -0
- package/src/database/dialect-helpers.ts +50 -0
- package/src/database/migrations/034_published_at_index.ts +1 -1
- package/src/database/migrations/035_bounded_404_log.ts +56 -39
- package/src/database/migrations/runner.ts +156 -23
- package/src/database/repositories/audit.ts +6 -8
- package/src/database/repositories/byline.ts +6 -8
- package/src/database/repositories/comment.ts +12 -16
- package/src/database/repositories/content.ts +76 -52
- package/src/database/repositories/index.ts +1 -1
- package/src/database/repositories/media.ts +10 -13
- package/src/database/repositories/plugin-storage.ts +4 -6
- package/src/database/repositories/redirect.ts +26 -19
- package/src/database/repositories/taxonomy.ts +40 -3
- package/src/database/repositories/types.ts +57 -8
- package/src/database/repositories/user.ts +6 -8
- package/src/db/libsql.ts +1 -3
- package/src/db/sqlite.ts +2 -5
- package/src/emdash-runtime.ts +388 -247
- package/src/index.ts +14 -1
- package/src/loader.ts +30 -6
- package/src/mcp/server.ts +781 -141
- package/src/media/normalize.ts +1 -1
- package/src/media/url.ts +78 -0
- package/src/page/site-identity.ts +58 -0
- package/src/plugins/adapt-sandbox-entry.ts +22 -10
- package/src/plugins/context.ts +13 -10
- package/src/plugins/define-plugin.ts +40 -12
- package/src/plugins/email-console.ts +10 -3
- package/src/plugins/hooks.ts +34 -19
- package/src/plugins/index.ts +9 -0
- package/src/plugins/manifest-schema.ts +49 -2
- package/src/plugins/types.ts +174 -13
- package/src/preview/urls.ts +23 -3
- package/src/query.ts +149 -6
- package/src/redirects/cache.ts +38 -18
- package/src/request-cache.ts +3 -0
- package/src/schema/registry.ts +97 -5
- package/src/schema/zod-generator.ts +27 -5
- package/src/search/fts-manager.ts +0 -2
- package/src/search/query.ts +111 -26
- package/src/search/types.ts +8 -1
- package/src/sections/index.ts +7 -9
- package/src/seed/apply.ts +2 -0
- package/src/settings/index.ts +80 -6
- package/src/settings/types.ts +23 -1
- package/src/storage/s3.ts +12 -6
- package/src/taxonomies/index.ts +11 -1
- package/src/virtual-modules.d.ts +21 -1
- package/src/widgets/index.ts +1 -1
- package/dist/apply-5uslYdUu.mjs.map +0 -1
- package/dist/byline-C4OVd8b3.mjs.map +0 -1
- package/dist/bylines-hPTW79hw.mjs +0 -157
- package/dist/bylines-hPTW79hw.mjs.map +0 -1
- package/dist/cache-BkKBuIvS.mjs +0 -56
- package/dist/cache-BkKBuIvS.mjs.map +0 -1
- package/dist/chunk-ClPoSABd.mjs +0 -21
- package/dist/content-D7J5y73J.mjs.map +0 -1
- package/dist/dialect-helpers-DhTzaUxP.mjs.map +0 -1
- package/dist/error-CiYn9yDu.mjs.map +0 -1
- package/dist/index-De6_Xv3v.d.mts.map +0 -1
- package/dist/loader-DeiBJEMe.mjs.map +0 -1
- package/dist/manifest-schema-V30qsMft.mjs.map +0 -1
- package/dist/media-DqHVh136.mjs.map +0 -1
- package/dist/mode-CpNnGkPz.mjs.map +0 -1
- package/dist/placeholder-C-fk5hYI.mjs.map +0 -1
- package/dist/query-g4Ug-9j9.mjs.map +0 -1
- package/dist/redirect-CN0Rt9Ob.mjs.map +0 -1
- package/dist/registry-Ci3WxVAr.mjs.map +0 -1
- package/dist/request-cache-DiR961CV.mjs.map +0 -1
- package/dist/runner-BR2xKwhn.d.mts +0 -34
- package/dist/runner-BR2xKwhn.d.mts.map +0 -1
- package/dist/search-B0effn3j.mjs.map +0 -1
- package/dist/taxonomies-K2z0Uhnj.mjs.map +0 -1
- package/dist/types-CMMN0pNg.mjs +0 -31
- package/dist/types-CMMN0pNg.mjs.map +0 -1
- package/dist/types-DgrIP0tF.d.mts.map +0 -1
- package/dist/version-BnTKdfam.mjs +0 -7
package/dist/astro/types.d.mts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { f as MediaProvider, p as MediaProviderCapabilities } from "../placeholder-
|
|
2
|
-
import { t as Database } from "../types-
|
|
3
|
-
import {
|
|
4
|
-
import "../runner-
|
|
5
|
-
import { r as ContentItem } from "../types-
|
|
6
|
-
import {
|
|
7
|
-
import { d as Storage } from "../types-
|
|
8
|
-
import "../validate-
|
|
1
|
+
import { f as MediaProvider, p as MediaProviderCapabilities } from "../placeholder-BE4o_2dc.mjs";
|
|
2
|
+
import { t as Database } from "../types-CrtWgIvl.mjs";
|
|
3
|
+
import { Di as ContentListResponse, Jr as MediaListResponse, Oi as ContentResponse, Pr as SandboxRunner, Vi as MediaItem, Yr as MediaResponse, cn as HookPipeline, pn as EmDashConfig, sn as EmailPipeline } from "../index-BFRaVcD6.mjs";
|
|
4
|
+
import "../runner-Bnoj7vjK.mjs";
|
|
5
|
+
import { r as ContentItem } from "../types-CJsYGpco.mjs";
|
|
6
|
+
import { $ as ResolvedPlugin, A as PageFragmentContribution, N as PageMetadataContribution, X as PublicPageContext } from "../types-BuBIptGk.mjs";
|
|
7
|
+
import { d as Storage } from "../types-M78DQ1lx.mjs";
|
|
8
|
+
import "../validate-BfQh_C_y.mjs";
|
|
9
9
|
import "../index.mjs";
|
|
10
10
|
import { Kysely } from "kysely";
|
|
11
|
+
import { Element } from "@emdash-cms/blocks";
|
|
11
12
|
|
|
12
13
|
//#region src/astro/types.d.ts
|
|
13
14
|
/**
|
|
@@ -194,6 +195,18 @@ interface EmDashHandlers {
|
|
|
194
195
|
slug?: string;
|
|
195
196
|
status?: string;
|
|
196
197
|
authorId?: string | null;
|
|
198
|
+
bylines?: Array<{
|
|
199
|
+
bylineId: string;
|
|
200
|
+
roleLabel?: string | null;
|
|
201
|
+
}>;
|
|
202
|
+
seo?: {
|
|
203
|
+
title?: string | null;
|
|
204
|
+
description?: string | null;
|
|
205
|
+
image?: string | null;
|
|
206
|
+
canonical?: string | null;
|
|
207
|
+
noIndex?: boolean;
|
|
208
|
+
};
|
|
209
|
+
publishedAt?: string | null;
|
|
197
210
|
_rev?: string;
|
|
198
211
|
}) => Promise<HandlerResponse>;
|
|
199
212
|
handleContentDelete: (collection: string, id: string) => Promise<HandlerResponse>;
|
|
@@ -206,7 +219,9 @@ interface EmDashHandlers {
|
|
|
206
219
|
handleContentCountTrashed: (collection: string) => Promise<HandlerResponse>;
|
|
207
220
|
handleContentGetIncludingTrashed: (collection: string, id: string) => Promise<HandlerResponse>;
|
|
208
221
|
handleContentDuplicate: (collection: string, id: string, authorId?: string) => Promise<HandlerResponse>;
|
|
209
|
-
handleContentPublish: (collection: string, id: string
|
|
222
|
+
handleContentPublish: (collection: string, id: string, options?: {
|
|
223
|
+
publishedAt?: string;
|
|
224
|
+
}) => Promise<HandlerResponse>;
|
|
210
225
|
handleContentUnpublish: (collection: string, id: string) => Promise<HandlerResponse>;
|
|
211
226
|
handleContentSchedule: (collection: string, id: string, scheduledAt: string) => Promise<HandlerResponse>;
|
|
212
227
|
handleContentUnschedule: (collection: string, id: string) => Promise<HandlerResponse>;
|
|
@@ -265,16 +280,25 @@ interface EmDashHandlers {
|
|
|
265
280
|
}>;
|
|
266
281
|
storage: Storage | null;
|
|
267
282
|
db: Kysely<Database>;
|
|
283
|
+
getPublicMediaUrl?: (storageKey: string) => string;
|
|
268
284
|
hooks: HookPipeline;
|
|
269
285
|
email: EmailPipeline | null;
|
|
270
286
|
configuredPlugins: ResolvedPlugin[];
|
|
271
287
|
config: EmDashConfig;
|
|
272
|
-
|
|
288
|
+
getManifest: () => Promise<EmDashManifest>;
|
|
289
|
+
invalidateUrlPatternCache: () => void;
|
|
273
290
|
getSandboxRunner: () => SandboxRunner | null;
|
|
274
291
|
syncMarketplacePlugins: () => Promise<void>;
|
|
275
292
|
setPluginStatus: (pluginId: string, status: "active" | "inactive") => Promise<void>;
|
|
276
293
|
collectPageMetadata: (page: PublicPageContext) => Promise<PageMetadataContribution[]>;
|
|
277
294
|
collectPageFragments: (page: PublicPageContext) => Promise<PageFragmentContribution[]>;
|
|
295
|
+
/**
|
|
296
|
+
* Lazy search index health check. Search routes call this before
|
|
297
|
+
* querying so a crash-corrupted index gets repaired on first use
|
|
298
|
+
* rather than stalling cold start. Optional because it's only
|
|
299
|
+
* meaningful when an FTS5-capable runtime is wired in.
|
|
300
|
+
*/
|
|
301
|
+
ensureSearchHealthy?: () => Promise<void>;
|
|
278
302
|
}
|
|
279
303
|
//#endregion
|
|
280
304
|
export { type ContentItem, type ContentListResponse, type ContentResponse, type Database, EmDashHandlers, EmDashManifest, HandlerResponse, ManifestAuthMode, ManifestCollection, ManifestPlugin, type MediaItem, type MediaListResponse, type MediaResponse, type Storage };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/astro/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/astro/types.ts"],"mappings":";;;;;;;;;;;;;;;;UAyBiB,kBAAA;EAChB,KAAA;EACA,aAAA;EACA,QAAA;EACA,MAAA;EACA,UAAA;EACA,MAAA,EAAQ,MAAA;IAGN,IAAA;IACA,KAAA;IACA,QAAA;IACA,MAAA;IATF;;;;;;IAgBE,OAAA,GAAU,KAAA;MAAQ,KAAA;MAAe,KAAA;IAAA,KAAmB,MAAA;EAAA;AAAA;;;;UAQtC,cAAA;EAChB,OAAA;EAD8B;EAG9B,OAAA;EAUa;EARb,OAAA;EAsBY;;;;;;EAfZ,SAAA;EACA,UAAA,GAAa,KAAA;IACZ,IAAA;IACA,KAAA;IACA,IAAA;EAAA;EAED,gBAAA,GAAmB,KAAA;IAClB,EAAA;IACA,KAAA;IACA,IAAA;EAAA;EAED,YAAA,GAAe,KAAA;IACd,IAAA;IACA,KAAA;IACA,UAAA;IACA,QAAA,GAAW,OAAA;EAAA;EAFX;EAKD,kBAAA,GAAqB,KAAA;IACpB,IAAA;IACA,KAAA;IACA,IAAA;IACA,WAAA;IACA,WAAA;IACA,MAAA,GAAS,OAAA;EAAA;AAAA;;;;;;KASC,gBAAA;;;;UAKK,cAAA;EAChB,OAAA;EACA,MAAA;EACA,IAAA;EACA,WAAA,EAAa,MAAA,SAAe,kBAAA;EAC5B,OAAA,EAAS,MAAA,SAAe,cAAA;EAAA;;;;;;EAOxB,QAAA,EAAU,gBAAA;EAVV;;;;EAeA,aAAA;EAZA;;;;EAiBA,IAAA;IACC,aAAA;IACA,OAAA;IACA,mBAAA;EAAA;EAAA;;;EAKD,UAAA,EAAY,KAAA;IACX,IAAA;IACA,KAAA;IACA,aAAA;IACA,YAAA;IACA,WAAA;EAAA;EAYA;;;;EAND,WAAA;EAmBgB;;;;EAdhB,KAAA;IACC,IAAA;IACA,QAAA;IACA,OAAA;EAAA;AAAA;;;;;;AA4BF;;UAjBiB,eAAA;EAChB,OAAA;EACA,IAAA,GAAO,CAAA;EACP,KAAA;IACC,IAAA;IACA,OAAA;IACA,OAAA,GAAU,MAAA;EAAA;AAAA;;;;;;;;UAWK,cAAA;EAEhB,iBAAA,GACC,UAAA,UACA,MAAA;IACC,MAAA;IACA,KAAA;IACA,MAAA;IACA,OAAA;IACA,KAAA;IACA,MAAA;EAAA,MAEG,OAAA,CAAQ,eAAA;EAEb,gBAAA,GACC,UAAA,UACA,EAAA,UACA,MAAA,cACI,OAAA,CACJ,eAAA;IACC,IAAA;MACC,EAAA;MACA,QAAA;MAAA,CACC,GAAA;IAAA;IAEF,IAAA;EAAA;EAIF,mBAAA,GACC,UAAA,UACA,IAAA;IACC,IAAA,EAAM,MAAA;IACN,IAAA;IACA,MAAA;IACA,QAAA;IACA,MAAA;IACA,aAAA;IACA,SAAA;IACA,WAAA;EAAA,MAEG,OAAA,CAAQ,eAAA;EAEb,mBAAA,GACC,UAAA,UACA,EAAA,UACA,IAAA;IACC,IAAA,GAAO,MAAA;IACP,IAAA;IACA,MAAA;IACA,QAAA;IACA,OAAA,GAAU,KAAA;MAAQ,QAAA;MAAkB,SAAA;IAAA;IACpC,GAAA;MACC,KAAA;MACA,WAAA;MACA,KAAA;MACA,SAAA;MACA,OAAA;IAAA;IAED,WAAA;IACA,IAAA;EAAA,MAEG,OAAA,CAAQ,eAAA;EAEb,mBAAA,GAAsB,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAGjE,wBAAA,GACC,UAAA,UACA,MAAA;IAAW,MAAA;IAAiB,KAAA;EAAA,MACxB,OAAA,CAAQ,eAAA;EAEb,oBAAA,GAAuB,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAElE,4BAAA,GAA+B,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAE1E,yBAAA,GAA4B,UAAA,aAAuB,OAAA,CAAQ,eAAA;EAE3D,gCAAA,GAAmC,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAE9E,sBAAA,GACC,UAAA,UACA,EAAA,UACA,QAAA,cACI,OAAA,CAAQ,eAAA;EAGb,oBAAA,GACC,UAAA,UACA,EAAA,UACA,OAAA;IAAY,WAAA;EAAA,MACR,OAAA,CAAQ,eAAA;EAEb,sBAAA,GAAyB,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAEpE,qBAAA,GACC,UAAA,UACA,EAAA,UACA,WAAA,aACI,OAAA,CAAQ,eAAA;EAEb,uBAAA,GAA0B,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAErE,2BAAA,GAA8B,UAAA,aAAuB,OAAA,CAAQ,eAAA;EAE7D,yBAAA,GAA4B,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAEvE,oBAAA,GAAuB,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAElE,yBAAA,GAA4B,UAAA,UAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAGvE,eAAA,GAAkB,MAAA;IACjB,MAAA;IACA,KAAA;IACA,QAAA;EAAA,MACK,OAAA,CAAQ,eAAA;EAEd,cAAA,GAAiB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAExC,iBAAA,GAAoB,KAAA;IACnB,QAAA;IACA,QAAA;IACA,IAAA;IACA,KAAA;IACA,MAAA;IACA,UAAA;IACA,WAAA;IACA,QAAA;IACA,aAAA;IACA,QAAA;EAAA,MACK,OAAA,CAAQ,eAAA;EAEd,iBAAA,GACC,EAAA,UACA,KAAA;IAAS,GAAA;IAAc,OAAA;IAAkB,KAAA;IAAgB,MAAA;EAAA,MACrD,OAAA,CAAQ,eAAA;EAEb,iBAAA,GAAoB,EAAA,aAAe,OAAA,CAAQ,eAAA;EAG3C,kBAAA,GACC,UAAA,UACA,OAAA,UACA,MAAA;IAAW,KAAA;EAAA,MACP,OAAA,CAAQ,eAAA;EAEb,iBAAA,GAAoB,UAAA,aAAuB,OAAA,CAC1C,eAAA;IACC,IAAA;MACC,EAAA;MACA,UAAA;MACA,OAAA;MACA,QAAA;MAAA,CACC,GAAA;IAAA;EAAA;EAKJ,qBAAA,GAAwB,UAAA,UAAoB,YAAA,aAAyB,OAAA,CAAQ,eAAA;EAG7E,oBAAA,GACC,QAAA,UACA,MAAA,UACA,IAAA,UACA,OAAA,EAAS,OAAA,KACL,OAAA,CAAQ,eAAA;EAGb,kBAAA,GAAqB,QAAA,UAAkB,IAAA;IAAmB,MAAA;EAAA;EAG1D,gBAAA,GAAmB,UAAA,aANP,aAAA;EAOZ,oBAAA,QAA4B,KAAA;IAC3B,EAAA;IACA,IAAA;IACA,IAAA;IACA,YAAA,EALkF,yBAAA;EAAA;EASnF,OAAA,EARiC,OAAA;EASjC,EAAA,EAAI,MAAA,CADkC,QAAA;EAEtC,iBAAA,IAAqB,UAAA;EAGrB,KAAA,EAJU,YAAA;EAOV,KAAA,EAHiD,aAAA;EAMjD,iBAAA,EAHkD,cAAA;EAMlD,MAAA,EAH+D,YAAA;EAQ/D,WAAA,QAAmB,OAAA,CAAQ,cAAA;EAK3B,yBAAA;EAGA,gBAAA,QAR0B,aAAA;EAW1B,sBAAA,QAA8B,OAAA;EAG9B,eAAA,GAAkB,QAAA,UAAkB,MAAA,4BAAkC,OAAA;EAGtE,mBAAA,GACC,IAAA,EAJ4E,iBAAA,KAKxE,OAAA,CADiD,wBAAA;EAEtD,oBAAA,GACC,IAAA,EAFW,iBAAA,KAGP,OAAA,CADiD,wBAAA;EA9JhC;;;;;;EAuKtB,mBAAA,SAA4B,OAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base64-
|
|
1
|
+
{"version":3,"file":"base64-BRICGH2l.mjs","names":[],"sources":["../src/utils/base64.ts"],"sourcesContent":["/**\n * Base64 encoding/decoding utilities.\n *\n * Uses native Uint8Array.prototype.toBase64 / Uint8Array.fromBase64 when\n * available (workerd, Node 26+, modern browsers), falls back to btoa/atob.\n *\n * All base64url encoding uses the { alphabet: \"base64url\" } option natively\n * or manual character replacement as fallback.\n *\n * Delete the fallback paths when the minimum Node version supports these\n * methods natively.\n */\n\nconst hasNative =\n\ttypeof Uint8Array.prototype.toBase64 === \"function\" &&\n\ttypeof Uint8Array.fromBase64 === \"function\";\n\n// Regex patterns for base64url character replacement\nconst BASE64_PLUS_PATTERN = /\\+/g;\nconst BASE64_SLASH_PATTERN = /\\//g;\nconst BASE64_PADDING_PATTERN = /=+$/;\nconst BASE64URL_DASH_PATTERN = /-/g;\nconst BASE64URL_UNDERSCORE_PATTERN = /_/g;\n\n// ---------------------------------------------------------------------------\n// Standard base64 (for opaque tokens, cursors, Basic Auth, etc.)\n// ---------------------------------------------------------------------------\n\n/** Encode a UTF-8 string as standard base64. */\nexport function encodeBase64(str: string): string {\n\tconst bytes = new TextEncoder().encode(str);\n\tif (hasNative) return bytes.toBase64();\n\tlet binary = \"\";\n\tfor (const b of bytes) binary += String.fromCharCode(b);\n\treturn btoa(binary);\n}\n\n/** Decode a standard base64 string to a UTF-8 string. */\nexport function decodeBase64(base64: string): string {\n\tif (hasNative) return new TextDecoder().decode(Uint8Array.fromBase64(base64));\n\tconst binary = atob(base64);\n\tconst bytes = new Uint8Array(binary.length);\n\tfor (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n\treturn new TextDecoder().decode(bytes);\n}\n\n// ---------------------------------------------------------------------------\n// Base64url (for tokens, HMAC signatures, PKCE, etc.)\n// ---------------------------------------------------------------------------\n\n/** Encode bytes as base64url without padding. */\nexport function encodeBase64url(bytes: Uint8Array): string {\n\tif (hasNative) return bytes.toBase64({ alphabet: \"base64url\", omitPadding: true });\n\tlet binary = \"\";\n\tfor (const b of bytes) binary += String.fromCharCode(b);\n\treturn btoa(binary)\n\t\t.replace(BASE64_PLUS_PATTERN, \"-\")\n\t\t.replace(BASE64_SLASH_PATTERN, \"_\")\n\t\t.replace(BASE64_PADDING_PATTERN, \"\");\n}\n\n/** Decode a base64url string (with or without padding) to bytes. */\nexport function decodeBase64url(encoded: string): Uint8Array {\n\tif (hasNative) return Uint8Array.fromBase64(encoded, { alphabet: \"base64url\" });\n\tconst base64 = encoded\n\t\t.replace(BASE64URL_DASH_PATTERN, \"+\")\n\t\t.replace(BASE64URL_UNDERSCORE_PATTERN, \"/\");\n\tconst padded = base64 + \"=\".repeat((4 - (base64.length % 4)) % 4);\n\tconst binary = atob(padded);\n\tconst bytes = new Uint8Array(binary.length);\n\tfor (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n\treturn bytes;\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAM,YACL,OAAO,WAAW,UAAU,aAAa,cACzC,OAAO,WAAW,eAAe;AAGlC,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,yBAAyB;AAC/B,MAAM,yBAAyB;AAC/B,MAAM,+BAA+B;;AAOrC,SAAgB,aAAa,KAAqB;CACjD,MAAM,QAAQ,IAAI,aAAa,CAAC,OAAO,IAAI;AAC3C,KAAI,UAAW,QAAO,MAAM,UAAU;CACtC,IAAI,SAAS;AACb,MAAK,MAAM,KAAK,MAAO,WAAU,OAAO,aAAa,EAAE;AACvD,QAAO,KAAK,OAAO;;;AAIpB,SAAgB,aAAa,QAAwB;AACpD,KAAI,UAAW,QAAO,IAAI,aAAa,CAAC,OAAO,WAAW,WAAW,OAAO,CAAC;CAC7E,MAAM,SAAS,KAAK,OAAO;CAC3B,MAAM,QAAQ,IAAI,WAAW,OAAO,OAAO;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,OAAM,KAAK,OAAO,WAAW,EAAE;AACvE,QAAO,IAAI,aAAa,CAAC,OAAO,MAAM;;;AAQvC,SAAgB,gBAAgB,OAA2B;AAC1D,KAAI,UAAW,QAAO,MAAM,SAAS;EAAE,UAAU;EAAa,aAAa;EAAM,CAAC;CAClF,IAAI,SAAS;AACb,MAAK,MAAM,KAAK,MAAO,WAAU,OAAO,aAAa,EAAE;AACvD,QAAO,KAAK,OAAO,CACjB,QAAQ,qBAAqB,IAAI,CACjC,QAAQ,sBAAsB,IAAI,CAClC,QAAQ,wBAAwB,GAAG;;;AAItC,SAAgB,gBAAgB,SAA6B;AAC5D,KAAI,UAAW,QAAO,WAAW,WAAW,SAAS,EAAE,UAAU,aAAa,CAAC;CAC/E,MAAM,SAAS,QACb,QAAQ,wBAAwB,IAAI,CACpC,QAAQ,8BAA8B,IAAI;CAC5C,MAAM,SAAS,SAAS,IAAI,QAAQ,IAAK,OAAO,SAAS,KAAM,EAAE;CACjE,MAAM,SAAS,KAAK,OAAO;CAC3B,MAAM,QAAQ,IAAI,WAAW,OAAO,OAAO;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,OAAM,KAAK,OAAO,WAAW,EAAE;AACvE,QAAO"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { c as listTablesLike } from "./dialect-helpers-BKCvISIQ.mjs";
|
|
3
|
+
import { i as encodeCursor, r as decodeCursor } from "./types-CRxNbK-Z.mjs";
|
|
4
4
|
import { t as withTransaction } from "./transaction-Cn2rjY78.mjs";
|
|
5
|
-
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-
|
|
5
|
+
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-NBQVDOci.mjs";
|
|
6
6
|
import { sql } from "kysely";
|
|
7
7
|
import { ulid } from "ulidx";
|
|
8
8
|
|
|
@@ -48,7 +48,7 @@ var BylineRepository = class {
|
|
|
48
48
|
if (options?.userId !== void 0) query = query.where("user_id", "=", options.userId);
|
|
49
49
|
if (options?.cursor) {
|
|
50
50
|
const decoded = decodeCursor(options.cursor);
|
|
51
|
-
|
|
51
|
+
query = query.where((eb) => eb.or([eb("created_at", "<", decoded.orderValue), eb.and([eb("created_at", "=", decoded.orderValue), eb("id", "<", decoded.id)])]));
|
|
52
52
|
}
|
|
53
53
|
const rows = await query.execute();
|
|
54
54
|
const items = rows.slice(0, limit).map(rowToByline);
|
|
@@ -217,4 +217,4 @@ var BylineRepository = class {
|
|
|
217
217
|
|
|
218
218
|
//#endregion
|
|
219
219
|
export { BylineRepository as t };
|
|
220
|
-
//# sourceMappingURL=byline-
|
|
220
|
+
//# sourceMappingURL=byline-BSaNL1w7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byline-BSaNL1w7.mjs","names":[],"sources":["../src/database/repositories/byline.ts"],"sourcesContent":["import { sql, type Kysely, type Selectable } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { listTablesLike } from \"../dialect-helpers.js\";\nimport { withTransaction } from \"../transaction.js\";\nimport type { BylineTable, Database } from \"../types.js\";\nimport { validateIdentifier } from \"../validate.js\";\nimport {\n\tdecodeCursor,\n\tencodeCursor,\n\ttype BylineSummary,\n\ttype ContentBylineCredit,\n\ttype FindManyResult,\n} from \"./types.js\";\n\ntype BylineRow = Selectable<BylineTable>;\n\nexport interface CreateBylineInput {\n\tslug: string;\n\tdisplayName: string;\n\tbio?: string | null;\n\tavatarMediaId?: string | null;\n\twebsiteUrl?: string | null;\n\tuserId?: string | null;\n\tisGuest?: boolean;\n}\n\nexport interface UpdateBylineInput {\n\tslug?: string;\n\tdisplayName?: string;\n\tbio?: string | null;\n\tavatarMediaId?: string | null;\n\twebsiteUrl?: string | null;\n\tuserId?: string | null;\n\tisGuest?: boolean;\n}\n\nexport interface ContentBylineInput {\n\tbylineId: string;\n\troleLabel?: string | null;\n}\n\nfunction rowToByline(row: BylineRow): BylineSummary {\n\treturn {\n\t\tid: row.id,\n\t\tslug: row.slug,\n\t\tdisplayName: row.display_name,\n\t\tbio: row.bio,\n\t\tavatarMediaId: row.avatar_media_id,\n\t\twebsiteUrl: row.website_url,\n\t\tuserId: row.user_id,\n\t\tisGuest: row.is_guest === 1,\n\t\tcreatedAt: row.created_at,\n\t\tupdatedAt: row.updated_at,\n\t};\n}\n\nexport class BylineRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\tasync findById(id: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findBySlug(slug: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findByUserId(userId: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"user_id\", \"=\", userId)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findMany(options?: {\n\t\tsearch?: string;\n\t\tisGuest?: boolean;\n\t\tuserId?: string;\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t}): Promise<FindManyResult<BylineSummary>> {\n\t\tconst limit = Math.min(Math.max(options?.limit ?? 50, 1), 100);\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\tif (options?.search) {\n\t\t\tconst escaped = options.search\n\t\t\t\t.replaceAll(\"\\\\\", \"\\\\\\\\\")\n\t\t\t\t.replaceAll(\"%\", \"\\\\%\")\n\t\t\t\t.replaceAll(\"_\", \"\\\\_\");\n\t\t\tconst term = `%${escaped}%`;\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([eb(\"display_name\", \"like\", term), eb(\"slug\", \"like\", term)]),\n\t\t\t);\n\t\t}\n\n\t\tif (options?.isGuest !== undefined) {\n\t\t\tquery = query.where(\"is_guest\", \"=\", options.isGuest ? 1 : 0);\n\t\t}\n\n\t\tif (options?.userId !== undefined) {\n\t\t\tquery = query.where(\"user_id\", \"=\", options.userId);\n\t\t}\n\n\t\tif (options?.cursor) {\n\t\t\tconst decoded = decodeCursor(options.cursor);\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([\n\t\t\t\t\teb(\"created_at\", \"<\", decoded.orderValue),\n\t\t\t\t\teb.and([eb(\"created_at\", \"=\", decoded.orderValue), eb(\"id\", \"<\", decoded.id)]),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\tconst items = rows.slice(0, limit).map(rowToByline);\n\t\tconst result: FindManyResult<BylineSummary> = { items };\n\n\t\tif (rows.length > limit) {\n\t\t\tconst last = items.at(-1);\n\t\t\tif (last) {\n\t\t\t\tresult.nextCursor = encodeCursor(last.createdAt, last.id);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync create(input: CreateBylineInput): Promise<BylineSummary> {\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_bylines\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tslug: input.slug,\n\t\t\t\tdisplay_name: input.displayName,\n\t\t\t\tbio: input.bio ?? null,\n\t\t\t\tavatar_media_id: input.avatarMediaId ?? null,\n\t\t\t\twebsite_url: input.websiteUrl ?? null,\n\t\t\t\tuser_id: input.userId ?? null,\n\t\t\t\tis_guest: input.isGuest ? 1 : 0,\n\t\t\t\tcreated_at: now,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.execute();\n\n\t\tconst byline = await this.findById(id);\n\t\tif (!byline) {\n\t\t\tthrow new Error(\"Failed to create byline\");\n\t\t}\n\t\treturn byline;\n\t}\n\n\tasync update(id: string, input: UpdateBylineInput): Promise<BylineSummary | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return null;\n\n\t\tconst updates: Record<string, unknown> = {\n\t\t\tupdated_at: new Date().toISOString(),\n\t\t};\n\n\t\tif (input.slug !== undefined) updates.slug = input.slug;\n\t\tif (input.displayName !== undefined) updates.display_name = input.displayName;\n\t\tif (input.bio !== undefined) updates.bio = input.bio;\n\t\tif (input.avatarMediaId !== undefined) updates.avatar_media_id = input.avatarMediaId;\n\t\tif (input.websiteUrl !== undefined) updates.website_url = input.websiteUrl;\n\t\tif (input.userId !== undefined) updates.user_id = input.userId;\n\t\tif (input.isGuest !== undefined) updates.is_guest = input.isGuest ? 1 : 0;\n\n\t\tawait this.db.updateTable(\"_emdash_bylines\").set(updates).where(\"id\", \"=\", id).execute();\n\t\treturn await this.findById(id);\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return false;\n\n\t\tawait withTransaction(this.db, async (trx) => {\n\t\t\tawait trx.deleteFrom(\"_emdash_content_bylines\").where(\"byline_id\", \"=\", id).execute();\n\n\t\t\tawait trx.deleteFrom(\"_emdash_bylines\").where(\"id\", \"=\", id).execute();\n\n\t\t\tconst tableNames = await listTablesLike(trx, \"ec_%\");\n\t\t\tfor (const tableName of tableNames) {\n\t\t\t\tvalidateIdentifier(tableName, \"content table\");\n\t\t\t\tawait sql`\n\t\t\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\t\t\tSET primary_byline_id = NULL\n\t\t\t\t\tWHERE primary_byline_id = ${id}\n\t\t\t\t`.execute(trx);\n\t\t\t}\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tasync getContentBylines(\n\t\tcollectionSlug: string,\n\t\tcontentId: string,\n\t): Promise<ContentBylineCredit[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_content_bylines as cb\")\n\t\t\t.innerJoin(\"_emdash_bylines as b\", \"b.id\", \"cb.byline_id\")\n\t\t\t.select([\n\t\t\t\t\"cb.sort_order as sort_order\",\n\t\t\t\t\"cb.role_label as role_label\",\n\t\t\t\t\"b.id as id\",\n\t\t\t\t\"b.slug as slug\",\n\t\t\t\t\"b.display_name as display_name\",\n\t\t\t\t\"b.bio as bio\",\n\t\t\t\t\"b.avatar_media_id as avatar_media_id\",\n\t\t\t\t\"b.website_url as website_url\",\n\t\t\t\t\"b.user_id as user_id\",\n\t\t\t\t\"b.is_guest as is_guest\",\n\t\t\t\t\"b.created_at as created_at\",\n\t\t\t\t\"b.updated_at as updated_at\",\n\t\t\t])\n\t\t\t.where(\"cb.collection_slug\", \"=\", collectionSlug)\n\t\t\t.where(\"cb.content_id\", \"=\", contentId)\n\t\t\t.orderBy(\"cb.sort_order\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn rows.map((row) => ({\n\t\t\tbyline: rowToByline(row),\n\t\t\tsortOrder: row.sort_order,\n\t\t\troleLabel: row.role_label,\n\t\t}));\n\t}\n\n\t/**\n\t * Batch-fetch byline credits for multiple content items in a single query.\n\t * Returns a Map keyed by contentId.\n\t */\n\tasync getContentBylinesMany(\n\t\tcollectionSlug: string,\n\t\tcontentIds: string[],\n\t): Promise<Map<string, ContentBylineCredit[]>> {\n\t\tconst result = new Map<string, ContentBylineCredit[]>();\n\t\tif (contentIds.length === 0) return result;\n\n\t\tconst uniqueContentIds = [...new Set(contentIds)];\n\t\tfor (const chunk of chunks(uniqueContentIds, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_content_bylines as cb\")\n\t\t\t\t.innerJoin(\"_emdash_bylines as b\", \"b.id\", \"cb.byline_id\")\n\t\t\t\t.select([\n\t\t\t\t\t\"cb.content_id as content_id\",\n\t\t\t\t\t\"cb.sort_order as sort_order\",\n\t\t\t\t\t\"cb.role_label as role_label\",\n\t\t\t\t\t\"b.id as id\",\n\t\t\t\t\t\"b.slug as slug\",\n\t\t\t\t\t\"b.display_name as display_name\",\n\t\t\t\t\t\"b.bio as bio\",\n\t\t\t\t\t\"b.avatar_media_id as avatar_media_id\",\n\t\t\t\t\t\"b.website_url as website_url\",\n\t\t\t\t\t\"b.user_id as user_id\",\n\t\t\t\t\t\"b.is_guest as is_guest\",\n\t\t\t\t\t\"b.created_at as created_at\",\n\t\t\t\t\t\"b.updated_at as updated_at\",\n\t\t\t\t])\n\t\t\t\t.where(\"cb.collection_slug\", \"=\", collectionSlug)\n\t\t\t\t.where(\"cb.content_id\", \"in\", chunk)\n\t\t\t\t.orderBy(\"cb.sort_order\", \"asc\")\n\t\t\t\t.execute();\n\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst contentId = row.content_id;\n\t\t\t\tconst credit: ContentBylineCredit = {\n\t\t\t\t\tbyline: rowToByline(row),\n\t\t\t\t\tsortOrder: row.sort_order,\n\t\t\t\t\troleLabel: row.role_label,\n\t\t\t\t};\n\t\t\t\tconst existing = result.get(contentId);\n\t\t\t\tif (existing) {\n\t\t\t\t\texisting.push(credit);\n\t\t\t\t} else {\n\t\t\t\t\tresult.set(contentId, [credit]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Batch-fetch byline profiles linked to user IDs in a single query.\n\t * Returns a Map keyed by userId.\n\t */\n\tasync findByUserIds(userIds: string[]): Promise<Map<string, BylineSummary>> {\n\t\tconst result = new Map<string, BylineSummary>();\n\t\tif (userIds.length === 0) return result;\n\n\t\tfor (const chunk of chunks(userIds, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t\t.selectAll()\n\t\t\t\t.where(\"user_id\", \"in\", chunk)\n\t\t\t\t.execute();\n\n\t\t\tfor (const row of rows) {\n\t\t\t\tif (row.user_id) {\n\t\t\t\t\tresult.set(row.user_id, rowToByline(row));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync setContentBylines(\n\t\tcollectionSlug: string,\n\t\tcontentId: string,\n\t\tinputBylines: ContentBylineInput[],\n\t): Promise<ContentBylineCredit[]> {\n\t\tvalidateIdentifier(collectionSlug, \"collection slug\");\n\t\tconst tableName = `ec_${collectionSlug}`;\n\t\tvalidateIdentifier(tableName, \"content table\");\n\n\t\tconst seen = new Set<string>();\n\t\tconst bylines = inputBylines.filter((item) => {\n\t\t\tif (seen.has(item.bylineId)) return false;\n\t\t\tseen.add(item.bylineId);\n\t\t\treturn true;\n\t\t});\n\n\t\t// This method is expected to be called within a transaction context\n\t\t// (content handlers wrap in withTransaction, seed applies sequentially).\n\t\t// All operations use this.db directly -- callers are responsible for\n\t\t// wrapping in a transaction when atomicity is required.\n\t\tif (bylines.length > 0) {\n\t\t\tconst ids = bylines.map((item) => item.bylineId);\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t\t.select(\"id\")\n\t\t\t\t.where(\"id\", \"in\", ids)\n\t\t\t\t.execute();\n\t\t\tif (rows.length !== ids.length) {\n\t\t\t\tthrow new Error(\"One or more byline IDs do not exist\");\n\t\t\t}\n\t\t}\n\n\t\tawait this.db\n\t\t\t.deleteFrom(\"_emdash_content_bylines\")\n\t\t\t.where(\"collection_slug\", \"=\", collectionSlug)\n\t\t\t.where(\"content_id\", \"=\", contentId)\n\t\t\t.execute();\n\n\t\tfor (let i = 0; i < bylines.length; i++) {\n\t\t\tconst item = bylines[i];\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_content_bylines\")\n\t\t\t\t.values({\n\t\t\t\t\tid: ulid(),\n\t\t\t\t\tcollection_slug: collectionSlug,\n\t\t\t\t\tcontent_id: contentId,\n\t\t\t\t\tbyline_id: item.bylineId,\n\t\t\t\t\tsort_order: i,\n\t\t\t\t\trole_label: item.roleLabel ?? null,\n\t\t\t\t\tcreated_at: new Date().toISOString(),\n\t\t\t\t})\n\t\t\t\t.execute();\n\t\t}\n\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET primary_byline_id = ${bylines[0]?.bylineId ?? null}\n\t\t\tWHERE id = ${contentId}\n\t\t`.execute(this.db);\n\n\t\treturn await this.getContentBylines(collectionSlug, contentId);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { i as __exportAll } from "./runner-C7ADox5q.mjs";
|
|
2
|
+
import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
|
|
3
|
+
import { t as BylineRepository } from "./byline-BSaNL1w7.mjs";
|
|
4
|
+
import { t as isMissingTableError } from "./db-errors-WRezodiz.mjs";
|
|
5
|
+
import { r as getDb } from "./loader-CKLbBnhK.mjs";
|
|
6
|
+
import { sql } from "kysely";
|
|
7
|
+
|
|
8
|
+
//#region src/bylines/index.ts
|
|
9
|
+
var bylines_exports = /* @__PURE__ */ __exportAll({
|
|
10
|
+
getByline: () => getByline,
|
|
11
|
+
getBylineBySlug: () => getBylineBySlug,
|
|
12
|
+
getBylinesForEntries: () => getBylinesForEntries,
|
|
13
|
+
invalidateBylineCache: () => invalidateBylineCache
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* No-op — kept for API compatibility.
|
|
17
|
+
*
|
|
18
|
+
* Used to invalidate a worker-lifetime "has any byline?" probe. That
|
|
19
|
+
* probe added a query on every cold isolate to save one query on sites
|
|
20
|
+
* with zero bylines (i.e. the wrong tradeoff), so we dropped it. The
|
|
21
|
+
* batch byline join below returns an empty map for empty sites at the
|
|
22
|
+
* same cost as the probe, without the pre-check.
|
|
23
|
+
*/
|
|
24
|
+
function invalidateBylineCache() {}
|
|
25
|
+
/**
|
|
26
|
+
* Get a byline by ID.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { getByline } from "emdash";
|
|
31
|
+
*
|
|
32
|
+
* const byline = await getByline("01HXYZ...");
|
|
33
|
+
* if (byline) {
|
|
34
|
+
* console.log(byline.displayName);
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
async function getByline(id) {
|
|
39
|
+
return new BylineRepository(await getDb()).findById(id);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get a byline by slug.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* import { getBylineBySlug } from "emdash";
|
|
47
|
+
*
|
|
48
|
+
* const byline = await getBylineBySlug("jane-doe");
|
|
49
|
+
* if (byline) {
|
|
50
|
+
* console.log(byline.displayName); // "Jane Doe"
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
async function getBylineBySlug(slug) {
|
|
55
|
+
return new BylineRepository(await getDb()).findBySlug(slug);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Batch-fetch byline credits for multiple content entries in a single query.
|
|
59
|
+
*
|
|
60
|
+
* Internal: consumed by `hydrateEntryBylines` in `query.ts` so that every
|
|
61
|
+
* entry returned from `getEmDashCollection` / `getEmDashEntry` already has
|
|
62
|
+
* `data.bylines` populated. Site code should rely on that eager hydration
|
|
63
|
+
* rather than calling this directly -- this function is not re-exported
|
|
64
|
+
* from the `emdash` package entry point.
|
|
65
|
+
*
|
|
66
|
+
* @param collection - The collection slug (e.g., "posts")
|
|
67
|
+
* @param entries - Entry id + authorId pairs (authorId is already on the row)
|
|
68
|
+
* @returns Map from entry ID to array of byline credits
|
|
69
|
+
*/
|
|
70
|
+
async function getBylinesForEntries(collection, entries) {
|
|
71
|
+
validateIdentifier(collection, "collection");
|
|
72
|
+
const result = /* @__PURE__ */ new Map();
|
|
73
|
+
for (const { id } of entries) result.set(id, []);
|
|
74
|
+
if (entries.length === 0) return result;
|
|
75
|
+
const repo = new BylineRepository(await getDb());
|
|
76
|
+
const entryIds = entries.map((e) => e.id);
|
|
77
|
+
let bylinesMap;
|
|
78
|
+
try {
|
|
79
|
+
bylinesMap = await repo.getContentBylinesMany(collection, entryIds);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (isMissingTableError(error)) return result;
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
const needsFallback = /* @__PURE__ */ new Map();
|
|
85
|
+
for (const { id, authorId } of entries) if (!bylinesMap.has(id) && authorId) needsFallback.set(id, authorId);
|
|
86
|
+
const uniqueAuthorIds = [...new Set(needsFallback.values())];
|
|
87
|
+
const authorBylineMap = await repo.findByUserIds(uniqueAuthorIds);
|
|
88
|
+
for (const { id } of entries) {
|
|
89
|
+
const explicit = bylinesMap.get(id);
|
|
90
|
+
if (explicit && explicit.length > 0) {
|
|
91
|
+
result.set(id, explicit.map((c) => ({
|
|
92
|
+
...c,
|
|
93
|
+
source: "explicit"
|
|
94
|
+
})));
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const authorId = needsFallback.get(id);
|
|
98
|
+
if (authorId) {
|
|
99
|
+
const fallback = authorBylineMap.get(authorId);
|
|
100
|
+
if (fallback) result.set(id, [{
|
|
101
|
+
byline: fallback,
|
|
102
|
+
sortOrder: 0,
|
|
103
|
+
roleLabel: null,
|
|
104
|
+
source: "inferred"
|
|
105
|
+
}]);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
export { getByline as n, getBylineBySlug as r, bylines_exports as t };
|
|
113
|
+
//# sourceMappingURL=bylines-CvJ3PYz2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bylines-CvJ3PYz2.mjs","names":[],"sources":["../src/bylines/index.ts"],"sourcesContent":["/**\n * Runtime API for bylines\n *\n * Provides functions to query byline profiles and byline credits\n * associated with content entries. Follows the same pattern as\n * the taxonomies runtime API.\n */\n\nimport { sql } from \"kysely\";\n\nimport { BylineRepository } from \"../database/repositories/byline.js\";\nimport type { BylineSummary, ContentBylineCredit } from \"../database/repositories/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\nimport { getDb } from \"../loader.js\";\nimport { isMissingTableError } from \"../utils/db-errors.js\";\n\n/**\n * No-op — kept for API compatibility.\n *\n * Used to invalidate a worker-lifetime \"has any byline?\" probe. That\n * probe added a query on every cold isolate to save one query on sites\n * with zero bylines (i.e. the wrong tradeoff), so we dropped it. The\n * batch byline join below returns an empty map for empty sites at the\n * same cost as the probe, without the pre-check.\n */\nexport function invalidateBylineCache(): void {\n\t// Intentionally empty.\n}\n\n/**\n * Get a byline by ID.\n *\n * @example\n * ```ts\n * import { getByline } from \"emdash\";\n *\n * const byline = await getByline(\"01HXYZ...\");\n * if (byline) {\n * console.log(byline.displayName);\n * }\n * ```\n */\nexport async function getByline(id: string): Promise<BylineSummary | null> {\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\treturn repo.findById(id);\n}\n\n/**\n * Get a byline by slug.\n *\n * @example\n * ```ts\n * import { getBylineBySlug } from \"emdash\";\n *\n * const byline = await getBylineBySlug(\"jane-doe\");\n * if (byline) {\n * console.log(byline.displayName); // \"Jane Doe\"\n * }\n * ```\n */\nexport async function getBylineBySlug(slug: string): Promise<BylineSummary | null> {\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\treturn repo.findBySlug(slug);\n}\n\n/**\n * Get byline credits for a single content entry.\n *\n * Returns explicit byline credits from the junction table. If none exist\n * but the entry has an `authorId`, falls back to the user-linked byline\n * (marked as source: \"inferred\").\n *\n * Internal: not re-exported from the `emdash` package entry point. Every\n * entry returned by `getEmDashCollection` / `getEmDashEntry` already has\n * `data.bylines` populated by `hydrateEntryBylines` (which uses the batch\n * helper `getBylinesForEntries` directly). Site code should read those\n * fields rather than calling this function.\n */\nexport async function getEntryBylines(\n\tcollection: string,\n\tentryId: string,\n): Promise<ContentBylineCredit[]> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\n\tconst explicit = await repo.getContentBylines(collection, entryId);\n\tif (explicit.length > 0) {\n\t\treturn explicit.map((c) => ({ ...c, source: \"explicit\" as const }));\n\t}\n\n\t// Fallback: look up user-linked byline from author_id\n\tconst authorId = await getAuthorId(db, collection, entryId);\n\tif (authorId) {\n\t\tconst fallback = await repo.findByUserId(authorId);\n\t\tif (fallback) {\n\t\t\treturn [{ byline: fallback, sortOrder: 0, roleLabel: null, source: \"inferred\" }];\n\t\t}\n\t}\n\n\treturn [];\n}\n\n/**\n * An entry reference for batch byline lookups.\n *\n * `authorId` is read directly from the row when computing the inferred-byline\n * fallback — passing it in avoids a redundant `SELECT id, author_id` against\n * the content table after every list/entry fetch.\n */\nexport interface BylineEntry {\n\tid: string;\n\tauthorId: string | null;\n}\n\n/**\n * Batch-fetch byline credits for multiple content entries in a single query.\n *\n * Internal: consumed by `hydrateEntryBylines` in `query.ts` so that every\n * entry returned from `getEmDashCollection` / `getEmDashEntry` already has\n * `data.bylines` populated. Site code should rely on that eager hydration\n * rather than calling this directly -- this function is not re-exported\n * from the `emdash` package entry point.\n *\n * @param collection - The collection slug (e.g., \"posts\")\n * @param entries - Entry id + authorId pairs (authorId is already on the row)\n * @returns Map from entry ID to array of byline credits\n */\nexport async function getBylinesForEntries(\n\tcollection: string,\n\tentries: BylineEntry[],\n): Promise<Map<string, ContentBylineCredit[]>> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst result = new Map<string, ContentBylineCredit[]>();\n\n\tfor (const { id } of entries) {\n\t\tresult.set(id, []);\n\t}\n\n\tif (entries.length === 0) {\n\t\treturn result;\n\t}\n\n\tconst db = await getDb();\n\tconst repo = new BylineRepository(db);\n\tconst entryIds = entries.map((e) => e.id);\n\n\t// Sites with no bylines get an empty map back for one query — the previous\n\t// \"has any bylines\" probe traded an extra round-trip on every request to\n\t// save that one query on empty sites, which is exactly backwards for the\n\t// common case. Pre-migration databases (bylines table missing) fall\n\t// through to the `isMissingTableError` catch below and return empty.\n\tlet bylinesMap;\n\ttry {\n\t\tbylinesMap = await repo.getContentBylinesMany(collection, entryIds);\n\t} catch (error) {\n\t\tif (isMissingTableError(error)) return result;\n\t\tthrow error;\n\t}\n\n\tconst needsFallback = new Map<string, string>();\n\tfor (const { id, authorId } of entries) {\n\t\tif (!bylinesMap.has(id) && authorId) {\n\t\t\tneedsFallback.set(id, authorId);\n\t\t}\n\t}\n\n\tconst uniqueAuthorIds = [...new Set(needsFallback.values())];\n\tconst authorBylineMap = await repo.findByUserIds(uniqueAuthorIds);\n\n\tfor (const { id } of entries) {\n\t\tconst explicit = bylinesMap.get(id);\n\t\tif (explicit && explicit.length > 0) {\n\t\t\tresult.set(\n\t\t\t\tid,\n\t\t\t\texplicit.map((c) => ({ ...c, source: \"explicit\" as const })),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst authorId = needsFallback.get(id);\n\t\tif (authorId) {\n\t\t\tconst fallback = authorBylineMap.get(authorId);\n\t\t\tif (fallback) {\n\t\t\t\tresult.set(id, [{ byline: fallback, sortOrder: 0, roleLabel: null, source: \"inferred\" }]);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Look up the author_id for a single content entry.\n * Uses raw SQL since we need dynamic table names.\n */\nasync function getAuthorId(\n\tdb: Awaited<ReturnType<typeof getDb>>,\n\tcollection: string,\n\tentryId: string,\n): Promise<string | null> {\n\tvalidateIdentifier(collection, \"collection\");\n\tconst tableName = `ec_${collection}`;\n\n\tconst result = await sql<{ author_id: string | null }>`\n\t\tSELECT author_id FROM ${sql.ref(tableName)}\n\t\tWHERE id = ${entryId}\n\t\tLIMIT 1\n\t`.execute(db);\n\n\treturn result.rows[0]?.author_id ?? null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,wBAA8B;;;;;;;;;;;;;;AAiB9C,eAAsB,UAAU,IAA2C;AAG1E,QADa,IAAI,iBADN,MAAM,OAAO,CACa,CACzB,SAAS,GAAG;;;;;;;;;;;;;;;AAgBzB,eAAsB,gBAAgB,MAA6C;AAGlF,QADa,IAAI,iBADN,MAAM,OAAO,CACa,CACzB,WAAW,KAAK;;;;;;;;;;;;;;;AAkE7B,eAAsB,qBACrB,YACA,SAC8C;AAC9C,oBAAmB,YAAY,aAAa;CAC5C,MAAM,yBAAS,IAAI,KAAoC;AAEvD,MAAK,MAAM,EAAE,QAAQ,QACpB,QAAO,IAAI,IAAI,EAAE,CAAC;AAGnB,KAAI,QAAQ,WAAW,EACtB,QAAO;CAIR,MAAM,OAAO,IAAI,iBADN,MAAM,OAAO,CACa;CACrC,MAAM,WAAW,QAAQ,KAAK,MAAM,EAAE,GAAG;CAOzC,IAAI;AACJ,KAAI;AACH,eAAa,MAAM,KAAK,sBAAsB,YAAY,SAAS;UAC3D,OAAO;AACf,MAAI,oBAAoB,MAAM,CAAE,QAAO;AACvC,QAAM;;CAGP,MAAM,gCAAgB,IAAI,KAAqB;AAC/C,MAAK,MAAM,EAAE,IAAI,cAAc,QAC9B,KAAI,CAAC,WAAW,IAAI,GAAG,IAAI,SAC1B,eAAc,IAAI,IAAI,SAAS;CAIjC,MAAM,kBAAkB,CAAC,GAAG,IAAI,IAAI,cAAc,QAAQ,CAAC,CAAC;CAC5D,MAAM,kBAAkB,MAAM,KAAK,cAAc,gBAAgB;AAEjE,MAAK,MAAM,EAAE,QAAQ,SAAS;EAC7B,MAAM,WAAW,WAAW,IAAI,GAAG;AACnC,MAAI,YAAY,SAAS,SAAS,GAAG;AACpC,UAAO,IACN,IACA,SAAS,KAAK,OAAO;IAAE,GAAG;IAAG,QAAQ;IAAqB,EAAE,CAC5D;AACD;;EAGD,MAAM,WAAW,cAAc,IAAI,GAAG;AACtC,MAAI,UAAU;GACb,MAAM,WAAW,gBAAgB,IAAI,SAAS;AAC9C,OAAI,SACH,QAAO,IAAI,IAAI,CAAC;IAAE,QAAQ;IAAU,WAAW;IAAG,WAAW;IAAM,QAAQ;IAAY,CAAC,CAAC;;;AAK5F,QAAO"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { i as __exportAll } from "./runner-C7ADox5q.mjs";
|
|
2
|
+
import { i as matchPattern, n as interpolateDestination, t as compilePattern } from "./patterns-CrCYkMBb.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/redirects/cache.ts
|
|
5
|
+
var cache_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
getCachedRedirects: () => getCachedRedirects,
|
|
7
|
+
invalidateRedirectCache: () => invalidateRedirectCache,
|
|
8
|
+
matchCachedPatterns: () => matchCachedPatterns,
|
|
9
|
+
setCachedRedirects: () => setCachedRedirects
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Cached enabled redirects.
|
|
13
|
+
* null = not yet populated, object = cached.
|
|
14
|
+
*/
|
|
15
|
+
let cachedRedirects = null;
|
|
16
|
+
/**
|
|
17
|
+
* Invalidate the cached redirects (both exact and pattern).
|
|
18
|
+
* Call when redirects are created, updated, or deleted.
|
|
19
|
+
*/
|
|
20
|
+
function invalidateRedirectCache() {
|
|
21
|
+
cachedRedirects = null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the cached redirects, or null if the cache is cold.
|
|
25
|
+
*/
|
|
26
|
+
function getCachedRedirects() {
|
|
27
|
+
return cachedRedirects;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Populate the cache from a list of enabled redirects (both exact and
|
|
31
|
+
* pattern). The caller is responsible for passing only enabled rows — the
|
|
32
|
+
* cache stores them as-is.
|
|
33
|
+
*/
|
|
34
|
+
function setCachedRedirects(redirects) {
|
|
35
|
+
const exact = /* @__PURE__ */ new Map();
|
|
36
|
+
const patterns = [];
|
|
37
|
+
for (const r of redirects) if (r.isPattern) patterns.push({
|
|
38
|
+
redirect: r,
|
|
39
|
+
compiled: compilePattern(r.source)
|
|
40
|
+
});
|
|
41
|
+
else exact.set(r.source, r);
|
|
42
|
+
cachedRedirects = {
|
|
43
|
+
exact,
|
|
44
|
+
patterns
|
|
45
|
+
};
|
|
46
|
+
return cachedRedirects;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Match a path against the cached pattern rules.
|
|
50
|
+
* Returns the resolved destination and matching redirect, or null.
|
|
51
|
+
*/
|
|
52
|
+
function matchCachedPatterns(rules, pathname) {
|
|
53
|
+
for (const { redirect, compiled } of rules) {
|
|
54
|
+
const params = matchPattern(compiled, pathname);
|
|
55
|
+
if (params) return {
|
|
56
|
+
redirect,
|
|
57
|
+
destination: interpolateDestination(redirect.destination, params)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { setCachedRedirects as a, matchCachedPatterns as i, getCachedRedirects as n, invalidateRedirectCache as r, cache_exports as t };
|
|
65
|
+
//# sourceMappingURL=cache-C6N_hhN7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-C6N_hhN7.mjs","names":[],"sources":["../src/redirects/cache.ts"],"sourcesContent":["/**\n * Redirect rule cache.\n *\n * Module-level cache for enabled redirect rules. The middleware populates this\n * on first request; route handlers invalidate it on writes.\n *\n * Both exact-match and pattern rules are loaded from one query and cached\n * together: exact rules indexed by source path in a Map, pattern rules\n * pre-compiled into an array. A single warm request issues zero database\n * queries; a cold isolate issues one.\n *\n * This module deliberately has NO Astro imports so it can be safely imported\n * from handlers, seed, CLI, and tests without dragging in `astro:middleware`.\n */\n\nimport type { Redirect } from \"../database/repositories/redirect.js\";\nimport type { CompiledPattern } from \"./patterns.js\";\nimport { compilePattern, interpolateDestination, matchPattern } from \"./patterns.js\";\n\nexport interface CachedRedirectRule {\n\tredirect: Redirect;\n\tcompiled: CompiledPattern;\n}\n\nexport interface CachedRedirects {\n\t/** Exact-match rules indexed by source path (`source` -> `Redirect`). */\n\texact: Map<string, Redirect>;\n\t/** Pattern rules with their compiled regexes, preserving insertion order. */\n\tpatterns: CachedRedirectRule[];\n}\n\n/**\n * Cached enabled redirects.\n * null = not yet populated, object = cached.\n */\nlet cachedRedirects: CachedRedirects | null = null;\n\n/**\n * Invalidate the cached redirects (both exact and pattern).\n * Call when redirects are created, updated, or deleted.\n */\nexport function invalidateRedirectCache(): void {\n\tcachedRedirects = null;\n}\n\n/**\n * Get the cached redirects, or null if the cache is cold.\n */\nexport function getCachedRedirects(): CachedRedirects | null {\n\treturn cachedRedirects;\n}\n\n/**\n * Populate the cache from a list of enabled redirects (both exact and\n * pattern). The caller is responsible for passing only enabled rows — the\n * cache stores them as-is.\n */\nexport function setCachedRedirects(redirects: Redirect[]): CachedRedirects {\n\tconst exact = new Map<string, Redirect>();\n\tconst patterns: CachedRedirectRule[] = [];\n\tfor (const r of redirects) {\n\t\tif (r.isPattern) {\n\t\t\tpatterns.push({ redirect: r, compiled: compilePattern(r.source) });\n\t\t} else {\n\t\t\texact.set(r.source, r);\n\t\t}\n\t}\n\tcachedRedirects = { exact, patterns };\n\treturn cachedRedirects;\n}\n\n/**\n * Match a path against the cached pattern rules.\n * Returns the resolved destination and matching redirect, or null.\n */\nexport function matchCachedPatterns(\n\trules: CachedRedirectRule[],\n\tpathname: string,\n): { redirect: Redirect; destination: string } | null {\n\tfor (const { redirect, compiled } of rules) {\n\t\tconst params = matchPattern(compiled, pathname);\n\t\tif (params) {\n\t\t\tconst dest = interpolateDestination(redirect.destination, params);\n\t\t\treturn { redirect, destination: dest };\n\t\t}\n\t}\n\treturn null;\n}\n"],"mappings":";;;;;;;;;;;;;;AAmCA,IAAI,kBAA0C;;;;;AAM9C,SAAgB,0BAAgC;AAC/C,mBAAkB;;;;;AAMnB,SAAgB,qBAA6C;AAC5D,QAAO;;;;;;;AAQR,SAAgB,mBAAmB,WAAwC;CAC1E,MAAM,wBAAQ,IAAI,KAAuB;CACzC,MAAM,WAAiC,EAAE;AACzC,MAAK,MAAM,KAAK,UACf,KAAI,EAAE,UACL,UAAS,KAAK;EAAE,UAAU;EAAG,UAAU,eAAe,EAAE,OAAO;EAAE,CAAC;KAElE,OAAM,IAAI,EAAE,QAAQ,EAAE;AAGxB,mBAAkB;EAAE;EAAO;EAAU;AACrC,QAAO;;;;;;AAOR,SAAgB,oBACf,OACA,UACqD;AACrD,MAAK,MAAM,EAAE,UAAU,cAAc,OAAO;EAC3C,MAAM,SAAS,aAAa,UAAU,SAAS;AAC/C,MAAI,OAEH,QAAO;GAAE;GAAU,aADN,uBAAuB,SAAS,aAAa,OAAO;GAC3B;;AAGxC,QAAO"}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import { i as __exportAll } from "./runner-C7ADox5q.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/utils/chunks.ts
|
|
4
|
+
var chunks_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
SQL_BATCH_SIZE: () => SQL_BATCH_SIZE,
|
|
6
|
+
chunks: () => chunks
|
|
7
|
+
});
|
|
2
8
|
/**
|
|
3
9
|
* Split an array into chunks of at most `size` elements.
|
|
4
10
|
*
|
|
@@ -15,5 +21,5 @@ function chunks(arr, size) {
|
|
|
15
21
|
const SQL_BATCH_SIZE = 50;
|
|
16
22
|
|
|
17
23
|
//#endregion
|
|
18
|
-
export { chunks as n, SQL_BATCH_SIZE as t };
|
|
19
|
-
//# sourceMappingURL=chunks-
|
|
24
|
+
export { chunks as n, chunks_exports as r, SQL_BATCH_SIZE as t };
|
|
25
|
+
//# sourceMappingURL=chunks-NBQVDOci.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunks-
|
|
1
|
+
{"version":3,"file":"chunks-NBQVDOci.mjs","names":[],"sources":["../src/utils/chunks.ts"],"sourcesContent":["/**\n * Split an array into chunks of at most `size` elements.\n *\n * Used to keep SQL `IN (?, ?, …)` clauses within Cloudflare D1's\n * bound-parameter limit (~100 per statement).\n */\nexport function chunks<T>(arr: T[], size: number): T[][] {\n\tif (arr.length === 0) return [];\n\tconst result: T[][] = [];\n\tfor (let i = 0; i < arr.length; i += size) {\n\t\tresult.push(arr.slice(i, i + size));\n\t}\n\treturn result;\n}\n\n/** Conservative default chunk size for SQL IN clauses (well within D1's limit). */\nexport const SQL_BATCH_SIZE = 50;\n"],"mappings":";;;;;;;;;;;;;AAMA,SAAgB,OAAU,KAAU,MAAqB;AACxD,KAAI,IAAI,WAAW,EAAG,QAAO,EAAE;CAC/B,MAAM,SAAgB,EAAE;AACxB,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,KACpC,QAAO,KAAK,IAAI,MAAM,GAAG,IAAI,KAAK,CAAC;AAEpC,QAAO;;;AAIR,MAAa,iBAAiB"}
|