emdash 0.16.1 → 0.17.1

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 (566) hide show
  1. package/dist/{adapters-C4yd_UJR.d.mts → adapters-C5AWLJSD.d.mts} +1 -1
  2. package/dist/{adapters-C4yd_UJR.d.mts.map → adapters-C5AWLJSD.d.mts.map} +1 -1
  3. package/dist/{allowed-origins-D0fFk9a6.mjs → allowed-origins-CyYLEJkp.mjs} +2 -2
  4. package/dist/{allowed-origins-D0fFk9a6.mjs.map → allowed-origins-CyYLEJkp.mjs.map} +1 -1
  5. package/dist/api/route-utils.d.mts +3 -3
  6. package/dist/api/route-utils.mjs +16 -16
  7. package/dist/api/schemas/index.d.mts +2 -2
  8. package/dist/api/schemas/index.mjs +3 -3
  9. package/dist/{api-BNKqxyFX.mjs → api-Dmz40c2V.mjs} +44 -22
  10. package/dist/api-Dmz40c2V.mjs.map +1 -0
  11. package/dist/{api-tokens-ucpcNXDt.mjs → api-tokens-VrXNiNvV.mjs} +2 -2
  12. package/dist/{api-tokens-ucpcNXDt.mjs.map → api-tokens-VrXNiNvV.mjs.map} +1 -1
  13. package/dist/{apply-BOPaD-s9.mjs → apply-CuuZG6op.mjs} +93 -31
  14. package/dist/apply-CuuZG6op.mjs.map +1 -0
  15. package/dist/astro/index.d.mts +10 -10
  16. package/dist/astro/index.mjs +28 -3
  17. package/dist/astro/index.mjs.map +1 -1
  18. package/dist/astro/middleware/auth.d.mts +9 -9
  19. package/dist/astro/middleware/auth.mjs +6 -6
  20. package/dist/astro/middleware/redirect.d.mts.map +1 -1
  21. package/dist/astro/middleware/redirect.mjs +9 -5
  22. package/dist/astro/middleware/redirect.mjs.map +1 -1
  23. package/dist/astro/middleware/request-context.mjs +2 -2
  24. package/dist/astro/middleware/setup.mjs +1 -1
  25. package/dist/astro/middleware.mjs +66 -65
  26. package/dist/astro/middleware.mjs.map +1 -1
  27. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +5 -5
  28. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +5 -5
  29. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  30. package/dist/astro/routes/api/admin/api-tokens/index.mjs +5 -5
  31. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.d.mts +8 -0
  32. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.d.mts.map +1 -0
  33. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +23 -0
  34. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs.map +1 -0
  35. package/dist/astro/routes/api/admin/byline-fields/_slug_.d.mts +10 -0
  36. package/dist/astro/routes/api/admin/byline-fields/_slug_.d.mts.map +1 -0
  37. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +55 -0
  38. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs.map +1 -0
  39. package/dist/astro/routes/api/admin/byline-fields/index.d.mts +9 -0
  40. package/dist/astro/routes/api/admin/byline-fields/index.d.mts.map +1 -0
  41. package/dist/astro/routes/api/admin/byline-fields/index.mjs +43 -0
  42. package/dist/astro/routes/api/admin/byline-fields/index.mjs.map +1 -0
  43. package/dist/astro/routes/api/admin/byline-fields/reorder.d.mts +8 -0
  44. package/dist/astro/routes/api/admin/byline-fields/reorder.d.mts.map +1 -0
  45. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +27 -0
  46. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs.map +1 -0
  47. package/dist/astro/routes/api/admin/bylines/_id_/index.d.mts.map +1 -1
  48. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +27 -28
  49. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs.map +1 -1
  50. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +13 -12
  51. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs.map +1 -1
  52. package/dist/astro/routes/api/admin/bylines/index.mjs +15 -13
  53. package/dist/astro/routes/api/admin/bylines/index.mjs.map +1 -1
  54. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +10 -10
  55. package/dist/astro/routes/api/admin/comments/_id_.mjs +5 -5
  56. package/dist/astro/routes/api/admin/comments/bulk.mjs +8 -8
  57. package/dist/astro/routes/api/admin/comments/counts.mjs +5 -5
  58. package/dist/astro/routes/api/admin/comments/index.mjs +8 -8
  59. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +4 -4
  60. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  61. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +4 -4
  62. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +4 -4
  63. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +35 -34
  64. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs.map +1 -1
  65. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +35 -34
  66. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs.map +1 -1
  67. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +34 -33
  68. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs.map +1 -1
  69. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +34 -33
  70. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs.map +1 -1
  71. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +34 -33
  72. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs.map +1 -1
  73. package/dist/astro/routes/api/admin/plugins/index.mjs +34 -33
  74. package/dist/astro/routes/api/admin/plugins/index.mjs.map +1 -1
  75. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +3 -3
  76. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +34 -33
  77. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs.map +1 -1
  78. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +34 -33
  79. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs.map +1 -1
  80. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +34 -33
  81. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs.map +1 -1
  82. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +34 -33
  83. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs.map +1 -1
  84. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +35 -34
  85. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs.map +1 -1
  86. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs +34 -33
  87. package/dist/astro/routes/api/admin/plugins/registry/artifact.mjs.map +1 -1
  88. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +35 -34
  89. package/dist/astro/routes/api/admin/plugins/registry/install.mjs.map +1 -1
  90. package/dist/astro/routes/api/admin/plugins/updates.mjs +34 -33
  91. package/dist/astro/routes/api/admin/plugins/updates.mjs.map +1 -1
  92. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +34 -33
  93. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs.map +1 -1
  94. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +3 -3
  95. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +34 -33
  96. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs.map +1 -1
  97. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +2 -2
  98. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  99. package/dist/astro/routes/api/admin/users/_id_/index.mjs +5 -5
  100. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +3 -3
  101. package/dist/astro/routes/api/admin/users/index.mjs +5 -5
  102. package/dist/astro/routes/api/auth/dev-bypass.mjs +5 -5
  103. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  104. package/dist/astro/routes/api/auth/invite/complete.mjs +9 -9
  105. package/dist/astro/routes/api/auth/invite/index.mjs +6 -6
  106. package/dist/astro/routes/api/auth/invite/register-options.mjs +8 -8
  107. package/dist/astro/routes/api/auth/logout.mjs +3 -3
  108. package/dist/astro/routes/api/auth/magic-link/send.mjs +8 -8
  109. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  110. package/dist/astro/routes/api/auth/me.d.mts.map +1 -1
  111. package/dist/astro/routes/api/auth/me.mjs +18 -11
  112. package/dist/astro/routes/api/auth/me.mjs.map +1 -1
  113. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  114. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  115. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  116. package/dist/astro/routes/api/auth/passkey/_id_.mjs +5 -5
  117. package/dist/astro/routes/api/auth/passkey/index.mjs +2 -2
  118. package/dist/astro/routes/api/auth/passkey/options.mjs +10 -10
  119. package/dist/astro/routes/api/auth/passkey/register/options.mjs +8 -8
  120. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +9 -9
  121. package/dist/astro/routes/api/auth/passkey/verify.mjs +9 -9
  122. package/dist/astro/routes/api/auth/signup/complete.mjs +9 -9
  123. package/dist/astro/routes/api/auth/signup/request.mjs +8 -8
  124. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  125. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +11 -11
  126. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +3 -3
  127. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +3 -3
  128. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +3 -3
  129. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +3 -3
  130. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +9 -9
  131. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +6 -6
  132. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +3 -3
  133. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +3 -3
  134. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +6 -6
  135. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.d.mts.map +1 -1
  136. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +18 -13
  137. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs.map +1 -1
  138. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +3 -3
  139. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +3 -3
  140. package/dist/astro/routes/api/content/_collection_/_id_.d.mts.map +1 -1
  141. package/dist/astro/routes/api/content/_collection_/_id_.mjs +9 -7
  142. package/dist/astro/routes/api/content/_collection_/_id_.mjs.map +1 -1
  143. package/dist/astro/routes/api/content/_collection_/index.mjs +6 -6
  144. package/dist/astro/routes/api/content/_collection_/trash.mjs +6 -6
  145. package/dist/astro/routes/api/dashboard.mjs +7 -7
  146. package/dist/astro/routes/api/dev/emails.mjs +3 -3
  147. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  148. package/dist/astro/routes/api/import/probe.mjs +10 -10
  149. package/dist/astro/routes/api/import/wordpress/analyze.mjs +4 -4
  150. package/dist/astro/routes/api/import/wordpress/execute.d.mts +9 -9
  151. package/dist/astro/routes/api/import/wordpress/execute.mjs +11 -10
  152. package/dist/astro/routes/api/import/wordpress/execute.mjs.map +1 -1
  153. package/dist/astro/routes/api/import/wordpress/media.mjs +8 -8
  154. package/dist/astro/routes/api/import/wordpress/prepare.mjs +9 -9
  155. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +8 -8
  156. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  157. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +10 -10
  158. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +1 -1
  159. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +13 -11
  160. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs.map +1 -1
  161. package/dist/astro/routes/api/manifest.mjs +4 -4
  162. package/dist/astro/routes/api/mcp.mjs +34 -30
  163. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  164. package/dist/astro/routes/api/media/_id_/confirm.mjs +6 -6
  165. package/dist/astro/routes/api/media/_id_.mjs +6 -6
  166. package/dist/astro/routes/api/media/file/_...key_.mjs +2 -2
  167. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +3 -3
  168. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +3 -3
  169. package/dist/astro/routes/api/media/providers/index.mjs +3 -3
  170. package/dist/astro/routes/api/media/upload-url.mjs +8 -8
  171. package/dist/astro/routes/api/media.d.mts.map +1 -1
  172. package/dist/astro/routes/api/media.mjs +13 -12
  173. package/dist/astro/routes/api/media.mjs.map +1 -1
  174. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +7 -7
  175. package/dist/astro/routes/api/menus/_name_/items.mjs +7 -7
  176. package/dist/astro/routes/api/menus/_name_/reorder.mjs +7 -7
  177. package/dist/astro/routes/api/menus/_name_/translations.mjs +7 -7
  178. package/dist/astro/routes/api/menus/_name_.mjs +7 -7
  179. package/dist/astro/routes/api/menus/index.mjs +7 -7
  180. package/dist/astro/routes/api/oauth/authorize.mjs +6 -6
  181. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  182. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  183. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  184. package/dist/astro/routes/api/oauth/register.mjs +3 -3
  185. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  186. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  187. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  188. package/dist/astro/routes/api/openapi.json.mjs +10 -7
  189. package/dist/astro/routes/api/openapi.json.mjs.map +1 -1
  190. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +4 -4
  191. package/dist/astro/routes/api/redirects/404s/index.mjs +8 -8
  192. package/dist/astro/routes/api/redirects/404s/summary.mjs +8 -8
  193. package/dist/astro/routes/api/redirects/_id_.mjs +9 -9
  194. package/dist/astro/routes/api/redirects/index.mjs +9 -9
  195. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +3 -3
  196. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +3 -3
  197. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +34 -33
  198. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs.map +1 -1
  199. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +34 -33
  200. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs.map +1 -1
  201. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +34 -33
  202. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs.map +1 -1
  203. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +34 -33
  204. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs.map +1 -1
  205. package/dist/astro/routes/api/schema/collections/index.mjs +34 -33
  206. package/dist/astro/routes/api/schema/collections/index.mjs.map +1 -1
  207. package/dist/astro/routes/api/schema/index.mjs +6 -6
  208. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +34 -33
  209. package/dist/astro/routes/api/schema/orphans/_slug_.mjs.map +1 -1
  210. package/dist/astro/routes/api/schema/orphans/index.mjs +34 -33
  211. package/dist/astro/routes/api/schema/orphans/index.mjs.map +1 -1
  212. package/dist/astro/routes/api/search/enable.mjs +9 -9
  213. package/dist/astro/routes/api/search/index.mjs +8 -8
  214. package/dist/astro/routes/api/search/rebuild.mjs +9 -9
  215. package/dist/astro/routes/api/search/stats.mjs +6 -6
  216. package/dist/astro/routes/api/search/suggest.mjs +8 -8
  217. package/dist/astro/routes/api/sections/_slug_.mjs +8 -8
  218. package/dist/astro/routes/api/sections/index.mjs +8 -8
  219. package/dist/astro/routes/api/settings/email.mjs +4 -4
  220. package/dist/astro/routes/api/settings.mjs +11 -11
  221. package/dist/astro/routes/api/setup/admin-verify.mjs +10 -10
  222. package/dist/astro/routes/api/setup/admin.mjs +9 -9
  223. package/dist/astro/routes/api/setup/dev-bypass.mjs +24 -23
  224. package/dist/astro/routes/api/setup/dev-bypass.mjs.map +1 -1
  225. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  226. package/dist/astro/routes/api/setup/index.mjs +24 -23
  227. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  228. package/dist/astro/routes/api/setup/status.mjs +4 -4
  229. package/dist/astro/routes/api/snapshot.mjs +5 -5
  230. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +12 -12
  231. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +12 -12
  232. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +12 -12
  233. package/dist/astro/routes/api/taxonomies/index.mjs +12 -12
  234. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  235. package/dist/astro/routes/api/typegen.mjs +5 -5
  236. package/dist/astro/routes/api/well-known/auth.mjs +1 -1
  237. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +2 -2
  238. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +2 -2
  239. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +6 -6
  240. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +8 -8
  241. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +8 -8
  242. package/dist/astro/routes/api/widget-areas/_name_.mjs +5 -5
  243. package/dist/astro/routes/api/widget-areas/index.mjs +8 -8
  244. package/dist/astro/routes/api/widget-components.mjs +3 -3
  245. package/dist/astro/routes/robots.txt.mjs +6 -6
  246. package/dist/astro/routes/sitemap-_collection_.xml.mjs +8 -8
  247. package/dist/astro/routes/sitemap.xml.mjs +7 -7
  248. package/dist/astro/types.d.mts +13 -12
  249. package/dist/astro/types.d.mts.map +1 -1
  250. package/dist/auth/providers/github.d.mts +1 -1
  251. package/dist/auth/providers/google.d.mts +1 -1
  252. package/dist/{authorize-Bn4S4DUT.mjs → authorize-_wWM_44T.mjs} +2 -2
  253. package/dist/{authorize-Bn4S4DUT.mjs.map → authorize-_wWM_44T.mjs.map} +1 -1
  254. package/dist/byline-BrIVWLm-.mjs +925 -0
  255. package/dist/byline-BrIVWLm-.mjs.map +1 -0
  256. package/dist/{bylines-DWLnr6-k.d.mts → byline-fields-BNy7Ng1U.d.mts} +151 -23
  257. package/dist/byline-fields-BNy7Ng1U.d.mts.map +1 -0
  258. package/dist/byline-fields-DC3Wkk-U.mjs +123 -0
  259. package/dist/byline-fields-DC3Wkk-U.mjs.map +1 -0
  260. package/dist/byline-fields-Dr-xcb6S.mjs +238 -0
  261. package/dist/byline-fields-Dr-xcb6S.mjs.map +1 -0
  262. package/dist/byline-registry-CxK5g559.mjs +406 -0
  263. package/dist/byline-registry-CxK5g559.mjs.map +1 -0
  264. package/dist/{bylines-n6nykUyI.mjs → bylines-C_POWmGT.mjs} +25 -11
  265. package/dist/{bylines-n6nykUyI.mjs.map → bylines-C_POWmGT.mjs.map} +1 -1
  266. package/dist/bylines-sqExMElV.mjs +204 -0
  267. package/dist/bylines-sqExMElV.mjs.map +1 -0
  268. package/dist/{cache-BcI1yUjR.mjs → cache-wsDkA8ru.mjs} +2 -2
  269. package/dist/{cache-BcI1yUjR.mjs.map → cache-wsDkA8ru.mjs.map} +1 -1
  270. package/dist/{challenge-store-Dng1SxKT.mjs → challenge-store-DGwuCc4R.mjs} +1 -1
  271. package/dist/{challenge-store-Dng1SxKT.mjs.map → challenge-store-DGwuCc4R.mjs.map} +1 -1
  272. package/dist/{chunks-cYG4SnIP.mjs → chunks-BAYkM-CF.mjs} +2 -2
  273. package/dist/{chunks-cYG4SnIP.mjs.map → chunks-BAYkM-CF.mjs.map} +1 -1
  274. package/dist/cli/index.mjs +140 -32
  275. package/dist/cli/index.mjs.map +1 -1
  276. package/dist/client/cf-access.d.mts +1 -1
  277. package/dist/client/index.d.mts +2 -1
  278. package/dist/client/index.d.mts.map +1 -1
  279. package/dist/client/index.mjs +4 -2
  280. package/dist/client/index.mjs.map +1 -1
  281. package/dist/{comment-C76G-9tz.mjs → comment-Cd29aktf.mjs} +2 -2
  282. package/dist/{comment-C76G-9tz.mjs.map → comment-Cd29aktf.mjs.map} +1 -1
  283. package/dist/{comments-CCxFFGY1.mjs → comments-B7ufhkxN.mjs} +3 -3
  284. package/dist/{comments-CCxFFGY1.mjs.map → comments-B7ufhkxN.mjs.map} +1 -1
  285. package/dist/{components-Dx3DM0gg.mjs → components-CTfpu3PZ.mjs} +1 -1
  286. package/dist/{components-Dx3DM0gg.mjs.map → components-CTfpu3PZ.mjs.map} +1 -1
  287. package/dist/{content-8voQNTXX.mjs → content-BbqKo3Kc.mjs} +22 -3
  288. package/dist/content-BbqKo3Kc.mjs.map +1 -0
  289. package/dist/{context-B7qiYrz2.mjs → context-BsF1rhoI.mjs} +9 -9
  290. package/dist/{context-B7qiYrz2.mjs.map → context-BsF1rhoI.mjs.map} +1 -1
  291. package/dist/{cron-Bd3b3iuj.mjs → cron-DZovZUnC.mjs} +1 -1
  292. package/dist/{cron-Bd3b3iuj.mjs.map → cron-DZovZUnC.mjs.map} +1 -1
  293. package/dist/{dashboard-BeaFSPpx.mjs → dashboard-BwIX9r-X.mjs} +4 -4
  294. package/dist/{dashboard-BeaFSPpx.mjs.map → dashboard-BwIX9r-X.mjs.map} +1 -1
  295. package/dist/db/index.d.mts +3 -3
  296. package/dist/db/index.mjs +1 -1
  297. package/dist/db/libsql.d.mts +1 -1
  298. package/dist/db/postgres.d.mts +1 -1
  299. package/dist/db/sqlite.d.mts +1 -1
  300. package/dist/{db-errors-BiYqoX-n.mjs → db-errors-CtzxKBxe.mjs} +1 -1
  301. package/dist/{db-errors-BiYqoX-n.mjs.map → db-errors-CtzxKBxe.mjs.map} +1 -1
  302. package/dist/{default-BvTAYCzx.mjs → default-xLFNSsZ9.mjs} +1 -1
  303. package/dist/{default-BvTAYCzx.mjs.map → default-xLFNSsZ9.mjs.map} +1 -1
  304. package/dist/{device-flow-B9oG8PwP.mjs → device-flow-ptLrVINd.mjs} +4 -4
  305. package/dist/{device-flow-B9oG8PwP.mjs.map → device-flow-ptLrVINd.mjs.map} +1 -1
  306. package/dist/{email-console-CubRll9q.mjs → email-console-DHT2Fbpj.mjs} +1 -1
  307. package/dist/{email-console-CubRll9q.mjs.map → email-console-DHT2Fbpj.mjs.map} +1 -1
  308. package/dist/{error-ChfADBuu.mjs → error-npZWBSb7.mjs} +7 -3
  309. package/dist/error-npZWBSb7.mjs.map +1 -0
  310. package/dist/{escape-Cg6kMELH.mjs → escape-bIyGoW5W.mjs} +1 -1
  311. package/dist/{escape-Cg6kMELH.mjs.map → escape-bIyGoW5W.mjs.map} +1 -1
  312. package/dist/{fts-manager-C_b-4x8u.mjs → fts-manager-DmUAk-kQ.mjs} +2 -2
  313. package/dist/{fts-manager-C_b-4x8u.mjs.map → fts-manager-DmUAk-kQ.mjs.map} +1 -1
  314. package/dist/{hash-DlUxGhQS.mjs → hash-9w3pd3-m.mjs} +1 -1
  315. package/dist/{hash-DlUxGhQS.mjs.map → hash-9w3pd3-m.mjs.map} +1 -1
  316. package/dist/{import-DG80rC_I.mjs → import-Dh8bWmyq.mjs} +3 -3
  317. package/dist/{import-DG80rC_I.mjs.map → import-Dh8bWmyq.mjs.map} +1 -1
  318. package/dist/{index-D_p_jIP1.d.mts → index-CjKdMZ3U.d.mts} +38 -16
  319. package/dist/index-CjKdMZ3U.d.mts.map +1 -0
  320. package/dist/{index-CC42STEm.d.mts → index-D60_SzHG.d.mts} +3 -3
  321. package/dist/{index-CC42STEm.d.mts.map → index-D60_SzHG.d.mts.map} +1 -1
  322. package/dist/index.d.mts +17 -17
  323. package/dist/index.mjs +55 -54
  324. package/dist/{load-CLFRjk9r.mjs → load-DsoLq7ex.mjs} +2 -2
  325. package/dist/{load-CLFRjk9r.mjs.map → load-DsoLq7ex.mjs.map} +1 -1
  326. package/dist/{loader-D-vIJjfY.mjs → loader-CJ6lWO0d.mjs} +75 -19
  327. package/dist/loader-CJ6lWO0d.mjs.map +1 -0
  328. package/dist/{manifest-schema-Czqf0TLu.mjs → manifest-schema-Cj-YrzrF.mjs} +1 -1
  329. package/dist/{manifest-schema-Czqf0TLu.mjs.map → manifest-schema-Cj-YrzrF.mjs.map} +1 -1
  330. package/dist/media/index.d.mts +1 -1
  331. package/dist/media/index.mjs +2 -2
  332. package/dist/media/local-runtime.d.mts +11 -11
  333. package/dist/media/local-runtime.mjs +5 -5
  334. package/dist/{media-allowlist-BNloC69x.mjs → media-allowlist-CMcoYIjQ.mjs} +2 -2
  335. package/dist/{media-allowlist-BNloC69x.mjs.map → media-allowlist-CMcoYIjQ.mjs.map} +1 -1
  336. package/dist/{media-CKQd8AYU.mjs → media-jk_HzzOl.mjs} +7 -2
  337. package/dist/media-jk_HzzOl.mjs.map +1 -0
  338. package/dist/{menus-arUNspyU.mjs → menus-B-5-3aon.mjs} +2 -2
  339. package/dist/{menus-arUNspyU.mjs.map → menus-B-5-3aon.mjs.map} +1 -1
  340. package/dist/{menus-C-nWT5Tu.mjs → menus-CyMO6GBx.mjs} +27 -11
  341. package/dist/menus-CyMO6GBx.mjs.map +1 -0
  342. package/dist/{mime-KV5TqkMN.mjs → mime-CCEzze7W.mjs} +1 -1
  343. package/dist/{mime-KV5TqkMN.mjs.map → mime-CCEzze7W.mjs.map} +1 -1
  344. package/dist/{mode-CaaiebZI.mjs → mode-BjlXswIw.mjs} +1 -1
  345. package/dist/{mode-CaaiebZI.mjs.map → mode-BjlXswIw.mjs.map} +1 -1
  346. package/dist/{normalize-CN5kRSMC.mjs → normalize-DVV8nbrL.mjs} +1 -1
  347. package/dist/{normalize-CN5kRSMC.mjs.map → normalize-DVV8nbrL.mjs.map} +1 -1
  348. package/dist/{oauth-authorization-CTMeVfvj.mjs → oauth-authorization-DvBAL75d.mjs} +4 -4
  349. package/dist/{oauth-authorization-CTMeVfvj.mjs.map → oauth-authorization-DvBAL75d.mjs.map} +1 -1
  350. package/dist/{oauth-clients-eJCbkVSG.mjs → oauth-clients-8mPDStMv.mjs} +1 -1
  351. package/dist/{oauth-clients-eJCbkVSG.mjs.map → oauth-clients-8mPDStMv.mjs.map} +1 -1
  352. package/dist/{oauth-state-store-vOSdOeGe.mjs → oauth-state-store-BJ7YtrfD.mjs} +1 -1
  353. package/dist/{oauth-state-store-vOSdOeGe.mjs.map → oauth-state-store-BJ7YtrfD.mjs.map} +1 -1
  354. package/dist/{oauth-user-lookup-3JwsVw6N.mjs → oauth-user-lookup-BdDSDvjF.mjs} +1 -1
  355. package/dist/{oauth-user-lookup-3JwsVw6N.mjs.map → oauth-user-lookup-BdDSDvjF.mjs.map} +1 -1
  356. package/dist/{options-DhV-gwJb.d.mts → options-tb7DJROi.d.mts} +3 -3
  357. package/dist/{options-DhV-gwJb.d.mts.map → options-tb7DJROi.d.mts.map} +1 -1
  358. package/dist/page/index.d.mts +2 -2
  359. package/dist/{parse-DHbXfvxO.mjs → parse-4zO5Y2DL.mjs} +2 -2
  360. package/dist/{parse-DHbXfvxO.mjs.map → parse-4zO5Y2DL.mjs.map} +1 -1
  361. package/dist/{passkey-config-BloQOT3y.mjs → passkey-config-BDVM86Tj.mjs} +1 -1
  362. package/dist/{passkey-config-BloQOT3y.mjs.map → passkey-config-BDVM86Tj.mjs.map} +1 -1
  363. package/dist/{placeholder-KCkkCtgQ.d.mts → placeholder-B9lUUEmj.d.mts} +1 -1
  364. package/dist/{placeholder-KCkkCtgQ.d.mts.map → placeholder-B9lUUEmj.d.mts.map} +1 -1
  365. package/dist/{placeholder-LqmHqvBw.mjs → placeholder-BZxr8W1j.mjs} +1 -1
  366. package/dist/{placeholder-LqmHqvBw.mjs.map → placeholder-BZxr8W1j.mjs.map} +1 -1
  367. package/dist/plugin-types.d.mts +1 -1
  368. package/dist/plugin-utils.d.mts +9 -9
  369. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  370. package/dist/plugins/adapt-sandbox-entry.mjs +2 -2
  371. package/dist/{preview-D4z0WONU.mjs → preview-BfuRkVKW.mjs} +2 -2
  372. package/dist/{preview-D4z0WONU.mjs.map → preview-BfuRkVKW.mjs.map} +1 -1
  373. package/dist/{public-url-CUWWFME2.mjs → public-url-egRHCy1m.mjs} +1 -1
  374. package/dist/{public-url-CUWWFME2.mjs.map → public-url-egRHCy1m.mjs.map} +1 -1
  375. package/dist/{query-7m6-l0f_.mjs → query-Bt52mHXp.mjs} +19 -18
  376. package/dist/query-Bt52mHXp.mjs.map +1 -0
  377. package/dist/{rate-limit-D8RAXN8b.mjs → rate-limit-D6VQqBk_.mjs} +2 -2
  378. package/dist/{rate-limit-D8RAXN8b.mjs.map → rate-limit-D6VQqBk_.mjs.map} +1 -1
  379. package/dist/{redirect-CjfDGrTd.mjs → redirect-BZUJltlj.mjs} +2 -2
  380. package/dist/{redirect-CjfDGrTd.mjs.map → redirect-BZUJltlj.mjs.map} +1 -1
  381. package/dist/{redirect-BINiRYq4.mjs → redirect-Cw3JTlmj.mjs} +1 -1
  382. package/dist/{redirect-BINiRYq4.mjs.map → redirect-Cw3JTlmj.mjs.map} +1 -1
  383. package/dist/{redirects-COMLwsV5.mjs → redirects-C0L9JUk4.mjs} +19 -6
  384. package/dist/redirects-C0L9JUk4.mjs.map +1 -0
  385. package/dist/{redirects-CowoEHdE.mjs → redirects-DnYuqsEf.mjs} +3 -3
  386. package/dist/{redirects-CowoEHdE.mjs.map → redirects-DnYuqsEf.mjs.map} +1 -1
  387. package/dist/{registry-Cyp-dx6J.mjs → registry-Dn6gsx3L.mjs} +13 -5
  388. package/dist/{registry-Cyp-dx6J.mjs.map → registry-Dn6gsx3L.mjs.map} +1 -1
  389. package/dist/{request-cache-dzCt8TZB.mjs → request-cache-BYMs-BGX.mjs} +23 -2
  390. package/dist/{request-cache-dzCt8TZB.mjs.map → request-cache-BYMs-BGX.mjs.map} +1 -1
  391. package/dist/{request-meta-C_Cjii-T.mjs → request-meta-7ByVLxB-.mjs} +2 -2
  392. package/dist/{request-meta-C_Cjii-T.mjs.map → request-meta-7ByVLxB-.mjs.map} +1 -1
  393. package/dist/{resolve-D6sM-SgF.mjs → resolve-BqYMVG0D.mjs} +1 -1
  394. package/dist/{resolve-D6sM-SgF.mjs.map → resolve-BqYMVG0D.mjs.map} +1 -1
  395. package/dist/{runner-DSQBurMS.d.mts → runner-DM1yR5qd.d.mts} +2 -2
  396. package/dist/{runner-DSQBurMS.d.mts.map → runner-DM1yR5qd.d.mts.map} +1 -1
  397. package/dist/{runner-Drnvs96u.mjs → runner-eAgyIkeg.mjs} +284 -158
  398. package/dist/runner-eAgyIkeg.mjs.map +1 -0
  399. package/dist/runtime.d.mts +10 -10
  400. package/dist/runtime.mjs +2 -2
  401. package/dist/{schema-CI9mYPX3.mjs → schema--mYZX4D7.mjs} +5 -5
  402. package/dist/{schema-CI9mYPX3.mjs.map → schema--mYZX4D7.mjs.map} +1 -1
  403. package/dist/{search-DKz_mGBP.mjs → search-C6U_NvZI.mjs} +4 -4
  404. package/dist/{search-DKz_mGBP.mjs.map → search-C6U_NvZI.mjs.map} +1 -1
  405. package/dist/{secrets-rPdhEBkD.mjs → secrets-YYbTgB1w.mjs} +1 -1
  406. package/dist/{secrets-rPdhEBkD.mjs.map → secrets-YYbTgB1w.mjs.map} +1 -1
  407. package/dist/{sections-DBbCDIAT.mjs → sections-Ba-rJLKb.mjs} +3 -3
  408. package/dist/{sections-DBbCDIAT.mjs.map → sections-Ba-rJLKb.mjs.map} +1 -1
  409. package/dist/seed/index.d.mts +2 -2
  410. package/dist/seed/index.mjs +18 -17
  411. package/dist/seo/index.d.mts +1 -1
  412. package/dist/{seo-BGCyDlkb.mjs → seo-BTzb5ksq.mjs} +2 -2
  413. package/dist/{seo-BGCyDlkb.mjs.map → seo-BTzb5ksq.mjs.map} +1 -1
  414. package/dist/{seo-Dq707mNQ.mjs → seo-DfjLvu8i.mjs} +1 -1
  415. package/dist/{seo-Dq707mNQ.mjs.map → seo-DfjLvu8i.mjs.map} +1 -1
  416. package/dist/{service-B0H7U1Y9.mjs → service-Cn-kIfZn.mjs} +3 -3
  417. package/dist/{service-B0H7U1Y9.mjs.map → service-Cn-kIfZn.mjs.map} +1 -1
  418. package/dist/{settings-DfwNyQkf.mjs → settings-C65OSm41.mjs} +3 -3
  419. package/dist/{settings-DfwNyQkf.mjs.map → settings-C65OSm41.mjs.map} +1 -1
  420. package/dist/{settings-BSXRtTzk.mjs → settings-ChlQbwU0.mjs} +4 -4
  421. package/dist/{settings-BSXRtTzk.mjs.map → settings-ChlQbwU0.mjs.map} +1 -1
  422. package/dist/{setup-complete-MzzN9u0b.mjs → setup-complete-VoEZfasi.mjs} +1 -1
  423. package/dist/{setup-complete-MzzN9u0b.mjs.map → setup-complete-VoEZfasi.mjs.map} +1 -1
  424. package/dist/{setup-nonce-DXuriHsg.mjs → setup-nonce-Bm0uKqmf.mjs} +1 -1
  425. package/dist/{setup-nonce-DXuriHsg.mjs.map → setup-nonce-Bm0uKqmf.mjs.map} +1 -1
  426. package/dist/{site-url-xkhw1tcz.mjs → site-url-Cm8-sJy7.mjs} +1 -1
  427. package/dist/{site-url-xkhw1tcz.mjs.map → site-url-Cm8-sJy7.mjs.map} +1 -1
  428. package/dist/{ssrf-MZ-zrG6-.mjs → ssrf-BsVGIE0Z.mjs} +1 -1
  429. package/dist/{ssrf-MZ-zrG6-.mjs.map → ssrf-BsVGIE0Z.mjs.map} +1 -1
  430. package/dist/storage/local.d.mts +1 -1
  431. package/dist/storage/local.mjs +1 -1
  432. package/dist/storage/s3.d.mts +1 -1
  433. package/dist/storage/s3.mjs +1 -1
  434. package/dist/{taxonomies-CcvrMLbR.mjs → taxonomies-ByLlXrv5.mjs} +8 -8
  435. package/dist/{taxonomies-CcvrMLbR.mjs.map → taxonomies-ByLlXrv5.mjs.map} +1 -1
  436. package/dist/{taxonomies-4vx0nmMr.mjs → taxonomies-CbO6v7EE.mjs} +4 -4
  437. package/dist/{taxonomies-4vx0nmMr.mjs.map → taxonomies-CbO6v7EE.mjs.map} +1 -1
  438. package/dist/{taxonomy-zqGQUqgu.mjs → taxonomy-BBK-UAEo.mjs} +3 -3
  439. package/dist/{taxonomy-zqGQUqgu.mjs.map → taxonomy-BBK-UAEo.mjs.map} +1 -1
  440. package/dist/{tokens-N8otWMmj.mjs → tokens-Bx2afeT-.mjs} +1 -1
  441. package/dist/{tokens-N8otWMmj.mjs.map → tokens-Bx2afeT-.mjs.map} +1 -1
  442. package/dist/{transport-B6CHddbu.mjs → transport--Ck3RBin.mjs} +1 -1
  443. package/dist/{transport-B6CHddbu.mjs.map → transport--Ck3RBin.mjs.map} +1 -1
  444. package/dist/{transport-C2MGqtL6.d.mts → transport-OnMNbsIA.d.mts} +1 -1
  445. package/dist/{transport-C2MGqtL6.d.mts.map → transport-OnMNbsIA.d.mts.map} +1 -1
  446. package/dist/{trusted-proxy-97pajC2f.mjs → trusted-proxy-B4AfnoAp.mjs} +1 -1
  447. package/dist/{trusted-proxy-97pajC2f.mjs.map → trusted-proxy-B4AfnoAp.mjs.map} +1 -1
  448. package/dist/types-D8bhH891.mjs +125 -0
  449. package/dist/{types-DSZl1Dsv.mjs.map → types-D8bhH891.mjs.map} +1 -1
  450. package/dist/{types-DGHWRQgr.d.mts → types-DMwSpvcw.d.mts} +2 -2
  451. package/dist/{types-DGHWRQgr.d.mts.map → types-DMwSpvcw.d.mts.map} +1 -1
  452. package/dist/{types-bYmRn_Uy.d.mts → types-DWnN7weG.d.mts} +1 -1
  453. package/dist/{types-bYmRn_Uy.d.mts.map → types-DWnN7weG.d.mts.map} +1 -1
  454. package/dist/{types-Dgo6y-Ut.d.mts → types-DX6v9KzJ.d.mts} +1 -1
  455. package/dist/{types-Dgo6y-Ut.d.mts.map → types-DX6v9KzJ.d.mts.map} +1 -1
  456. package/dist/{types-DaqNzqVt.d.mts → types-DawhLFwy.d.mts} +35 -1
  457. package/dist/{types-DaqNzqVt.d.mts.map → types-DawhLFwy.d.mts.map} +1 -1
  458. package/dist/{types-CpUuGcd5.d.mts → types-DbCWhHet.d.mts} +8 -2
  459. package/dist/{types-CpUuGcd5.d.mts.map → types-DbCWhHet.d.mts.map} +1 -1
  460. package/dist/{types-Cd9UCu3t.mjs → types-DpFmlNyB.mjs} +1 -1
  461. package/dist/{types-Cd9UCu3t.mjs.map → types-DpFmlNyB.mjs.map} +1 -1
  462. package/dist/{types-D599-ruj.d.mts → types-Qa7-HJJC.d.mts} +1 -1
  463. package/dist/{types-D599-ruj.d.mts.map → types-Qa7-HJJC.d.mts.map} +1 -1
  464. package/dist/{types-B0bmgwMG.mjs → types-SF1DwGf2.mjs} +2 -2
  465. package/dist/types-SF1DwGf2.mjs.map +1 -0
  466. package/dist/{types-DaYDYW6g.d.mts → types-i8_uzhMD.d.mts} +40 -2
  467. package/dist/types-i8_uzhMD.d.mts.map +1 -0
  468. package/dist/{types-CkDSF81F.d.mts → types-kwqCOUxj.d.mts} +1 -1
  469. package/dist/{types-CkDSF81F.d.mts.map → types-kwqCOUxj.d.mts.map} +1 -1
  470. package/dist/{user-hUSOaIJy.mjs → user-X4rtyO4Y.mjs} +2 -2
  471. package/dist/{user-hUSOaIJy.mjs.map → user-X4rtyO4Y.mjs.map} +1 -1
  472. package/dist/{utils-C3wTAP-P.mjs → utils-C4Ih4DML.mjs} +1 -1
  473. package/dist/{utils-C3wTAP-P.mjs.map → utils-C4Ih4DML.mjs.map} +1 -1
  474. package/dist/{validate-IGltez8n.mjs → validate-DactmcJG.mjs} +23 -3
  475. package/dist/validate-DactmcJG.mjs.map +1 -0
  476. package/dist/{validate-DQtHw9NT.d.mts → validate-Dy6nkNls.d.mts} +25 -5
  477. package/dist/{validate-DQtHw9NT.d.mts.map → validate-Dy6nkNls.d.mts.map} +1 -1
  478. package/dist/{validation-Bmymau7y.mjs → validation-BYA4i85b.mjs} +6 -6
  479. package/dist/{validation-Bmymau7y.mjs.map → validation-BYA4i85b.mjs.map} +1 -1
  480. package/dist/version-CWbvq9LG.mjs +7 -0
  481. package/dist/{version-ITD3PlQd.mjs.map → version-CWbvq9LG.mjs.map} +1 -1
  482. package/dist/{widgets-yHQa4c6c.mjs → widgets-DG-1jxnz.mjs} +3 -3
  483. package/dist/{widgets-yHQa4c6c.mjs.map → widgets-DG-1jxnz.mjs.map} +1 -1
  484. package/dist/{zod-generator-B80aap1J.mjs → zod-generator-BNAObjSt.mjs} +3 -3
  485. package/dist/{zod-generator-B80aap1J.mjs.map → zod-generator-BNAObjSt.mjs.map} +1 -1
  486. package/package.json +7 -7
  487. package/src/api/errors.ts +7 -0
  488. package/src/api/handlers/byline-fields.ts +212 -0
  489. package/src/api/handlers/bylines.ts +126 -5
  490. package/src/api/handlers/content.ts +43 -2
  491. package/src/api/handlers/media.ts +2 -0
  492. package/src/api/openapi/document.ts +3 -0
  493. package/src/api/schemas/byline-fields.ts +188 -0
  494. package/src/api/schemas/bylines.ts +42 -0
  495. package/src/api/schemas/content.ts +2 -0
  496. package/src/api/schemas/index.ts +1 -0
  497. package/src/api/schemas/media.ts +2 -0
  498. package/src/astro/integration/routes.ts +27 -0
  499. package/src/astro/integration/vite-config.ts +16 -0
  500. package/src/astro/middleware/redirect.ts +5 -1
  501. package/src/astro/routes/api/admin/byline-fields/[slug]/usage.ts +36 -0
  502. package/src/astro/routes/api/admin/byline-fields/[slug].ts +92 -0
  503. package/src/astro/routes/api/admin/byline-fields/index.ts +66 -0
  504. package/src/astro/routes/api/admin/byline-fields/reorder.ts +39 -0
  505. package/src/astro/routes/api/admin/bylines/[id]/index.ts +23 -21
  506. package/src/astro/routes/api/admin/bylines/index.ts +1 -0
  507. package/src/astro/routes/api/auth/me.ts +21 -10
  508. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +15 -3
  509. package/src/astro/routes/api/content/[collection]/[id].ts +3 -1
  510. package/src/astro/routes/api/media.ts +1 -0
  511. package/src/astro/types.ts +1 -0
  512. package/src/bylines/field-defs-cache.ts +138 -0
  513. package/src/bylines/index.ts +37 -4
  514. package/src/cli/commands/content.ts +4 -2
  515. package/src/cli/commands/export-seed.ts +174 -12
  516. package/src/client/index.ts +4 -1
  517. package/src/components/InlinePortableTextEditor.tsx +69 -0
  518. package/src/content/converters/portable-text-to-prosemirror.ts +7 -0
  519. package/src/content/converters/prosemirror-to-portable-text.ts +16 -0
  520. package/src/content/converters/types.ts +10 -0
  521. package/src/database/migrations/041_content_locale_list_index.ts +47 -0
  522. package/src/database/migrations/042_byline_fields.ts +157 -0
  523. package/src/database/migrations/runner.ts +4 -0
  524. package/src/database/repositories/byline.ts +758 -50
  525. package/src/database/repositories/content.ts +43 -3
  526. package/src/database/repositories/media.ts +14 -0
  527. package/src/database/repositories/types.ts +38 -0
  528. package/src/database/types.ts +44 -0
  529. package/src/emdash-runtime.ts +4 -1
  530. package/src/index.ts +1 -0
  531. package/src/loader.ts +98 -10
  532. package/src/mcp/server.ts +10 -1
  533. package/src/query.ts +7 -7
  534. package/src/request-cache.ts +23 -0
  535. package/src/schema/byline-registry.ts +671 -0
  536. package/src/schema/registry.ts +14 -0
  537. package/src/schema/types.ts +133 -0
  538. package/src/seed/apply.ts +101 -14
  539. package/src/seed/types.ts +21 -0
  540. package/src/seed/validate.ts +39 -0
  541. package/dist/api-BNKqxyFX.mjs.map +0 -1
  542. package/dist/apply-BOPaD-s9.mjs.map +0 -1
  543. package/dist/byline-BDylH_m4.mjs +0 -404
  544. package/dist/byline-BDylH_m4.mjs.map +0 -1
  545. package/dist/bylines-B7TFEvFf.mjs +0 -118
  546. package/dist/bylines-B7TFEvFf.mjs.map +0 -1
  547. package/dist/bylines-DWLnr6-k.d.mts.map +0 -1
  548. package/dist/content-8voQNTXX.mjs.map +0 -1
  549. package/dist/error-ChfADBuu.mjs.map +0 -1
  550. package/dist/index-D_p_jIP1.d.mts.map +0 -1
  551. package/dist/loader-D-vIJjfY.mjs.map +0 -1
  552. package/dist/media-CKQd8AYU.mjs.map +0 -1
  553. package/dist/menus-C-nWT5Tu.mjs.map +0 -1
  554. package/dist/query-7m6-l0f_.mjs.map +0 -1
  555. package/dist/redirects-COMLwsV5.mjs.map +0 -1
  556. package/dist/runner-Drnvs96u.mjs.map +0 -1
  557. package/dist/setup-Cf_TyOv5.mjs +0 -137
  558. package/dist/setup-Cf_TyOv5.mjs.map +0 -1
  559. package/dist/types-B0bmgwMG.mjs.map +0 -1
  560. package/dist/types-DSZl1Dsv.mjs +0 -83
  561. package/dist/types-DaYDYW6g.d.mts.map +0 -1
  562. package/dist/validate-IGltez8n.mjs.map +0 -1
  563. package/dist/version-ITD3PlQd.mjs +0 -7
  564. /package/dist/{api-tokens-iPIHAY8N.mjs → api-tokens-B6VgoE6M.mjs} +0 -0
  565. /package/dist/{ssrf-BIcd-aXW.mjs → ssrf-BvgVcfNQ.mjs} +0 -0
  566. /package/dist/{types-1NNkmTIn.mjs → types-Cj2S6FuC.mjs} +0 -0
@@ -0,0 +1,925 @@
1
+ import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
2
+ import { c as listTablesLike } from "./dialect-helpers-BKCvISIQ.mjs";
3
+ import { i as encodeCursor, r as decodeCursor, t as EmDashValidationError } from "./types-SF1DwGf2.mjs";
4
+ import { t as withTransaction } from "./transaction-NQj4VJ7Z.mjs";
5
+ import { getRequestContext } from "./request-context.mjs";
6
+ import { i as setRequestCacheEntry, n as peekRequestCache, r as requestCached, t as clearRequestCacheEntry } from "./request-cache-BYMs-BGX.mjs";
7
+ import { n as BylineSchemaRegistry } from "./byline-registry-CxK5g559.mjs";
8
+ import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-BAYkM-CF.mjs";
9
+ import { sql } from "kysely";
10
+ import { ulid } from "ulidx";
11
+
12
+ //#region src/bylines/field-defs-cache.ts
13
+ const HOLDER_KEY = Symbol.for("emdash:byline-field-defs");
14
+ const g = globalThis;
15
+ const holder = g[HOLDER_KEY] ?? (() => {
16
+ const h = {
17
+ cached: null,
18
+ cachedVersion: -1
19
+ };
20
+ g[HOLDER_KEY] = h;
21
+ return h;
22
+ })();
23
+ const REQUEST_CACHE_KEY_VERSION = "byline-fields-version";
24
+ const REQUEST_CACHE_KEY_DEFS_PREFIX = "byline-field-defs:";
25
+ /**
26
+ * Read the persisted `options.byline_fields_version` counter. Cached for
27
+ * the duration of the current request via `requestCached`. Returns `0`
28
+ * when the row is missing (matches `BylineSchemaRegistry.getVersion`).
29
+ */
30
+ async function getBylineFieldsVersion(db) {
31
+ return requestCached(REQUEST_CACHE_KEY_VERSION, () => new BylineSchemaRegistry(db).getVersion());
32
+ }
33
+ /**
34
+ * Resolve registered byline custom-field definitions. Two-tier cache:
35
+ * per-request via `requestCached`, then per-isolate via the global
36
+ * holder.
37
+ *
38
+ * The global holder is bypassed for isolated requests (playground / DO
39
+ * preview, which point at a divergent schema) and for dirty versions
40
+ * (odd counter — see `BylineSchemaRegistry`'s class JSDoc — indicates
41
+ * an in-flight or crashed mutation). Both bypass paths still hit the
42
+ * per-request cache, so a single render dedupes within itself.
43
+ *
44
+ * Always returns an array. Empty = no custom fields registered.
45
+ */
46
+ async function getBylineFieldDefs(db) {
47
+ const isolated = getRequestContext()?.dbIsIsolated === true;
48
+ const version = await getBylineFieldsVersion(db);
49
+ const dirty = version % 2 !== 0;
50
+ return requestCached(`${REQUEST_CACHE_KEY_DEFS_PREFIX}${version}`, async () => {
51
+ if (isolated || dirty) return new BylineSchemaRegistry(db).listFields();
52
+ if (holder.cached !== null && holder.cachedVersion === version) return holder.cached;
53
+ const defs = new BylineSchemaRegistry(db).listFields().catch((error) => {
54
+ if (holder.cached === defs) {
55
+ holder.cached = null;
56
+ holder.cachedVersion = -1;
57
+ }
58
+ throw error;
59
+ });
60
+ holder.cached = defs;
61
+ holder.cachedVersion = version;
62
+ return defs;
63
+ });
64
+ }
65
+
66
+ //#endregion
67
+ //#region src/database/repositories/byline.ts
68
+ function rowToByline(row) {
69
+ return {
70
+ id: row.id,
71
+ slug: row.slug,
72
+ displayName: row.display_name,
73
+ bio: row.bio,
74
+ avatarMediaId: row.avatar_media_id,
75
+ avatarStorageKey: row.avatar_storage_key ?? null,
76
+ avatarAlt: row.avatar_alt ?? null,
77
+ websiteUrl: row.website_url,
78
+ userId: row.user_id,
79
+ isGuest: row.is_guest === 1,
80
+ createdAt: row.created_at,
81
+ updatedAt: row.updated_at,
82
+ locale: row.locale,
83
+ translationGroup: row.translation_group
84
+ };
85
+ }
86
+ /**
87
+ * Merge a single decoded value into a `BylineSummary.customFields` map.
88
+ * Centralised so the merge semantics (null storage, JSON.parse failure
89
+ * handling) live in one place across both translatable and group-shared
90
+ * paths.
91
+ *
92
+ * A stored row with `value = NULL` (representing an explicit null) is
93
+ * surfaced as `null` in `customFields`. A row with a malformed JSON
94
+ * payload is dropped silently with a `console.warn` — a corrupted
95
+ * payload shouldn't break the entire byline hydration; the field-defs
96
+ * cache will let admins replace the value, and the warning makes the
97
+ * issue debuggable. (Storage path uses `JSON.stringify`, so the only
98
+ * way to get malformed JSON is direct DB tampering or a future
99
+ * migration bug.)
100
+ */
101
+ function assignCustomFieldValue(summary, field, stored) {
102
+ const target = summary.customFields ?? {};
103
+ if (stored === null) target[field.slug] = null;
104
+ else try {
105
+ target[field.slug] = JSON.parse(stored);
106
+ } catch {
107
+ console.warn(`[BylineRepository] dropping malformed JSON for byline=${summary.id} field=${field.slug}: ${stored.slice(0, 60)}`);
108
+ return;
109
+ }
110
+ summary.customFields = target;
111
+ }
112
+ /**
113
+ * Coerce a raw write-path value to `CustomFieldValue`, throwing
114
+ * `EmDashValidationError` on type mismatch. `null` clears the field
115
+ * (DELETE in the write path).
116
+ *
117
+ * TODO: `field.required` is not enforced. The admin UI exposes the
118
+ * toggle but the backend accepts missing values; design pass needed
119
+ * on the enforcement model.
120
+ */
121
+ function coerceFieldValue(field, raw) {
122
+ if (raw === null) return null;
123
+ switch (field.type) {
124
+ case "string":
125
+ case "text":
126
+ if (typeof raw !== "string") throw new EmDashValidationError(`Byline field "${field.slug}" expects a string value (received ${typeof raw})`, {
127
+ slug: field.slug,
128
+ type: field.type,
129
+ received: typeof raw
130
+ });
131
+ return raw;
132
+ case "url": {
133
+ if (typeof raw !== "string") throw new EmDashValidationError(`Byline field "${field.slug}" expects a string value (received ${typeof raw})`, {
134
+ slug: field.slug,
135
+ type: field.type,
136
+ received: typeof raw
137
+ });
138
+ if (raw === "") return raw;
139
+ let parsed;
140
+ try {
141
+ parsed = new URL(raw);
142
+ } catch {
143
+ throw new EmDashValidationError(`Byline field "${field.slug}" expects a valid URL (received "${raw}")`, {
144
+ slug: field.slug,
145
+ type: field.type,
146
+ received: raw
147
+ });
148
+ }
149
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new EmDashValidationError(`Byline field "${field.slug}" must use http or https scheme (received "${parsed.protocol}")`, {
150
+ slug: field.slug,
151
+ type: field.type,
152
+ received: raw,
153
+ protocol: parsed.protocol
154
+ });
155
+ return raw;
156
+ }
157
+ case "boolean":
158
+ if (typeof raw !== "boolean") throw new EmDashValidationError(`Byline field "${field.slug}" expects a boolean value (received ${typeof raw})`, {
159
+ slug: field.slug,
160
+ type: field.type,
161
+ received: typeof raw
162
+ });
163
+ return raw;
164
+ case "select": {
165
+ if (typeof raw !== "string") throw new EmDashValidationError(`Byline field "${field.slug}" expects a string value (received ${typeof raw})`, {
166
+ slug: field.slug,
167
+ type: field.type,
168
+ received: typeof raw
169
+ });
170
+ const options = field.validation?.options ?? [];
171
+ if (!options.includes(raw)) throw new EmDashValidationError(`Byline field "${field.slug}" value "${raw}" is not one of the registered choices`, {
172
+ slug: field.slug,
173
+ value: raw,
174
+ options
175
+ });
176
+ return raw;
177
+ }
178
+ }
179
+ }
180
+ /**
181
+ * Byline repository for content credits.
182
+ *
183
+ * Bylines are per-locale (migration 040). Translations of the same byline
184
+ * share a `translation_group` ULID. `_emdash_content_bylines.byline_id` and
185
+ * `ec_*.primary_byline_id` store the translation_group (not a row id) so a
186
+ * single credit spans every locale variant of a byline.
187
+ *
188
+ * The repository does not resolve locale fallbacks on its own — callers
189
+ * supply the locale they want. Hydration is strict per locale: a credit at
190
+ * locale X renders iff a byline row exists at locale X within the credited
191
+ * translation group. This mirrors `TaxonomyRepository.getTermsForEntry` and
192
+ * the convention established by PR #916.
193
+ *
194
+ * Runtime helpers in `packages/core/src/bylines/index.ts` may layer fallback
195
+ * resolution on top for the "look up one byline by slug" path, but the
196
+ * relation-hydration methods on this class are always strict.
197
+ */
198
+ var BylineRepository = class {
199
+ constructor(db) {
200
+ this.db = db;
201
+ }
202
+ /**
203
+ * Merge `customFields` onto each `BylineSummary` produced from the
204
+ * given rows. Two batched queries total — one against
205
+ * `_emdash_byline_field_values` (keyed by `byline_id`), one against
206
+ * `_emdash_byline_field_group_values` (keyed by `translation_group`)
207
+ * — both chunked at `SQL_BATCH_SIZE` for D1's bound-parameter cap.
208
+ *
209
+ * When zero fields are registered, every row gets `customFields = {}`
210
+ * with no value-table reads (the field-defs cache returns `[]`).
211
+ * Group-shared values are looked up via the row's `translation_group`,
212
+ * so every locale sibling of the same byline identity sees the same
213
+ * non-translatable value without re-reading per row.
214
+ *
215
+ * **Duplicate-row handling.** Callers (notably `getContentBylinesMany`
216
+ * for list views with repeated authors) can pass the same byline row
217
+ * multiple times. We assign values by *iterating both `rows` and
218
+ * `summaries` in lockstep by index*, not by deduping into a Map keyed
219
+ * on byline id. A Map approach silently drops earlier duplicates' merge
220
+ * step (last writer wins, earlier instances keep their initial `{}`).
221
+ * Iterating by index gives every duplicate its own merged copy.
222
+ *
223
+ * Hydration is *strict per row* — values are merged onto whichever
224
+ * `BylineRow` produced them. Fallback semantics (e.g. "if no value
225
+ * for this locale, show the default-locale value") are not the
226
+ * repository's concern; consumers layer them on top if wanted, the
227
+ * same way `BylineRepository` doesn't resolve locale fallback for
228
+ * the base byline lookup.
229
+ */
230
+ async withCustomFields(rows) {
231
+ const summaries = rows.map(rowToByline);
232
+ for (const summary of summaries) summary.customFields = {};
233
+ await this.applyCustomFieldsTo(summaries);
234
+ return summaries;
235
+ }
236
+ async withCustomFieldsOne(row) {
237
+ if (!row) return null;
238
+ const [result] = await this.withCustomFields([row]);
239
+ return result ?? null;
240
+ }
241
+ /**
242
+ * Hydrate `customFields` on each `BylineSummary`, mutating in place.
243
+ *
244
+ * The public entry point for callers that fetch byline rows in
245
+ * multiple passes (e.g. `getBylinesForEntries`, which buckets by
246
+ * locale and calls `getContentBylinesMany` per bucket) and want a
247
+ * single batched hydration over the union of bylines, not one per
248
+ * pass. Use with the `skipHydration` option on the read methods to
249
+ * defer customFields work to a single call here.
250
+ *
251
+ * Two batched queries total (translatable + group-shared) regardless
252
+ * of how many bylines, locales, or translation_groups are in the
253
+ * input — meets the Phase 3 query-count envelope for mixed-locale
254
+ * list views even when sibling locales reference disjoint
255
+ * translation_groups.
256
+ *
257
+ * Replaces any existing `customFields` on each summary with a freshly
258
+ * fetched map. Callers that want to merge rather than replace should
259
+ * not use this entry point.
260
+ */
261
+ async hydrateBylineCustomFields(summaries) {
262
+ for (const summary of summaries) summary.customFields = {};
263
+ await this.applyCustomFieldsTo(summaries);
264
+ }
265
+ /**
266
+ * Shared merge engine for `withCustomFields` and
267
+ * `hydrateBylineCustomFields`. Reads field defs (cached), batches the
268
+ * translatable + group-shared fetches, and walks `summaries` directly
269
+ * to apply values.
270
+ *
271
+ * Iterates `summaries` (not a `summaryById` map) so duplicate
272
+ * `BylineSummary` objects sharing the same `id` — e.g. the same
273
+ * author credited to multiple entries — each get their own merged
274
+ * values. The previous Map-based dedup silently dropped earlier
275
+ * duplicates' merge step.
276
+ */
277
+ async applyCustomFieldsTo(summaries) {
278
+ if (summaries.length === 0) return;
279
+ const defs = await getBylineFieldDefs(this.db);
280
+ if (defs.length === 0) return;
281
+ const fieldById = new Map(defs.map((d) => [d.id, d]));
282
+ const translatableByByline = /* @__PURE__ */ new Map();
283
+ const bylineIds = [...new Set(summaries.map((s) => s.id))];
284
+ for (const chunk of chunks(bylineIds, SQL_BATCH_SIZE)) {
285
+ const trRows = await this.db.selectFrom("_emdash_byline_field_values").select([
286
+ "byline_id",
287
+ "field_id",
288
+ "value"
289
+ ]).where("byline_id", "in", chunk).execute();
290
+ for (const trRow of trRows) {
291
+ let fieldMap = translatableByByline.get(trRow.byline_id);
292
+ if (!fieldMap) {
293
+ fieldMap = /* @__PURE__ */ new Map();
294
+ translatableByByline.set(trRow.byline_id, fieldMap);
295
+ }
296
+ fieldMap.set(trRow.field_id, trRow.value);
297
+ }
298
+ }
299
+ const groups = [...new Set(summaries.map((s) => s.translationGroup).filter((g) => typeof g === "string" && g.length > 0))];
300
+ const groupByGroup = await this.loadGroupValuesByIds(groups);
301
+ for (const summary of summaries) {
302
+ const trValues = translatableByByline.get(summary.id);
303
+ if (trValues) for (const [fieldId, value] of trValues) {
304
+ const field = fieldById.get(fieldId);
305
+ if (!field || !field.translatable) continue;
306
+ assignCustomFieldValue(summary, field, value);
307
+ }
308
+ if (summary.translationGroup) {
309
+ const grpValues = groupByGroup.get(summary.translationGroup);
310
+ if (grpValues) for (const [fieldId, value] of grpValues) {
311
+ const field = fieldById.get(fieldId);
312
+ if (!field || field.translatable) continue;
313
+ assignCustomFieldValue(summary, field, value);
314
+ }
315
+ }
316
+ }
317
+ }
318
+ /**
319
+ * Resolve the group-shared custom-field values for a set of
320
+ * translation_groups, sharing work across hydration calls within the
321
+ * same request via per-group `requestCached` entries.
322
+ *
323
+ * The non-translatable storage table (`_emdash_byline_field_group_values`)
324
+ * is keyed by `translation_group`, which is locale-agnostic. Combining
325
+ * this method with `skipHydration` on `getContentBylinesMany` and a
326
+ * single `hydrateBylineCustomFields` call (see
327
+ * `getBylinesForEntries`) keeps mixed-locale list hydration to **one**
328
+ * batched group-shared SQL per request — even with disjoint
329
+ * translation_groups across locale buckets. Solo callers (`findById`,
330
+ * `findMany`, etc.) still get the same per-call batching they had
331
+ * before; the cache simply means a second call in the same request
332
+ * for an overlapping group is free.
333
+ *
334
+ * Cache key: `byline-field-group-values:${groupId}` — one entry per
335
+ * group. Writes use `setRequestCacheEntry` (idempotent, doesn't
336
+ * overwrite); `BylineRepository.update` calls `clearRequestCacheEntry`
337
+ * after a group-shared write to keep the cache fresh within the same
338
+ * request.
339
+ */
340
+ async loadGroupValuesByIds(groups) {
341
+ const result = /* @__PURE__ */ new Map();
342
+ if (groups.length === 0) return result;
343
+ const missing = [];
344
+ for (const g of groups) {
345
+ const cached = peekRequestCache(`byline-field-group-values:${g}`);
346
+ if (cached) result.set(g, await cached);
347
+ else missing.push(g);
348
+ }
349
+ if (missing.length === 0) return result;
350
+ const fetched = /* @__PURE__ */ new Map();
351
+ for (const g of missing) fetched.set(g, /* @__PURE__ */ new Map());
352
+ for (const chunk of chunks(missing, SQL_BATCH_SIZE)) {
353
+ const grpRows = await this.db.selectFrom("_emdash_byline_field_group_values").select([
354
+ "translation_group",
355
+ "field_id",
356
+ "value"
357
+ ]).where("translation_group", "in", chunk).execute();
358
+ for (const grpRow of grpRows) {
359
+ const fieldMap = fetched.get(grpRow.translation_group);
360
+ if (!fieldMap) continue;
361
+ fieldMap.set(grpRow.field_id, grpRow.value);
362
+ }
363
+ }
364
+ for (const g of missing) {
365
+ const m = fetched.get(g);
366
+ if (!m) continue;
367
+ setRequestCacheEntry(`byline-field-group-values:${g}`, m);
368
+ result.set(g, m);
369
+ }
370
+ return result;
371
+ }
372
+ async findById(id) {
373
+ const row = await this.db.selectFrom("_emdash_bylines").selectAll().where("id", "=", id).executeTakeFirst();
374
+ return this.withCustomFieldsOne(row);
375
+ }
376
+ /**
377
+ * Find a byline by slug. When `locale` is provided, filter by it strictly.
378
+ * When omitted, returns the lowest-locale-code match (deterministic across
379
+ * calls). Mirrors `TaxonomyRepository.findBySlug`.
380
+ */
381
+ async findBySlug(slug, options) {
382
+ let query = this.db.selectFrom("_emdash_bylines").selectAll().where("slug", "=", slug);
383
+ if (options?.locale !== void 0) query = query.where("locale", "=", options.locale);
384
+ const row = await query.orderBy("locale", "asc").executeTakeFirst();
385
+ return this.withCustomFieldsOne(row);
386
+ }
387
+ /**
388
+ * Find the byline linked to a CMS user. Post-migration 040 the partial
389
+ * unique on user_id is `(user_id, locale)`, so `locale` is required to
390
+ * disambiguate when multiple locale variants exist. When omitted, returns
391
+ * the lowest-locale-code match.
392
+ */
393
+ async findByUserId(userId, options) {
394
+ let query = this.db.selectFrom("_emdash_bylines").selectAll().where("user_id", "=", userId);
395
+ if (options?.locale !== void 0) query = query.where("locale", "=", options.locale);
396
+ const row = await query.orderBy("locale", "asc").executeTakeFirst();
397
+ return this.withCustomFieldsOne(row);
398
+ }
399
+ async findMany(options) {
400
+ const limit = Math.min(Math.max(options?.limit ?? 50, 1), 100);
401
+ let query = this.db.selectFrom("_emdash_bylines").selectAll().orderBy("created_at", "desc").orderBy("id", "desc").limit(limit + 1);
402
+ if (options?.search) {
403
+ const term = `%${options.search.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_")}%`;
404
+ query = query.where((eb) => eb.or([eb("display_name", "like", term), eb("slug", "like", term)]));
405
+ }
406
+ if (options?.isGuest !== void 0) query = query.where("is_guest", "=", options.isGuest ? 1 : 0);
407
+ if (options?.userId !== void 0) query = query.where("user_id", "=", options.userId);
408
+ if (options?.locale !== void 0) query = query.where("locale", "=", options.locale);
409
+ if (options?.cursor) {
410
+ const decoded = decodeCursor(options.cursor);
411
+ query = query.where((eb) => eb.or([eb("created_at", "<", decoded.orderValue), eb.and([eb("created_at", "=", decoded.orderValue), eb("id", "<", decoded.id)])]));
412
+ }
413
+ const rows = await query.execute();
414
+ const pageRows = rows.slice(0, limit);
415
+ const items = await this.withCustomFields(pageRows);
416
+ const result = { items };
417
+ if (rows.length > limit) {
418
+ const last = items.at(-1);
419
+ if (last) result.nextCursor = encodeCursor(last.createdAt, last.id);
420
+ }
421
+ return result;
422
+ }
423
+ /**
424
+ * List every sibling row in `translation_group`. Used by the admin
425
+ * `TranslationsPanel` to render one entry per configured locale.
426
+ */
427
+ async listTranslations(id) {
428
+ const anchor = await this.findById(id);
429
+ if (!anchor) return [];
430
+ const group = anchor.translationGroup ?? anchor.id;
431
+ return this.findByTranslationGroup(group);
432
+ }
433
+ /**
434
+ * Direct lookup by `translation_group`. Returns every locale variant of a
435
+ * byline, ordered by locale code (deterministic).
436
+ */
437
+ async findByTranslationGroup(translationGroup) {
438
+ const rows = await this.db.selectFrom("_emdash_bylines").selectAll().where("translation_group", "=", translationGroup).orderBy("locale", "asc").execute();
439
+ return this.withCustomFields(rows);
440
+ }
441
+ /**
442
+ * Validate a `customFields` input map into a write list before any row
443
+ * write — throws `EmDashValidationError` on unknown slugs, type
444
+ * mismatches, or select-choice misses.
445
+ */
446
+ async resolveCustomFieldWrites(customFields) {
447
+ if (!customFields || Object.keys(customFields).length === 0) return [];
448
+ const defs = await getBylineFieldDefs(this.db);
449
+ const bySlug = new Map(defs.map((d) => [d.slug, d]));
450
+ const writes = [];
451
+ for (const [slug, raw] of Object.entries(customFields)) {
452
+ const field = bySlug.get(slug);
453
+ if (!field) throw new EmDashValidationError(`Unknown byline custom field "${slug}"`, {
454
+ slug,
455
+ registered: defs.map((d) => d.slug)
456
+ });
457
+ writes.push({
458
+ field,
459
+ value: coerceFieldValue(field, raw)
460
+ });
461
+ }
462
+ return writes;
463
+ }
464
+ /**
465
+ * Write a validated custom-field list against a byline row inside the
466
+ * caller's transaction. Per-field writes route to
467
+ * `_emdash_byline_field_values` (translatable) or
468
+ * `_emdash_byline_field_group_values` (group-shared); `null` clears.
469
+ * Returns `true` when any group-shared row was touched so the caller
470
+ * can invalidate the per-request cache post-commit.
471
+ */
472
+ async applyCustomFieldWritesInTrx(trx, bylineId, translationGroup, writes, now) {
473
+ if (writes.length === 0) return false;
474
+ let touchedGroupShared = false;
475
+ for (const { field, value } of writes) {
476
+ if (!field.translatable) touchedGroupShared = true;
477
+ if (field.translatable) if (value === null) await trx.deleteFrom("_emdash_byline_field_values").where("byline_id", "=", bylineId).where("field_id", "=", field.id).execute();
478
+ else {
479
+ const encoded = JSON.stringify(value);
480
+ await trx.insertInto("_emdash_byline_field_values").values({
481
+ byline_id: bylineId,
482
+ field_id: field.id,
483
+ value: encoded,
484
+ created_at: now,
485
+ updated_at: now
486
+ }).onConflict((oc) => oc.columns(["byline_id", "field_id"]).doUpdateSet({
487
+ value: encoded,
488
+ updated_at: now
489
+ })).execute();
490
+ }
491
+ else if (value === null) await trx.deleteFrom("_emdash_byline_field_group_values").where("translation_group", "=", translationGroup).where("field_id", "=", field.id).execute();
492
+ else {
493
+ const encoded = JSON.stringify(value);
494
+ await trx.insertInto("_emdash_byline_field_group_values").values({
495
+ translation_group: translationGroup,
496
+ field_id: field.id,
497
+ value: encoded,
498
+ created_at: now,
499
+ updated_at: now
500
+ }).onConflict((oc) => oc.columns(["translation_group", "field_id"]).doUpdateSet({
501
+ value: encoded,
502
+ updated_at: now
503
+ })).execute();
504
+ }
505
+ }
506
+ return touchedGroupShared;
507
+ }
508
+ async create(input) {
509
+ const id = ulid();
510
+ const now = (/* @__PURE__ */ new Date()).toISOString();
511
+ const customFieldWrites = await this.resolveCustomFieldWrites(input.customFields);
512
+ let translationGroup = id;
513
+ if (input.translationOf) {
514
+ const source = await this.findById(input.translationOf);
515
+ if (!source) throw new Error("Source byline for translation not found");
516
+ translationGroup = source.translationGroup ?? source.id;
517
+ }
518
+ let touchedGroupShared = false;
519
+ await withTransaction(this.db, async (trx) => {
520
+ await trx.insertInto("_emdash_bylines").values({
521
+ id,
522
+ slug: input.slug,
523
+ display_name: input.displayName,
524
+ bio: input.bio ?? null,
525
+ avatar_media_id: input.avatarMediaId ?? null,
526
+ website_url: input.websiteUrl ?? null,
527
+ user_id: input.userId ?? null,
528
+ is_guest: input.isGuest ? 1 : 0,
529
+ created_at: now,
530
+ updated_at: now,
531
+ ...input.locale !== void 0 ? { locale: input.locale } : {},
532
+ translation_group: translationGroup
533
+ }).execute();
534
+ touchedGroupShared = await this.applyCustomFieldWritesInTrx(trx, id, translationGroup, customFieldWrites, now);
535
+ });
536
+ if (touchedGroupShared) clearRequestCacheEntry(`byline-field-group-values:${translationGroup}`);
537
+ const byline = await this.findById(id);
538
+ if (!byline) throw new Error("Failed to create byline");
539
+ return byline;
540
+ }
541
+ async update(id, input) {
542
+ const existing = await this.findById(id);
543
+ if (!existing) return null;
544
+ const customFieldWrites = await this.resolveCustomFieldWrites(input.customFields);
545
+ const now = (/* @__PURE__ */ new Date()).toISOString();
546
+ const updates = { updated_at: now };
547
+ if (input.slug !== void 0) updates.slug = input.slug;
548
+ if (input.displayName !== void 0) updates.display_name = input.displayName;
549
+ if (input.bio !== void 0) updates.bio = input.bio;
550
+ if (input.avatarMediaId !== void 0) updates.avatar_media_id = input.avatarMediaId;
551
+ if (input.websiteUrl !== void 0) updates.website_url = input.websiteUrl;
552
+ if (input.userId !== void 0) updates.user_id = input.userId;
553
+ if (input.isGuest !== void 0) updates.is_guest = input.isGuest ? 1 : 0;
554
+ const group = existing.translationGroup ?? existing.id;
555
+ let touchedGroupShared = false;
556
+ await withTransaction(this.db, async (trx) => {
557
+ await trx.updateTable("_emdash_bylines").set(updates).where("id", "=", id).execute();
558
+ touchedGroupShared = await this.applyCustomFieldWritesInTrx(trx, id, group, customFieldWrites, now);
559
+ });
560
+ if (touchedGroupShared) clearRequestCacheEntry(`byline-field-group-values:${group}`);
561
+ return await this.findById(id);
562
+ }
563
+ /**
564
+ * Delete a byline row. When this row is the last sibling in its
565
+ * translation group, also drops every junction row pointing at the group,
566
+ * clears `primary_byline_id` references, and removes the byline's
567
+ * non-translatable custom-field values. When other siblings remain in
568
+ * the group, junctions, `primary_byline_id` pointers, and group-shared
569
+ * custom-field values stay intact — the credit (and its shared metadata)
570
+ * lives on at other locales.
571
+ *
572
+ * **Application-level cascade.** The byline domain has standardised on
573
+ * app-level cascade rather than trusting FK ON DELETE CASCADE, partly
574
+ * because migration 040 had to strip its own FK to support the
575
+ * translation_group remap (#1021), and partly so cleanup doesn't
576
+ * depend on `PRAGMA foreign_keys = ON` (set in production via
577
+ * `connection.ts:60`, but easy to bypass in tests, scripts, and
578
+ * one-off tools). Every byline-related deletion table is cleared
579
+ * explicitly here:
580
+ *
581
+ * - `_emdash_byline_field_values` (per-byline translatable values) —
582
+ * migration 041 declares FK ON DELETE CASCADE on `byline_id`; the
583
+ * explicit DELETE removes the dependency on that pragma.
584
+ * - `_emdash_content_bylines` — migration 040 dropped its FK.
585
+ * - `ec_*.primary_byline_id` — never had an FK.
586
+ * - `_emdash_byline_field_group_values` (translation-group-keyed) —
587
+ * keyed by a text column with no FK to bylines, so app-level cleanup
588
+ * is the only path.
589
+ *
590
+ * The FKs that remain (migration 041) serve as defense-in-depth.
591
+ */
592
+ async delete(id) {
593
+ const existing = await this.findById(id);
594
+ if (!existing) return false;
595
+ const group = existing.translationGroup ?? existing.id;
596
+ await withTransaction(this.db, async (trx) => {
597
+ await trx.deleteFrom("_emdash_byline_field_values").where("byline_id", "=", id).execute();
598
+ await trx.deleteFrom("_emdash_bylines").where("id", "=", id).execute();
599
+ const remaining = await trx.selectFrom("_emdash_bylines").select(({ fn }) => [fn.count("id").as("count")]).where("translation_group", "=", group).executeTakeFirst();
600
+ if (Number(remaining?.count ?? 0) > 0) return;
601
+ await trx.deleteFrom("_emdash_content_bylines").where("byline_id", "=", group).execute();
602
+ await trx.deleteFrom("_emdash_byline_field_group_values").where("translation_group", "=", group).execute();
603
+ const tableNames = await listTablesLike(trx, "ec_%");
604
+ for (const tableName of tableNames) {
605
+ validateIdentifier(tableName, "content table");
606
+ await sql`
607
+ UPDATE ${sql.ref(tableName)}
608
+ SET primary_byline_id = NULL
609
+ WHERE primary_byline_id = ${group}
610
+ `.execute(trx);
611
+ }
612
+ });
613
+ return true;
614
+ }
615
+ /**
616
+ * Strict per-locale credit hydration. Joins `_emdash_content_bylines` to
617
+ * `_emdash_bylines` on `translation_group = byline_id`, then filters to
618
+ * the requested locale. Credits whose translation group lacks a row at
619
+ * the requested locale are omitted — callers wanting fallback behaviour
620
+ * apply it themselves. Mirrors `TaxonomyRepository.getTermsForEntry`.
621
+ */
622
+ async getContentBylines(collectionSlug, contentId, options) {
623
+ let query = this.db.selectFrom("_emdash_content_bylines as cb").innerJoin("_emdash_bylines as b", "b.translation_group", "cb.byline_id").leftJoin("media as m", "m.id", "b.avatar_media_id").select([
624
+ "cb.sort_order as sort_order",
625
+ "cb.role_label as role_label",
626
+ "b.id as id",
627
+ "b.slug as slug",
628
+ "b.display_name as display_name",
629
+ "b.bio as bio",
630
+ "b.avatar_media_id as avatar_media_id",
631
+ "m.storage_key as avatar_storage_key",
632
+ "m.alt as avatar_alt",
633
+ "b.website_url as website_url",
634
+ "b.user_id as user_id",
635
+ "b.is_guest as is_guest",
636
+ "b.created_at as created_at",
637
+ "b.updated_at as updated_at",
638
+ "b.locale as locale",
639
+ "b.translation_group as translation_group"
640
+ ]).where("cb.collection_slug", "=", collectionSlug).where("cb.content_id", "=", contentId).orderBy("cb.sort_order", "asc");
641
+ if (options?.locale !== void 0) query = query.where("b.locale", "=", options.locale);
642
+ const rows = await query.execute();
643
+ const bylineRows = rows.map((row) => ({
644
+ id: row.id,
645
+ slug: row.slug,
646
+ display_name: row.display_name,
647
+ bio: row.bio,
648
+ avatar_media_id: row.avatar_media_id,
649
+ avatar_storage_key: row.avatar_storage_key,
650
+ avatar_alt: row.avatar_alt,
651
+ website_url: row.website_url,
652
+ user_id: row.user_id,
653
+ is_guest: row.is_guest,
654
+ created_at: row.created_at,
655
+ updated_at: row.updated_at,
656
+ locale: row.locale,
657
+ translation_group: row.translation_group
658
+ }));
659
+ const hydrated = await this.withCustomFields(bylineRows);
660
+ return rows.map((row, i) => {
661
+ const byline = hydrated[i];
662
+ if (!byline) throw new Error("getContentBylines: hydration row count mismatch");
663
+ return {
664
+ byline,
665
+ sortOrder: row.sort_order,
666
+ roleLabel: row.role_label
667
+ };
668
+ });
669
+ }
670
+ /**
671
+ * Does this entry have any explicit byline credits — at any locale?
672
+ *
673
+ * Used to disambiguate "no credits exist" (fall back to author-linked
674
+ * byline) from "credits exist but don't resolve at the requested locale"
675
+ * (strict per-locale model: render no byline). Without this check the
676
+ * locale-strict hydration would silently turn a missing translation into
677
+ * an author-inferred byline, contradicting editorial intent.
678
+ */
679
+ async hasContentBylines(collectionSlug, contentId) {
680
+ return await this.db.selectFrom("_emdash_content_bylines").select("id").where("collection_slug", "=", collectionSlug).where("content_id", "=", contentId).limit(1).executeTakeFirst() !== void 0;
681
+ }
682
+ /**
683
+ * Batch variant of `hasContentBylines`. Returns the set of content IDs
684
+ * that have at least one junction row (locale-agnostic).
685
+ */
686
+ async hasContentBylinesMany(collectionSlug, contentIds) {
687
+ const result = /* @__PURE__ */ new Set();
688
+ if (contentIds.length === 0) return result;
689
+ const uniqueContentIds = [...new Set(contentIds)];
690
+ for (const chunk of chunks(uniqueContentIds, SQL_BATCH_SIZE)) {
691
+ const rows = await this.db.selectFrom("_emdash_content_bylines").select("content_id").distinct().where("collection_slug", "=", collectionSlug).where("content_id", "in", chunk).execute();
692
+ for (const row of rows) result.add(row.content_id);
693
+ }
694
+ return result;
695
+ }
696
+ /**
697
+ * Batch variant of `getContentBylines`. Same strict-per-locale semantics
698
+ * applied to the requested locale (single value, not per-entry).
699
+ *
700
+ * When callers need per-entry-locale filtering (e.g. a list endpoint
701
+ * returning entries at mixed locales), they should group the input ids by
702
+ * the entry's locale and call this method once per group.
703
+ *
704
+ * When the caller will issue multiple `getContentBylinesMany` calls in
705
+ * one request (e.g. per locale bucket) and wants a *single* batched
706
+ * customFields hydration over the union of returned bylines, pass
707
+ * `skipHydration: true` on each call and finish with
708
+ * `hydrateBylineCustomFields(allBylines)`. The returned bylines carry
709
+ * `customFields = {}` until that hydration call runs — matching the
710
+ * "always populated" invariant from AC #6 — so callers that forget to
711
+ * hydrate get an empty map rather than `undefined`.
712
+ */
713
+ async getContentBylinesMany(collectionSlug, contentIds, options) {
714
+ const result = /* @__PURE__ */ new Map();
715
+ if (contentIds.length === 0) return result;
716
+ const uniqueContentIds = [...new Set(contentIds)];
717
+ for (const chunk of chunks(uniqueContentIds, SQL_BATCH_SIZE)) {
718
+ let query = this.db.selectFrom("_emdash_content_bylines as cb").innerJoin("_emdash_bylines as b", "b.translation_group", "cb.byline_id").leftJoin("media as m", "m.id", "b.avatar_media_id").select([
719
+ "cb.content_id as content_id",
720
+ "cb.sort_order as sort_order",
721
+ "cb.role_label as role_label",
722
+ "b.id as id",
723
+ "b.slug as slug",
724
+ "b.display_name as display_name",
725
+ "b.bio as bio",
726
+ "b.avatar_media_id as avatar_media_id",
727
+ "m.storage_key as avatar_storage_key",
728
+ "m.alt as avatar_alt",
729
+ "b.website_url as website_url",
730
+ "b.user_id as user_id",
731
+ "b.is_guest as is_guest",
732
+ "b.created_at as created_at",
733
+ "b.updated_at as updated_at",
734
+ "b.locale as locale",
735
+ "b.translation_group as translation_group"
736
+ ]).where("cb.collection_slug", "=", collectionSlug).where("cb.content_id", "in", chunk).orderBy("cb.sort_order", "asc");
737
+ if (options?.locale !== void 0) query = query.where("b.locale", "=", options.locale);
738
+ const rows = await query.execute();
739
+ const bylineRows = rows.map((row) => ({
740
+ id: row.id,
741
+ slug: row.slug,
742
+ display_name: row.display_name,
743
+ bio: row.bio,
744
+ avatar_media_id: row.avatar_media_id,
745
+ avatar_storage_key: row.avatar_storage_key,
746
+ avatar_alt: row.avatar_alt,
747
+ website_url: row.website_url,
748
+ user_id: row.user_id,
749
+ is_guest: row.is_guest,
750
+ created_at: row.created_at,
751
+ updated_at: row.updated_at,
752
+ locale: row.locale,
753
+ translation_group: row.translation_group
754
+ }));
755
+ let bylines;
756
+ if (options?.skipHydration === true) {
757
+ bylines = bylineRows.map(rowToByline);
758
+ for (const b of bylines) b.customFields = {};
759
+ } else bylines = await this.withCustomFields(bylineRows);
760
+ for (let i = 0; i < rows.length; i++) {
761
+ const row = rows[i];
762
+ const byline = bylines[i];
763
+ if (!row || !byline) continue;
764
+ const contentId = row.content_id;
765
+ const credit = {
766
+ byline,
767
+ sortOrder: row.sort_order,
768
+ roleLabel: row.role_label
769
+ };
770
+ const existing = result.get(contentId);
771
+ if (existing) existing.push(credit);
772
+ else result.set(contentId, [credit]);
773
+ }
774
+ }
775
+ return result;
776
+ }
777
+ /**
778
+ * Batch-fetch byline profiles linked to user IDs in a single query.
779
+ * Strict-locale variant of `findByUserId`.
780
+ *
781
+ * `skipHydration: true` returns bylines with `customFields = {}` so
782
+ * callers issuing multiple `findByUserIds` calls in one request (e.g.
783
+ * the per-locale-bucket author-fallback path in `getBylinesForEntries`)
784
+ * can defer customFields hydration to a single batched
785
+ * `hydrateBylineCustomFields` call across the union — keeping the
786
+ * Phase 3 query-count envelope at "+1 group-shared query per
787
+ * hydration pass" even when buckets fetch disjoint author bylines.
788
+ */
789
+ async findByUserIds(userIds, options) {
790
+ const result = /* @__PURE__ */ new Map();
791
+ if (userIds.length === 0) return result;
792
+ for (const chunk of chunks(userIds, SQL_BATCH_SIZE)) {
793
+ let query = this.db.selectFrom("_emdash_bylines as b").leftJoin("media as m", "m.id", "b.avatar_media_id").select([
794
+ "b.id as id",
795
+ "b.slug as slug",
796
+ "b.display_name as display_name",
797
+ "b.bio as bio",
798
+ "b.avatar_media_id as avatar_media_id",
799
+ "m.storage_key as avatar_storage_key",
800
+ "m.alt as avatar_alt",
801
+ "b.website_url as website_url",
802
+ "b.user_id as user_id",
803
+ "b.is_guest as is_guest",
804
+ "b.created_at as created_at",
805
+ "b.updated_at as updated_at",
806
+ "b.locale as locale",
807
+ "b.translation_group as translation_group"
808
+ ]).where("b.user_id", "in", chunk);
809
+ if (options?.locale !== void 0) query = query.where("b.locale", "=", options.locale);
810
+ const rows = await query.execute();
811
+ let bylines;
812
+ if (options?.skipHydration === true) {
813
+ bylines = rows.map(rowToByline);
814
+ for (const b of bylines) b.customFields = {};
815
+ } else bylines = await this.withCustomFields(rows);
816
+ for (let i = 0; i < rows.length; i++) {
817
+ const row = rows[i];
818
+ const summary = bylines[i];
819
+ if (!row || !summary || !row.user_id) continue;
820
+ result.set(row.user_id, summary);
821
+ }
822
+ }
823
+ return result;
824
+ }
825
+ /**
826
+ * Clone every junction row from `sourceContentId` to `targetContentId`,
827
+ * preserving `sort_order` and `role_label`. Used by the content
828
+ * translation flow: a newly created translation inherits the source's
829
+ * byline credits at the storage level. Because the junction stores
830
+ * `translation_group` (not a row id), the copy is locale-agnostic — the
831
+ * credits resolve to whichever locale variants of each byline exist when
832
+ * the translated entry is hydrated.
833
+ *
834
+ * No-op when the source has no credits. Skips when the target already
835
+ * has credits (idempotent for re-runs).
836
+ */
837
+ async copyContentBylines(collection, sourceContentId, targetContentId) {
838
+ validateIdentifier(collection, "collection slug");
839
+ const tableName = `ec_${collection}`;
840
+ validateIdentifier(tableName, "content table");
841
+ if (await this.db.selectFrom("_emdash_content_bylines").select("id").where("collection_slug", "=", collection).where("content_id", "=", targetContentId).executeTakeFirst()) return;
842
+ const sourceRows = await this.db.selectFrom("_emdash_content_bylines").select([
843
+ "byline_id",
844
+ "sort_order",
845
+ "role_label"
846
+ ]).where("collection_slug", "=", collection).where("content_id", "=", sourceContentId).orderBy("sort_order", "asc").execute();
847
+ if (sourceRows.length === 0) return;
848
+ const now = (/* @__PURE__ */ new Date()).toISOString();
849
+ await this.db.insertInto("_emdash_content_bylines").values(sourceRows.map((row) => ({
850
+ id: ulid(),
851
+ collection_slug: collection,
852
+ content_id: targetContentId,
853
+ byline_id: row.byline_id,
854
+ sort_order: row.sort_order,
855
+ role_label: row.role_label,
856
+ created_at: now
857
+ }))).execute();
858
+ const firstByline = sourceRows[0]?.byline_id ?? null;
859
+ await sql`
860
+ UPDATE ${sql.ref(tableName)}
861
+ SET primary_byline_id = ${firstByline}
862
+ WHERE id = ${targetContentId}
863
+ `.execute(this.db);
864
+ }
865
+ /**
866
+ * Replace the set of byline credits on a content entry. Accepts row ids
867
+ * at the wire (consistent with how the admin sends them), translates
868
+ * each to its `translation_group` on write, and stores the group in
869
+ * `_emdash_content_bylines.byline_id` and `ec_*.primary_byline_id`.
870
+ *
871
+ * The returned credits are hydrated with strict-locale matching at the
872
+ * locale of the rows the caller supplied (i.e. the locale of the byline
873
+ * each `bylineId` resolves to) — adequate for the autosave round-trip,
874
+ * which then re-hydrates the entry against its own locale separately.
875
+ */
876
+ async setContentBylines(collectionSlug, contentId, inputBylines) {
877
+ validateIdentifier(collectionSlug, "collection slug");
878
+ const tableName = `ec_${collectionSlug}`;
879
+ validateIdentifier(tableName, "content table");
880
+ const idToGroup = /* @__PURE__ */ new Map();
881
+ if (inputBylines.length > 0) {
882
+ const wireIds = [...new Set(inputBylines.map((item) => item.bylineId))];
883
+ const rows = await this.db.selectFrom("_emdash_bylines").select(["id", "translation_group"]).where("id", "in", wireIds).execute();
884
+ if (rows.length !== wireIds.length) throw new Error("One or more byline IDs do not exist");
885
+ for (const row of rows) idToGroup.set(row.id, row.translation_group ?? row.id);
886
+ }
887
+ const seenGroups = /* @__PURE__ */ new Set();
888
+ const bylines = [];
889
+ for (const item of inputBylines) {
890
+ const group = idToGroup.get(item.bylineId);
891
+ if (!group) throw new Error(`Missing translation_group for byline ${item.bylineId}`);
892
+ if (seenGroups.has(group)) continue;
893
+ seenGroups.add(group);
894
+ bylines.push({
895
+ ...item,
896
+ group
897
+ });
898
+ }
899
+ await this.db.deleteFrom("_emdash_content_bylines").where("collection_slug", "=", collectionSlug).where("content_id", "=", contentId).execute();
900
+ for (let i = 0; i < bylines.length; i++) {
901
+ const item = bylines[i];
902
+ if (!item) continue;
903
+ await this.db.insertInto("_emdash_content_bylines").values({
904
+ id: ulid(),
905
+ collection_slug: collectionSlug,
906
+ content_id: contentId,
907
+ byline_id: item.group,
908
+ sort_order: i,
909
+ role_label: item.roleLabel ?? null,
910
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
911
+ }).execute();
912
+ }
913
+ const primaryGroup = bylines[0]?.group ?? null;
914
+ await sql`
915
+ UPDATE ${sql.ref(tableName)}
916
+ SET primary_byline_id = ${primaryGroup}
917
+ WHERE id = ${contentId}
918
+ `.execute(this.db);
919
+ return await this.getContentBylines(collectionSlug, contentId);
920
+ }
921
+ };
922
+
923
+ //#endregion
924
+ export { BylineRepository as t };
925
+ //# sourceMappingURL=byline-BrIVWLm-.mjs.map