emdash 0.0.0-b → 0.0.2

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 -43
  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 +1336 -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-C0hCbYnD.mjs +1412 -0
  127. package/dist/runner-C0hCbYnD.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 +684 -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 +349 -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 +335 -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 +116 -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 +115 -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 +101 -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 +58 -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 +68 -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 +697 -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 +286 -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 +170 -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 +39 -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 +249 -0
  646. package/src/storage/s3.ts +263 -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
@@ -0,0 +1,309 @@
1
+ /**
2
+ * Runtime API for taxonomies
3
+ *
4
+ * Provides functions to query taxonomy definitions and terms.
5
+ */
6
+
7
+ import { getDb } from "../loader.js";
8
+ import type { TaxonomyDef, TaxonomyTerm, TaxonomyTermRow } from "./types.js";
9
+
10
+ /**
11
+ * Get all taxonomy definitions
12
+ */
13
+ export async function getTaxonomyDefs(): Promise<TaxonomyDef[]> {
14
+ const db = await getDb();
15
+
16
+ const rows = await db.selectFrom("_emdash_taxonomy_defs").selectAll().execute();
17
+
18
+ return rows.map((row) => ({
19
+ id: row.id,
20
+ name: row.name,
21
+ label: row.label,
22
+ labelSingular: row.label_singular ?? undefined,
23
+ hierarchical: row.hierarchical === 1,
24
+ collections: row.collections ? JSON.parse(row.collections) : [],
25
+ }));
26
+ }
27
+
28
+ /**
29
+ * Get a single taxonomy definition by name
30
+ */
31
+ export async function getTaxonomyDef(name: string): Promise<TaxonomyDef | null> {
32
+ const db = await getDb();
33
+
34
+ const row = await db
35
+ .selectFrom("_emdash_taxonomy_defs")
36
+ .selectAll()
37
+ .where("name", "=", name)
38
+ .executeTakeFirst();
39
+
40
+ if (!row) return null;
41
+
42
+ return {
43
+ id: row.id,
44
+ name: row.name,
45
+ label: row.label,
46
+ labelSingular: row.label_singular ?? undefined,
47
+ hierarchical: row.hierarchical === 1,
48
+ collections: row.collections ? JSON.parse(row.collections) : [],
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Get all terms for a taxonomy (as tree for hierarchical, flat for tags)
54
+ */
55
+ export async function getTaxonomyTerms(taxonomyName: string): Promise<TaxonomyTerm[]> {
56
+ const db = await getDb();
57
+
58
+ // Get taxonomy definition to check if hierarchical
59
+ const def = await getTaxonomyDef(taxonomyName);
60
+ if (!def) return [];
61
+
62
+ // Get all terms for this taxonomy
63
+ const rows = await db
64
+ .selectFrom("taxonomies")
65
+ .selectAll()
66
+ .where("name", "=", taxonomyName)
67
+ .orderBy("label", "asc")
68
+ .execute();
69
+
70
+ // Count entries for each term
71
+ const countsResult = await db
72
+ .selectFrom("content_taxonomies")
73
+ .select(["taxonomy_id"])
74
+ .select((eb) => eb.fn.count<number>("entry_id").as("count"))
75
+ .groupBy("taxonomy_id")
76
+ .execute();
77
+
78
+ const counts = new Map<string, number>();
79
+ for (const row of countsResult) {
80
+ counts.set(row.taxonomy_id, row.count);
81
+ }
82
+
83
+ const flatTerms: TaxonomyTermRow[] = rows.map((row) => ({
84
+ id: row.id,
85
+ name: row.name,
86
+ slug: row.slug,
87
+ label: row.label,
88
+ parent_id: row.parent_id,
89
+ data: row.data,
90
+ }));
91
+
92
+ // If hierarchical, build tree. Otherwise return flat
93
+ if (def.hierarchical) {
94
+ return buildTree(flatTerms, counts);
95
+ }
96
+
97
+ return flatTerms.map((term) => ({
98
+ id: term.id,
99
+ name: term.name,
100
+ slug: term.slug,
101
+ label: term.label,
102
+ children: [],
103
+ count: counts.get(term.id) ?? 0,
104
+ }));
105
+ }
106
+
107
+ /**
108
+ * Get a single term by taxonomy and slug
109
+ */
110
+ export async function getTerm(taxonomyName: string, slug: string): Promise<TaxonomyTerm | null> {
111
+ const db = await getDb();
112
+
113
+ const row = await db
114
+ .selectFrom("taxonomies")
115
+ .selectAll()
116
+ .where("name", "=", taxonomyName)
117
+ .where("slug", "=", slug)
118
+ .executeTakeFirst();
119
+
120
+ if (!row) return null;
121
+
122
+ // Get entry count
123
+ const countResult = await db
124
+ .selectFrom("content_taxonomies")
125
+ .select((eb) => eb.fn.count<number>("entry_id").as("count"))
126
+ .where("taxonomy_id", "=", row.id)
127
+ .executeTakeFirst();
128
+
129
+ const count = countResult?.count ?? 0;
130
+
131
+ // Get children if hierarchical
132
+ const childRows = await db
133
+ .selectFrom("taxonomies")
134
+ .selectAll()
135
+ .where("parent_id", "=", row.id)
136
+ .orderBy("label", "asc")
137
+ .execute();
138
+
139
+ const children = childRows.map((child) => ({
140
+ id: child.id,
141
+ name: child.name,
142
+ slug: child.slug,
143
+ label: child.label,
144
+ parentId: child.parent_id ?? undefined,
145
+ children: [],
146
+ }));
147
+
148
+ return {
149
+ id: row.id,
150
+ name: row.name,
151
+ slug: row.slug,
152
+ label: row.label,
153
+ parentId: row.parent_id ?? undefined,
154
+ description: row.data ? JSON.parse(row.data).description : undefined,
155
+ children,
156
+ count,
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Get terms assigned to an entry
162
+ */
163
+ export async function getEntryTerms(
164
+ collection: string,
165
+ entryId: string,
166
+ taxonomyName?: string,
167
+ ): Promise<TaxonomyTerm[]> {
168
+ const db = await getDb();
169
+
170
+ let query = db
171
+ .selectFrom("content_taxonomies")
172
+ .innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id")
173
+ .selectAll("taxonomies")
174
+ .where("content_taxonomies.collection", "=", collection)
175
+ .where("content_taxonomies.entry_id", "=", entryId);
176
+
177
+ if (taxonomyName) {
178
+ query = query.where("taxonomies.name", "=", taxonomyName);
179
+ }
180
+
181
+ const rows = await query.execute();
182
+
183
+ return rows.map((row) => ({
184
+ id: row.id,
185
+ name: row.name,
186
+ slug: row.slug,
187
+ label: row.label,
188
+ parentId: row.parent_id ?? undefined,
189
+ children: [],
190
+ }));
191
+ }
192
+
193
+ /**
194
+ * Get terms for multiple entries in a single query (batched API)
195
+ *
196
+ * This is more efficient than calling getEntryTerms for each entry
197
+ * when you need terms for a list of entries.
198
+ *
199
+ * @param collection - The collection type (e.g., "posts")
200
+ * @param entryIds - Array of entry IDs
201
+ * @param taxonomyName - The taxonomy name (e.g., "categories")
202
+ * @returns Map from entry ID to array of terms
203
+ */
204
+ export async function getTermsForEntries(
205
+ collection: string,
206
+ entryIds: string[],
207
+ taxonomyName: string,
208
+ ): Promise<Map<string, TaxonomyTerm[]>> {
209
+ const result = new Map<string, TaxonomyTerm[]>();
210
+
211
+ // Initialize all entry IDs with empty arrays
212
+ for (const id of entryIds) {
213
+ result.set(id, []);
214
+ }
215
+
216
+ if (entryIds.length === 0) {
217
+ return result;
218
+ }
219
+
220
+ const db = await getDb();
221
+
222
+ const rows = await db
223
+ .selectFrom("content_taxonomies")
224
+ .innerJoin("taxonomies", "taxonomies.id", "content_taxonomies.taxonomy_id")
225
+ .select([
226
+ "content_taxonomies.entry_id",
227
+ "taxonomies.id",
228
+ "taxonomies.name",
229
+ "taxonomies.slug",
230
+ "taxonomies.label",
231
+ "taxonomies.parent_id",
232
+ ])
233
+ .where("content_taxonomies.collection", "=", collection)
234
+ .where("content_taxonomies.entry_id", "in", entryIds)
235
+ .where("taxonomies.name", "=", taxonomyName)
236
+ .execute();
237
+
238
+ for (const row of rows) {
239
+ const entryId = row.entry_id;
240
+ const term: TaxonomyTerm = {
241
+ id: row.id,
242
+ name: row.name,
243
+ slug: row.slug,
244
+ label: row.label,
245
+ parentId: row.parent_id ?? undefined,
246
+ children: [],
247
+ };
248
+
249
+ const terms = result.get(entryId);
250
+ if (terms) {
251
+ terms.push(term);
252
+ }
253
+ }
254
+
255
+ return result;
256
+ }
257
+
258
+ /**
259
+ * Get entries by term (wraps getEmDashCollection)
260
+ */
261
+ export async function getEntriesByTerm(
262
+ collection: string,
263
+ taxonomyName: string,
264
+ termSlug: string,
265
+ ): Promise<Array<{ id: string; data: Record<string, unknown> }>> {
266
+ const { getEmDashCollection } = await import("../query.js");
267
+
268
+ // Build options as the expected type — getEmDashCollection accepts
269
+ // a generic options object with `where` for filtering by taxonomy
270
+ const options: Record<string, unknown> = {
271
+ where: { [taxonomyName]: termSlug },
272
+ };
273
+ const { entries } = await getEmDashCollection(collection, options);
274
+
275
+ return entries;
276
+ }
277
+
278
+ /**
279
+ * Build tree structure from flat terms
280
+ */
281
+ function buildTree(flatTerms: TaxonomyTermRow[], counts: Map<string, number>): TaxonomyTerm[] {
282
+ const map = new Map<string, TaxonomyTerm>();
283
+ const roots: TaxonomyTerm[] = [];
284
+
285
+ // First pass: create nodes
286
+ for (const term of flatTerms) {
287
+ map.set(term.id, {
288
+ id: term.id,
289
+ name: term.name,
290
+ slug: term.slug,
291
+ label: term.label,
292
+ parentId: term.parent_id ?? undefined,
293
+ description: term.data ? JSON.parse(term.data).description : undefined,
294
+ children: [],
295
+ count: counts.get(term.id) ?? 0,
296
+ });
297
+ }
298
+
299
+ // Second pass: build tree
300
+ for (const term of map.values()) {
301
+ if (term.parentId && map.has(term.parentId)) {
302
+ map.get(term.parentId)!.children.push(term);
303
+ } else {
304
+ roots.push(term);
305
+ }
306
+ }
307
+
308
+ return roots;
309
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Taxonomy types for EmDash CMS
3
+ */
4
+
5
+ /**
6
+ * Taxonomy definition - describes a taxonomy like "category" or "tag"
7
+ */
8
+ export interface TaxonomyDef {
9
+ id: string;
10
+ name: string; // 'category', 'tag', 'genre'
11
+ label: string; // 'Categories', 'Tags'
12
+ labelSingular?: string; // 'Category', 'Tag'
13
+ hierarchical: boolean;
14
+ collections: string[]; // ['posts', 'pages']
15
+ }
16
+
17
+ /**
18
+ * Taxonomy term - a specific term within a taxonomy (e.g., "News" in "category")
19
+ */
20
+ export interface TaxonomyTerm {
21
+ id: string;
22
+ name: string; // Taxonomy name ('category')
23
+ slug: string; // Term slug ('news')
24
+ label: string; // Display label ('News')
25
+ parentId?: string;
26
+ description?: string;
27
+ children: TaxonomyTerm[]; // For tree structure
28
+ count?: number; // Entry count
29
+ }
30
+
31
+ /**
32
+ * Flat version for DB row
33
+ */
34
+ export interface TaxonomyTermRow {
35
+ id: string;
36
+ name: string;
37
+ slug: string;
38
+ label: string;
39
+ parent_id: string | null;
40
+ data: string | null; // JSON
41
+ }
42
+
43
+ /**
44
+ * Input for creating a term
45
+ */
46
+ export interface CreateTermInput {
47
+ slug: string;
48
+ label: string;
49
+ parentId?: string;
50
+ description?: string;
51
+ }
52
+
53
+ /**
54
+ * Input for updating a term
55
+ */
56
+ export interface UpdateTermInput {
57
+ slug?: string;
58
+ label?: string;
59
+ parentId?: string | null;
60
+ description?: string;
61
+ }
package/src/ui.ts ADDED
@@ -0,0 +1,75 @@
1
+ /**
2
+ * EmDash UI Components
3
+ *
4
+ * Image component for rendering optimized images:
5
+ *
6
+ * ```astro
7
+ * ---
8
+ * import { Image } from "emdash/ui";
9
+ * ---
10
+ * <Image image={post.data.featured_image} />
11
+ * ```
12
+ *
13
+ * Portable Text component for rich content:
14
+ *
15
+ * ```astro
16
+ * ---
17
+ * import { PortableText } from "emdash/ui";
18
+ * ---
19
+ * <PortableText value={post.data.content} />
20
+ * ```
21
+ *
22
+ * Override specific Portable Text components:
23
+ *
24
+ * ```astro
25
+ * <PortableText value={content} components={{ type: { image: MyImage } }} />
26
+ * ```
27
+ */
28
+
29
+ // Re-export types and utilities from astro-portabletext
30
+ export {
31
+ type PortableTextProps,
32
+ type TypedObject,
33
+ type SomePortableTextComponents,
34
+ type Block,
35
+ type ArbitraryTypedObject,
36
+ type PortableTextBlock,
37
+ type PortableTextMarkDefinition,
38
+ type PortableTextSpan,
39
+ type PortableTextListItemBlock,
40
+ usePortableText,
41
+ mergeComponents,
42
+ } from "astro-portabletext";
43
+
44
+ // EmDash PortableText wrapper and components
45
+ export {
46
+ // Main Image component for EmDash media
47
+ EmDashImage as Image,
48
+ // Main component (wrapper with EmDash defaults)
49
+ PortableText,
50
+ // Comment components
51
+ Comments,
52
+ CommentForm,
53
+ // Widget components
54
+ WidgetArea,
55
+ // Components object for manual use
56
+ emdashComponents,
57
+ // Portable Text block types (prefixed to avoid collision with Image)
58
+ Image as PTImage,
59
+ Code,
60
+ Embed,
61
+ Gallery,
62
+ Columns,
63
+ Break,
64
+ HtmlBlock,
65
+ // Marks
66
+ Superscript,
67
+ Subscript,
68
+ Underline,
69
+ StrikeThrough,
70
+ Link,
71
+ // Public page contribution components
72
+ EmDashHead,
73
+ EmDashBodyStart,
74
+ EmDashBodyEnd,
75
+ } from "./components/index.js";
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Base64 encoding/decoding utilities.
3
+ *
4
+ * Uses native Uint8Array.prototype.toBase64 / Uint8Array.fromBase64 when
5
+ * available (workerd, Node 26+, modern browsers), falls back to btoa/atob.
6
+ *
7
+ * All base64url encoding uses the { alphabet: "base64url" } option natively
8
+ * or manual character replacement as fallback.
9
+ *
10
+ * Delete the fallback paths when the minimum Node version supports these
11
+ * methods natively.
12
+ */
13
+
14
+ const hasNative =
15
+ typeof Uint8Array.prototype.toBase64 === "function" &&
16
+ typeof Uint8Array.fromBase64 === "function";
17
+
18
+ // Regex patterns for base64url character replacement
19
+ const BASE64_PLUS_PATTERN = /\+/g;
20
+ const BASE64_SLASH_PATTERN = /\//g;
21
+ const BASE64_PADDING_PATTERN = /=+$/;
22
+ const BASE64URL_DASH_PATTERN = /-/g;
23
+ const BASE64URL_UNDERSCORE_PATTERN = /_/g;
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Standard base64 (for opaque tokens, cursors, Basic Auth, etc.)
27
+ // ---------------------------------------------------------------------------
28
+
29
+ /** Encode a UTF-8 string as standard base64. */
30
+ export function encodeBase64(str: string): string {
31
+ const bytes = new TextEncoder().encode(str);
32
+ if (hasNative) return bytes.toBase64();
33
+ let binary = "";
34
+ for (const b of bytes) binary += String.fromCharCode(b);
35
+ return btoa(binary);
36
+ }
37
+
38
+ /** Decode a standard base64 string to a UTF-8 string. */
39
+ export function decodeBase64(base64: string): string {
40
+ if (hasNative) return new TextDecoder().decode(Uint8Array.fromBase64(base64));
41
+ const binary = atob(base64);
42
+ const bytes = new Uint8Array(binary.length);
43
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
44
+ return new TextDecoder().decode(bytes);
45
+ }
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // Base64url (for tokens, HMAC signatures, PKCE, etc.)
49
+ // ---------------------------------------------------------------------------
50
+
51
+ /** Encode bytes as base64url without padding. */
52
+ export function encodeBase64url(bytes: Uint8Array): string {
53
+ if (hasNative) return bytes.toBase64({ alphabet: "base64url", omitPadding: true });
54
+ let binary = "";
55
+ for (const b of bytes) binary += String.fromCharCode(b);
56
+ return btoa(binary)
57
+ .replace(BASE64_PLUS_PATTERN, "-")
58
+ .replace(BASE64_SLASH_PATTERN, "_")
59
+ .replace(BASE64_PADDING_PATTERN, "");
60
+ }
61
+
62
+ /** Decode a base64url string (with or without padding) to bytes. */
63
+ export function decodeBase64url(encoded: string): Uint8Array {
64
+ if (hasNative) return Uint8Array.fromBase64(encoded, { alphabet: "base64url" });
65
+ const base64 = encoded
66
+ .replace(BASE64URL_DASH_PATTERN, "+")
67
+ .replace(BASE64URL_UNDERSCORE_PATTERN, "/");
68
+ const padded = base64 + "=".repeat((4 - (base64.length % 4)) % 4);
69
+ const binary = atob(padded);
70
+ const bytes = new Uint8Array(binary.length);
71
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
72
+ return bytes;
73
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
3
+ * For cache invalidation / ETags — not for security.
4
+ */
5
+ export async function hashString(content: string): Promise<string> {
6
+ const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(content));
7
+ return Array.from(new Uint8Array(buf).slice(0, 8), (b) => b.toString(16).padStart(2, "0")).join(
8
+ "",
9
+ );
10
+ }
11
+
12
+ /**
13
+ * Compute content hash using Web Crypto API
14
+ *
15
+ * Uses SHA-1 which is the fastest option in SubtleCrypto.
16
+ * SHA-1 is cryptographically weak but fine for content deduplication
17
+ * where we only need to detect identical files, not resist attacks.
18
+ *
19
+ * Returns hex string prefixed with "sha1:" for future-proofing
20
+ */
21
+ export async function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string> {
22
+ // SubtleCrypto.digest() requires BufferSource (ArrayBuffer | ArrayBufferView<ArrayBuffer>).
23
+ // Uint8Array.buffer is ArrayBufferLike which may include SharedArrayBuffer in the type system,
24
+ // so we ensure we have a plain ArrayBuffer.
25
+ let buf: ArrayBuffer;
26
+ if (content instanceof ArrayBuffer) {
27
+ buf = content;
28
+ } else {
29
+ buf = new ArrayBuffer(content.byteLength);
30
+ new Uint8Array(buf).set(content);
31
+ }
32
+ const hashBuffer = await crypto.subtle.digest("SHA-1", buf);
33
+ const hashArray = new Uint8Array(hashBuffer);
34
+ const hashHex = Array.from(hashArray, (b) => b.toString(16).padStart(2, "0")).join("");
35
+ return `sha1:${hashHex}`;
36
+ }
@@ -0,0 +1,20 @@
1
+ import sanitizeHtml from "sanitize-html";
2
+
3
+ /**
4
+ * Sanitize HTML content to prevent XSS attacks.
5
+ *
6
+ * Allows standard formatting tags, images, iframes (from specific providers),
7
+ * and basic attributes.
8
+ */
9
+ export function sanitizeContent(html: string): string {
10
+ return sanitizeHtml(html, {
11
+ allowedTags: [...sanitizeHtml.defaults.allowedTags, "img", "span", "iframe"],
12
+ allowedAttributes: {
13
+ ...sanitizeHtml.defaults.allowedAttributes,
14
+ "*": ["class", "id", "data-*"],
15
+ iframe: ["src", "width", "height", "frameborder", "allow", "allowfullscreen"],
16
+ img: ["src", "srcset", "alt", "title", "width", "height", "loading"],
17
+ },
18
+ allowedIframeHostnames: ["www.youtube.com", "player.vimeo.com"],
19
+ });
20
+ }
@@ -0,0 +1,29 @@
1
+ // Regex patterns for slug normalization
2
+ const DIACRITICS_PATTERN = /[\u0300-\u036f]/g;
3
+ const WHITESPACE_UNDERSCORE_PATTERN = /[\s_]+/g;
4
+ const NON_ALPHANUMERIC_HYPHEN_PATTERN = /[^a-z0-9-]/g;
5
+ const MULTIPLE_HYPHENS_PATTERN = /-+/g;
6
+ const LEADING_TRAILING_HYPHEN_PATTERN = /^-|-$/g;
7
+ const TRAILING_HYPHEN_PATTERN = /-$/;
8
+
9
+ /**
10
+ * Convert a string to a URL-friendly slug.
11
+ *
12
+ * Handles unicode by normalizing to NFD and stripping diacritics,
13
+ * so "café" becomes "cafe", "naïve" becomes "naive", etc.
14
+ */
15
+ export function slugify(text: string, maxLength: number = 80): string {
16
+ return (
17
+ text
18
+ .toLowerCase()
19
+ .normalize("NFD")
20
+ .replace(DIACRITICS_PATTERN, "")
21
+ .replace(WHITESPACE_UNDERSCORE_PATTERN, "-")
22
+ .replace(NON_ALPHANUMERIC_HYPHEN_PATTERN, "")
23
+ .replace(MULTIPLE_HYPHENS_PATTERN, "-")
24
+ .replace(LEADING_TRAILING_HYPHEN_PATTERN, "")
25
+ .slice(0, maxLength)
26
+ // Clean trailing hyphen from truncation
27
+ .replace(TRAILING_HYPHEN_PATTERN, "")
28
+ );
29
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * URL scheme validation utilities
3
+ *
4
+ * Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
5
+ * by allowlisting known-safe schemes before rendering into href attributes.
6
+ */
7
+
8
+ /**
9
+ * Matches URLs that are safe to render in href attributes.
10
+ *
11
+ * Allowed:
12
+ * - http:// and https://
13
+ * - mailto: and tel:
14
+ * - Relative paths (starting with /)
15
+ * - Fragment links (starting with #)
16
+ * - Protocol-relative URLs are NOT allowed (starting with //) as they can
17
+ * redirect to attacker-controlled hosts.
18
+ */
19
+ const SAFE_URL_SCHEME_RE = /^(https?:|mailto:|tel:|\/(?!\/)|#)/i;
20
+
21
+ /**
22
+ * Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
23
+ *
24
+ * Use this at the render layer as the primary defense against XSS via
25
+ * dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * sanitizeHref("https://example.com") // "https://example.com"
30
+ * sanitizeHref("/about") // "/about"
31
+ * sanitizeHref("#section") // "#section"
32
+ * sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
33
+ * sanitizeHref("javascript:alert(1)") // "#"
34
+ * sanitizeHref("data:text/html,<script>") // "#"
35
+ * sanitizeHref("") // "#"
36
+ * ```
37
+ */
38
+ export function sanitizeHref(url: string | undefined | null): string {
39
+ if (!url) return "#";
40
+ return SAFE_URL_SCHEME_RE.test(url) ? url : "#";
41
+ }
42
+
43
+ /**
44
+ * Returns true if the URL uses a safe scheme for rendering in href attributes.
45
+ */
46
+ export function isSafeHref(url: string): boolean {
47
+ return SAFE_URL_SCHEME_RE.test(url);
48
+ }