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.
Files changed (317) hide show
  1. package/dist/{adapters-BKSf3T9R.d.mts → adapters-BktHA7EO.d.mts} +1 -1
  2. package/dist/{adapters-BKSf3T9R.d.mts.map → adapters-BktHA7EO.d.mts.map} +1 -1
  3. package/dist/{apply-x0eMK1lX.mjs → apply-UsrFuO7l.mjs} +207 -355
  4. package/dist/apply-UsrFuO7l.mjs.map +1 -0
  5. package/dist/astro/index.d.mts +6 -6
  6. package/dist/astro/index.d.mts.map +1 -1
  7. package/dist/astro/index.mjs +118 -4
  8. package/dist/astro/index.mjs.map +1 -1
  9. package/dist/astro/middleware/auth.d.mts +6 -7
  10. package/dist/astro/middleware/auth.d.mts.map +1 -1
  11. package/dist/astro/middleware/auth.mjs +14 -57
  12. package/dist/astro/middleware/auth.mjs.map +1 -1
  13. package/dist/astro/middleware/redirect.d.mts.map +1 -1
  14. package/dist/astro/middleware/redirect.mjs +15 -10
  15. package/dist/astro/middleware/redirect.mjs.map +1 -1
  16. package/dist/astro/middleware/request-context.d.mts.map +1 -1
  17. package/dist/astro/middleware/request-context.mjs +8 -5
  18. package/dist/astro/middleware/request-context.mjs.map +1 -1
  19. package/dist/astro/middleware/setup.mjs +1 -1
  20. package/dist/astro/middleware.d.mts.map +1 -1
  21. package/dist/astro/middleware.mjs +70 -121
  22. package/dist/astro/middleware.mjs.map +1 -1
  23. package/dist/astro/types.d.mts +25 -10
  24. package/dist/astro/types.d.mts.map +1 -1
  25. package/dist/{byline-Chbr2GoP.mjs → byline-C3vnhIpU.mjs} +4 -4
  26. package/dist/{byline-Chbr2GoP.mjs.map → byline-C3vnhIpU.mjs.map} +1 -1
  27. package/dist/bylines-esI7ioa9.mjs +113 -0
  28. package/dist/bylines-esI7ioa9.mjs.map +1 -0
  29. package/dist/cache-fTzxgMFJ.mjs +65 -0
  30. package/dist/cache-fTzxgMFJ.mjs.map +1 -0
  31. package/dist/{chunks-HGz06Soa.mjs → chunks-Da2-b-oA.mjs} +8 -2
  32. package/dist/{chunks-HGz06Soa.mjs.map → chunks-Da2-b-oA.mjs.map} +1 -1
  33. package/dist/cli/index.mjs +456 -90
  34. package/dist/cli/index.mjs.map +1 -1
  35. package/dist/client/cf-access.d.mts +1 -1
  36. package/dist/client/index.d.mts +1 -1
  37. package/dist/client/index.mjs +3 -3
  38. package/dist/client/index.mjs.map +1 -1
  39. package/dist/{config-BXwuX8Bx.mjs → config-CVssduLe.mjs} +1 -1
  40. package/dist/{config-BXwuX8Bx.mjs.map → config-CVssduLe.mjs.map} +1 -1
  41. package/dist/{content-BcQPYxdV.mjs → content-C7G4QXkK.mjs} +42 -14
  42. package/dist/content-C7G4QXkK.mjs.map +1 -0
  43. package/dist/db/index.d.mts +3 -3
  44. package/dist/db/index.mjs +2 -2
  45. package/dist/db/libsql.d.mts +1 -1
  46. package/dist/db/libsql.d.mts.map +1 -1
  47. package/dist/db/libsql.mjs +7 -2
  48. package/dist/db/libsql.mjs.map +1 -1
  49. package/dist/db/postgres.d.mts +1 -1
  50. package/dist/db/sqlite.d.mts +1 -1
  51. package/dist/db/sqlite.d.mts.map +1 -1
  52. package/dist/db/sqlite.mjs +8 -3
  53. package/dist/db/sqlite.mjs.map +1 -1
  54. package/dist/{db-errors-l1Qh2RPR.mjs → db-errors-B7P2pSCn.mjs} +1 -1
  55. package/dist/{db-errors-l1Qh2RPR.mjs.map → db-errors-B7P2pSCn.mjs.map} +1 -1
  56. package/dist/{default-DCVqE5ib.mjs → default-pHuz9WF6.mjs} +1 -1
  57. package/dist/{default-DCVqE5ib.mjs.map → default-pHuz9WF6.mjs.map} +1 -1
  58. package/dist/{dialect-helpers-DhTzaUxP.mjs → dialect-helpers-BKCvISIQ.mjs} +19 -2
  59. package/dist/dialect-helpers-BKCvISIQ.mjs.map +1 -0
  60. package/dist/{error-zG5T1UGA.mjs → error-DqnRMM5z.mjs} +1 -1
  61. package/dist/{error-zG5T1UGA.mjs.map → error-DqnRMM5z.mjs.map} +1 -1
  62. package/dist/{index-DIb-CzNx.d.mts → index-DjPMOfO0.d.mts} +162 -87
  63. package/dist/index-DjPMOfO0.d.mts.map +1 -0
  64. package/dist/index.d.mts +11 -11
  65. package/dist/index.mjs +27 -24
  66. package/dist/{load-CyEoextb.mjs → load-sXRuM7Us.mjs} +2 -2
  67. package/dist/{load-CyEoextb.mjs.map → load-sXRuM7Us.mjs.map} +1 -1
  68. package/dist/{loader-CndGj8kM.mjs → loader-Bx2_9-5e.mjs} +53 -8
  69. package/dist/loader-Bx2_9-5e.mjs.map +1 -0
  70. package/dist/{manifest-schema-DH9xhc6t.mjs → manifest-schema-CXAbd1vH.mjs} +33 -3
  71. package/dist/manifest-schema-CXAbd1vH.mjs.map +1 -0
  72. package/dist/media/index.d.mts +1 -1
  73. package/dist/media/index.mjs +1 -1
  74. package/dist/media/local-runtime.d.mts +7 -7
  75. package/dist/{mode-BnAOqItE.mjs → mode-YhqNVef_.mjs} +1 -1
  76. package/dist/{mode-BnAOqItE.mjs.map → mode-YhqNVef_.mjs.map} +1 -1
  77. package/dist/options-nPxWnrya.mjs +117 -0
  78. package/dist/options-nPxWnrya.mjs.map +1 -0
  79. package/dist/page/index.d.mts +2 -2
  80. package/dist/{patterns-CrCYkMBb.mjs → patterns-DsUZ4uxI.mjs} +1 -1
  81. package/dist/{patterns-CrCYkMBb.mjs.map → patterns-DsUZ4uxI.mjs.map} +1 -1
  82. package/dist/{placeholder-D29tWZ7o.d.mts → placeholder-CDPtkelt.d.mts} +1 -1
  83. package/dist/{placeholder-D29tWZ7o.d.mts.map → placeholder-CDPtkelt.d.mts.map} +1 -1
  84. package/dist/{placeholder-C-fk5hYI.mjs → placeholder-Ci0RLeCk.mjs} +1 -1
  85. package/dist/{placeholder-C-fk5hYI.mjs.map → placeholder-Ci0RLeCk.mjs.map} +1 -1
  86. package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
  87. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -1
  88. package/dist/plugins/adapt-sandbox-entry.mjs +6 -5
  89. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -1
  90. package/dist/public-url-B1AxbbbQ.mjs +51 -0
  91. package/dist/public-url-B1AxbbbQ.mjs.map +1 -0
  92. package/dist/{query-fqEdLFms.mjs → query-Bo-msrmu.mjs} +114 -16
  93. package/dist/query-Bo-msrmu.mjs.map +1 -0
  94. package/dist/{redirect-D_pshWdf.mjs → redirect-C5H7VGIX.mjs} +11 -6
  95. package/dist/redirect-C5H7VGIX.mjs.map +1 -0
  96. package/dist/{registry-C3Mr0ODu.mjs → registry-Beb7wxFc.mjs} +39 -5
  97. package/dist/registry-Beb7wxFc.mjs.map +1 -0
  98. package/dist/{request-cache-Ci7f5pBb.mjs → request-cache-C-tIpYIw.mjs} +1 -1
  99. package/dist/{request-cache-Ci7f5pBb.mjs.map → request-cache-C-tIpYIw.mjs.map} +1 -1
  100. package/dist/runner-Clwe4Mme.d.mts +44 -0
  101. package/dist/runner-Clwe4Mme.d.mts.map +1 -0
  102. package/dist/{runner-tQ7BJ4T7.mjs → runner-DMnlIkh4.mjs} +616 -191
  103. package/dist/runner-DMnlIkh4.mjs.map +1 -0
  104. package/dist/runtime.d.mts +6 -6
  105. package/dist/runtime.mjs +2 -2
  106. package/dist/{search-BoZYFuUk.mjs → search-DkN-BqsS.mjs} +270 -152
  107. package/dist/search-DkN-BqsS.mjs.map +1 -0
  108. package/dist/secrets-CZ8rxLX3.mjs +314 -0
  109. package/dist/secrets-CZ8rxLX3.mjs.map +1 -0
  110. package/dist/seed/index.d.mts +2 -2
  111. package/dist/seed/index.mjs +13 -11
  112. package/dist/seo/index.d.mts +1 -1
  113. package/dist/storage/local.d.mts +1 -1
  114. package/dist/storage/local.mjs +1 -1
  115. package/dist/storage/s3.d.mts +1 -1
  116. package/dist/storage/s3.mjs +1 -1
  117. package/dist/taxonomies-CTtewrSQ.mjs +407 -0
  118. package/dist/taxonomies-CTtewrSQ.mjs.map +1 -0
  119. package/dist/taxonomy-DSxx2K2L.mjs +218 -0
  120. package/dist/taxonomy-DSxx2K2L.mjs.map +1 -0
  121. package/dist/{tokens-D9vnZqYS.mjs → tokens-CyRDPVW2.mjs} +1 -1
  122. package/dist/{tokens-D9vnZqYS.mjs.map → tokens-CyRDPVW2.mjs.map} +1 -1
  123. package/dist/{transaction-Cn2rjY78.mjs → transaction-D44LBXvU.mjs} +1 -1
  124. package/dist/{transaction-Cn2rjY78.mjs.map → transaction-D44LBXvU.mjs.map} +1 -1
  125. package/dist/{transport-CUnEL3Vs.d.mts → transport-DX_5rpsq.d.mts} +1 -1
  126. package/dist/{transport-CUnEL3Vs.d.mts.map → transport-DX_5rpsq.d.mts.map} +1 -1
  127. package/dist/{transport-C9ugt2Nr.mjs → transport-xpzIjCIB.mjs} +6 -5
  128. package/dist/{transport-C9ugt2Nr.mjs.map → transport-xpzIjCIB.mjs.map} +1 -1
  129. package/dist/{types-BrA0xf5I.d.mts → types-B_CXXnzh.d.mts} +1 -1
  130. package/dist/{types-BrA0xf5I.d.mts.map → types-B_CXXnzh.d.mts.map} +1 -1
  131. package/dist/{types-DIMwPFub.d.mts → types-C-aFbqmA.d.mts} +1 -1
  132. package/dist/{types-DIMwPFub.d.mts.map → types-C-aFbqmA.d.mts.map} +1 -1
  133. package/dist/types-CoO6mpV3.mjs +68 -0
  134. package/dist/types-CoO6mpV3.mjs.map +1 -0
  135. package/dist/{types-i36XcA_X.d.mts → types-D19uBYWn.d.mts} +83 -7
  136. package/dist/types-D19uBYWn.d.mts.map +1 -0
  137. package/dist/{types-BmPPSUEx.d.mts → types-Dl1fgFjn.d.mts} +24 -2
  138. package/dist/{types-BmPPSUEx.d.mts.map → types-Dl1fgFjn.d.mts.map} +1 -1
  139. package/dist/{types-CS8FIX7L.d.mts → types-Dtx1mSMX.d.mts} +9 -1
  140. package/dist/types-Dtx1mSMX.d.mts.map +1 -0
  141. package/dist/{types-Bm1dn-q3.mjs → types-Eg829jj9.mjs} +1 -1
  142. package/dist/{types-Bm1dn-q3.mjs.map → types-Eg829jj9.mjs.map} +1 -1
  143. package/dist/{types-CgqmmMJB.mjs → types-K-EkEQCI.mjs} +1 -1
  144. package/dist/{types-CgqmmMJB.mjs.map → types-K-EkEQCI.mjs.map} +1 -1
  145. package/dist/{validate-CxVsLehf.mjs → validate-CBIbxM3L.mjs} +14 -10
  146. package/dist/validate-CBIbxM3L.mjs.map +1 -0
  147. package/dist/{validate-DHxmpFJt.d.mts → validate-DHGwADqO.d.mts} +18 -5
  148. package/dist/validate-DHGwADqO.d.mts.map +1 -0
  149. package/dist/{validation-C-ZpN2GI.mjs → validation-B1NYiEos.mjs} +6 -6
  150. package/dist/{validation-C-ZpN2GI.mjs.map → validation-B1NYiEos.mjs.map} +1 -1
  151. package/dist/version-CMD42IRC.mjs +7 -0
  152. package/dist/{version-Bbq8TCrz.mjs.map → version-CMD42IRC.mjs.map} +1 -1
  153. package/dist/{zod-generator-CpwccCIv.mjs → zod-generator-BNJDQBSZ.mjs} +11 -6
  154. package/dist/{zod-generator-CpwccCIv.mjs.map → zod-generator-BNJDQBSZ.mjs.map} +1 -1
  155. package/locals.d.ts +1 -6
  156. package/package.json +9 -8
  157. package/src/api/handlers/comments.ts +6 -4
  158. package/src/api/handlers/content.ts +40 -1
  159. package/src/api/handlers/dashboard.ts +29 -36
  160. package/src/api/handlers/device-flow.ts +5 -0
  161. package/src/api/handlers/marketplace.ts +11 -4
  162. package/src/api/handlers/menus.ts +256 -75
  163. package/src/api/handlers/oauth-authorization.ts +72 -33
  164. package/src/api/handlers/revision.ts +23 -14
  165. package/src/api/handlers/taxonomies.ts +273 -100
  166. package/src/api/public-url.ts +48 -2
  167. package/src/api/schemas/comments.ts +2 -2
  168. package/src/api/schemas/common.ts +7 -0
  169. package/src/api/schemas/content.ts +17 -0
  170. package/src/api/schemas/menus.ts +23 -0
  171. package/src/api/schemas/sections.ts +3 -3
  172. package/src/api/schemas/taxonomies.ts +39 -0
  173. package/src/api/schemas/users.ts +1 -1
  174. package/src/api/types.ts +5 -1
  175. package/src/astro/integration/index.ts +17 -0
  176. package/src/astro/integration/routes.ts +10 -0
  177. package/src/astro/integration/runtime.ts +30 -0
  178. package/src/astro/integration/virtual-modules.ts +32 -2
  179. package/src/astro/integration/vite-config.ts +6 -1
  180. package/src/astro/middleware/auth.ts +13 -6
  181. package/src/astro/middleware/redirect.ts +29 -16
  182. package/src/astro/middleware/request-context.ts +15 -5
  183. package/src/astro/middleware.ts +23 -9
  184. package/src/astro/routes/api/auth/invite/complete.ts +6 -1
  185. package/src/astro/routes/api/auth/passkey/register/verify.ts +6 -1
  186. package/src/astro/routes/api/auth/passkey/verify.ts +6 -1
  187. package/src/astro/routes/api/auth/signup/complete.ts +6 -1
  188. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -2
  189. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +4 -2
  190. package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +1 -1
  191. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +34 -12
  192. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +32 -2
  193. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +4 -2
  194. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +3 -2
  195. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +8 -4
  196. package/src/astro/routes/api/content/[collection]/[id].ts +12 -0
  197. package/src/astro/routes/api/import/wordpress/execute.ts +3 -1
  198. package/src/astro/routes/api/import/wordpress/prepare.ts +7 -8
  199. package/src/astro/routes/api/import/wordpress/rewrite-url-helpers.ts +196 -0
  200. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +9 -177
  201. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +3 -1
  202. package/src/astro/routes/api/manifest.ts +62 -45
  203. package/src/astro/routes/api/media/[id]/confirm.ts +10 -1
  204. package/src/astro/routes/api/media/providers/[providerId]/index.ts +12 -3
  205. package/src/astro/routes/api/menus/[name]/items.ts +16 -6
  206. package/src/astro/routes/api/menus/[name]/reorder.ts +8 -3
  207. package/src/astro/routes/api/menus/[name]/translations.ts +82 -0
  208. package/src/astro/routes/api/menus/[name].ts +19 -10
  209. package/src/astro/routes/api/menus/index.ts +9 -6
  210. package/src/astro/routes/api/openapi.json.ts +27 -10
  211. package/src/astro/routes/api/redirects/404s/index.ts +10 -4
  212. package/src/astro/routes/api/redirects/404s/summary.ts +4 -2
  213. package/src/astro/routes/api/redirects/[id].ts +10 -4
  214. package/src/astro/routes/api/redirects/index.ts +7 -3
  215. package/src/astro/routes/api/revisions/[revisionId]/index.ts +1 -1
  216. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +0 -2
  217. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +0 -1
  218. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +0 -1
  219. package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -2
  220. package/src/astro/routes/api/schema/collections/index.ts +1 -1
  221. package/src/astro/routes/api/search/index.ts +10 -2
  222. package/src/astro/routes/api/sections/[slug].ts +10 -4
  223. package/src/astro/routes/api/sections/index.ts +7 -3
  224. package/src/astro/routes/api/setup/admin-verify.ts +6 -1
  225. package/src/astro/routes/api/snapshot.ts +44 -18
  226. package/src/astro/routes/api/taxonomies/[name]/terms/[slug]/translations.ts +89 -0
  227. package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +22 -22
  228. package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +11 -14
  229. package/src/astro/routes/api/taxonomies/index.ts +9 -7
  230. package/src/astro/routes/api/themes/preview.ts +11 -5
  231. package/src/astro/types.ts +23 -3
  232. package/src/auth/allowed-origins.ts +168 -0
  233. package/src/auth/passkey-config.ts +35 -13
  234. package/src/bylines/index.ts +37 -88
  235. package/src/cli/commands/auth.ts +28 -6
  236. package/src/cli/commands/bundle-utils.ts +11 -2
  237. package/src/cli/commands/bundle.ts +28 -8
  238. package/src/cli/commands/content.ts +13 -0
  239. package/src/cli/commands/export-seed.ts +82 -21
  240. package/src/cli/commands/login.ts +8 -1
  241. package/src/cli/commands/plugin-init.ts +216 -90
  242. package/src/cli/commands/publish.ts +24 -0
  243. package/src/cli/commands/secrets.ts +183 -0
  244. package/src/cli/credentials.ts +1 -1
  245. package/src/cli/index.ts +5 -1
  246. package/src/client/index.ts +4 -4
  247. package/src/client/transport.ts +17 -7
  248. package/src/components/Break.astro +2 -2
  249. package/src/components/EmDashHead.astro +18 -13
  250. package/src/components/Embed.astro +1 -1
  251. package/src/components/Gallery.astro +1 -1
  252. package/src/components/Image.astro +1 -1
  253. package/src/components/InlinePortableTextEditor.tsx +104 -18
  254. package/src/config/secrets.ts +528 -0
  255. package/src/database/dialect-helpers.ts +50 -0
  256. package/src/database/migrations/034_published_at_index.ts +1 -1
  257. package/src/database/migrations/035_bounded_404_log.ts +56 -39
  258. package/src/database/migrations/036_i18n_menus_and_taxonomies.ts +477 -0
  259. package/src/database/migrations/runner.ts +158 -23
  260. package/src/database/repositories/content.ts +47 -12
  261. package/src/database/repositories/redirect.ts +14 -3
  262. package/src/database/repositories/taxonomy.ts +212 -82
  263. package/src/database/types.ts +10 -2
  264. package/src/db/libsql.ts +1 -3
  265. package/src/db/sqlite.ts +2 -5
  266. package/src/emdash-runtime.ts +84 -159
  267. package/src/i18n/resolve.ts +37 -0
  268. package/src/index.ts +9 -0
  269. package/src/loader.ts +73 -3
  270. package/src/mcp/server.ts +180 -54
  271. package/src/menus/index.ts +143 -124
  272. package/src/menus/types.ts +15 -1
  273. package/src/page/site-identity.ts +58 -0
  274. package/src/plugins/adapt-sandbox-entry.ts +22 -10
  275. package/src/plugins/context.ts +13 -10
  276. package/src/plugins/define-plugin.ts +40 -12
  277. package/src/plugins/hooks.ts +23 -19
  278. package/src/plugins/index.ts +9 -0
  279. package/src/plugins/manifest-schema.ts +37 -2
  280. package/src/plugins/types.ts +151 -11
  281. package/src/preview/urls.ts +23 -3
  282. package/src/query.ts +148 -5
  283. package/src/redirects/cache.ts +38 -18
  284. package/src/schema/registry.ts +56 -0
  285. package/src/schema/zod-generator.ts +39 -7
  286. package/src/seed/apply.ts +142 -54
  287. package/src/seed/types.ts +14 -1
  288. package/src/seed/validate.ts +27 -13
  289. package/src/settings/index.ts +80 -6
  290. package/src/settings/types.ts +23 -1
  291. package/src/taxonomies/index.ts +237 -210
  292. package/src/taxonomies/types.ts +10 -0
  293. package/dist/apply-x0eMK1lX.mjs.map +0 -1
  294. package/dist/bylines-CRNsVG88.mjs +0 -157
  295. package/dist/bylines-CRNsVG88.mjs.map +0 -1
  296. package/dist/cache-BkKBuIvS.mjs +0 -56
  297. package/dist/cache-BkKBuIvS.mjs.map +0 -1
  298. package/dist/chunk-ClPoSABd.mjs +0 -21
  299. package/dist/content-BcQPYxdV.mjs.map +0 -1
  300. package/dist/dialect-helpers-DhTzaUxP.mjs.map +0 -1
  301. package/dist/index-DIb-CzNx.d.mts.map +0 -1
  302. package/dist/loader-CndGj8kM.mjs.map +0 -1
  303. package/dist/manifest-schema-DH9xhc6t.mjs.map +0 -1
  304. package/dist/query-fqEdLFms.mjs.map +0 -1
  305. package/dist/redirect-D_pshWdf.mjs.map +0 -1
  306. package/dist/registry-C3Mr0ODu.mjs.map +0 -1
  307. package/dist/runner-OURCaApa.d.mts +0 -34
  308. package/dist/runner-OURCaApa.d.mts.map +0 -1
  309. package/dist/runner-tQ7BJ4T7.mjs.map +0 -1
  310. package/dist/search-BoZYFuUk.mjs.map +0 -1
  311. package/dist/taxonomies-B4IAshV8.mjs +0 -308
  312. package/dist/taxonomies-B4IAshV8.mjs.map +0 -1
  313. package/dist/types-CS8FIX7L.d.mts.map +0 -1
  314. package/dist/types-i36XcA_X.d.mts.map +0 -1
  315. package/dist/validate-CxVsLehf.mjs.map +0 -1
  316. package/dist/validate-DHxmpFJt.d.mts.map +0 -1
  317. package/dist/version-Bbq8TCrz.mjs +0 -7
@@ -0,0 +1,407 @@
1
+ import { i as __exportAll } from "./runner-DMnlIkh4.mjs";
2
+ import { getRequestContext } from "./request-context.mjs";
3
+ import { n as getI18nConfig, r as isI18nEnabled, t as getFallbackChain } from "./config-CVssduLe.mjs";
4
+ import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-Da2-b-oA.mjs";
5
+ import { t as isMissingTableError } from "./db-errors-B7P2pSCn.mjs";
6
+ import { r as getDb } from "./loader-Bx2_9-5e.mjs";
7
+ import { n as requestCached, r as setRequestCacheEntry, t as peekRequestCache } from "./request-cache-C-tIpYIw.mjs";
8
+
9
+ //#region src/i18n/resolve.ts
10
+ /**
11
+ * Shared locale-resolution helpers.
12
+ *
13
+ * Matches the pattern used by `query.ts` for content: an explicit locale wins,
14
+ * otherwise we fall back to the request-context locale, otherwise to
15
+ * `defaultLocale` when i18n is enabled, otherwise to `undefined` (meaning "do
16
+ * not filter by locale" — legacy single-locale behaviour).
17
+ */
18
+ /**
19
+ * Resolve the locale to use for a query given an optional explicit value.
20
+ * Returns `undefined` when no locale information is available; callers should
21
+ * treat that as "do not filter by locale".
22
+ */
23
+ function resolveLocale(explicit) {
24
+ if (explicit !== void 0) return explicit;
25
+ const ctxLocale = getRequestContext()?.locale;
26
+ if (ctxLocale !== void 0) return ctxLocale;
27
+ const cfg = getI18nConfig();
28
+ if (cfg && isI18nEnabled()) return cfg.defaultLocale;
29
+ }
30
+ /**
31
+ * Fallback chain to try when looking up a single item. When i18n is disabled
32
+ * or the locale is unspecified, returns a single-element array (or empty when
33
+ * no locale resolves) so callers can iterate uniformly.
34
+ */
35
+ function resolveLocaleChain(explicit) {
36
+ const locale = resolveLocale(explicit);
37
+ if (locale === void 0) return [];
38
+ if (!isI18nEnabled()) return [locale];
39
+ return getFallbackChain(locale);
40
+ }
41
+
42
+ //#endregion
43
+ //#region src/taxonomies/index.ts
44
+ /**
45
+ * Runtime API for taxonomies.
46
+ *
47
+ * All helpers are locale-aware. When a locale is not passed explicitly we fall
48
+ * back to the request context or the configured `defaultLocale` (see
49
+ * `i18n/resolve.ts`).
50
+ *
51
+ * Because `content_taxonomies.taxonomy_id` stores the translation_group (not a
52
+ * specific term id), the joins here are `taxonomies.translation_group =
53
+ * content_taxonomies.taxonomy_id` + filter by `taxonomies.locale`, which picks
54
+ * the right per-locale term.
55
+ */
56
+ var taxonomies_exports = /* @__PURE__ */ __exportAll({
57
+ getAllTermsForEntries: () => getAllTermsForEntries,
58
+ getEntriesByTerm: () => getEntriesByTerm,
59
+ getEntryTerms: () => getEntryTerms,
60
+ getTaxonomyDef: () => getTaxonomyDef,
61
+ getTaxonomyDefs: () => getTaxonomyDefs,
62
+ getTaxonomyTerms: () => getTaxonomyTerms,
63
+ getTerm: () => getTerm,
64
+ getTermsForEntries: () => getTermsForEntries,
65
+ invalidateTermCache: () => invalidateTermCache
66
+ });
67
+ /**
68
+ * No-op — kept for API compatibility.
69
+ */
70
+ function invalidateTermCache() {}
71
+ /**
72
+ * Get every taxonomy definition. Definitions are per-locale (one row per
73
+ * locale inside the same translation_group) — by default we resolve to the
74
+ * active locale.
75
+ */
76
+ async function getTaxonomyDefs(options = {}) {
77
+ const locale = resolveLocale(options.locale);
78
+ return requestCached(`taxonomy-defs:${locale ?? "*"}`, async () => {
79
+ let query = (await getDb()).selectFrom("_emdash_taxonomy_defs").selectAll();
80
+ if (locale !== void 0) query = query.where("locale", "=", locale);
81
+ return (await query.execute()).map(rowToTaxonomyDef);
82
+ });
83
+ }
84
+ /**
85
+ * Get a single taxonomy definition by name. Uses the fallback chain so even
86
+ * if there is no translation for the active locale we still return something.
87
+ *
88
+ * If `getTaxonomyDefs()` has already loaded the full list in this request
89
+ * (which happens during entry-term hydration on every page that renders a
90
+ * collection), search the matching def in memory rather than running a
91
+ * second query against `_emdash_taxonomy_defs`.
92
+ */
93
+ async function getTaxonomyDef(name, options = {}) {
94
+ const chain = resolveLocaleChain(options.locale);
95
+ const allDefs = peekRequestCache(`taxonomy-defs:${resolveLocale(options.locale) ?? "*"}`);
96
+ if (allDefs) {
97
+ const defs = await allDefs;
98
+ if (chain.length === 0) return defs.find((d) => d.name === name) ?? null;
99
+ for (const locale of chain) {
100
+ const found = defs.find((d) => d.name === name && d.locale === locale);
101
+ if (found) return found;
102
+ }
103
+ return null;
104
+ }
105
+ return requestCached(`taxonomy-def:${name}:${chain.join(",")}`, async () => {
106
+ const db = await getDb();
107
+ if (chain.length === 0) {
108
+ const row = await db.selectFrom("_emdash_taxonomy_defs").selectAll().where("name", "=", name).orderBy("locale", "asc").executeTakeFirst();
109
+ return row ? rowToTaxonomyDef(row) : null;
110
+ }
111
+ for (const locale of chain) {
112
+ const row = await db.selectFrom("_emdash_taxonomy_defs").selectAll().where("name", "=", name).where("locale", "=", locale).executeTakeFirst();
113
+ if (row) return rowToTaxonomyDef(row);
114
+ }
115
+ return null;
116
+ });
117
+ }
118
+ /**
119
+ * All terms of a taxonomy in a specific locale (flat for non-hierarchical,
120
+ * tree for hierarchical).
121
+ */
122
+ async function getTaxonomyTerms(taxonomyName, options = {}) {
123
+ const locale = resolveLocale(options.locale);
124
+ return requestCached(`taxonomy-terms:${taxonomyName}:${locale ?? "*"}`, async () => {
125
+ const db = await getDb();
126
+ const def = await getTaxonomyDef(taxonomyName, options);
127
+ if (!def) return [];
128
+ let termsQuery = db.selectFrom("taxonomies").selectAll().where("name", "=", taxonomyName).orderBy("label", "asc");
129
+ if (locale !== void 0) termsQuery = termsQuery.where("locale", "=", locale);
130
+ const rows = await termsQuery.execute();
131
+ const countsResult = await db.selectFrom("content_taxonomies").select(["taxonomy_id"]).select((eb) => eb.fn.count("entry_id").as("count")).groupBy("taxonomy_id").execute();
132
+ const counts = /* @__PURE__ */ new Map();
133
+ for (const row of countsResult) counts.set(row.taxonomy_id, row.count);
134
+ const flatTerms = rows.map((row) => ({
135
+ id: row.id,
136
+ name: row.name,
137
+ slug: row.slug,
138
+ label: row.label,
139
+ parent_id: row.parent_id,
140
+ data: row.data,
141
+ locale: row.locale,
142
+ translation_group: row.translation_group
143
+ }));
144
+ if (def.hierarchical) return buildTree(flatTerms, counts);
145
+ return flatTerms.map((term) => ({
146
+ id: term.id,
147
+ name: term.name,
148
+ slug: term.slug,
149
+ label: term.label,
150
+ children: [],
151
+ count: counts.get(term.translation_group ?? term.id) ?? 0,
152
+ locale: term.locale,
153
+ translationGroup: term.translation_group
154
+ }));
155
+ });
156
+ }
157
+ /**
158
+ * Get a single term by (taxonomy, slug). Honours the fallback chain — if the
159
+ * slug exists in a fallback locale, we return that row (useful for deep-linking
160
+ * to a term page when the translation is missing).
161
+ */
162
+ async function getTerm(taxonomyName, slug, options = {}) {
163
+ const db = await getDb();
164
+ const chain = resolveLocaleChain(options.locale);
165
+ let row;
166
+ const selectTerm = () => db.selectFrom("taxonomies").selectAll().where("name", "=", taxonomyName).where("slug", "=", slug);
167
+ if (chain.length === 0) row = await selectTerm().orderBy("locale", "asc").executeTakeFirst();
168
+ else {
169
+ row = void 0;
170
+ for (const locale of chain) {
171
+ row = await selectTerm().where("locale", "=", locale).executeTakeFirst();
172
+ if (row) break;
173
+ }
174
+ }
175
+ if (!row) return null;
176
+ const count = (await db.selectFrom("content_taxonomies").select((eb) => eb.fn.count("entry_id").as("count")).where("taxonomy_id", "=", row.translation_group ?? row.id).executeTakeFirst())?.count ?? 0;
177
+ let childrenQuery = db.selectFrom("taxonomies").selectAll().where("parent_id", "=", row.id).orderBy("label", "asc");
178
+ const termLocale = row.locale;
179
+ if (termLocale) childrenQuery = childrenQuery.where("locale", "=", termLocale);
180
+ const children = (await childrenQuery.execute()).map((child) => ({
181
+ id: child.id,
182
+ name: child.name,
183
+ slug: child.slug,
184
+ label: child.label,
185
+ parentId: child.parent_id ?? void 0,
186
+ children: [],
187
+ locale: child.locale,
188
+ translationGroup: child.translation_group
189
+ }));
190
+ return {
191
+ id: row.id,
192
+ name: row.name,
193
+ slug: row.slug,
194
+ label: row.label,
195
+ parentId: row.parent_id ?? void 0,
196
+ description: row.data ? JSON.parse(row.data).description : void 0,
197
+ children,
198
+ count,
199
+ locale: row.locale,
200
+ translationGroup: row.translation_group
201
+ };
202
+ }
203
+ /**
204
+ * Terms assigned to a content entry, resolved into the active locale. Terms
205
+ * whose translation_group lacks a row in the requested locale are omitted.
206
+ */
207
+ function getEntryTerms(collection, entryId, taxonomyName, options = {}) {
208
+ const locale = resolveLocale(options.locale);
209
+ return requestCached(`terms:${collection}:${entryId}:${taxonomyName ?? "*"}:${locale ?? "*"}`, async () => {
210
+ let query = (await getDb()).selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.translation_group", "content_taxonomies.taxonomy_id").selectAll("taxonomies").where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "=", entryId);
211
+ if (taxonomyName) query = query.where("taxonomies.name", "=", taxonomyName);
212
+ if (locale !== void 0) query = query.where("taxonomies.locale", "=", locale);
213
+ return (await query.execute()).map((row) => ({
214
+ id: row.id,
215
+ name: row.name,
216
+ slug: row.slug,
217
+ label: row.label,
218
+ parentId: row.parent_id ?? void 0,
219
+ children: [],
220
+ locale: row.locale,
221
+ translationGroup: row.translation_group
222
+ }));
223
+ });
224
+ }
225
+ /**
226
+ * Terms for multiple entries of one taxonomy, single query.
227
+ */
228
+ async function getTermsForEntries(collection, entryIds, taxonomyName, options = {}) {
229
+ const result = /* @__PURE__ */ new Map();
230
+ const uniqueIds = [...new Set(entryIds)];
231
+ for (const id of uniqueIds) result.set(id, []);
232
+ if (uniqueIds.length === 0) return result;
233
+ const db = await getDb();
234
+ const locale = resolveLocale(options.locale);
235
+ for (const chunk of chunks(uniqueIds, SQL_BATCH_SIZE)) {
236
+ let rows;
237
+ try {
238
+ let query = db.selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.translation_group", "content_taxonomies.taxonomy_id").select([
239
+ "content_taxonomies.entry_id",
240
+ "taxonomies.id",
241
+ "taxonomies.name",
242
+ "taxonomies.slug",
243
+ "taxonomies.label",
244
+ "taxonomies.parent_id",
245
+ "taxonomies.locale",
246
+ "taxonomies.translation_group"
247
+ ]).where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "in", chunk).where("taxonomies.name", "=", taxonomyName);
248
+ if (locale !== void 0) query = query.where("taxonomies.locale", "=", locale);
249
+ rows = await query.execute();
250
+ } catch (error) {
251
+ if (isMissingTableError(error)) return result;
252
+ throw error;
253
+ }
254
+ for (const row of rows) {
255
+ const term = {
256
+ id: row.id,
257
+ name: row.name,
258
+ slug: row.slug,
259
+ label: row.label,
260
+ parentId: row.parent_id ?? void 0,
261
+ children: [],
262
+ locale: row.locale,
263
+ translationGroup: row.translation_group
264
+ };
265
+ const terms = result.get(row.entry_id);
266
+ if (terms) terms.push(term);
267
+ }
268
+ }
269
+ return result;
270
+ }
271
+ /**
272
+ * Batch-fetch terms for multiple entries across ALL taxonomies in one query.
273
+ * Primes the request-cache for subsequent per-entry calls to `getEntryTerms`.
274
+ */
275
+ async function getAllTermsForEntries(collection, entryIds, options = {}) {
276
+ const result = /* @__PURE__ */ new Map();
277
+ const uniqueIds = [...new Set(entryIds)];
278
+ for (const id of uniqueIds) result.set(id, {});
279
+ if (uniqueIds.length === 0) return result;
280
+ const db = await getDb();
281
+ const locale = resolveLocale(options.locale);
282
+ const applicableTaxonomyNames = await getCollectionTaxonomyNames(collection, { locale });
283
+ for (const chunk of chunks(uniqueIds, SQL_BATCH_SIZE)) {
284
+ let rows;
285
+ try {
286
+ let query = db.selectFrom("content_taxonomies").innerJoin("taxonomies", "taxonomies.translation_group", "content_taxonomies.taxonomy_id").select([
287
+ "content_taxonomies.entry_id",
288
+ "taxonomies.id",
289
+ "taxonomies.name",
290
+ "taxonomies.slug",
291
+ "taxonomies.label",
292
+ "taxonomies.parent_id",
293
+ "taxonomies.locale",
294
+ "taxonomies.translation_group"
295
+ ]).where("content_taxonomies.collection", "=", collection).where("content_taxonomies.entry_id", "in", chunk).orderBy("taxonomies.label", "asc");
296
+ if (locale !== void 0) query = query.where("taxonomies.locale", "=", locale);
297
+ rows = await query.execute();
298
+ } catch (error) {
299
+ if (isMissingTableError(error)) {
300
+ for (const id of uniqueIds) primeEntryTermsCache(collection, id, {}, applicableTaxonomyNames, locale);
301
+ return result;
302
+ }
303
+ throw error;
304
+ }
305
+ for (const row of rows) {
306
+ const term = {
307
+ id: row.id,
308
+ name: row.name,
309
+ slug: row.slug,
310
+ label: row.label,
311
+ parentId: row.parent_id ?? void 0,
312
+ children: [],
313
+ locale: row.locale,
314
+ translationGroup: row.translation_group
315
+ };
316
+ const byTaxonomy = result.get(row.entry_id);
317
+ if (!byTaxonomy) continue;
318
+ const existing = byTaxonomy[row.name];
319
+ if (existing) existing.push(term);
320
+ else byTaxonomy[row.name] = [term];
321
+ }
322
+ }
323
+ for (const [entryId, byTaxonomy] of result) primeEntryTermsCache(collection, entryId, byTaxonomy, applicableTaxonomyNames, locale);
324
+ return result;
325
+ }
326
+ /**
327
+ * Return the list of taxonomy names applicable to a collection, request-
328
+ * cached so a page render only pays for it once.
329
+ *
330
+ * Returns an empty list when taxonomies haven't been defined yet.
331
+ */
332
+ async function getCollectionTaxonomyNames(collection, options) {
333
+ try {
334
+ return (await getTaxonomyDefs(options)).filter((d) => d.collections.includes(collection)).map((d) => d.name);
335
+ } catch (error) {
336
+ if (isMissingTableError(error)) return [];
337
+ throw error;
338
+ }
339
+ }
340
+ /**
341
+ * Pre-populate the request-cache for every getEntryTerms call-shape that
342
+ * could hit this entry:
343
+ *
344
+ * getEntryTerms(collection, entryId) -> key `terms:C:E:*`
345
+ * getEntryTerms(collection, entryId, "tag") -> key `terms:C:E:tag`
346
+ * getEntryTerms(collection, entryId, "category") -> key `terms:C:E:category`
347
+ * ...one per taxonomy that applies to this collection
348
+ *
349
+ * Taxonomies with no rows on this entry are seeded with `[]` so legacy
350
+ * callers short-circuit to the cached empty array instead of re-querying.
351
+ */
352
+ function primeEntryTermsCache(collection, entryId, byTaxonomy, applicableTaxonomyNames, locale) {
353
+ const localeKey = locale ?? "*";
354
+ for (const name of applicableTaxonomyNames) setRequestCacheEntry(`terms:${collection}:${entryId}:${name}:${localeKey}`, byTaxonomy[name] ?? []);
355
+ for (const [name, terms] of Object.entries(byTaxonomy)) setRequestCacheEntry(`terms:${collection}:${entryId}:${name}:${localeKey}`, terms);
356
+ const allTerms = Object.values(byTaxonomy).flat();
357
+ setRequestCacheEntry(`terms:${collection}:${entryId}:*:${localeKey}`, allTerms);
358
+ }
359
+ /**
360
+ * Get entries by term. Both the lookup (term slug in the active locale) and
361
+ * the content query respect the active locale.
362
+ */
363
+ async function getEntriesByTerm(collection, taxonomyName, termSlug, options = {}) {
364
+ const { getEmDashCollection } = await import("./query-Bo-msrmu.mjs").then((n) => n.o);
365
+ const queryOptions = { where: { [taxonomyName]: termSlug } };
366
+ if (options.locale !== void 0) queryOptions.locale = options.locale;
367
+ const { entries } = await getEmDashCollection(collection, queryOptions);
368
+ return entries;
369
+ }
370
+ function rowToTaxonomyDef(row) {
371
+ return {
372
+ id: row.id,
373
+ name: row.name,
374
+ label: row.label,
375
+ labelSingular: row.label_singular ?? void 0,
376
+ hierarchical: row.hierarchical === 1,
377
+ collections: row.collections ? JSON.parse(row.collections) : [],
378
+ locale: row.locale,
379
+ translationGroup: row.translation_group
380
+ };
381
+ }
382
+ /**
383
+ * Build tree structure from flat terms
384
+ */
385
+ function buildTree(flatTerms, counts) {
386
+ const map = /* @__PURE__ */ new Map();
387
+ const roots = [];
388
+ for (const term of flatTerms) map.set(term.id, {
389
+ id: term.id,
390
+ name: term.name,
391
+ slug: term.slug,
392
+ label: term.label,
393
+ parentId: term.parent_id ?? void 0,
394
+ description: term.data ? JSON.parse(term.data).description : void 0,
395
+ children: [],
396
+ count: counts.get(term.translation_group ?? term.id) ?? 0,
397
+ locale: term.locale,
398
+ translationGroup: term.translation_group
399
+ });
400
+ for (const term of map.values()) if (term.parentId && map.has(term.parentId)) map.get(term.parentId).children.push(term);
401
+ else roots.push(term);
402
+ return roots;
403
+ }
404
+
405
+ //#endregion
406
+ export { getTaxonomyDefs as a, getTermsForEntries as c, resolveLocale as d, resolveLocaleChain as f, getTaxonomyDef as i, invalidateTermCache as l, getEntriesByTerm as n, getTaxonomyTerms as o, getEntryTerms as r, getTerm as s, getAllTermsForEntries as t, taxonomies_exports as u };
407
+ //# sourceMappingURL=taxonomies-CTtewrSQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taxonomies-CTtewrSQ.mjs","names":[],"sources":["../src/i18n/resolve.ts","../src/taxonomies/index.ts"],"sourcesContent":["/**\n * Shared locale-resolution helpers.\n *\n * Matches the pattern used by `query.ts` for content: an explicit locale wins,\n * otherwise we fall back to the request-context locale, otherwise to\n * `defaultLocale` when i18n is enabled, otherwise to `undefined` (meaning \"do\n * not filter by locale\" — legacy single-locale behaviour).\n */\n\nimport { getRequestContext } from \"../request-context.js\";\nimport { getFallbackChain, getI18nConfig, isI18nEnabled } from \"./config.js\";\n\n/**\n * Resolve the locale to use for a query given an optional explicit value.\n * Returns `undefined` when no locale information is available; callers should\n * treat that as \"do not filter by locale\".\n */\nexport function resolveLocale(explicit?: string): string | undefined {\n\tif (explicit !== undefined) return explicit;\n\tconst ctxLocale = getRequestContext()?.locale;\n\tif (ctxLocale !== undefined) return ctxLocale;\n\tconst cfg = getI18nConfig();\n\tif (cfg && isI18nEnabled()) return cfg.defaultLocale;\n\treturn undefined;\n}\n\n/**\n * Fallback chain to try when looking up a single item. When i18n is disabled\n * or the locale is unspecified, returns a single-element array (or empty when\n * no locale resolves) so callers can iterate uniformly.\n */\nexport function resolveLocaleChain(explicit?: string): string[] {\n\tconst locale = resolveLocale(explicit);\n\tif (locale === undefined) return [];\n\tif (!isI18nEnabled()) return [locale];\n\treturn getFallbackChain(locale);\n}\n","/**\n * Runtime API for taxonomies.\n *\n * All helpers are locale-aware. When a locale is not passed explicitly we fall\n * back to the request context or the configured `defaultLocale` (see\n * `i18n/resolve.ts`).\n *\n * Because `content_taxonomies.taxonomy_id` stores the translation_group (not a\n * specific term id), the joins here are `taxonomies.translation_group =\n * content_taxonomies.taxonomy_id` + filter by `taxonomies.locale`, which picks\n * the right per-locale term.\n */\n\nimport { resolveLocale, resolveLocaleChain } from \"../i18n/resolve.js\";\nimport { getDb } from \"../loader.js\";\nimport { peekRequestCache, requestCached, setRequestCacheEntry } from \"../request-cache.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../utils/chunks.js\";\nimport { isMissingTableError } from \"../utils/db-errors.js\";\nimport type { TaxonomyDef, TaxonomyTerm, TaxonomyTermRow } from \"./types.js\";\n\nexport interface TaxonomyQueryOptions {\n\tlocale?: string;\n}\n\n/**\n * No-op — kept for API compatibility.\n */\nexport function invalidateTermCache(): void {\n\t// Intentionally empty.\n}\n\n/**\n * Get every taxonomy definition. Definitions are per-locale (one row per\n * locale inside the same translation_group) — by default we resolve to the\n * active locale.\n */\nexport async function getTaxonomyDefs(options: TaxonomyQueryOptions = {}): Promise<TaxonomyDef[]> {\n\tconst locale = resolveLocale(options.locale);\n\treturn requestCached(`taxonomy-defs:${locale ?? \"*\"}`, async () => {\n\t\tconst db = await getDb();\n\t\tlet query = db.selectFrom(\"_emdash_taxonomy_defs\").selectAll();\n\t\tif (locale !== undefined) query = query.where(\"locale\", \"=\", locale);\n\t\tconst rows = await query.execute();\n\t\treturn rows.map(rowToTaxonomyDef);\n\t});\n}\n\n/**\n * Get a single taxonomy definition by name. Uses the fallback chain so even\n * if there is no translation for the active locale we still return something.\n *\n * If `getTaxonomyDefs()` has already loaded the full list in this request\n * (which happens during entry-term hydration on every page that renders a\n * collection), search the matching def in memory rather than running a\n * second query against `_emdash_taxonomy_defs`.\n */\nexport async function getTaxonomyDef(\n\tname: string,\n\toptions: TaxonomyQueryOptions = {},\n): Promise<TaxonomyDef | null> {\n\tconst chain = resolveLocaleChain(options.locale);\n\tconst peekKey = `taxonomy-defs:${resolveLocale(options.locale) ?? \"*\"}`;\n\tconst allDefs = peekRequestCache<TaxonomyDef[]>(peekKey);\n\tif (allDefs) {\n\t\tconst defs = await allDefs;\n\t\tif (chain.length === 0) return defs.find((d) => d.name === name) ?? null;\n\t\tfor (const locale of chain) {\n\t\t\tconst found = defs.find((d) => d.name === name && d.locale === locale);\n\t\t\tif (found) return found;\n\t\t}\n\t\treturn null;\n\t}\n\n\treturn requestCached(`taxonomy-def:${name}:${chain.join(\",\")}`, async () => {\n\t\tconst db = await getDb();\n\n\t\tif (chain.length === 0) {\n\t\t\tconst row = await db\n\t\t\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t\t\t.selectAll()\n\t\t\t\t.where(\"name\", \"=\", name)\n\t\t\t\t.orderBy(\"locale\", \"asc\")\n\t\t\t\t.executeTakeFirst();\n\t\t\treturn row ? rowToTaxonomyDef(row) : null;\n\t\t}\n\n\t\tfor (const locale of chain) {\n\t\t\tconst row = await db\n\t\t\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t\t\t.selectAll()\n\t\t\t\t.where(\"name\", \"=\", name)\n\t\t\t\t.where(\"locale\", \"=\", locale)\n\t\t\t\t.executeTakeFirst();\n\t\t\tif (row) return rowToTaxonomyDef(row);\n\t\t}\n\t\treturn null;\n\t});\n}\n\n/**\n * All terms of a taxonomy in a specific locale (flat for non-hierarchical,\n * tree for hierarchical).\n */\nexport async function getTaxonomyTerms(\n\ttaxonomyName: string,\n\toptions: TaxonomyQueryOptions = {},\n): Promise<TaxonomyTerm[]> {\n\tconst locale = resolveLocale(options.locale);\n\treturn requestCached(`taxonomy-terms:${taxonomyName}:${locale ?? \"*\"}`, async () => {\n\t\tconst db = await getDb();\n\n\t\tconst def = await getTaxonomyDef(taxonomyName, options);\n\t\tif (!def) return [];\n\n\t\tlet termsQuery = db\n\t\t\t.selectFrom(\"taxonomies\")\n\t\t\t.selectAll()\n\t\t\t.where(\"name\", \"=\", taxonomyName)\n\t\t\t.orderBy(\"label\", \"asc\");\n\t\tif (locale !== undefined) termsQuery = termsQuery.where(\"locale\", \"=\", locale);\n\t\tconst rows = await termsQuery.execute();\n\n\t\t// Counts are keyed by translation_group (what the pivot stores).\n\t\tconst countsResult = await db\n\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t.select([\"taxonomy_id\"])\n\t\t\t.select((eb) => eb.fn.count<number>(\"entry_id\").as(\"count\"))\n\t\t\t.groupBy(\"taxonomy_id\")\n\t\t\t.execute();\n\t\tconst counts = new Map<string, number>();\n\t\tfor (const row of countsResult) counts.set(row.taxonomy_id, row.count);\n\n\t\tconst flatTerms: TaxonomyTermRow[] = rows.map((row) => ({\n\t\t\tid: row.id,\n\t\t\tname: row.name,\n\t\t\tslug: row.slug,\n\t\t\tlabel: row.label,\n\t\t\tparent_id: row.parent_id,\n\t\t\tdata: row.data,\n\t\t\tlocale: row.locale,\n\t\t\ttranslation_group: row.translation_group,\n\t\t}));\n\n\t\tif (def.hierarchical) return buildTree(flatTerms, counts);\n\n\t\treturn flatTerms.map((term) => ({\n\t\t\tid: term.id,\n\t\t\tname: term.name,\n\t\t\tslug: term.slug,\n\t\t\tlabel: term.label,\n\t\t\tchildren: [],\n\t\t\tcount: counts.get(term.translation_group ?? term.id) ?? 0,\n\t\t\tlocale: term.locale,\n\t\t\ttranslationGroup: term.translation_group,\n\t\t}));\n\t});\n}\n\n/**\n * Get a single term by (taxonomy, slug). Honours the fallback chain — if the\n * slug exists in a fallback locale, we return that row (useful for deep-linking\n * to a term page when the translation is missing).\n */\nexport async function getTerm(\n\ttaxonomyName: string,\n\tslug: string,\n\toptions: TaxonomyQueryOptions = {},\n): Promise<TaxonomyTerm | null> {\n\tconst db = await getDb();\n\tconst chain = resolveLocaleChain(options.locale);\n\n\tlet row: Awaited<ReturnType<ReturnType<typeof selectTerm>[\"executeTakeFirst\"]>>;\n\tconst selectTerm = () =>\n\t\tdb\n\t\t\t.selectFrom(\"taxonomies\")\n\t\t\t.selectAll()\n\t\t\t.where(\"name\", \"=\", taxonomyName)\n\t\t\t.where(\"slug\", \"=\", slug);\n\n\tif (chain.length === 0) {\n\t\trow = await selectTerm().orderBy(\"locale\", \"asc\").executeTakeFirst();\n\t} else {\n\t\trow = undefined;\n\t\tfor (const locale of chain) {\n\t\t\trow = await selectTerm().where(\"locale\", \"=\", locale).executeTakeFirst();\n\t\t\tif (row) break;\n\t\t}\n\t}\n\n\tif (!row) return null;\n\n\tconst countResult = await db\n\t\t.selectFrom(\"content_taxonomies\")\n\t\t.select((eb) => eb.fn.count<number>(\"entry_id\").as(\"count\"))\n\t\t.where(\"taxonomy_id\", \"=\", row.translation_group ?? row.id)\n\t\t.executeTakeFirst();\n\tconst count = countResult?.count ?? 0;\n\n\tlet childrenQuery = db\n\t\t.selectFrom(\"taxonomies\")\n\t\t.selectAll()\n\t\t.where(\"parent_id\", \"=\", row.id)\n\t\t.orderBy(\"label\", \"asc\");\n\tconst termLocale = row.locale;\n\tif (termLocale) childrenQuery = childrenQuery.where(\"locale\", \"=\", termLocale);\n\tconst childRows = await childrenQuery.execute();\n\n\tconst children = childRows.map<TaxonomyTerm>((child) => ({\n\t\tid: child.id,\n\t\tname: child.name,\n\t\tslug: child.slug,\n\t\tlabel: child.label,\n\t\tparentId: child.parent_id ?? undefined,\n\t\tchildren: [],\n\t\tlocale: child.locale,\n\t\ttranslationGroup: child.translation_group,\n\t}));\n\n\treturn {\n\t\tid: row.id,\n\t\tname: row.name,\n\t\tslug: row.slug,\n\t\tlabel: row.label,\n\t\tparentId: row.parent_id ?? undefined,\n\t\tdescription: row.data ? JSON.parse(row.data).description : undefined,\n\t\tchildren,\n\t\tcount,\n\t\tlocale: row.locale,\n\t\ttranslationGroup: row.translation_group,\n\t};\n}\n\n/**\n * Terms assigned to a content entry, resolved into the active locale. Terms\n * whose translation_group lacks a row in the requested locale are omitted.\n */\nexport function getEntryTerms(\n\tcollection: string,\n\tentryId: string,\n\ttaxonomyName?: string,\n\toptions: TaxonomyQueryOptions = {},\n): Promise<TaxonomyTerm[]> {\n\tconst locale = resolveLocale(options.locale);\n\treturn requestCached(\n\t\t`terms:${collection}:${entryId}:${taxonomyName ?? \"*\"}:${locale ?? \"*\"}`,\n\t\tasync () => {\n\t\t\tconst db = await getDb();\n\n\t\t\tlet query = db\n\t\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t\t.innerJoin(\"taxonomies\", \"taxonomies.translation_group\", \"content_taxonomies.taxonomy_id\")\n\t\t\t\t.selectAll(\"taxonomies\")\n\t\t\t\t.where(\"content_taxonomies.collection\", \"=\", collection)\n\t\t\t\t.where(\"content_taxonomies.entry_id\", \"=\", entryId);\n\n\t\t\tif (taxonomyName) query = query.where(\"taxonomies.name\", \"=\", taxonomyName);\n\t\t\tif (locale !== undefined) query = query.where(\"taxonomies.locale\", \"=\", locale);\n\n\t\t\tconst rows = await query.execute();\n\t\t\treturn rows.map<TaxonomyTerm>((row) => ({\n\t\t\t\tid: row.id,\n\t\t\t\tname: row.name,\n\t\t\t\tslug: row.slug,\n\t\t\t\tlabel: row.label,\n\t\t\t\tparentId: row.parent_id ?? undefined,\n\t\t\t\tchildren: [],\n\t\t\t\tlocale: row.locale,\n\t\t\t\ttranslationGroup: row.translation_group,\n\t\t\t}));\n\t\t},\n\t);\n}\n\n/**\n * Terms for multiple entries of one taxonomy, single query.\n */\nexport async function getTermsForEntries(\n\tcollection: string,\n\tentryIds: string[],\n\ttaxonomyName: string,\n\toptions: TaxonomyQueryOptions = {},\n): Promise<Map<string, TaxonomyTerm[]>> {\n\tconst result = new Map<string, TaxonomyTerm[]>();\n\tconst uniqueIds = [...new Set(entryIds)];\n\tfor (const id of uniqueIds) result.set(id, []);\n\tif (uniqueIds.length === 0) return result;\n\n\tconst db = await getDb();\n\tconst locale = resolveLocale(options.locale);\n\n\tfor (const chunk of chunks(uniqueIds, SQL_BATCH_SIZE)) {\n\t\tlet rows;\n\t\ttry {\n\t\t\tlet query = db\n\t\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t\t.innerJoin(\"taxonomies\", \"taxonomies.translation_group\", \"content_taxonomies.taxonomy_id\")\n\t\t\t\t.select([\n\t\t\t\t\t\"content_taxonomies.entry_id\",\n\t\t\t\t\t\"taxonomies.id\",\n\t\t\t\t\t\"taxonomies.name\",\n\t\t\t\t\t\"taxonomies.slug\",\n\t\t\t\t\t\"taxonomies.label\",\n\t\t\t\t\t\"taxonomies.parent_id\",\n\t\t\t\t\t\"taxonomies.locale\",\n\t\t\t\t\t\"taxonomies.translation_group\",\n\t\t\t\t])\n\t\t\t\t.where(\"content_taxonomies.collection\", \"=\", collection)\n\t\t\t\t.where(\"content_taxonomies.entry_id\", \"in\", chunk)\n\t\t\t\t.where(\"taxonomies.name\", \"=\", taxonomyName);\n\t\t\tif (locale !== undefined) query = query.where(\"taxonomies.locale\", \"=\", locale);\n\t\t\trows = await query.execute();\n\t\t} catch (error) {\n\t\t\tif (isMissingTableError(error)) return result;\n\t\t\tthrow error;\n\t\t}\n\n\t\tfor (const row of rows) {\n\t\t\tconst term: TaxonomyTerm = {\n\t\t\t\tid: row.id,\n\t\t\t\tname: row.name,\n\t\t\t\tslug: row.slug,\n\t\t\t\tlabel: row.label,\n\t\t\t\tparentId: row.parent_id ?? undefined,\n\t\t\t\tchildren: [],\n\t\t\t\tlocale: row.locale,\n\t\t\t\ttranslationGroup: row.translation_group,\n\t\t\t};\n\t\t\tconst terms = result.get(row.entry_id);\n\t\t\tif (terms) terms.push(term);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Batch-fetch terms for multiple entries across ALL taxonomies in one query.\n * Primes the request-cache for subsequent per-entry calls to `getEntryTerms`.\n */\nexport async function getAllTermsForEntries(\n\tcollection: string,\n\tentryIds: string[],\n\toptions: TaxonomyQueryOptions = {},\n): Promise<Map<string, Record<string, TaxonomyTerm[]>>> {\n\tconst result = new Map<string, Record<string, TaxonomyTerm[]>>();\n\tconst uniqueIds = [...new Set(entryIds)];\n\tfor (const id of uniqueIds) result.set(id, {});\n\tif (uniqueIds.length === 0) return result;\n\n\tconst db = await getDb();\n\tconst locale = resolveLocale(options.locale);\n\tconst applicableTaxonomyNames = await getCollectionTaxonomyNames(collection, { locale });\n\n\tfor (const chunk of chunks(uniqueIds, SQL_BATCH_SIZE)) {\n\t\tlet rows;\n\t\ttry {\n\t\t\tlet query = db\n\t\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t\t.innerJoin(\"taxonomies\", \"taxonomies.translation_group\", \"content_taxonomies.taxonomy_id\")\n\t\t\t\t.select([\n\t\t\t\t\t\"content_taxonomies.entry_id\",\n\t\t\t\t\t\"taxonomies.id\",\n\t\t\t\t\t\"taxonomies.name\",\n\t\t\t\t\t\"taxonomies.slug\",\n\t\t\t\t\t\"taxonomies.label\",\n\t\t\t\t\t\"taxonomies.parent_id\",\n\t\t\t\t\t\"taxonomies.locale\",\n\t\t\t\t\t\"taxonomies.translation_group\",\n\t\t\t\t])\n\t\t\t\t.where(\"content_taxonomies.collection\", \"=\", collection)\n\t\t\t\t.where(\"content_taxonomies.entry_id\", \"in\", chunk)\n\t\t\t\t.orderBy(\"taxonomies.label\", \"asc\");\n\t\t\tif (locale !== undefined) query = query.where(\"taxonomies.locale\", \"=\", locale);\n\t\t\trows = await query.execute();\n\t\t} catch (error) {\n\t\t\tif (isMissingTableError(error)) {\n\t\t\t\tfor (const id of uniqueIds) {\n\t\t\t\t\tprimeEntryTermsCache(collection, id, {}, applicableTaxonomyNames, locale);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\tfor (const row of rows) {\n\t\t\tconst term: TaxonomyTerm = {\n\t\t\t\tid: row.id,\n\t\t\t\tname: row.name,\n\t\t\t\tslug: row.slug,\n\t\t\t\tlabel: row.label,\n\t\t\t\tparentId: row.parent_id ?? undefined,\n\t\t\t\tchildren: [],\n\t\t\t\tlocale: row.locale,\n\t\t\t\ttranslationGroup: row.translation_group,\n\t\t\t};\n\t\t\tconst byTaxonomy = result.get(row.entry_id);\n\t\t\tif (!byTaxonomy) continue;\n\t\t\tconst existing = byTaxonomy[row.name];\n\t\t\tif (existing) existing.push(term);\n\t\t\telse byTaxonomy[row.name] = [term];\n\t\t}\n\t}\n\n\tfor (const [entryId, byTaxonomy] of result) {\n\t\tprimeEntryTermsCache(collection, entryId, byTaxonomy, applicableTaxonomyNames, locale);\n\t}\n\n\treturn result;\n}\n\n/**\n * Return the list of taxonomy names applicable to a collection, request-\n * cached so a page render only pays for it once.\n *\n * Returns an empty list when taxonomies haven't been defined yet.\n */\nasync function getCollectionTaxonomyNames(\n\tcollection: string,\n\toptions: TaxonomyQueryOptions,\n): Promise<string[]> {\n\ttry {\n\t\tconst defs = await getTaxonomyDefs(options);\n\t\treturn defs.filter((d) => d.collections.includes(collection)).map((d) => d.name);\n\t} catch (error) {\n\t\tif (isMissingTableError(error)) return [];\n\t\tthrow error;\n\t}\n}\n\n/**\n * Pre-populate the request-cache for every getEntryTerms call-shape that\n * could hit this entry:\n *\n * getEntryTerms(collection, entryId) -> key `terms:C:E:*`\n * getEntryTerms(collection, entryId, \"tag\") -> key `terms:C:E:tag`\n * getEntryTerms(collection, entryId, \"category\") -> key `terms:C:E:category`\n * ...one per taxonomy that applies to this collection\n *\n * Taxonomies with no rows on this entry are seeded with `[]` so legacy\n * callers short-circuit to the cached empty array instead of re-querying.\n */\nfunction primeEntryTermsCache(\n\tcollection: string,\n\tentryId: string,\n\tbyTaxonomy: Record<string, TaxonomyTerm[]>,\n\tapplicableTaxonomyNames: string[],\n\tlocale: string | undefined,\n): void {\n\tconst localeKey = locale ?? \"*\";\n\tfor (const name of applicableTaxonomyNames) {\n\t\tsetRequestCacheEntry(\n\t\t\t`terms:${collection}:${entryId}:${name}:${localeKey}`,\n\t\t\tbyTaxonomy[name] ?? [],\n\t\t);\n\t}\n\tfor (const [name, terms] of Object.entries(byTaxonomy)) {\n\t\tsetRequestCacheEntry(`terms:${collection}:${entryId}:${name}:${localeKey}`, terms);\n\t}\n\tconst allTerms = Object.values(byTaxonomy).flat();\n\tsetRequestCacheEntry(`terms:${collection}:${entryId}:*:${localeKey}`, allTerms);\n}\n\n/**\n * Get entries by term. Both the lookup (term slug in the active locale) and\n * the content query respect the active locale.\n */\nexport async function getEntriesByTerm(\n\tcollection: string,\n\ttaxonomyName: string,\n\ttermSlug: string,\n\toptions: TaxonomyQueryOptions = {},\n): Promise<Array<{ id: string; data: Record<string, unknown> }>> {\n\tconst { getEmDashCollection } = await import(\"../query.js\");\n\n\tconst queryOptions: Record<string, unknown> = {\n\t\twhere: { [taxonomyName]: termSlug },\n\t};\n\tif (options.locale !== undefined) queryOptions.locale = options.locale;\n\tconst { entries } = await getEmDashCollection(collection, queryOptions);\n\treturn entries;\n}\n\nfunction rowToTaxonomyDef(row: {\n\tid: string;\n\tname: string;\n\tlabel: string;\n\tlabel_singular: string | null;\n\thierarchical: number;\n\tcollections: string | null;\n\tlocale: string;\n\ttranslation_group: string | null;\n}): TaxonomyDef {\n\treturn {\n\t\tid: row.id,\n\t\tname: row.name,\n\t\tlabel: row.label,\n\t\tlabelSingular: row.label_singular ?? undefined,\n\t\thierarchical: row.hierarchical === 1,\n\t\tcollections: row.collections ? JSON.parse(row.collections) : [],\n\t\tlocale: row.locale,\n\t\ttranslationGroup: row.translation_group,\n\t};\n}\n\n/**\n * Build tree structure from flat terms\n */\nfunction buildTree(flatTerms: TaxonomyTermRow[], counts: Map<string, number>): TaxonomyTerm[] {\n\tconst map = new Map<string, TaxonomyTerm>();\n\tconst roots: TaxonomyTerm[] = [];\n\n\tfor (const term of flatTerms) {\n\t\tmap.set(term.id, {\n\t\t\tid: term.id,\n\t\t\tname: term.name,\n\t\t\tslug: term.slug,\n\t\t\tlabel: term.label,\n\t\t\tparentId: term.parent_id ?? undefined,\n\t\t\tdescription: term.data ? JSON.parse(term.data).description : undefined,\n\t\t\tchildren: [],\n\t\t\tcount: counts.get(term.translation_group ?? term.id) ?? 0,\n\t\t\tlocale: term.locale,\n\t\t\ttranslationGroup: term.translation_group,\n\t\t});\n\t}\n\n\tfor (const term of map.values()) {\n\t\tif (term.parentId && map.has(term.parentId)) {\n\t\t\tmap.get(term.parentId)!.children.push(term);\n\t\t} else {\n\t\t\troots.push(term);\n\t\t}\n\t}\n\n\treturn roots;\n}\n"],"mappings":"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"}