emdash 0.0.0-a → 0.0.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 (661) hide show
  1. package/README.md +87 -1
  2. package/dist/adapters-BLMa4JGD.d.mts +106 -0
  3. package/dist/adapters-BLMa4JGD.d.mts.map +1 -0
  4. package/dist/apply-Bjfq_b4-.mjs +1293 -0
  5. package/dist/apply-Bjfq_b4-.mjs.map +1 -0
  6. package/dist/astro/index.d.mts +51 -0
  7. package/dist/astro/index.d.mts.map +1 -0
  8. package/dist/astro/index.mjs +1333 -0
  9. package/dist/astro/index.mjs.map +1 -0
  10. package/dist/astro/middleware/auth.d.mts +31 -0
  11. package/dist/astro/middleware/auth.d.mts.map +1 -0
  12. package/dist/astro/middleware/auth.mjs +654 -0
  13. package/dist/astro/middleware/auth.mjs.map +1 -0
  14. package/dist/astro/middleware/redirect.d.mts +22 -0
  15. package/dist/astro/middleware/redirect.d.mts.map +1 -0
  16. package/dist/astro/middleware/redirect.mjs +63 -0
  17. package/dist/astro/middleware/redirect.mjs.map +1 -0
  18. package/dist/astro/middleware/request-context.d.mts +18 -0
  19. package/dist/astro/middleware/request-context.d.mts.map +1 -0
  20. package/dist/astro/middleware/request-context.mjs +1310 -0
  21. package/dist/astro/middleware/request-context.mjs.map +1 -0
  22. package/dist/astro/middleware/setup.d.mts +20 -0
  23. package/dist/astro/middleware/setup.d.mts.map +1 -0
  24. package/dist/astro/middleware/setup.mjs +47 -0
  25. package/dist/astro/middleware/setup.mjs.map +1 -0
  26. package/dist/astro/middleware.d.mts +13 -0
  27. package/dist/astro/middleware.d.mts.map +1 -0
  28. package/dist/astro/middleware.mjs +1613 -0
  29. package/dist/astro/middleware.mjs.map +1 -0
  30. package/dist/astro/types.d.mts +250 -0
  31. package/dist/astro/types.d.mts.map +1 -0
  32. package/dist/astro/types.mjs +1 -0
  33. package/dist/base64-MBPo9ozB.mjs +59 -0
  34. package/dist/base64-MBPo9ozB.mjs.map +1 -0
  35. package/dist/byline-CL847F26.mjs +213 -0
  36. package/dist/byline-CL847F26.mjs.map +1 -0
  37. package/dist/bylines-C2a-2TGt.mjs +136 -0
  38. package/dist/bylines-C2a-2TGt.mjs.map +1 -0
  39. package/dist/chunk-ClPoSABd.mjs +21 -0
  40. package/dist/cli/index.d.mts +1 -0
  41. package/dist/cli/index.mjs +3909 -0
  42. package/dist/cli/index.mjs.map +1 -0
  43. package/dist/client/cf-access.d.mts +60 -0
  44. package/dist/client/cf-access.d.mts.map +1 -0
  45. package/dist/client/cf-access.mjs +179 -0
  46. package/dist/client/cf-access.mjs.map +1 -0
  47. package/dist/client/index.d.mts +398 -0
  48. package/dist/client/index.d.mts.map +1 -0
  49. package/dist/client/index.mjs +346 -0
  50. package/dist/client/index.mjs.map +1 -0
  51. package/dist/config-CKE8p9xM.mjs +55 -0
  52. package/dist/config-CKE8p9xM.mjs.map +1 -0
  53. package/dist/connection-B4zVnQIa.mjs +40 -0
  54. package/dist/connection-B4zVnQIa.mjs.map +1 -0
  55. package/dist/content-D6C2WsZC.mjs +824 -0
  56. package/dist/content-D6C2WsZC.mjs.map +1 -0
  57. package/dist/db/index.d.mts +4 -0
  58. package/dist/db/index.mjs +62 -0
  59. package/dist/db/index.mjs.map +1 -0
  60. package/dist/db/libsql.d.mts +11 -0
  61. package/dist/db/libsql.d.mts.map +1 -0
  62. package/dist/db/libsql.mjs +17 -0
  63. package/dist/db/libsql.mjs.map +1 -0
  64. package/dist/db/postgres.d.mts +11 -0
  65. package/dist/db/postgres.d.mts.map +1 -0
  66. package/dist/db/postgres.mjs +30 -0
  67. package/dist/db/postgres.mjs.map +1 -0
  68. package/dist/db/sqlite.d.mts +11 -0
  69. package/dist/db/sqlite.d.mts.map +1 -0
  70. package/dist/db/sqlite.mjs +16 -0
  71. package/dist/db/sqlite.mjs.map +1 -0
  72. package/dist/default-Cyi4aAxu.mjs +81 -0
  73. package/dist/default-Cyi4aAxu.mjs.map +1 -0
  74. package/dist/dialect-helpers-B9uSp2GJ.mjs +90 -0
  75. package/dist/dialect-helpers-B9uSp2GJ.mjs.map +1 -0
  76. package/dist/error-Cxz0tQeO.mjs +27 -0
  77. package/dist/error-Cxz0tQeO.mjs.map +1 -0
  78. package/dist/index-C1xF3OGh.d.mts +4527 -0
  79. package/dist/index-C1xF3OGh.d.mts.map +1 -0
  80. package/dist/index.d.mts +16 -0
  81. package/dist/index.mjs +30 -0
  82. package/dist/load-yOOlckBj.mjs +28 -0
  83. package/dist/load-yOOlckBj.mjs.map +1 -0
  84. package/dist/loader-fz8Q_3EO.mjs +447 -0
  85. package/dist/loader-fz8Q_3EO.mjs.map +1 -0
  86. package/dist/manifest-schema-Dcl0R6nM.mjs +184 -0
  87. package/dist/manifest-schema-Dcl0R6nM.mjs.map +1 -0
  88. package/dist/media/index.d.mts +26 -0
  89. package/dist/media/index.d.mts.map +1 -0
  90. package/dist/media/index.mjs +55 -0
  91. package/dist/media/index.mjs.map +1 -0
  92. package/dist/media/local-runtime.d.mts +39 -0
  93. package/dist/media/local-runtime.d.mts.map +1 -0
  94. package/dist/media/local-runtime.mjs +133 -0
  95. package/dist/media/local-runtime.mjs.map +1 -0
  96. package/dist/media-DqHVh136.mjs +200 -0
  97. package/dist/media-DqHVh136.mjs.map +1 -0
  98. package/dist/mode-C2EzN1uE.mjs +23 -0
  99. package/dist/mode-C2EzN1uE.mjs.map +1 -0
  100. package/dist/page/index.d.mts +140 -0
  101. package/dist/page/index.d.mts.map +1 -0
  102. package/dist/page/index.mjs +416 -0
  103. package/dist/page/index.mjs.map +1 -0
  104. package/dist/placeholder-CmGAmqeO.d.mts +276 -0
  105. package/dist/placeholder-CmGAmqeO.d.mts.map +1 -0
  106. package/dist/placeholder-SmpOx-_v.mjs +243 -0
  107. package/dist/placeholder-SmpOx-_v.mjs.map +1 -0
  108. package/dist/plugin-utils.d.mts +58 -0
  109. package/dist/plugin-utils.d.mts.map +1 -0
  110. package/dist/plugin-utils.mjs +78 -0
  111. package/dist/plugin-utils.mjs.map +1 -0
  112. package/dist/plugins/adapt-sandbox-entry.d.mts +22 -0
  113. package/dist/plugins/adapt-sandbox-entry.d.mts.map +1 -0
  114. package/dist/plugins/adapt-sandbox-entry.mjs +113 -0
  115. package/dist/plugins/adapt-sandbox-entry.mjs.map +1 -0
  116. package/dist/query-CS_iSj34.mjs +460 -0
  117. package/dist/query-CS_iSj34.mjs.map +1 -0
  118. package/dist/redirect-DIfIni3r.mjs +329 -0
  119. package/dist/redirect-DIfIni3r.mjs.map +1 -0
  120. package/dist/registry-D_w5HW4G.mjs +863 -0
  121. package/dist/registry-D_w5HW4G.mjs.map +1 -0
  122. package/dist/request-context.d.mts +49 -0
  123. package/dist/request-context.d.mts.map +1 -0
  124. package/dist/request-context.mjs +43 -0
  125. package/dist/request-context.mjs.map +1 -0
  126. package/dist/runner-B-u2F2b6.mjs +1412 -0
  127. package/dist/runner-B-u2F2b6.mjs.map +1 -0
  128. package/dist/runner-EAtf0ZIe.d.mts +27 -0
  129. package/dist/runner-EAtf0ZIe.d.mts.map +1 -0
  130. package/dist/runtime.d.mts +26 -0
  131. package/dist/runtime.d.mts.map +1 -0
  132. package/dist/runtime.mjs +42 -0
  133. package/dist/runtime.mjs.map +1 -0
  134. package/dist/search-DG603UrT.mjs +9211 -0
  135. package/dist/search-DG603UrT.mjs.map +1 -0
  136. package/dist/seed/index.d.mts +3 -0
  137. package/dist/seed/index.mjs +15 -0
  138. package/dist/seo/index.d.mts +70 -0
  139. package/dist/seo/index.d.mts.map +1 -0
  140. package/dist/seo/index.mjs +70 -0
  141. package/dist/seo/index.mjs.map +1 -0
  142. package/dist/storage/local.d.mts +39 -0
  143. package/dist/storage/local.d.mts.map +1 -0
  144. package/dist/storage/local.mjs +166 -0
  145. package/dist/storage/local.mjs.map +1 -0
  146. package/dist/storage/s3.d.mts +32 -0
  147. package/dist/storage/s3.d.mts.map +1 -0
  148. package/dist/storage/s3.mjs +175 -0
  149. package/dist/storage/s3.mjs.map +1 -0
  150. package/dist/tokens-DpgrkrXK.mjs +171 -0
  151. package/dist/tokens-DpgrkrXK.mjs.map +1 -0
  152. package/dist/transport-BFGblqwG.d.mts +42 -0
  153. package/dist/transport-BFGblqwG.d.mts.map +1 -0
  154. package/dist/transport-yxiQsi8I.mjs +418 -0
  155. package/dist/transport-yxiQsi8I.mjs.map +1 -0
  156. package/dist/types-BRuPJGdV.d.mts +102 -0
  157. package/dist/types-BRuPJGdV.d.mts.map +1 -0
  158. package/dist/types-C4-fAxN3.d.mts +182 -0
  159. package/dist/types-C4-fAxN3.d.mts.map +1 -0
  160. package/dist/types-CMMN0pNg.mjs +31 -0
  161. package/dist/types-CMMN0pNg.mjs.map +1 -0
  162. package/dist/types-CUBbjgmP.mjs +16 -0
  163. package/dist/types-CUBbjgmP.mjs.map +1 -0
  164. package/dist/types-DRjfYOEv.d.mts +426 -0
  165. package/dist/types-DRjfYOEv.d.mts.map +1 -0
  166. package/dist/types-DY5zk5HN.mjs +73 -0
  167. package/dist/types-DY5zk5HN.mjs.map +1 -0
  168. package/dist/types-DaNLHo_T.d.mts +184 -0
  169. package/dist/types-DaNLHo_T.d.mts.map +1 -0
  170. package/dist/types-DvhsUmSJ.d.mts +1111 -0
  171. package/dist/types-DvhsUmSJ.d.mts.map +1 -0
  172. package/dist/validate-CpBtVMsD.d.mts +378 -0
  173. package/dist/validate-CpBtVMsD.d.mts.map +1 -0
  174. package/dist/validate-CqRJb_xU.mjs +97 -0
  175. package/dist/validate-CqRJb_xU.mjs.map +1 -0
  176. package/dist/validate-O7PWmlnq.mjs +328 -0
  177. package/dist/validate-O7PWmlnq.mjs.map +1 -0
  178. package/locals.d.ts +46 -0
  179. package/package.json +233 -19
  180. package/src/api/authorize.ts +63 -0
  181. package/src/api/csrf.ts +48 -0
  182. package/src/api/error.ts +99 -0
  183. package/src/api/errors.ts +445 -0
  184. package/src/api/escape.ts +9 -0
  185. package/src/api/handlers/api-tokens.ts +240 -0
  186. package/src/api/handlers/comments.ts +314 -0
  187. package/src/api/handlers/content.ts +1315 -0
  188. package/src/api/handlers/dashboard.ts +205 -0
  189. package/src/api/handlers/device-flow.ts +687 -0
  190. package/src/api/handlers/index.ts +163 -0
  191. package/src/api/handlers/manifest.ts +158 -0
  192. package/src/api/handlers/marketplace.ts +930 -0
  193. package/src/api/handlers/media.ts +207 -0
  194. package/src/api/handlers/menus.ts +493 -0
  195. package/src/api/handlers/oauth-authorization.ts +429 -0
  196. package/src/api/handlers/oauth-clients.ts +353 -0
  197. package/src/api/handlers/oauth-user-lookup.ts +39 -0
  198. package/src/api/handlers/plugins.ts +254 -0
  199. package/src/api/handlers/redirects.ts +360 -0
  200. package/src/api/handlers/revision.ts +145 -0
  201. package/src/api/handlers/schema.ts +534 -0
  202. package/src/api/handlers/sections.ts +289 -0
  203. package/src/api/handlers/seo.ts +115 -0
  204. package/src/api/handlers/settings.ts +49 -0
  205. package/src/api/handlers/snapshot.ts +350 -0
  206. package/src/api/handlers/taxonomies.ts +523 -0
  207. package/src/api/index.ts +6 -0
  208. package/src/api/openapi/document.ts +2368 -0
  209. package/src/api/openapi/index.ts +1 -0
  210. package/src/api/parse.ts +139 -0
  211. package/src/api/redirect.ts +14 -0
  212. package/src/api/rev.ts +67 -0
  213. package/src/api/schemas/auth.ts +112 -0
  214. package/src/api/schemas/bylines.ts +85 -0
  215. package/src/api/schemas/comments.ts +117 -0
  216. package/src/api/schemas/common.ts +89 -0
  217. package/src/api/schemas/content.ts +191 -0
  218. package/src/api/schemas/import.ts +52 -0
  219. package/src/api/schemas/index.ts +17 -0
  220. package/src/api/schemas/media.ts +116 -0
  221. package/src/api/schemas/menus.ts +111 -0
  222. package/src/api/schemas/redirects.ts +155 -0
  223. package/src/api/schemas/schema.ts +203 -0
  224. package/src/api/schemas/search.ts +63 -0
  225. package/src/api/schemas/sections.ts +67 -0
  226. package/src/api/schemas/settings.ts +63 -0
  227. package/src/api/schemas/setup.ts +37 -0
  228. package/src/api/schemas/taxonomies.ts +113 -0
  229. package/src/api/schemas/users.ts +96 -0
  230. package/src/api/schemas/widgets.ts +80 -0
  231. package/src/api/site-url.ts +25 -0
  232. package/src/api/types.ts +82 -0
  233. package/src/astro/index.ts +27 -0
  234. package/src/astro/integration/index.ts +303 -0
  235. package/src/astro/integration/routes.ts +834 -0
  236. package/src/astro/integration/runtime.ts +338 -0
  237. package/src/astro/integration/virtual-modules.ts +469 -0
  238. package/src/astro/integration/vite-config.ts +328 -0
  239. package/src/astro/middleware/auth.ts +743 -0
  240. package/src/astro/middleware/redirect.ts +89 -0
  241. package/src/astro/middleware/request-context.ts +129 -0
  242. package/src/astro/middleware/setup.ts +89 -0
  243. package/src/astro/middleware.ts +398 -0
  244. package/src/astro/routes/PluginRegistry.tsx +15 -0
  245. package/src/astro/routes/admin.astro +81 -0
  246. package/src/astro/routes/api/admin/allowed-domains/[domain].ts +112 -0
  247. package/src/astro/routes/api/admin/allowed-domains/index.ts +108 -0
  248. package/src/astro/routes/api/admin/api-tokens/[id].ts +40 -0
  249. package/src/astro/routes/api/admin/api-tokens/index.ts +68 -0
  250. package/src/astro/routes/api/admin/bylines/[id]/index.ts +87 -0
  251. package/src/astro/routes/api/admin/bylines/index.ts +72 -0
  252. package/src/astro/routes/api/admin/comments/[id]/status.ts +120 -0
  253. package/src/astro/routes/api/admin/comments/[id].ts +64 -0
  254. package/src/astro/routes/api/admin/comments/bulk.ts +42 -0
  255. package/src/astro/routes/api/admin/comments/counts.ts +30 -0
  256. package/src/astro/routes/api/admin/comments/index.ts +46 -0
  257. package/src/astro/routes/api/admin/hooks/exclusive/[hookName].ts +91 -0
  258. package/src/astro/routes/api/admin/hooks/exclusive/index.ts +51 -0
  259. package/src/astro/routes/api/admin/oauth-clients/[id].ts +110 -0
  260. package/src/astro/routes/api/admin/oauth-clients/index.ts +71 -0
  261. package/src/astro/routes/api/admin/plugins/[id]/disable.ts +39 -0
  262. package/src/astro/routes/api/admin/plugins/[id]/enable.ts +39 -0
  263. package/src/astro/routes/api/admin/plugins/[id]/index.ts +38 -0
  264. package/src/astro/routes/api/admin/plugins/[id]/uninstall.ts +48 -0
  265. package/src/astro/routes/api/admin/plugins/[id]/update.ts +59 -0
  266. package/src/astro/routes/api/admin/plugins/index.ts +32 -0
  267. package/src/astro/routes/api/admin/plugins/marketplace/[id]/icon.ts +61 -0
  268. package/src/astro/routes/api/admin/plugins/marketplace/[id]/index.ts +33 -0
  269. package/src/astro/routes/api/admin/plugins/marketplace/[id]/install.ts +62 -0
  270. package/src/astro/routes/api/admin/plugins/marketplace/index.ts +38 -0
  271. package/src/astro/routes/api/admin/plugins/updates.ts +28 -0
  272. package/src/astro/routes/api/admin/themes/marketplace/[id]/index.ts +33 -0
  273. package/src/astro/routes/api/admin/themes/marketplace/[id]/thumbnail.ts +61 -0
  274. package/src/astro/routes/api/admin/themes/marketplace/index.ts +45 -0
  275. package/src/astro/routes/api/admin/users/[id]/disable.ts +69 -0
  276. package/src/astro/routes/api/admin/users/[id]/enable.ts +48 -0
  277. package/src/astro/routes/api/admin/users/[id]/index.ts +146 -0
  278. package/src/astro/routes/api/admin/users/[id]/send-recovery.ts +72 -0
  279. package/src/astro/routes/api/admin/users/index.ts +66 -0
  280. package/src/astro/routes/api/auth/dev-bypass.ts +139 -0
  281. package/src/astro/routes/api/auth/invite/accept.ts +52 -0
  282. package/src/astro/routes/api/auth/invite/complete.ts +84 -0
  283. package/src/astro/routes/api/auth/invite/index.ts +99 -0
  284. package/src/astro/routes/api/auth/logout.ts +40 -0
  285. package/src/astro/routes/api/auth/magic-link/send.ts +89 -0
  286. package/src/astro/routes/api/auth/magic-link/verify.ts +71 -0
  287. package/src/astro/routes/api/auth/me.ts +60 -0
  288. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +219 -0
  289. package/src/astro/routes/api/auth/oauth/[provider].ts +119 -0
  290. package/src/astro/routes/api/auth/passkey/[id].ts +124 -0
  291. package/src/astro/routes/api/auth/passkey/index.ts +54 -0
  292. package/src/astro/routes/api/auth/passkey/options.ts +82 -0
  293. package/src/astro/routes/api/auth/passkey/register/options.ts +86 -0
  294. package/src/astro/routes/api/auth/passkey/register/verify.ts +117 -0
  295. package/src/astro/routes/api/auth/passkey/verify.ts +66 -0
  296. package/src/astro/routes/api/auth/signup/complete.ts +85 -0
  297. package/src/astro/routes/api/auth/signup/request.ts +77 -0
  298. package/src/astro/routes/api/auth/signup/verify.ts +53 -0
  299. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +312 -0
  300. package/src/astro/routes/api/content/[collection]/[id]/compare.ts +28 -0
  301. package/src/astro/routes/api/content/[collection]/[id]/discard-draft.ts +54 -0
  302. package/src/astro/routes/api/content/[collection]/[id]/duplicate.ts +61 -0
  303. package/src/astro/routes/api/content/[collection]/[id]/permanent.ts +33 -0
  304. package/src/astro/routes/api/content/[collection]/[id]/preview-url.ts +107 -0
  305. package/src/astro/routes/api/content/[collection]/[id]/publish.ts +56 -0
  306. package/src/astro/routes/api/content/[collection]/[id]/restore.ts +54 -0
  307. package/src/astro/routes/api/content/[collection]/[id]/revisions.ts +31 -0
  308. package/src/astro/routes/api/content/[collection]/[id]/schedule.ts +105 -0
  309. package/src/astro/routes/api/content/[collection]/[id]/terms/[taxonomy].ts +140 -0
  310. package/src/astro/routes/api/content/[collection]/[id]/translations.ts +30 -0
  311. package/src/astro/routes/api/content/[collection]/[id]/unpublish.ts +56 -0
  312. package/src/astro/routes/api/content/[collection]/[id].ts +137 -0
  313. package/src/astro/routes/api/content/[collection]/index.ts +59 -0
  314. package/src/astro/routes/api/content/[collection]/trash.ts +33 -0
  315. package/src/astro/routes/api/dashboard.ts +32 -0
  316. package/src/astro/routes/api/dev/emails.ts +36 -0
  317. package/src/astro/routes/api/import/probe.ts +47 -0
  318. package/src/astro/routes/api/import/wordpress/analyze.ts +510 -0
  319. package/src/astro/routes/api/import/wordpress/execute.ts +283 -0
  320. package/src/astro/routes/api/import/wordpress/media.ts +338 -0
  321. package/src/astro/routes/api/import/wordpress/prepare.ts +181 -0
  322. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +393 -0
  323. package/src/astro/routes/api/import/wordpress-plugin/analyze.ts +111 -0
  324. package/src/astro/routes/api/import/wordpress-plugin/callback.ts +58 -0
  325. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +347 -0
  326. package/src/astro/routes/api/manifest.ts +62 -0
  327. package/src/astro/routes/api/mcp.ts +124 -0
  328. package/src/astro/routes/api/media/[id]/confirm.ts +93 -0
  329. package/src/astro/routes/api/media/[id].ts +145 -0
  330. package/src/astro/routes/api/media/file/[key].ts +79 -0
  331. package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +86 -0
  332. package/src/astro/routes/api/media/providers/[providerId]/index.ts +111 -0
  333. package/src/astro/routes/api/media/providers/index.ts +30 -0
  334. package/src/astro/routes/api/media/upload-url.ts +137 -0
  335. package/src/astro/routes/api/media.ts +190 -0
  336. package/src/astro/routes/api/menus/[name]/items.ts +87 -0
  337. package/src/astro/routes/api/menus/[name]/reorder.ts +33 -0
  338. package/src/astro/routes/api/menus/[name].ts +65 -0
  339. package/src/astro/routes/api/menus/index.ts +47 -0
  340. package/src/astro/routes/api/oauth/authorize.ts +412 -0
  341. package/src/astro/routes/api/oauth/device/authorize.ts +45 -0
  342. package/src/astro/routes/api/oauth/device/code.ts +51 -0
  343. package/src/astro/routes/api/oauth/device/token.ts +69 -0
  344. package/src/astro/routes/api/oauth/token/refresh.ts +38 -0
  345. package/src/astro/routes/api/oauth/token/revoke.ts +38 -0
  346. package/src/astro/routes/api/oauth/token.ts +184 -0
  347. package/src/astro/routes/api/openapi.json.ts +32 -0
  348. package/src/astro/routes/api/plugins/[pluginId]/[...path].ts +92 -0
  349. package/src/astro/routes/api/redirects/404s/index.ts +72 -0
  350. package/src/astro/routes/api/redirects/404s/summary.ts +33 -0
  351. package/src/astro/routes/api/redirects/[id].ts +84 -0
  352. package/src/astro/routes/api/redirects/index.ts +52 -0
  353. package/src/astro/routes/api/revisions/[revisionId]/index.ts +29 -0
  354. package/src/astro/routes/api/revisions/[revisionId]/restore.ts +62 -0
  355. package/src/astro/routes/api/schema/collections/[slug]/fields/[fieldSlug].ts +76 -0
  356. package/src/astro/routes/api/schema/collections/[slug]/fields/index.ts +52 -0
  357. package/src/astro/routes/api/schema/collections/[slug]/fields/reorder.ts +32 -0
  358. package/src/astro/routes/api/schema/collections/[slug]/index.ts +80 -0
  359. package/src/astro/routes/api/schema/collections/index.ts +47 -0
  360. package/src/astro/routes/api/schema/index.ts +109 -0
  361. package/src/astro/routes/api/schema/orphans/[slug].ts +36 -0
  362. package/src/astro/routes/api/schema/orphans/index.ts +26 -0
  363. package/src/astro/routes/api/search/enable.ts +64 -0
  364. package/src/astro/routes/api/search/index.ts +55 -0
  365. package/src/astro/routes/api/search/rebuild.ts +72 -0
  366. package/src/astro/routes/api/search/stats.ts +35 -0
  367. package/src/astro/routes/api/search/suggest.ts +53 -0
  368. package/src/astro/routes/api/sections/[slug].ts +84 -0
  369. package/src/astro/routes/api/sections/index.ts +52 -0
  370. package/src/astro/routes/api/settings/email.ts +150 -0
  371. package/src/astro/routes/api/settings.ts +67 -0
  372. package/src/astro/routes/api/setup/admin-verify.ts +100 -0
  373. package/src/astro/routes/api/setup/admin.ts +94 -0
  374. package/src/astro/routes/api/setup/dev-bypass.ts +199 -0
  375. package/src/astro/routes/api/setup/dev-reset.ts +40 -0
  376. package/src/astro/routes/api/setup/index.ts +126 -0
  377. package/src/astro/routes/api/setup/status.ts +122 -0
  378. package/src/astro/routes/api/snapshot.ts +75 -0
  379. package/src/astro/routes/api/taxonomies/[name]/terms/[slug].ts +95 -0
  380. package/src/astro/routes/api/taxonomies/[name]/terms/index.ts +69 -0
  381. package/src/astro/routes/api/taxonomies/index.ts +59 -0
  382. package/src/astro/routes/api/themes/preview.ts +77 -0
  383. package/src/astro/routes/api/typegen.ts +114 -0
  384. package/src/astro/routes/api/well-known/auth.ts +68 -0
  385. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +44 -0
  386. package/src/astro/routes/api/well-known/oauth-protected-resource.ts +37 -0
  387. package/src/astro/routes/api/widget-areas/[name]/reorder.ts +72 -0
  388. package/src/astro/routes/api/widget-areas/[name]/widgets/[id].ts +127 -0
  389. package/src/astro/routes/api/widget-areas/[name]/widgets.ts +80 -0
  390. package/src/astro/routes/api/widget-areas/[name].ts +87 -0
  391. package/src/astro/routes/api/widget-areas/index.ts +99 -0
  392. package/src/astro/routes/api/widget-components.ts +22 -0
  393. package/src/astro/routes/robots.txt.ts +77 -0
  394. package/src/astro/routes/sitemap.xml.ts +97 -0
  395. package/src/astro/storage/adapters.ts +74 -0
  396. package/src/astro/storage/index.ts +19 -0
  397. package/src/astro/storage/types.ts +60 -0
  398. package/src/astro/types.ts +346 -0
  399. package/src/auth/api-tokens.ts +25 -0
  400. package/src/auth/challenge-store.ts +80 -0
  401. package/src/auth/mode.ts +96 -0
  402. package/src/auth/oauth-state-store.ts +96 -0
  403. package/src/auth/passkey-config.ts +27 -0
  404. package/src/auth/rate-limit.ts +158 -0
  405. package/src/auth/scopes.ts +33 -0
  406. package/src/auth/types.ts +104 -0
  407. package/src/aws-sdk.d.ts +100 -0
  408. package/src/bylines/index.ts +237 -0
  409. package/src/cleanup.ts +153 -0
  410. package/src/cli/client-factory.ts +100 -0
  411. package/src/cli/commands/auth.ts +46 -0
  412. package/src/cli/commands/bundle-utils.ts +247 -0
  413. package/src/cli/commands/bundle.ts +609 -0
  414. package/src/cli/commands/content.ts +442 -0
  415. package/src/cli/commands/dev.ts +191 -0
  416. package/src/cli/commands/doctor.ts +211 -0
  417. package/src/cli/commands/export-seed.ts +630 -0
  418. package/src/cli/commands/import/wordpress.ts +1056 -0
  419. package/src/cli/commands/init.ts +192 -0
  420. package/src/cli/commands/login.ts +547 -0
  421. package/src/cli/commands/media.ts +165 -0
  422. package/src/cli/commands/menu.ts +67 -0
  423. package/src/cli/commands/plugin-init.ts +291 -0
  424. package/src/cli/commands/plugin-validate.ts +31 -0
  425. package/src/cli/commands/plugin.ts +33 -0
  426. package/src/cli/commands/publish.ts +699 -0
  427. package/src/cli/commands/schema.ts +233 -0
  428. package/src/cli/commands/search-cmd.ts +54 -0
  429. package/src/cli/commands/seed.ts +288 -0
  430. package/src/cli/commands/taxonomy.ts +128 -0
  431. package/src/cli/commands/types.ts +68 -0
  432. package/src/cli/credentials.ts +236 -0
  433. package/src/cli/index.ts +70 -0
  434. package/src/cli/output.ts +75 -0
  435. package/src/cli/wxr/parser.ts +969 -0
  436. package/src/client/cf-access.ts +193 -0
  437. package/src/client/index.ts +854 -0
  438. package/src/client/portable-text.ts +413 -0
  439. package/src/client/transport.ts +200 -0
  440. package/src/comments/moderator.ts +46 -0
  441. package/src/comments/notifications.ts +144 -0
  442. package/src/comments/query.ts +105 -0
  443. package/src/comments/service.ts +213 -0
  444. package/src/components/Break.astro +45 -0
  445. package/src/components/Button.astro +71 -0
  446. package/src/components/Buttons.astro +49 -0
  447. package/src/components/Code.astro +59 -0
  448. package/src/components/Columns.astro +59 -0
  449. package/src/components/CommentForm.astro +315 -0
  450. package/src/components/Comments.astro +232 -0
  451. package/src/components/Cover.astro +128 -0
  452. package/src/components/EmDashBodyEnd.astro +32 -0
  453. package/src/components/EmDashBodyStart.astro +32 -0
  454. package/src/components/EmDashHead.astro +53 -0
  455. package/src/components/EmDashImage.astro +178 -0
  456. package/src/components/EmDashMedia.astro +167 -0
  457. package/src/components/Embed.astro +128 -0
  458. package/src/components/File.astro +122 -0
  459. package/src/components/Gallery.astro +93 -0
  460. package/src/components/HtmlBlock.astro +33 -0
  461. package/src/components/Image.astro +178 -0
  462. package/src/components/InlineEditor.astro +27 -0
  463. package/src/components/InlinePortableTextEditor.tsx +1905 -0
  464. package/src/components/LiveSearch.astro +614 -0
  465. package/src/components/PortableText.astro +51 -0
  466. package/src/components/Pullquote.astro +51 -0
  467. package/src/components/Table.astro +108 -0
  468. package/src/components/WidgetArea.astro +22 -0
  469. package/src/components/WidgetRenderer.astro +72 -0
  470. package/src/components/index.ts +116 -0
  471. package/src/components/marks/Link.astro +31 -0
  472. package/src/components/marks/StrikeThrough.astro +7 -0
  473. package/src/components/marks/Subscript.astro +7 -0
  474. package/src/components/marks/Superscript.astro +7 -0
  475. package/src/components/marks/Underline.astro +7 -0
  476. package/src/components/widgets/Archives.astro +65 -0
  477. package/src/components/widgets/Categories.astro +35 -0
  478. package/src/components/widgets/RecentPosts.astro +51 -0
  479. package/src/components/widgets/Search.astro +18 -0
  480. package/src/components/widgets/Tags.astro +38 -0
  481. package/src/content/converters/index.ts +9 -0
  482. package/src/content/converters/portable-text-to-prosemirror.ts +385 -0
  483. package/src/content/converters/prosemirror-to-portable-text.ts +413 -0
  484. package/src/content/converters/types.ts +120 -0
  485. package/src/content/index.ts +5 -0
  486. package/src/database/connection.ts +67 -0
  487. package/src/database/dialect-helpers.ts +138 -0
  488. package/src/database/index.ts +5 -0
  489. package/src/database/migrations/001_initial.ts +136 -0
  490. package/src/database/migrations/002_media_status.ts +26 -0
  491. package/src/database/migrations/003_schema_registry.ts +79 -0
  492. package/src/database/migrations/004_plugins.ts +62 -0
  493. package/src/database/migrations/005_menus.ts +67 -0
  494. package/src/database/migrations/006_taxonomy_defs.ts +51 -0
  495. package/src/database/migrations/007_widgets.ts +42 -0
  496. package/src/database/migrations/008_auth.ts +194 -0
  497. package/src/database/migrations/009_user_disabled.ts +27 -0
  498. package/src/database/migrations/011_sections.ts +65 -0
  499. package/src/database/migrations/012_search.ts +25 -0
  500. package/src/database/migrations/013_scheduled_publishing.ts +51 -0
  501. package/src/database/migrations/014_draft_revisions.ts +72 -0
  502. package/src/database/migrations/015_indexes.ts +82 -0
  503. package/src/database/migrations/016_api_tokens.ts +89 -0
  504. package/src/database/migrations/017_authorization_codes.ts +45 -0
  505. package/src/database/migrations/018_seo.ts +56 -0
  506. package/src/database/migrations/019_i18n.ts +618 -0
  507. package/src/database/migrations/020_collection_url_pattern.ts +23 -0
  508. package/src/database/migrations/021_remove_section_categories.ts +43 -0
  509. package/src/database/migrations/022_marketplace_plugin_state.ts +46 -0
  510. package/src/database/migrations/023_plugin_metadata.ts +33 -0
  511. package/src/database/migrations/024_media_placeholders.ts +32 -0
  512. package/src/database/migrations/025_oauth_clients.ts +28 -0
  513. package/src/database/migrations/026_cron_tasks.ts +49 -0
  514. package/src/database/migrations/027_comments.ts +87 -0
  515. package/src/database/migrations/028_drop_author_url.ts +9 -0
  516. package/src/database/migrations/029_redirects.ts +67 -0
  517. package/src/database/migrations/030_widen_scheduled_index.ts +48 -0
  518. package/src/database/migrations/031_bylines.ts +90 -0
  519. package/src/database/migrations/032_rate_limits.ts +42 -0
  520. package/src/database/migrations/runner.ts +170 -0
  521. package/src/database/repositories/audit.ts +294 -0
  522. package/src/database/repositories/byline.ts +387 -0
  523. package/src/database/repositories/comment.ts +458 -0
  524. package/src/database/repositories/content.ts +1144 -0
  525. package/src/database/repositories/index.ts +30 -0
  526. package/src/database/repositories/media.ts +347 -0
  527. package/src/database/repositories/options.ts +150 -0
  528. package/src/database/repositories/plugin-storage.ts +373 -0
  529. package/src/database/repositories/redirect.ts +480 -0
  530. package/src/database/repositories/revision.ts +200 -0
  531. package/src/database/repositories/seo.ts +176 -0
  532. package/src/database/repositories/taxonomy.ts +294 -0
  533. package/src/database/repositories/types.ts +132 -0
  534. package/src/database/repositories/user.ts +258 -0
  535. package/src/database/transaction.ts +54 -0
  536. package/src/database/types.ts +501 -0
  537. package/src/database/validate.ts +138 -0
  538. package/src/db/adapters.ts +125 -0
  539. package/src/db/index.ts +37 -0
  540. package/src/db/libsql.ts +23 -0
  541. package/src/db/postgres.ts +30 -0
  542. package/src/db/sqlite.ts +27 -0
  543. package/src/emdash-runtime.ts +2096 -0
  544. package/src/fields/boolean.ts +34 -0
  545. package/src/fields/datetime.ts +44 -0
  546. package/src/fields/file.ts +41 -0
  547. package/src/fields/image.ts +34 -0
  548. package/src/fields/index.ts +42 -0
  549. package/src/fields/integer.ts +50 -0
  550. package/src/fields/json.ts +37 -0
  551. package/src/fields/multiselect.ts +48 -0
  552. package/src/fields/number.ts +52 -0
  553. package/src/fields/portable-text.ts +33 -0
  554. package/src/fields/reference.ts +29 -0
  555. package/src/fields/richtext.ts +31 -0
  556. package/src/fields/select.ts +46 -0
  557. package/src/fields/slug.ts +38 -0
  558. package/src/fields/text.ts +55 -0
  559. package/src/fields/textarea.ts +52 -0
  560. package/src/fields/types.ts +64 -0
  561. package/src/i18n/config.ts +68 -0
  562. package/src/import/index.ts +90 -0
  563. package/src/import/menus.ts +436 -0
  564. package/src/import/registry.ts +111 -0
  565. package/src/import/sections.ts +103 -0
  566. package/src/import/settings.ts +281 -0
  567. package/src/import/sources/wordpress-plugin.ts +641 -0
  568. package/src/import/sources/wordpress-rest.ts +191 -0
  569. package/src/import/sources/wxr.ts +330 -0
  570. package/src/import/ssrf.ts +260 -0
  571. package/src/import/types.ts +418 -0
  572. package/src/import/utils.ts +412 -0
  573. package/src/index.ts +481 -0
  574. package/src/loader.ts +770 -0
  575. package/src/mcp/server.ts +1463 -0
  576. package/src/media/index.ts +32 -0
  577. package/src/media/local-runtime.ts +213 -0
  578. package/src/media/local.ts +46 -0
  579. package/src/media/normalize.ts +190 -0
  580. package/src/media/placeholder.ts +150 -0
  581. package/src/media/provider-loader.ts +78 -0
  582. package/src/media/types.ts +279 -0
  583. package/src/menus/index.ts +324 -0
  584. package/src/menus/types.ts +112 -0
  585. package/src/page/context.ts +93 -0
  586. package/src/page/fragments.ts +89 -0
  587. package/src/page/index.ts +58 -0
  588. package/src/page/jsonld.ts +94 -0
  589. package/src/page/metadata.ts +185 -0
  590. package/src/page/seo-contributions.ts +136 -0
  591. package/src/plugin-utils.ts +80 -0
  592. package/src/plugins/adapt-sandbox-entry.ts +207 -0
  593. package/src/plugins/context.ts +833 -0
  594. package/src/plugins/cron.ts +361 -0
  595. package/src/plugins/define-plugin.ts +259 -0
  596. package/src/plugins/email-console.ts +73 -0
  597. package/src/plugins/email.ts +209 -0
  598. package/src/plugins/hooks.ts +1273 -0
  599. package/src/plugins/index.ts +193 -0
  600. package/src/plugins/manager.ts +595 -0
  601. package/src/plugins/manifest-schema.ts +230 -0
  602. package/src/plugins/marketplace.ts +460 -0
  603. package/src/plugins/request-meta.ts +139 -0
  604. package/src/plugins/routes.ts +302 -0
  605. package/src/plugins/sandbox/index.ts +18 -0
  606. package/src/plugins/sandbox/noop.ts +76 -0
  607. package/src/plugins/sandbox/types.ts +173 -0
  608. package/src/plugins/scheduler/node.ts +122 -0
  609. package/src/plugins/scheduler/piggyback.ts +71 -0
  610. package/src/plugins/scheduler/types.ts +27 -0
  611. package/src/plugins/state.ts +208 -0
  612. package/src/plugins/storage-indexes.ts +326 -0
  613. package/src/plugins/storage-query.ts +240 -0
  614. package/src/plugins/types.ts +1284 -0
  615. package/src/preview/helpers.ts +27 -0
  616. package/src/preview/index.ts +40 -0
  617. package/src/preview/tokens.ts +279 -0
  618. package/src/preview/urls.ts +118 -0
  619. package/src/query.ts +674 -0
  620. package/src/redirects/patterns.ts +224 -0
  621. package/src/request-context.ts +67 -0
  622. package/src/runtime.ts +21 -0
  623. package/src/schema/index.ts +29 -0
  624. package/src/schema/query.ts +44 -0
  625. package/src/schema/registry.ts +965 -0
  626. package/src/schema/types.ts +276 -0
  627. package/src/schema/zod-generator.ts +413 -0
  628. package/src/search/fts-manager.ts +452 -0
  629. package/src/search/index.ts +26 -0
  630. package/src/search/query.ts +396 -0
  631. package/src/search/text-extraction.ts +162 -0
  632. package/src/search/types.ts +114 -0
  633. package/src/sections/index.ts +226 -0
  634. package/src/sections/types.ts +86 -0
  635. package/src/seed/apply.ts +1141 -0
  636. package/src/seed/default.ts +86 -0
  637. package/src/seed/index.ts +28 -0
  638. package/src/seed/load.ts +35 -0
  639. package/src/seed/types.ts +341 -0
  640. package/src/seed/validate.ts +642 -0
  641. package/src/seo/index.ts +179 -0
  642. package/src/settings/index.ts +203 -0
  643. package/src/settings/types.ts +58 -0
  644. package/src/storage/index.ts +28 -0
  645. package/src/storage/local.ts +253 -0
  646. package/src/storage/s3.ts +271 -0
  647. package/src/storage/types.ts +204 -0
  648. package/src/taxonomies/index.ts +309 -0
  649. package/src/taxonomies/types.ts +61 -0
  650. package/src/ui.ts +75 -0
  651. package/src/utils/base64.ts +73 -0
  652. package/src/utils/hash.ts +36 -0
  653. package/src/utils/sanitize.ts +20 -0
  654. package/src/utils/slugify.ts +29 -0
  655. package/src/utils/url.ts +48 -0
  656. package/src/virtual-modules.d.ts +111 -0
  657. package/src/visual-editing/editable.ts +108 -0
  658. package/src/visual-editing/toolbar.ts +1229 -0
  659. package/src/widgets/components.ts +105 -0
  660. package/src/widgets/index.ts +131 -0
  661. package/src/widgets/types.ts +81 -0
package/src/query.ts ADDED
@@ -0,0 +1,674 @@
1
+ /**
2
+ * Query functions for EmDash content
3
+ *
4
+ * These wrap Astro's getLiveCollection/getLiveEntry with type filtering.
5
+ * Use these instead of calling Astro's functions directly.
6
+ *
7
+ * Error handling follows Astro's pattern - returns { entries/entry, error }
8
+ * so callers can gracefully handle errors (including 404s).
9
+ *
10
+ * Preview mode is handled implicitly via ALS request context —
11
+ * no parameters needed. The middleware verifies the preview token
12
+ * and sets the context; query functions read it automatically.
13
+ */
14
+
15
+ import { getFallbackChain, getI18nConfig, isI18nEnabled } from "./i18n/config.js";
16
+ import { getRequestContext } from "./request-context.js";
17
+ import {
18
+ createEditable,
19
+ createNoop,
20
+ type EditProxy,
21
+ type EditableOptions,
22
+ } from "./visual-editing/editable.js";
23
+
24
+ /**
25
+ * Collection type registry for type-safe queries.
26
+ *
27
+ * This interface is extended by the generated emdash-env.d.ts file
28
+ * to provide type inference for collection names and their data shapes.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * // In emdash-env.d.ts (generated):
33
+ * declare module "emdash" {
34
+ * interface EmDashCollections {
35
+ * posts: { title: string; content: PortableTextBlock[]; };
36
+ * pages: { title: string; body: PortableTextBlock[]; };
37
+ * }
38
+ * }
39
+ *
40
+ * // Then in your code:
41
+ * const { entries } = await getEmDashCollection("posts");
42
+ * // entries[0].data.title is typed as string
43
+ * ```
44
+ */
45
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
46
+ export interface EmDashCollections {}
47
+
48
+ /**
49
+ * Helper type to infer the data type for a collection.
50
+ * Returns the registered type if known, otherwise falls back to Record<string, unknown>.
51
+ */
52
+ export type InferCollectionData<T extends string> = T extends keyof EmDashCollections
53
+ ? EmDashCollections[T]
54
+ : Record<string, unknown>;
55
+
56
+ /**
57
+ * Sort direction
58
+ */
59
+ export type SortDirection = "asc" | "desc";
60
+
61
+ /**
62
+ * Order by specification - field name to direction
63
+ * @example { created_at: "desc" } - Sort by created_at descending
64
+ * @example { title: "asc" } - Sort by title ascending
65
+ * @example { published_at: "desc", title: "asc" } - Multi-field sort
66
+ */
67
+ export type OrderBySpec = Record<string, SortDirection>;
68
+
69
+ export interface CollectionFilter {
70
+ status?: "draft" | "published" | "archived";
71
+ limit?: number;
72
+ /**
73
+ * Opaque cursor for keyset pagination.
74
+ * Pass the `nextCursor` value from a previous result to fetch the next page.
75
+ * @example
76
+ * ```ts
77
+ * const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
78
+ * const { entries, nextCursor } = await getEmDashCollection("posts", {
79
+ * limit: 10,
80
+ * cursor,
81
+ * });
82
+ * ```
83
+ */
84
+ cursor?: string;
85
+ /**
86
+ * Filter by field values or taxonomy terms
87
+ * @example { category: 'news' } - Filter by taxonomy term
88
+ * @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
89
+ */
90
+ where?: Record<string, string | string[]>;
91
+ /**
92
+ * Order results by field(s)
93
+ * @default { created_at: "desc" }
94
+ * @example { created_at: "desc" } - Sort by created_at descending (default)
95
+ * @example { title: "asc" } - Sort by title ascending
96
+ * @example { published_at: "desc", title: "asc" } - Multi-field sort
97
+ */
98
+ orderBy?: OrderBySpec;
99
+ /**
100
+ * Filter by locale. When set, only returns entries in this locale.
101
+ * Only relevant when i18n is configured.
102
+ * @example "en" — English entries only
103
+ * @example "fr" — French entries only
104
+ */
105
+ locale?: string;
106
+ }
107
+
108
+ export interface ContentEntry<T = Record<string, unknown>> {
109
+ id: string;
110
+ data: T;
111
+ /** Visual editing annotations. Spread onto elements: {...entry.edit.title} */
112
+ edit: EditProxy;
113
+ }
114
+
115
+ /** Cache hint returned by the content loader for route caching */
116
+ export interface CacheHint {
117
+ tags?: string[];
118
+ lastModified?: Date;
119
+ }
120
+
121
+ /**
122
+ * Result from getEmDashCollection
123
+ */
124
+ export interface CollectionResult<T> {
125
+ /** The entries (empty array if error or none found) */
126
+ entries: ContentEntry<T>[];
127
+ /** Error if the query failed */
128
+ error?: Error;
129
+ /** Cache hint for route caching (pass to Astro.cache.set()) */
130
+ cacheHint: CacheHint;
131
+ /**
132
+ * Opaque cursor for the next page.
133
+ * Undefined when there are no more results.
134
+ * Pass this as `cursor` in the next query to get the next page.
135
+ */
136
+ nextCursor?: string;
137
+ }
138
+
139
+ /**
140
+ * Result from getEmDashEntry
141
+ */
142
+ export interface EntryResult<T> {
143
+ /** The entry, or null if not found */
144
+ entry: ContentEntry<T> | null;
145
+ /** Error if the query failed (not set for "not found", only for actual errors) */
146
+ error?: Error;
147
+ /** Whether we're in preview mode (valid token was provided) */
148
+ isPreview: boolean;
149
+ /** Set when a fallback locale was used instead of the requested locale */
150
+ fallbackLocale?: string;
151
+ /** Cache hint for route caching (pass to Astro.cache.set()) */
152
+ cacheHint: CacheHint;
153
+ }
154
+
155
+ const COLLECTION_NAME = "_emdash";
156
+
157
+ /** Symbol key for edit metadata on PT arrays — avoids collision with user data */
158
+ const EMDASH_EDIT = Symbol.for("__emdash");
159
+
160
+ /** Edit metadata attached to PT arrays in edit mode */
161
+ export interface EditFieldMeta {
162
+ collection: string;
163
+ id: string;
164
+ field: string;
165
+ }
166
+
167
+ /** Type guard for EditFieldMeta */
168
+ function isEditFieldMeta(value: unknown): value is EditFieldMeta {
169
+ if (typeof value !== "object" || value === null) return false;
170
+ if (!("collection" in value) || !("id" in value) || !("field" in value)) return false;
171
+ // After `in` checks, TS narrows to Record<"collection" | "id" | "field", unknown>
172
+ const { collection, id, field } = value;
173
+ return typeof collection === "string" && typeof id === "string" && typeof field === "string";
174
+ }
175
+
176
+ /**
177
+ * Read edit metadata from a value (returns undefined if not tagged).
178
+ * Uses Object.getOwnPropertyDescriptor to access Symbol-keyed property
179
+ * without an unsafe type assertion.
180
+ */
181
+ export function getEditMeta(value: unknown): EditFieldMeta | undefined {
182
+ if (value && typeof value === "object") {
183
+ const desc = Object.getOwnPropertyDescriptor(value, EMDASH_EDIT);
184
+ const meta: unknown = desc?.value;
185
+ if (isEditFieldMeta(meta)) {
186
+ return meta;
187
+ }
188
+ }
189
+ return undefined;
190
+ }
191
+
192
+ /**
193
+ * Tag PT-like arrays in entry data with edit metadata (non-enumerable).
194
+ * A PT array is identified by: is an array, first element has _type property.
195
+ */
196
+ function tagEditableFields(data: Record<string, unknown>, collection: string, id: string): void {
197
+ for (const [field, value] of Object.entries(data)) {
198
+ if (
199
+ Array.isArray(value) &&
200
+ value.length > 0 &&
201
+ value[0] &&
202
+ typeof value[0] === "object" &&
203
+ "_type" in value[0]
204
+ ) {
205
+ Object.defineProperty(value, EMDASH_EDIT, {
206
+ value: { collection, id, field } satisfies EditFieldMeta,
207
+ enumerable: false,
208
+ configurable: true,
209
+ });
210
+ }
211
+ }
212
+ }
213
+
214
+ /** Safely read a string field from a Record, with optional fallback */
215
+ function dataStr(data: Record<string, unknown>, key: string, fallback = ""): string {
216
+ const val = data[key];
217
+ return typeof val === "string" ? val : fallback;
218
+ }
219
+
220
+ /** Type guard for Record<string, unknown> */
221
+ function isRecord(value: unknown): value is Record<string, unknown> {
222
+ return typeof value === "object" && value !== null && !Array.isArray(value);
223
+ }
224
+
225
+ /** Extract data as Record from an Astro entry (which is any-typed) */
226
+ function entryData(entry: { data?: unknown }): Record<string, unknown> {
227
+ return isRecord(entry.data) ? entry.data : {};
228
+ }
229
+
230
+ /** Extract the database ID from entry data (data.id is the ULID, entry.id is the slug) */
231
+ function entryDatabaseId(entry: { id: string; data?: unknown }): string {
232
+ const d = entryData(entry);
233
+ return dataStr(d, "id") || entry.id;
234
+ }
235
+
236
+ /** Extract edit options from entry data for the proxy */
237
+ function entryEditOptions(entry: { data?: unknown }): EditableOptions {
238
+ const data = entryData(entry);
239
+ const status = dataStr(data, "status", "draft");
240
+ const draftRevisionId = dataStr(data, "draftRevisionId") || undefined;
241
+ const liveRevisionId = dataStr(data, "liveRevisionId") || undefined;
242
+ const hasDraft = !!draftRevisionId && draftRevisionId !== liveRevisionId;
243
+ return { status, hasDraft };
244
+ }
245
+
246
+ /**
247
+ * Get all entries of a content type
248
+ *
249
+ * Returns { entries, error } for graceful error handling.
250
+ *
251
+ * When emdash-env.d.ts is generated, the collection name will be
252
+ * type-checked and the return type will be inferred automatically.
253
+ *
254
+ * @example
255
+ * ```ts
256
+ * import { getEmDashCollection } from "emdash";
257
+ *
258
+ * const { entries: posts, error } = await getEmDashCollection("posts");
259
+ * if (error) {
260
+ * console.error("Failed to load posts:", error);
261
+ * return;
262
+ * }
263
+ * // posts[0].data.title is typed (if emdash-env.d.ts exists)
264
+ *
265
+ * // With filters
266
+ * const { entries: drafts } = await getEmDashCollection("posts", { status: "draft" });
267
+ * ```
268
+ */
269
+ export async function getEmDashCollection<T extends string, D = InferCollectionData<T>>(
270
+ type: T,
271
+ filter?: CollectionFilter,
272
+ ): Promise<CollectionResult<D>> {
273
+ // Dynamic import to avoid build-time issues
274
+ const { getLiveCollection } = await import("astro:content");
275
+
276
+ // Resolve locale: explicit filter > ALS context > defaultLocale (when i18n enabled)
277
+ // Without this, queries return all locale rows, producing broken IDs
278
+ const ctx = getRequestContext();
279
+ const i18nConfig = getI18nConfig();
280
+ const resolvedLocale =
281
+ filter?.locale ?? ctx?.locale ?? (isI18nEnabled() ? i18nConfig!.defaultLocale : undefined);
282
+
283
+ const result = await getLiveCollection(COLLECTION_NAME, {
284
+ type,
285
+ status: filter?.status,
286
+ limit: filter?.limit,
287
+ cursor: filter?.cursor,
288
+ where: filter?.where,
289
+ orderBy: filter?.orderBy,
290
+ locale: resolvedLocale,
291
+ });
292
+
293
+ const { entries, error, cacheHint } = result;
294
+ // nextCursor is returned by the emdash loader but not part of Astro's base
295
+ // LiveLoader return type. Extract it safely via property descriptor to avoid
296
+ // an unsafe type assertion on the `any`-typed result object.
297
+ const rawCursor = Object.getOwnPropertyDescriptor(result, "nextCursor")?.value;
298
+ const nextCursor: string | undefined = typeof rawCursor === "string" ? rawCursor : undefined;
299
+
300
+ if (error) {
301
+ return { entries: [], error, cacheHint: {} };
302
+ }
303
+
304
+ const isEditMode = ctx?.editMode ?? false;
305
+ const entriesWithEdit = entries.map((entry: ContentEntry<D>) => {
306
+ const dbId = entryDatabaseId(entry);
307
+ if (isEditMode) {
308
+ tagEditableFields(entryData(entry), type, dbId);
309
+ }
310
+ return {
311
+ ...entry,
312
+ edit: isEditMode ? createEditable(type, dbId, entryEditOptions(entry)) : createNoop(),
313
+ };
314
+ });
315
+
316
+ // Eagerly hydrate bylines for all entries
317
+ await hydrateEntryBylines(type, entriesWithEdit);
318
+
319
+ return { entries: entriesWithEdit, nextCursor, cacheHint: cacheHint ?? {} };
320
+ }
321
+
322
+ /**
323
+ * Get a single entry by type and ID/slug
324
+ *
325
+ * Returns { entry, error, isPreview } for graceful error handling.
326
+ * - entry is null if not found (not an error)
327
+ * - error is set only for actual errors (db issues, etc.)
328
+ *
329
+ * Preview mode is detected automatically from request context (ALS).
330
+ * When the URL has a valid `_preview` token, the middleware sets preview
331
+ * context and this function serves draft revision data if available.
332
+ *
333
+ * @example
334
+ * ```ts
335
+ * import { getEmDashEntry } from "emdash";
336
+ *
337
+ * // Simple usage — preview just works via middleware
338
+ * const { entry: post, isPreview, error } = await getEmDashEntry("posts", "my-slug");
339
+ * if (!post) return Astro.redirect("/404");
340
+ * ```
341
+ */
342
+ export async function getEmDashEntry<T extends string, D = InferCollectionData<T>>(
343
+ type: T,
344
+ id: string,
345
+ options?: { locale?: string },
346
+ ): Promise<EntryResult<D>> {
347
+ // Dynamic import to avoid build-time issues
348
+ const { getLiveEntry } = await import("astro:content");
349
+
350
+ // Check ALS for preview and edit mode context
351
+ const ctx = getRequestContext();
352
+ const preview = ctx?.preview;
353
+ const isEditMode = ctx?.editMode ?? false;
354
+ const isPreviewMode = !!preview && preview.collection === type;
355
+ // Edit mode implies preview — editors should see draft content
356
+ const serveDrafts = isPreviewMode || isEditMode;
357
+
358
+ // Resolve locale: explicit option > ALS context > undefined (no filter)
359
+ const requestedLocale = options?.locale ?? ctx?.locale;
360
+
361
+ /** Wrap a raw Astro entry with edit proxy, tagging editable fields if needed */
362
+ function wrapEntry(raw: ContentEntry<D>): ContentEntry<D> {
363
+ const dbId = entryDatabaseId(raw);
364
+ if (isEditMode) {
365
+ tagEditableFields(entryData(raw), type, dbId);
366
+ }
367
+ return {
368
+ ...raw,
369
+ edit: isEditMode ? createEditable(type, dbId, entryEditOptions(raw)) : createNoop(),
370
+ };
371
+ }
372
+
373
+ /** Check if an entry is publicly visible (published or scheduled past its time) */
374
+ function isVisible(entry: ContentEntry<D>): boolean {
375
+ const data = entryData(entry);
376
+ const status = dataStr(data, "status");
377
+ const scheduledAt = dataStr(data, "scheduledAt") || undefined;
378
+ const isPublished = status === "published";
379
+ const isScheduledAndReady =
380
+ status === "scheduled" && scheduledAt && new Date(scheduledAt) <= new Date();
381
+ return isPublished || !!isScheduledAndReady;
382
+ }
383
+
384
+ // Build the fallback chain: [requestedLocale, fallback1, ..., defaultLocale]
385
+ // When i18n is disabled or no locale requested, just use a single-element chain
386
+ const localeChain =
387
+ requestedLocale && isI18nEnabled() ? getFallbackChain(requestedLocale) : [requestedLocale];
388
+
389
+ /** Return a successful EntryResult with bylines hydrated */
390
+ async function successResult(
391
+ wrapped: ContentEntry<D>,
392
+ opts: { isPreview: boolean; fallbackLocale?: string; cacheHint: CacheHint },
393
+ ): Promise<EntryResult<D>> {
394
+ await hydrateEntryBylines(type, [wrapped]);
395
+ return {
396
+ entry: wrapped,
397
+ isPreview: opts.isPreview,
398
+ fallbackLocale: opts.fallbackLocale,
399
+ cacheHint: opts.cacheHint,
400
+ };
401
+ }
402
+
403
+ if (serveDrafts) {
404
+ // Draft mode: try each locale in the fallback chain
405
+ for (let i = 0; i < localeChain.length; i++) {
406
+ const locale = localeChain[i];
407
+ const fallbackLocale = i > 0 ? locale : undefined;
408
+
409
+ const {
410
+ entry: baseEntry,
411
+ error: baseError,
412
+ cacheHint,
413
+ } = await getLiveEntry(COLLECTION_NAME, {
414
+ type,
415
+ id,
416
+ locale,
417
+ });
418
+
419
+ if (baseError) {
420
+ return { entry: null, error: baseError, isPreview: serveDrafts, cacheHint: {} };
421
+ }
422
+
423
+ if (!baseEntry) continue; // Try next locale in chain
424
+
425
+ // Check if entry has a draft revision — if so, re-fetch with revision data
426
+ const baseData = entryData(baseEntry);
427
+ const draftRevisionId = dataStr(baseData, "draftRevisionId") || undefined;
428
+
429
+ if (draftRevisionId) {
430
+ const { entry: draftEntry, error: draftError } = await getLiveEntry(COLLECTION_NAME, {
431
+ type,
432
+ id,
433
+ revisionId: draftRevisionId,
434
+ locale,
435
+ });
436
+
437
+ if (!draftError && draftEntry) {
438
+ return successResult(wrapEntry(draftEntry), {
439
+ isPreview: serveDrafts,
440
+ fallbackLocale,
441
+ cacheHint: cacheHint ?? {},
442
+ });
443
+ }
444
+ }
445
+
446
+ return successResult(wrapEntry(baseEntry), {
447
+ isPreview: serveDrafts,
448
+ fallbackLocale,
449
+ cacheHint: cacheHint ?? {},
450
+ });
451
+ }
452
+
453
+ // No entry found in any locale
454
+ return { entry: null, isPreview: serveDrafts, cacheHint: {} };
455
+ }
456
+
457
+ // Normal mode: try each locale in the fallback chain, only return published content
458
+ for (let i = 0; i < localeChain.length; i++) {
459
+ const locale = localeChain[i];
460
+ const fallbackLocale = i > 0 ? locale : undefined;
461
+
462
+ const { entry, error, cacheHint } = await getLiveEntry(COLLECTION_NAME, { type, id, locale });
463
+ if (error) {
464
+ return { entry: null, error, isPreview: false, cacheHint: {} };
465
+ }
466
+
467
+ if (entry && isVisible(entry)) {
468
+ return successResult(wrapEntry(entry), {
469
+ isPreview: false,
470
+ fallbackLocale,
471
+ cacheHint: cacheHint ?? {},
472
+ });
473
+ }
474
+ // Entry not found or not visible in this locale — try next
475
+ }
476
+
477
+ return { entry: null, isPreview: false, cacheHint: {} };
478
+ }
479
+
480
+ /**
481
+ * Eagerly hydrate byline data onto entry.data for one or more entries.
482
+ *
483
+ * Attaches `bylines` (array of ContentBylineCredit) and `byline`
484
+ * (primary BylineSummary or null) to each entry's data object.
485
+ * Uses batch queries to avoid N+1.
486
+ *
487
+ * Fails silently if the byline tables don't exist yet (pre-migration).
488
+ */
489
+ async function hydrateEntryBylines<D>(type: string, entries: ContentEntry<D>[]): Promise<void> {
490
+ if (entries.length === 0) return;
491
+
492
+ try {
493
+ const { getBylinesForEntries } = await import("./bylines/index.js");
494
+
495
+ const ids = entries.map((e) => dataStr(entryData(e), "id")).filter(Boolean);
496
+ if (ids.length === 0) return;
497
+
498
+ const bylinesMap = await getBylinesForEntries(type, ids);
499
+
500
+ for (const entry of entries) {
501
+ const data = entryData(entry);
502
+ const dbId = dataStr(data, "id");
503
+ if (!dbId) continue;
504
+
505
+ const credits = bylinesMap.get(dbId) ?? [];
506
+ data.bylines = credits;
507
+ data.byline = credits[0]?.byline ?? null;
508
+ }
509
+ } catch (err) {
510
+ // Only swallow "table not found" errors from pre-migration databases
511
+ const msg = err instanceof Error ? err.message : "";
512
+ if (!msg.includes("no such table")) {
513
+ console.warn("[emdash] Failed to hydrate bylines:", msg);
514
+ }
515
+ }
516
+ }
517
+
518
+ /**
519
+ * Translation summary for a single locale variant
520
+ */
521
+ export interface TranslationSummary {
522
+ /** Content item ID */
523
+ id: string;
524
+ /** Locale code (e.g. "en", "fr") */
525
+ locale: string;
526
+ /** URL slug */
527
+ slug: string | null;
528
+ /** Current status */
529
+ status: string;
530
+ }
531
+
532
+ /**
533
+ * Result from getTranslations
534
+ */
535
+ export interface TranslationsResult {
536
+ /** The translation group ID (shared across locales) */
537
+ translationGroup: string;
538
+ /** All locale variants in this group */
539
+ translations: TranslationSummary[];
540
+ /** Error if the query failed */
541
+ error?: Error;
542
+ }
543
+
544
+ /**
545
+ * Get all translations of a content item.
546
+ *
547
+ * Given a content entry, returns all locale variants that share the same
548
+ * translation group. This is useful for building language switcher UI.
549
+ *
550
+ * @example
551
+ * ```ts
552
+ * import { getEmDashEntry, getTranslations } from "emdash";
553
+ *
554
+ * const { entry: post } = await getEmDashEntry("posts", "hello-world", { locale: "en" });
555
+ * const { translations } = await getTranslations("posts", post.data.id);
556
+ * // translations = [{ id: "...", locale: "en", slug: "hello-world", status: "published" }, ...]
557
+ * ```
558
+ */
559
+ export async function getTranslations(type: string, id: string): Promise<TranslationsResult> {
560
+ try {
561
+ const db = (await import("./loader.js")).getDb;
562
+ const dbInstance = await db();
563
+ const { ContentRepository } = await import("./database/repositories/content.js");
564
+ const repo = new ContentRepository(dbInstance);
565
+
566
+ // Find the item to get its translation group
567
+ const item = await repo.findByIdOrSlug(type, id);
568
+ if (!item) {
569
+ return {
570
+ translationGroup: "",
571
+ translations: [],
572
+ error: new Error(`Content item not found: ${id}`),
573
+ };
574
+ }
575
+
576
+ const group = item.translationGroup || item.id;
577
+ const translations = await repo.findTranslations(type, group);
578
+
579
+ return {
580
+ translationGroup: group,
581
+ translations: translations.map((t) => ({
582
+ id: t.id,
583
+ locale: t.locale || "en",
584
+ slug: t.slug,
585
+ status: t.status,
586
+ })),
587
+ };
588
+ } catch (error) {
589
+ return {
590
+ translationGroup: "",
591
+ translations: [],
592
+ error: error instanceof Error ? error : new Error(String(error)),
593
+ };
594
+ }
595
+ }
596
+
597
+ /**
598
+ * Result from resolveEmDashPath
599
+ */
600
+ export interface ResolvePathResult<T = Record<string, unknown>> {
601
+ /** The matched entry */
602
+ entry: ContentEntry<T>;
603
+ /** The collection slug that matched */
604
+ collection: string;
605
+ /** Extracted parameters from the URL pattern (e.g. { slug: "my-post" }) */
606
+ params: Record<string, string>;
607
+ }
608
+
609
+ /** Matches `{paramName}` placeholders in URL patterns */
610
+ const URL_PARAM_PATTERN = /\{(\w+)\}/g;
611
+
612
+ /** Convert a URL pattern like "/blog/{slug}" to a regex and param name list */
613
+ function patternToRegex(pattern: string): { regex: RegExp; paramNames: string[] } {
614
+ const paramNames: string[] = [];
615
+ const regexStr = pattern.replace(URL_PARAM_PATTERN, (_match, name: string) => {
616
+ paramNames.push(name);
617
+ return "([^/]+)";
618
+ });
619
+ return { regex: new RegExp(`^${regexStr}$`), paramNames };
620
+ }
621
+
622
+ /**
623
+ * Resolve a URL path to a content entry by matching against collection URL patterns.
624
+ *
625
+ * Loads all collections with a `urlPattern` set, converts each pattern to a regex,
626
+ * and tests the given path. On match, extracts the slug and fetches the entry.
627
+ *
628
+ * @example
629
+ * ```ts
630
+ * import { resolveEmDashPath } from "emdash";
631
+ *
632
+ * // Given pages with urlPattern "/{slug}" and posts with "/blog/{slug}":
633
+ * const result = await resolveEmDashPath("/blog/hello-world");
634
+ * if (result) {
635
+ * console.log(result.collection); // "posts"
636
+ * console.log(result.params.slug); // "hello-world"
637
+ * console.log(result.entry.data); // post data
638
+ * }
639
+ * ```
640
+ */
641
+ export async function resolveEmDashPath<T = Record<string, unknown>>(
642
+ path: string,
643
+ ): Promise<ResolvePathResult<T> | null> {
644
+ const { getDb } = await import("./loader.js");
645
+ const { SchemaRegistry } = await import("./schema/registry.js");
646
+ const db = await getDb();
647
+ const registry = new SchemaRegistry(db);
648
+ const collections = await registry.listCollections();
649
+
650
+ for (const collection of collections) {
651
+ if (!collection.urlPattern) continue;
652
+
653
+ const { regex, paramNames } = patternToRegex(collection.urlPattern);
654
+ const match = path.match(regex);
655
+ if (!match) continue;
656
+
657
+ // Extract params
658
+ const params: Record<string, string> = {};
659
+ for (let i = 0; i < paramNames.length; i++) {
660
+ params[paramNames[i]] = match[i + 1];
661
+ }
662
+
663
+ // Look up entry by slug (most common pattern)
664
+ const slug = params.slug;
665
+ if (!slug) continue;
666
+
667
+ const { entry } = await getEmDashEntry<string, T>(collection.slug, slug);
668
+ if (entry) {
669
+ return { entry, collection: collection.slug, params };
670
+ }
671
+ }
672
+
673
+ return null;
674
+ }