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
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Media Provider Exports
3
+ *
4
+ * Public API for media providers.
5
+ */
6
+
7
+ // Types
8
+ export type {
9
+ MediaProviderDescriptor,
10
+ MediaProviderCapabilities,
11
+ MediaListOptions,
12
+ MediaListResult,
13
+ MediaProviderItem,
14
+ MediaUploadInput,
15
+ EmbedOptions,
16
+ EmbedResult,
17
+ ImageEmbed,
18
+ VideoEmbed,
19
+ AudioEmbed,
20
+ ComponentEmbed,
21
+ MediaProvider,
22
+ CreateMediaProviderFn,
23
+ MediaValue,
24
+ ThumbnailOptions,
25
+ } from "./types.js";
26
+
27
+ export { mediaItemToValue } from "./types.js";
28
+ export { normalizeMediaValue } from "./normalize.js";
29
+ export { generatePlaceholder, type PlaceholderData } from "./placeholder.js";
30
+
31
+ // Built-in providers
32
+ export { localMedia, type LocalMediaConfig } from "./local.js";
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Local Media Provider Runtime
3
+ *
4
+ * This is the runtime implementation loaded by the entrypoint.
5
+ * It wraps the existing MediaRepository and storage adapter.
6
+ *
7
+ * Note: This provider is special because it needs access to the database
8
+ * and storage adapter. The createMediaProvider function receives these
9
+ * via the config object, injected by the runtime.
10
+ */
11
+
12
+ import type { Kysely } from "kysely";
13
+
14
+ import { MediaRepository } from "../database/repositories/media.js";
15
+ import type { Database } from "../database/types.js";
16
+ import type { Storage } from "../index.js";
17
+ import type {
18
+ CreateMediaProviderFn,
19
+ MediaProvider,
20
+ MediaListOptions,
21
+ MediaProviderItem,
22
+ MediaValue,
23
+ EmbedResult,
24
+ EmbedOptions,
25
+ } from "./types.js";
26
+
27
+ export interface LocalMediaRuntimeConfig {
28
+ enabled?: boolean;
29
+ // These are injected by the runtime, not from user config
30
+ db?: Kysely<Database>;
31
+ storage?: Storage;
32
+ }
33
+
34
+ /**
35
+ * Create the local media provider
36
+ */
37
+ export const createMediaProvider: CreateMediaProviderFn<LocalMediaRuntimeConfig> = (config) => {
38
+ const { db, storage } = config;
39
+
40
+ if (!db) {
41
+ throw new Error("Local media provider requires database connection");
42
+ }
43
+
44
+ const repo = new MediaRepository(db);
45
+
46
+ const provider: MediaProvider = {
47
+ async list(options: MediaListOptions) {
48
+ const result = await repo.findMany({
49
+ cursor: options.cursor,
50
+ limit: options.limit,
51
+ mimeType: options.mimeType,
52
+ // TODO: Add search support when capabilities.search is true
53
+ });
54
+
55
+ return {
56
+ items: result.items.map((item) => ({
57
+ id: item.id,
58
+ filename: item.filename,
59
+ mimeType: item.mimeType,
60
+ size: item.size ?? undefined,
61
+ width: item.width ?? undefined,
62
+ height: item.height ?? undefined,
63
+ alt: item.alt ?? undefined,
64
+ previewUrl: `/_emdash/api/media/file/${item.storageKey}`,
65
+ meta: {
66
+ storageKey: item.storageKey,
67
+ caption: item.caption,
68
+ blurhash: item.blurhash,
69
+ dominantColor: item.dominantColor,
70
+ },
71
+ })),
72
+ nextCursor: result.nextCursor,
73
+ };
74
+ },
75
+
76
+ async get(id: string) {
77
+ const item = await repo.findById(id);
78
+ if (!item) return null;
79
+
80
+ return {
81
+ id: item.id,
82
+ filename: item.filename,
83
+ mimeType: item.mimeType,
84
+ size: item.size ?? undefined,
85
+ width: item.width ?? undefined,
86
+ height: item.height ?? undefined,
87
+ alt: item.alt ?? undefined,
88
+ previewUrl: `/_emdash/api/media/file/${item.storageKey}`,
89
+ meta: {
90
+ storageKey: item.storageKey,
91
+ caption: item.caption,
92
+ blurhash: item.blurhash,
93
+ dominantColor: item.dominantColor,
94
+ },
95
+ };
96
+ },
97
+
98
+ async upload(_input) {
99
+ if (!storage) {
100
+ throw new Error("Storage not configured for local media provider");
101
+ }
102
+
103
+ // This is handled by the existing media upload endpoint
104
+ // The provider interface is used by external providers
105
+ // For local, we delegate to the existing system
106
+ throw new Error("Local upload should use /_emdash/api/media endpoint");
107
+ },
108
+
109
+ async delete(id: string) {
110
+ const item = await repo.findById(id);
111
+ if (!item) return;
112
+
113
+ // Delete from storage if available
114
+ if (storage) {
115
+ try {
116
+ await storage.delete(item.storageKey);
117
+ } catch {
118
+ // Ignore storage deletion errors
119
+ }
120
+ }
121
+
122
+ await repo.delete(id);
123
+ },
124
+
125
+ getEmbed(value: MediaValue, _options?: EmbedOptions): EmbedResult {
126
+ const storageKey =
127
+ typeof value.meta?.storageKey === "string" ? value.meta.storageKey : value.id;
128
+ const src = `/_emdash/api/media/file/${storageKey}`;
129
+ const mimeType = value.mimeType || "";
130
+
131
+ // Determine embed type based on MIME type
132
+ if (mimeType.startsWith("image/")) {
133
+ return {
134
+ type: "image",
135
+ src,
136
+ width: value.width,
137
+ height: value.height,
138
+ alt: value.alt,
139
+ };
140
+ }
141
+
142
+ if (mimeType.startsWith("video/")) {
143
+ return {
144
+ type: "video",
145
+ src,
146
+ width: value.width,
147
+ height: value.height,
148
+ controls: true,
149
+ preload: "metadata",
150
+ };
151
+ }
152
+
153
+ if (mimeType.startsWith("audio/")) {
154
+ return {
155
+ type: "audio",
156
+ src,
157
+ controls: true,
158
+ preload: "metadata",
159
+ };
160
+ }
161
+
162
+ // Fallback: treat as image (for unknown types)
163
+ return {
164
+ type: "image",
165
+ src,
166
+ width: value.width,
167
+ height: value.height,
168
+ alt: value.alt,
169
+ };
170
+ },
171
+
172
+ getThumbnailUrl(id: string, _mimeType?: string) {
173
+ // For local media, return the file URL
174
+ return `/_emdash/api/media/file/${id}`;
175
+ },
176
+ };
177
+
178
+ return provider;
179
+ };
180
+
181
+ /**
182
+ * Helper to convert a MediaRepository item to MediaProviderItem
183
+ */
184
+ export function repoItemToProviderItem(item: {
185
+ id: string;
186
+ filename: string;
187
+ mimeType: string;
188
+ size: number | null;
189
+ width: number | null;
190
+ height: number | null;
191
+ alt: string | null;
192
+ caption: string | null;
193
+ storageKey: string;
194
+ blurhash: string | null;
195
+ dominantColor: string | null;
196
+ }): MediaProviderItem {
197
+ return {
198
+ id: item.id,
199
+ filename: item.filename,
200
+ mimeType: item.mimeType,
201
+ size: item.size ?? undefined,
202
+ width: item.width ?? undefined,
203
+ height: item.height ?? undefined,
204
+ alt: item.alt ?? undefined,
205
+ previewUrl: `/_emdash/api/media/file/${item.storageKey}`,
206
+ meta: {
207
+ storageKey: item.storageKey,
208
+ caption: item.caption,
209
+ blurhash: item.blurhash,
210
+ dominantColor: item.dominantColor,
211
+ },
212
+ };
213
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Local Media Provider
3
+ *
4
+ * The built-in media provider that wraps the current storage adapter and media database.
5
+ * This is the default provider and is available unless explicitly disabled.
6
+ */
7
+
8
+ import type { MediaProviderDescriptor } from "./types.js";
9
+
10
+ export interface LocalMediaConfig {
11
+ /** Whether the local provider is enabled (default true) */
12
+ enabled?: boolean;
13
+ }
14
+
15
+ /**
16
+ * Local media provider configuration
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { localMedia } from "emdash/media";
21
+ *
22
+ * emdash({
23
+ * mediaProviders: [
24
+ * localMedia(), // Uses defaults
25
+ * // or: localMedia({ enabled: false }) to disable
26
+ * ],
27
+ * })
28
+ * ```
29
+ */
30
+ export function localMedia(config: LocalMediaConfig = {}): MediaProviderDescriptor {
31
+ return {
32
+ id: "local",
33
+ name: "Library",
34
+ icon: "📁",
35
+ entrypoint: "emdash/media/local-runtime",
36
+ capabilities: {
37
+ browse: true,
38
+ search: false, // TODO: Add search support
39
+ upload: true,
40
+ delete: true,
41
+ },
42
+ config: {
43
+ enabled: config.enabled ?? true,
44
+ },
45
+ };
46
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Media Value Normalization
3
+ *
4
+ * Normalizes media field values into a consistent shape regardless of
5
+ * creation path (seed scripts, media picker, WP import, URL input).
6
+ *
7
+ * Called at content create/update time when a media provider is available,
8
+ * filling in missing dimensions, storageKey, mimeType, and filename from
9
+ * the provider's `get()` method.
10
+ */
11
+
12
+ import type { MediaProvider, MediaProviderItem, MediaValue } from "./types.js";
13
+
14
+ const INTERNAL_MEDIA_PREFIX = "/_emdash/api/media/file/";
15
+ const URL_PATTERN = /^https?:\/\//;
16
+
17
+ /**
18
+ * Normalize a media field value into a consistent MediaValue shape.
19
+ *
20
+ * - `null`/`undefined` → `null`
21
+ * - Bare URL string → `{ provider: "external", id: "", src: url }`
22
+ * - Bare internal media URL → resolved via local provider's `get()`
23
+ * - Object with `provider` + `id` → enriched with missing fields from provider
24
+ */
25
+ export async function normalizeMediaValue(
26
+ value: unknown,
27
+ getProvider: (id: string) => MediaProvider | undefined,
28
+ ): Promise<MediaValue | null> {
29
+ if (value == null) return null;
30
+
31
+ // Bare string URL
32
+ if (typeof value === "string") {
33
+ return normalizeStringUrl(value, getProvider);
34
+ }
35
+
36
+ // Not an object — can't normalize
37
+ if (!isRecord(value)) return null;
38
+
39
+ // Must have at least an id to be a valid media value
40
+ if (!("id" in value) && !("src" in value)) return null;
41
+
42
+ const provider = (typeof value.provider === "string" ? value.provider : undefined) || "local";
43
+ const id = typeof value.id === "string" ? value.id : "";
44
+
45
+ // External URLs — return as-is, no server-side dimension detection
46
+ if (provider === "external") {
47
+ return recordToMediaValue(value);
48
+ }
49
+
50
+ // Build the base value from the input
51
+ const result: MediaValue = { ...recordToMediaValue(value), provider };
52
+
53
+ // For local media, strip `src` — it's derived at display time from storageKey
54
+ if (provider === "local") {
55
+ delete result.src;
56
+ }
57
+
58
+ // Determine if we need to call the provider
59
+ const needsDimensions = result.width == null || result.height == null;
60
+ const needsStorageKey = provider === "local" && !result.meta?.storageKey;
61
+ const needsFileInfo = !result.mimeType || !result.filename;
62
+ const needsLookup = needsDimensions || needsStorageKey || needsFileInfo;
63
+
64
+ if (!needsLookup || !id) return result;
65
+
66
+ // Try to enrich from provider
67
+ const mediaProvider = getProvider(provider);
68
+ if (!mediaProvider?.get) return result;
69
+
70
+ let providerItem: MediaProviderItem | null;
71
+ try {
72
+ providerItem = await mediaProvider.get(id);
73
+ } catch {
74
+ return result;
75
+ }
76
+
77
+ if (!providerItem) return result;
78
+
79
+ return mergeProviderData(result, providerItem);
80
+ }
81
+
82
+ function normalizeStringUrl(
83
+ url: string,
84
+ getProvider: (id: string) => MediaProvider | undefined,
85
+ ): Promise<MediaValue | null> {
86
+ // Internal media URL — try to resolve via local provider
87
+ if (url.startsWith(INTERNAL_MEDIA_PREFIX)) {
88
+ return resolveInternalUrl(url, getProvider);
89
+ }
90
+
91
+ // External HTTP(S) URL
92
+ if (URL_PATTERN.test(url)) {
93
+ return Promise.resolve({
94
+ provider: "external",
95
+ id: "",
96
+ src: url,
97
+ });
98
+ }
99
+
100
+ // Unrecognized string — treat as external
101
+ return Promise.resolve({
102
+ provider: "external",
103
+ id: "",
104
+ src: url,
105
+ });
106
+ }
107
+
108
+ async function resolveInternalUrl(
109
+ url: string,
110
+ getProvider: (id: string) => MediaProvider | undefined,
111
+ ): Promise<MediaValue> {
112
+ const storageKey = url.slice(INTERNAL_MEDIA_PREFIX.length);
113
+ const localProvider = getProvider("local");
114
+
115
+ if (!localProvider?.get) {
116
+ return { provider: "external", id: "", src: url };
117
+ }
118
+
119
+ let item: MediaProviderItem | null;
120
+ try {
121
+ item = await localProvider.get(storageKey);
122
+ } catch {
123
+ return { provider: "external", id: "", src: url };
124
+ }
125
+
126
+ if (!item) {
127
+ return { provider: "external", id: "", src: url };
128
+ }
129
+
130
+ return {
131
+ provider: "local",
132
+ id: item.id,
133
+ filename: item.filename,
134
+ mimeType: item.mimeType,
135
+ width: item.width,
136
+ height: item.height,
137
+ alt: item.alt,
138
+ meta: item.meta,
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Merge provider data into an existing MediaValue, preserving caller-supplied fields.
144
+ * Caller `alt` takes priority over provider `alt` (per-usage, not per-image).
145
+ */
146
+ function mergeProviderData(existing: MediaValue, item: MediaProviderItem): MediaValue {
147
+ const result = { ...existing };
148
+
149
+ // Fill missing dimensions
150
+ if (result.width == null && item.width != null) result.width = item.width;
151
+ if (result.height == null && item.height != null) result.height = item.height;
152
+
153
+ // Fill missing file info
154
+ if (!result.filename && item.filename) result.filename = item.filename;
155
+ if (!result.mimeType && item.mimeType) result.mimeType = item.mimeType;
156
+
157
+ // Fill missing alt (provider alt is fallback, not override)
158
+ if (!result.alt && item.alt) result.alt = item.alt;
159
+
160
+ // Fill missing meta (merge, don't replace)
161
+ if (item.meta) {
162
+ result.meta = { ...item.meta, ...result.meta };
163
+ }
164
+
165
+ return result;
166
+ }
167
+
168
+ function isRecord(value: unknown): value is Record<string, unknown> {
169
+ return typeof value === "object" && value !== null && !Array.isArray(value);
170
+ }
171
+
172
+ /**
173
+ * Extract known MediaValue fields from a runtime-checked record.
174
+ * Avoids unsafe `as MediaValue` cast by reading each property explicitly.
175
+ */
176
+ function recordToMediaValue(obj: Record<string, unknown>): MediaValue {
177
+ const result: MediaValue = {
178
+ id: typeof obj.id === "string" ? obj.id : "",
179
+ };
180
+ if (typeof obj.provider === "string") result.provider = obj.provider;
181
+ if (typeof obj.src === "string") result.src = obj.src;
182
+ if (typeof obj.previewUrl === "string") result.previewUrl = obj.previewUrl;
183
+ if (typeof obj.filename === "string") result.filename = obj.filename;
184
+ if (typeof obj.mimeType === "string") result.mimeType = obj.mimeType;
185
+ if (typeof obj.width === "number") result.width = obj.width;
186
+ if (typeof obj.height === "number") result.height = obj.height;
187
+ if (typeof obj.alt === "string") result.alt = obj.alt;
188
+ if (isRecord(obj.meta)) result.meta = obj.meta;
189
+ return result;
190
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Image Placeholder Generation
3
+ *
4
+ * Generates blurhash and dominant color from image buffers for LQIP support.
5
+ * Decodes images via jpeg-js (pure JS) and upng-js (pure JS, uses pako for
6
+ * deflate). No Node-specific dependencies — works in Workers and Node SSR.
7
+ */
8
+
9
+ import { encode } from "blurhash";
10
+
11
+ export interface PlaceholderData {
12
+ blurhash: string;
13
+ dominantColor: string;
14
+ }
15
+
16
+ const SUPPORTED_TYPES: Record<string, "jpeg" | "png"> = {
17
+ "image/jpeg": "jpeg",
18
+ "image/jpg": "jpeg",
19
+ "image/png": "png",
20
+ };
21
+
22
+ /** Max width for blurhash input. Encode is O(w*h*components), so downsample first. */
23
+ const MAX_ENCODE_WIDTH = 32;
24
+
25
+ interface DecodedImage {
26
+ width: number;
27
+ height: number;
28
+ data: Uint8Array;
29
+ }
30
+
31
+ /**
32
+ * Decode a JPEG buffer into raw RGBA pixel data.
33
+ */
34
+ async function decodeJpeg(buffer: Uint8Array): Promise<DecodedImage> {
35
+ const { decode } = await import("jpeg-js");
36
+ const result = decode(buffer, { useTArray: true });
37
+ return { width: result.width, height: result.height, data: result.data };
38
+ }
39
+
40
+ /**
41
+ * Decode a PNG buffer into raw RGBA pixel data.
42
+ * Uses upng-js (pure JS with pako deflate) — no Node zlib dependency.
43
+ */
44
+ async function decodePng(buffer: Uint8Array): Promise<DecodedImage> {
45
+ // @ts-expect-error -- upng-js has no type declarations
46
+ const UPNG = (await import("upng-js")).default;
47
+ const img = UPNG.decode(buffer.buffer);
48
+ // toRGBA8 returns an array of frames; take the first frame
49
+ const frames: ArrayBuffer[] = UPNG.toRGBA8(img);
50
+ const rgba = new Uint8Array(frames[0]);
51
+ return { width: img.width, height: img.height, data: rgba };
52
+ }
53
+
54
+ /**
55
+ * Extract the dominant color from RGBA pixel data.
56
+ * Simple average of all non-transparent pixels.
57
+ */
58
+ function extractDominantColor(data: Uint8Array, width: number, height: number): string {
59
+ let r = 0;
60
+ let g = 0;
61
+ let b = 0;
62
+ let count = 0;
63
+
64
+ const len = width * height * 4;
65
+ for (let i = 0; i < len; i += 4) {
66
+ const a = data[i + 3];
67
+ if (a < 128) continue; // skip mostly-transparent pixels
68
+ r += data[i];
69
+ g += data[i + 1];
70
+ b += data[i + 2];
71
+ count++;
72
+ }
73
+
74
+ if (count === 0) return "rgb(0,0,0)";
75
+
76
+ const avgR = Math.round(r / count);
77
+ const avgG = Math.round(g / count);
78
+ const avgB = Math.round(b / count);
79
+ return `rgb(${avgR},${avgG},${avgB})`;
80
+ }
81
+
82
+ /**
83
+ * Generate blurhash and dominant color from an image buffer.
84
+ * Returns null for non-image MIME types or on failure.
85
+ */
86
+ export async function generatePlaceholder(
87
+ buffer: Uint8Array,
88
+ mimeType: string,
89
+ ): Promise<PlaceholderData | null> {
90
+ const format = SUPPORTED_TYPES[mimeType];
91
+ if (!format) return null;
92
+
93
+ try {
94
+ const imageData = format === "jpeg" ? await decodeJpeg(buffer) : await decodePng(buffer);
95
+ const { width, height, data } = imageData;
96
+
97
+ if (width === 0 || height === 0) return null;
98
+
99
+ // Downsample for blurhash encoding if needed
100
+ let encodePixels: Uint8ClampedArray;
101
+ let encodeWidth: number;
102
+ let encodeHeight: number;
103
+
104
+ if (width > MAX_ENCODE_WIDTH) {
105
+ const scale = MAX_ENCODE_WIDTH / width;
106
+ encodeWidth = MAX_ENCODE_WIDTH;
107
+ encodeHeight = Math.max(1, Math.round(height * scale));
108
+ encodePixels = downsample(data, width, height, encodeWidth, encodeHeight);
109
+ } else {
110
+ encodeWidth = width;
111
+ encodeHeight = height;
112
+ encodePixels = new Uint8ClampedArray(data.buffer, data.byteOffset, data.byteLength);
113
+ }
114
+
115
+ const blurhash = encode(encodePixels, encodeWidth, encodeHeight, 4, 3);
116
+ const dominantColor = extractDominantColor(data, width, height);
117
+
118
+ return { blurhash, dominantColor };
119
+ } catch {
120
+ return null;
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Nearest-neighbor downsample of RGBA pixel data.
126
+ */
127
+ function downsample(
128
+ src: Uint8Array,
129
+ srcW: number,
130
+ srcH: number,
131
+ dstW: number,
132
+ dstH: number,
133
+ ): Uint8ClampedArray {
134
+ const dst = new Uint8ClampedArray(dstW * dstH * 4);
135
+
136
+ for (let y = 0; y < dstH; y++) {
137
+ const srcY = Math.floor((y * srcH) / dstH);
138
+ for (let x = 0; x < dstW; x++) {
139
+ const srcX = Math.floor((x * srcW) / dstW);
140
+ const srcIdx = (srcY * srcW + srcX) * 4;
141
+ const dstIdx = (y * dstW + x) * 4;
142
+ dst[dstIdx] = src[srcIdx]!;
143
+ dst[dstIdx + 1] = src[srcIdx + 1]!;
144
+ dst[dstIdx + 2] = src[srcIdx + 2]!;
145
+ dst[dstIdx + 3] = src[srcIdx + 3]!;
146
+ }
147
+ }
148
+
149
+ return dst;
150
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Media Provider Loader
3
+ *
4
+ * Lazy-loads media providers from virtual module for frontend rendering.
5
+ * Similar pattern to getDb() - providers are loaded on first use and cached.
6
+ *
7
+ * This allows EmDashMedia component to render media without requiring
8
+ * the full EmDash runtime to be initialized.
9
+ */
10
+
11
+ import type { MediaProvider, MediaProviderCapabilities } from "./types.js";
12
+
13
+ /**
14
+ * Media provider entry from virtual module
15
+ */
16
+ interface MediaProviderEntry {
17
+ id: string;
18
+ name: string;
19
+ icon?: string;
20
+ capabilities: MediaProviderCapabilities;
21
+ createProvider: (ctx: Record<string, unknown>) => MediaProvider;
22
+ }
23
+
24
+ // Cached provider entries from virtual module
25
+ let virtualMediaProviders: MediaProviderEntry[] | undefined;
26
+
27
+ // Cached provider instances (shared across calls)
28
+ const mediaProviderInstances = new Map<string, MediaProvider>();
29
+
30
+ /**
31
+ * Load media providers from virtual module
32
+ */
33
+ async function loadMediaProviders(): Promise<void> {
34
+ if (virtualMediaProviders === undefined) {
35
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
36
+ // @ts-ignore - virtual module
37
+ const providersModule = await import("virtual:emdash/media-providers");
38
+ virtualMediaProviders = providersModule.mediaProviders || [];
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Get a media provider by ID.
44
+ *
45
+ * Used by EmDashMedia component for frontend rendering.
46
+ * Providers are lazy-loaded from virtual module and cached.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * const provider = await getMediaProvider("cloudflare-images");
51
+ * if (provider) {
52
+ * const embed = provider.getEmbed(mediaValue, { width: 800 });
53
+ * }
54
+ * ```
55
+ */
56
+ export async function getMediaProvider(providerId: string): Promise<MediaProvider | undefined> {
57
+ // Check cache first
58
+ const cached = mediaProviderInstances.get(providerId);
59
+ if (cached) {
60
+ return cached;
61
+ }
62
+
63
+ // Load media providers from virtual module
64
+ await loadMediaProviders();
65
+
66
+ // Find the provider entry
67
+ const entry = virtualMediaProviders?.find((p) => p.id === providerId);
68
+ if (!entry) {
69
+ return undefined;
70
+ }
71
+
72
+ // Create the provider instance
73
+ // For providers that don't need db/storage (like Cloudflare Images),
74
+ // they'll get empty context and use env vars directly
75
+ const provider = entry.createProvider({});
76
+ mediaProviderInstances.set(providerId, provider);
77
+ return provider;
78
+ }