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,4527 @@
1
+ import { _ as MediaValue, m as MediaProviderDescriptor } from "./placeholder-CmGAmqeO.mjs";
2
+ import { t as Database } from "./types-DRjfYOEv.mjs";
3
+ import { a as ContentSeoInput, c as FindManyOptions, l as FindManyResult, o as CreateContentInput, r as ContentItem, t as BylineSummary, u as UpdateContentInput } from "./types-BRuPJGdV.mjs";
4
+ import { D as PageMetadataContribution, G as RequestMeta, L as PluginDefinition, O as PageMetadataEvent, Q as StandardPluginDefinition, T as PageFragmentEvent, V as PluginStorageConfig, f as CronEvent, i as CommentAfterModerateEvent, n as CommentAfterCreateEvent, o as CommentBeforeCreateEvent, p as EmailMessage, q as ResolvedPlugin, w as PageFragmentContribution, x as MediaItem$1, z as PluginManifest } from "./types-DvhsUmSJ.mjs";
5
+ import { g as UpdateFieldInput, h as UpdateCollectionInput, i as CollectionWithFields, l as Field, o as CreateCollectionInput, s as CreateFieldInput, t as Collection } from "./types-C4-fAxN3.mjs";
6
+ import { C as SiteSettingKey, w as SiteSettings } from "./validate-CpBtVMsD.mjs";
7
+ import { d as Storage } from "./types-DaNLHo_T.mjs";
8
+ import { t as DatabaseDescriptor } from "./adapters-BLMa4JGD.mjs";
9
+ import { Kysely } from "kysely";
10
+ import { z } from "astro/zod";
11
+ import { z as z$1 } from "zod";
12
+ import { PortableTextBlock } from "@emdash-cms/gutenberg-to-portable-text";
13
+ import { Readable } from "node:stream";
14
+ import { LiveLoader } from "astro/loaders";
15
+
16
+ //#region src/database/connection.d.ts
17
+ interface DatabaseConfig {
18
+ url: string;
19
+ authToken?: string;
20
+ }
21
+ declare class EmDashDatabaseError extends Error {
22
+ cause?: unknown | undefined;
23
+ constructor(message: string, cause?: unknown | undefined);
24
+ }
25
+ //#endregion
26
+ //#region src/database/repositories/content.d.ts
27
+ /**
28
+ * Repository for content CRUD operations
29
+ *
30
+ * Content is stored in per-collection tables (ec_posts, ec_pages, etc.)
31
+ * Each field becomes a real column in the table.
32
+ */
33
+ declare class ContentRepository {
34
+ private db;
35
+ constructor(db: Kysely<Database>);
36
+ /**
37
+ * Create a new content item
38
+ */
39
+ create(input: CreateContentInput): Promise<ContentItem>;
40
+ /**
41
+ * Generate a unique slug for a content item within a collection.
42
+ *
43
+ * Checks the collection table for existing slugs that match `baseSlug`
44
+ * (optionally scoped to a locale) and appends a numeric suffix (`-1`,
45
+ * `-2`, etc.) on collision to guarantee uniqueness.
46
+ *
47
+ * Returns `null` if `baseSlug` is empty after slugification.
48
+ */
49
+ generateUniqueSlug(type: string, text: string, locale?: string): Promise<string | null>;
50
+ /**
51
+ * Duplicate a content item
52
+ * Creates a new draft copy with "(Copy)" appended to the title.
53
+ * A slug is auto-generated from the new title by the handler layer.
54
+ */
55
+ duplicate(type: string, id: string, authorId?: string): Promise<ContentItem>;
56
+ /**
57
+ * Find content by ID
58
+ */
59
+ findById(type: string, id: string): Promise<ContentItem | null>;
60
+ /**
61
+ * Find content by id, including trashed (soft-deleted) items.
62
+ * Used by restore endpoint for ownership checks.
63
+ */
64
+ findByIdIncludingTrashed(type: string, id: string): Promise<ContentItem | null>;
65
+ /**
66
+ * Find content by ID or slug. Tries ID first if it looks like a ULID,
67
+ * otherwise tries slug. Falls back to the other if the first lookup misses.
68
+ */
69
+ findByIdOrSlug(type: string, identifier: string, locale?: string): Promise<ContentItem | null>;
70
+ /**
71
+ * Find content by ID or slug, including trashed (soft-deleted) items.
72
+ * Used by restore/permanent-delete endpoints.
73
+ */
74
+ findByIdOrSlugIncludingTrashed(type: string, identifier: string, locale?: string): Promise<ContentItem | null>;
75
+ private _findByIdOrSlug;
76
+ /**
77
+ * Find content by slug
78
+ */
79
+ findBySlug(type: string, slug: string, locale?: string): Promise<ContentItem | null>;
80
+ /**
81
+ * Find content by slug, including trashed (soft-deleted) items.
82
+ * Used by restore/permanent-delete endpoints.
83
+ */
84
+ findBySlugIncludingTrashed(type: string, slug: string, locale?: string): Promise<ContentItem | null>;
85
+ /**
86
+ * Find many content items with filtering and pagination
87
+ */
88
+ findMany(type: string, options?: FindManyOptions): Promise<FindManyResult<ContentItem>>;
89
+ /**
90
+ * Update content
91
+ */
92
+ update(type: string, id: string, input: UpdateContentInput): Promise<ContentItem>;
93
+ /**
94
+ * Delete content (soft delete - moves to trash)
95
+ */
96
+ delete(type: string, id: string): Promise<boolean>;
97
+ /**
98
+ * Restore content from trash
99
+ */
100
+ restore(type: string, id: string): Promise<boolean>;
101
+ /**
102
+ * Permanently delete content (cannot be undone)
103
+ */
104
+ permanentDelete(type: string, id: string): Promise<boolean>;
105
+ /**
106
+ * Find trashed content items
107
+ */
108
+ findTrashed(type: string, options?: Omit<FindManyOptions, "where">): Promise<FindManyResult<ContentItem & {
109
+ deletedAt: string;
110
+ }>>;
111
+ /**
112
+ * Count trashed content items
113
+ */
114
+ countTrashed(type: string): Promise<number>;
115
+ /**
116
+ * Count content items
117
+ */
118
+ count(type: string, where?: {
119
+ status?: string;
120
+ authorId?: string;
121
+ locale?: string;
122
+ }): Promise<number>;
123
+ /**
124
+ * Schedule content for future publishing
125
+ *
126
+ * Sets status to 'scheduled' and stores the scheduled publish time.
127
+ * The content will be auto-published when the scheduled time is reached.
128
+ */
129
+ schedule(type: string, id: string, scheduledAt: string): Promise<ContentItem>;
130
+ /**
131
+ * Unschedule content
132
+ *
133
+ * Clears the scheduled time. Published posts stay published;
134
+ * draft/scheduled posts revert to 'draft'.
135
+ */
136
+ unschedule(type: string, id: string): Promise<ContentItem>;
137
+ /**
138
+ * Find content that is ready to be published
139
+ *
140
+ * Returns all content where scheduled_at <= now, regardless of status.
141
+ * This covers both draft-scheduled posts (status='scheduled') and
142
+ * published posts with scheduled draft changes (status='published').
143
+ */
144
+ findReadyToPublish(type: string): Promise<ContentItem[]>;
145
+ /**
146
+ * Find all translations in a translation group
147
+ */
148
+ findTranslations(type: string, translationGroup: string): Promise<ContentItem[]>;
149
+ /**
150
+ * Publish the current draft
151
+ *
152
+ * Promotes draft_revision_id to live_revision_id and clears draft pointer.
153
+ * Syncs the draft revision's data into the content table columns so the
154
+ * content table always reflects the published version.
155
+ * If no draft revision exists, creates one from current data and publishes it.
156
+ */
157
+ publish(type: string, id: string): Promise<ContentItem>;
158
+ /**
159
+ * Unpublish content
160
+ *
161
+ * Removes live pointer but preserves draft. If no draft exists,
162
+ * creates one from the live version so the content isn't lost.
163
+ */
164
+ unpublish(type: string, id: string): Promise<ContentItem>;
165
+ /**
166
+ * Discard pending draft changes
167
+ *
168
+ * Clears draft_revision_id. The content table columns already hold the
169
+ * published version, so no data sync is needed.
170
+ */
171
+ discardDraft(type: string, id: string): Promise<ContentItem>;
172
+ /**
173
+ * Sync data columns in the content table from a data object.
174
+ * Used to promote revision data into the content table on publish.
175
+ * Keys starting with _ are revision metadata (e.g. _slug) and are skipped.
176
+ */
177
+ private syncDataColumns;
178
+ /**
179
+ * Count content items with a pending schedule.
180
+ * Includes both draft-scheduled (status='scheduled') and published
181
+ * posts with scheduled draft changes (status='published', scheduled_at set).
182
+ */
183
+ countScheduled(type: string): Promise<number>;
184
+ /**
185
+ * Map database row to ContentItem
186
+ * Extracts system columns and puts content fields in data
187
+ * Excludes null values from data to match input semantics
188
+ */
189
+ private mapRow;
190
+ /**
191
+ * Map order field names to database columns.
192
+ * Only allows known fields to prevent column enumeration via crafted orderBy values.
193
+ */
194
+ private mapOrderField;
195
+ }
196
+ //#endregion
197
+ //#region src/database/repositories/media.d.ts
198
+ type MediaStatus = "pending" | "ready" | "failed";
199
+ interface MediaItem {
200
+ id: string;
201
+ filename: string;
202
+ mimeType: string;
203
+ size: number | null;
204
+ width: number | null;
205
+ height: number | null;
206
+ alt: string | null;
207
+ caption: string | null;
208
+ storageKey: string;
209
+ status: MediaStatus;
210
+ contentHash: string | null;
211
+ blurhash: string | null;
212
+ dominantColor: string | null;
213
+ createdAt: string;
214
+ authorId: string | null;
215
+ }
216
+ interface CreateMediaInput {
217
+ filename: string;
218
+ mimeType: string;
219
+ size?: number;
220
+ width?: number;
221
+ height?: number;
222
+ alt?: string;
223
+ caption?: string;
224
+ storageKey: string;
225
+ contentHash?: string;
226
+ blurhash?: string;
227
+ dominantColor?: string;
228
+ status?: MediaStatus;
229
+ authorId?: string;
230
+ }
231
+ interface FindManyMediaOptions {
232
+ limit?: number;
233
+ cursor?: string;
234
+ mimeType?: string;
235
+ status?: MediaStatus | "all";
236
+ }
237
+ /**
238
+ * Media repository for database operations
239
+ */
240
+ declare class MediaRepository {
241
+ private db;
242
+ constructor(db: Kysely<Database>);
243
+ /**
244
+ * Create a new media item
245
+ */
246
+ create(input: CreateMediaInput): Promise<MediaItem>;
247
+ /**
248
+ * Create a pending media item (for signed URL upload flow)
249
+ */
250
+ createPending(input: {
251
+ filename: string;
252
+ mimeType: string;
253
+ size?: number;
254
+ storageKey: string;
255
+ contentHash?: string;
256
+ authorId?: string;
257
+ }): Promise<MediaItem>;
258
+ /**
259
+ * Confirm upload (mark as ready)
260
+ */
261
+ confirmUpload(id: string, metadata?: {
262
+ width?: number;
263
+ height?: number;
264
+ size?: number;
265
+ }): Promise<MediaItem | null>;
266
+ /**
267
+ * Mark upload as failed
268
+ */
269
+ markFailed(id: string): Promise<MediaItem | null>;
270
+ /**
271
+ * Find media by ID
272
+ */
273
+ findById(id: string): Promise<MediaItem | null>;
274
+ /**
275
+ * Find media by filename
276
+ * Useful for idempotent imports
277
+ */
278
+ findByFilename(filename: string): Promise<MediaItem | null>;
279
+ /**
280
+ * Find media by content hash
281
+ * Used for deduplication - same content = same hash
282
+ */
283
+ findByContentHash(contentHash: string): Promise<MediaItem | null>;
284
+ /**
285
+ * Find many media items with cursor pagination
286
+ *
287
+ * Uses keyset pagination (cursor-based) for consistent results.
288
+ * The cursor encodes the created_at and id of the last item.
289
+ */
290
+ findMany(options?: FindManyMediaOptions): Promise<FindManyResult<MediaItem>>;
291
+ /**
292
+ * Update media metadata
293
+ */
294
+ update(id: string, input: Partial<Pick<CreateMediaInput, "alt" | "caption" | "width" | "height">>): Promise<MediaItem | null>;
295
+ /**
296
+ * Delete media item
297
+ */
298
+ delete(id: string): Promise<boolean>;
299
+ /**
300
+ * Count media items
301
+ */
302
+ count(mimeType?: string): Promise<number>;
303
+ /**
304
+ * Delete pending uploads older than the given age.
305
+ * Pending uploads that were never confirmed indicate abandoned upload flows.
306
+ *
307
+ * Returns the storage keys of deleted rows so callers can remove the
308
+ * corresponding files from object storage.
309
+ */
310
+ cleanupPendingUploads(maxAgeMs?: number): Promise<string[]>;
311
+ /**
312
+ * Convert database row to MediaItem
313
+ */
314
+ private rowToItem;
315
+ }
316
+ //#endregion
317
+ //#region src/database/repositories/revision.d.ts
318
+ interface Revision {
319
+ id: string;
320
+ collection: string;
321
+ entryId: string;
322
+ data: Record<string, unknown>;
323
+ authorId: string | null;
324
+ createdAt: string;
325
+ }
326
+ //#endregion
327
+ //#region src/database/repositories/comment.d.ts
328
+ /** Public-facing comment shape — no private fields */
329
+ interface PublicComment {
330
+ id: string;
331
+ parentId: string | null;
332
+ authorName: string;
333
+ isRegisteredUser: boolean;
334
+ body: string;
335
+ createdAt: string;
336
+ replies?: PublicComment[];
337
+ }
338
+ //#endregion
339
+ //#region src/database/repositories/byline.d.ts
340
+ interface ContentBylineInput {
341
+ bylineId: string;
342
+ roleLabel?: string | null;
343
+ }
344
+ //#endregion
345
+ //#region src/fields/types.d.ts
346
+ /**
347
+ * SQLite column types that map from field types
348
+ */
349
+ type ColumnType = "TEXT" | "REAL" | "INTEGER" | "JSON";
350
+ /**
351
+ * Base field definition
352
+ *
353
+ * Note: schema uses z.ZodTypeAny to accommodate optional/default wrappers
354
+ */
355
+ interface FieldDefinition<_T = unknown> {
356
+ type: string;
357
+ /**
358
+ * The SQLite column type to use when storing this field
359
+ */
360
+ columnType: ColumnType;
361
+ schema: z.ZodTypeAny;
362
+ options?: unknown;
363
+ ui?: FieldUIHints;
364
+ }
365
+ /**
366
+ * UI hints for admin rendering
367
+ */
368
+ interface FieldUIHints {
369
+ widget?: string;
370
+ placeholder?: string;
371
+ helpText?: string;
372
+ rows?: number;
373
+ min?: number | string;
374
+ max?: number | string;
375
+ [key: string]: unknown;
376
+ }
377
+ /**
378
+ * Portable Text block structure
379
+ */
380
+ interface PortableTextBlock$2 {
381
+ _type: string;
382
+ _key: string;
383
+ [key: string]: unknown;
384
+ }
385
+ /**
386
+ * @deprecated Use MediaValue instead. ImageValue is an alias for backwards compatibility.
387
+ */
388
+ type ImageValue = MediaValue;
389
+ /**
390
+ * File field value
391
+ */
392
+ interface FileValue {
393
+ id: string;
394
+ url: string;
395
+ filename: string;
396
+ mimeType: string;
397
+ size: number;
398
+ }
399
+ //#endregion
400
+ //#region src/fields/image.d.ts
401
+ /**
402
+ * Image field
403
+ * References media items from the media library
404
+ */
405
+ declare function image(options?: {
406
+ required?: boolean;
407
+ maxSize?: number;
408
+ allowedTypes?: string[];
409
+ }): FieldDefinition<ImageValue | undefined>;
410
+ //#endregion
411
+ //#region src/fields/reference.d.ts
412
+ /**
413
+ * Reference field
414
+ * References another content item by ID
415
+ */
416
+ declare function reference(collection: string, options?: {
417
+ required?: boolean;
418
+ }): FieldDefinition<string | undefined>;
419
+ //#endregion
420
+ //#region src/fields/portable-text.d.ts
421
+ /**
422
+ * Portable Text field
423
+ * Stores structured content in Portable Text format
424
+ */
425
+ declare function portableText(options?: {
426
+ required?: boolean;
427
+ }): FieldDefinition<PortableTextBlock$2[] | undefined>;
428
+ //#endregion
429
+ //#region src/api/types.d.ts
430
+ /**
431
+ * List response with cursor pagination
432
+ */
433
+ interface ListResponse<T> {
434
+ items: T[];
435
+ nextCursor?: string;
436
+ }
437
+ /**
438
+ * Content API responses
439
+ */
440
+ interface ContentListResponse extends ListResponse<ContentItem> {}
441
+ interface ContentResponse {
442
+ item: ContentItem;
443
+ /** Opaque revision token for optimistic concurrency */
444
+ _rev?: string;
445
+ }
446
+ /**
447
+ * Manifest API response
448
+ */
449
+ interface ManifestResponse {
450
+ version: string;
451
+ hash: string;
452
+ collections: Record<string, {
453
+ label: string;
454
+ labelSingular: string;
455
+ supports: string[];
456
+ fields: Record<string, FieldDescriptor>;
457
+ }>;
458
+ plugins: Record<string, {
459
+ adminPages?: Array<{
460
+ path: string;
461
+ component: string;
462
+ }>;
463
+ widgets?: string[];
464
+ }>;
465
+ }
466
+ interface FieldDescriptor {
467
+ kind: string;
468
+ label?: string;
469
+ required?: boolean;
470
+ options?: Array<{
471
+ value: string;
472
+ label: string;
473
+ }>;
474
+ }
475
+ /**
476
+ * Discriminated union for handler results.
477
+ *
478
+ * Handlers return `ApiResult<T>` -- either `{ success: true, data: T }` or
479
+ * `{ success: false, error: { code, message } }`. The `success` literal
480
+ * enables TypeScript narrowing on `.data`.
481
+ *
482
+ * The generic `E` parameter defaults to `ErrorCode` but can be narrowed to
483
+ * `OAuthErrorCode` for OAuth token-endpoint handlers.
484
+ *
485
+ * Use `unwrapResult()` from `error.ts` to convert to an HTTP Response.
486
+ */
487
+ type ApiResult<T, E extends string = string> = {
488
+ success: true;
489
+ data: T;
490
+ } | {
491
+ success: false;
492
+ error: {
493
+ code: E;
494
+ message: string;
495
+ details?: Record<string, unknown>;
496
+ };
497
+ };
498
+ /**
499
+ * API request context
500
+ */
501
+ interface ApiContext {
502
+ userId?: string;
503
+ userRole?: string;
504
+ }
505
+ //#endregion
506
+ //#region src/api/handlers/content.d.ts
507
+ /**
508
+ * Trashed content item with deletion timestamp
509
+ */
510
+ interface TrashedContentItem {
511
+ id: string;
512
+ type: string;
513
+ slug: string | null;
514
+ status: string;
515
+ data: Record<string, unknown>;
516
+ authorId: string | null;
517
+ createdAt: string;
518
+ updatedAt: string;
519
+ publishedAt: string | null;
520
+ deletedAt: string;
521
+ }
522
+ /**
523
+ * Create content list handler
524
+ */
525
+ declare function handleContentList(db: Kysely<Database>, collection: string, params: {
526
+ cursor?: string;
527
+ limit?: number;
528
+ status?: string;
529
+ orderBy?: string;
530
+ order?: "asc" | "desc";
531
+ locale?: string;
532
+ }): Promise<ApiResult<ContentListResponse>>;
533
+ /**
534
+ * Get single content item
535
+ */
536
+ declare function handleContentGet(db: Kysely<Database>, collection: string, id: string, locale?: string): Promise<ApiResult<ContentResponse>>;
537
+ /**
538
+ * Get a content item by id, including trashed items.
539
+ * Used by restore endpoint for ownership checks on soft-deleted items.
540
+ */
541
+ declare function handleContentGetIncludingTrashed(db: Kysely<Database>, collection: string, id: string, locale?: string): Promise<ApiResult<ContentResponse>>;
542
+ /**
543
+ * Create content item.
544
+ *
545
+ * Content + SEO writes are wrapped in a transaction so either both succeed
546
+ * or neither does. If `body.seo` is provided for a non-SEO collection, the
547
+ * API returns a validation error rather than silently dropping it.
548
+ */
549
+ declare function handleContentCreate(db: Kysely<Database>, collection: string, body: {
550
+ data: Record<string, unknown>;
551
+ slug?: string;
552
+ status?: string;
553
+ authorId?: string;
554
+ bylines?: ContentBylineInput[];
555
+ locale?: string;
556
+ translationOf?: string;
557
+ seo?: ContentSeoInput;
558
+ }): Promise<ApiResult<ContentResponse>>;
559
+ /**
560
+ * Update content item.
561
+ * If `_rev` is provided, validates it against the current version before writing.
562
+ * No `_rev` = blind write (backwards-compatible for admin UI).
563
+ *
564
+ * Content + SEO writes are wrapped in a transaction for atomicity.
565
+ */
566
+ declare function handleContentUpdate(db: Kysely<Database>, collection: string, id: string, body: {
567
+ data?: Record<string, unknown>;
568
+ slug?: string;
569
+ status?: string;
570
+ authorId?: string | null;
571
+ bylines?: ContentBylineInput[];
572
+ _rev?: string;
573
+ seo?: ContentSeoInput;
574
+ }): Promise<ApiResult<ContentResponse>>;
575
+ /**
576
+ * Duplicate content item.
577
+ *
578
+ * Only copies SEO data if the collection has SEO enabled.
579
+ * Always returns consistent `seo` shape for SEO-enabled collections.
580
+ */
581
+ declare function handleContentDuplicate(db: Kysely<Database>, collection: string, id: string, authorId?: string): Promise<ApiResult<{
582
+ item: ContentItem;
583
+ }>>;
584
+ /**
585
+ * Delete content item (soft delete - moves to trash)
586
+ */
587
+ declare function handleContentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
588
+ deleted: true;
589
+ }>>;
590
+ /**
591
+ * Restore content item from trash
592
+ */
593
+ declare function handleContentRestore(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
594
+ restored: true;
595
+ }>>;
596
+ /**
597
+ * Permanently delete content item (cannot be undone).
598
+ * Also cleans up associated SEO data.
599
+ */
600
+ declare function handleContentPermanentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
601
+ deleted: true;
602
+ }>>;
603
+ /**
604
+ * List trashed content items
605
+ */
606
+ declare function handleContentListTrashed(db: Kysely<Database>, collection: string, options?: {
607
+ limit?: number;
608
+ cursor?: string;
609
+ }): Promise<ApiResult<{
610
+ items: TrashedContentItem[];
611
+ nextCursor?: string;
612
+ }>>;
613
+ /**
614
+ * Count trashed content items
615
+ */
616
+ declare function handleContentCountTrashed(db: Kysely<Database>, collection: string): Promise<ApiResult<{
617
+ count: number;
618
+ }>>;
619
+ /**
620
+ * Schedule content for future publishing
621
+ */
622
+ declare function handleContentSchedule(db: Kysely<Database>, collection: string, id: string, scheduledAt: string): Promise<ApiResult<ContentResponse>>;
623
+ /**
624
+ * Unschedule content (revert to draft)
625
+ */
626
+ declare function handleContentUnschedule(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<ContentResponse>>;
627
+ /**
628
+ * Publish content immediately.
629
+ *
630
+ * Wrapped in a transaction because publish performs multiple writes
631
+ * (syncDataColumns, slug sync, status/revision update) that must
632
+ * be atomic to prevent FTS shadow table corruption on crash.
633
+ */
634
+ declare function handleContentPublish(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<ContentResponse>>;
635
+ /**
636
+ * Unpublish content (revert to draft).
637
+ *
638
+ * Wrapped in a transaction — unpublish may create a draft revision
639
+ * from the live version then update the status, which is multi-step.
640
+ */
641
+ declare function handleContentUnpublish(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<ContentResponse>>;
642
+ /**
643
+ * Count scheduled content items
644
+ */
645
+ declare function handleContentCountScheduled(db: Kysely<Database>, collection: string): Promise<ApiResult<{
646
+ count: number;
647
+ }>>;
648
+ /**
649
+ * Discard draft changes (revert to live version)
650
+ */
651
+ declare function handleContentDiscardDraft(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<ContentResponse>>;
652
+ /**
653
+ * Compare live and draft revisions
654
+ */
655
+ declare function handleContentCompare(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
656
+ hasChanges: boolean;
657
+ live: Record<string, unknown> | null;
658
+ draft: Record<string, unknown> | null;
659
+ }>>;
660
+ /**
661
+ * Get all translations for a content item.
662
+ * Returns the item's translation group members with locale and status info.
663
+ */
664
+ declare function handleContentTranslations(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
665
+ translationGroup: string;
666
+ translations: Array<{
667
+ id: string;
668
+ locale: string | null;
669
+ slug: string | null;
670
+ status: string;
671
+ updatedAt: string;
672
+ }>;
673
+ }>>;
674
+ //#endregion
675
+ //#region src/api/handlers/manifest.d.ts
676
+ interface CollectionDefinition {
677
+ schema: {
678
+ _def?: {
679
+ shape?: () => Record<string, unknown>;
680
+ };
681
+ shape?: Record<string, unknown>;
682
+ };
683
+ admin: {
684
+ label: string;
685
+ labelSingular?: string;
686
+ supports?: string[];
687
+ };
688
+ }
689
+ type CollectionMap = Record<string, CollectionDefinition>;
690
+ /**
691
+ * Generate admin manifest from collections
692
+ */
693
+ declare function generateManifest(collections: CollectionMap, plugins?: Record<string, {
694
+ adminPages?: Array<{
695
+ path: string;
696
+ component: string;
697
+ }>;
698
+ widgets?: string[];
699
+ }>): Promise<ManifestResponse>;
700
+ //#endregion
701
+ //#region src/api/handlers/revision.d.ts
702
+ interface RevisionListResponse {
703
+ items: Revision[];
704
+ total: number;
705
+ }
706
+ interface RevisionResponse {
707
+ item: Revision;
708
+ }
709
+ /**
710
+ * List revisions for a content entry
711
+ */
712
+ declare function handleRevisionList(db: Kysely<Database>, collection: string, entryId: string, params?: {
713
+ limit?: number;
714
+ }): Promise<ApiResult<RevisionListResponse>>;
715
+ /**
716
+ * Get a specific revision
717
+ */
718
+ declare function handleRevisionGet(db: Kysely<Database>, revisionId: string): Promise<ApiResult<RevisionResponse>>;
719
+ /**
720
+ * Restore a revision (updates content to this revision's data and creates new revision)
721
+ */
722
+ declare function handleRevisionRestore(db: Kysely<Database>, revisionId: string, callerUserId: string): Promise<ApiResult<ContentResponse>>;
723
+ //#endregion
724
+ //#region src/api/handlers/media.d.ts
725
+ interface MediaListResponse {
726
+ items: MediaItem[];
727
+ nextCursor?: string;
728
+ }
729
+ interface MediaResponse {
730
+ item: MediaItem;
731
+ }
732
+ /**
733
+ * List media items
734
+ */
735
+ declare function handleMediaList(db: Kysely<Database>, params: {
736
+ cursor?: string;
737
+ limit?: number;
738
+ mimeType?: string;
739
+ }): Promise<ApiResult<MediaListResponse>>;
740
+ /**
741
+ * Get single media item
742
+ */
743
+ declare function handleMediaGet(db: Kysely<Database>, id: string): Promise<ApiResult<MediaResponse>>;
744
+ /**
745
+ * Create media item (after file upload)
746
+ */
747
+ declare function handleMediaCreate(db: Kysely<Database>, input: {
748
+ filename: string;
749
+ mimeType: string;
750
+ size?: number;
751
+ width?: number;
752
+ height?: number;
753
+ alt?: string;
754
+ storageKey: string;
755
+ contentHash?: string;
756
+ blurhash?: string;
757
+ dominantColor?: string;
758
+ authorId?: string;
759
+ }): Promise<ApiResult<MediaResponse>>;
760
+ /**
761
+ * Update media metadata
762
+ */
763
+ declare function handleMediaUpdate(db: Kysely<Database>, id: string, input: {
764
+ alt?: string;
765
+ caption?: string;
766
+ width?: number;
767
+ height?: number;
768
+ }): Promise<ApiResult<MediaResponse>>;
769
+ /**
770
+ * Delete media item
771
+ */
772
+ declare function handleMediaDelete(db: Kysely<Database>, id: string): Promise<ApiResult<{
773
+ deleted: true;
774
+ }>>;
775
+ //#endregion
776
+ //#region src/schema/registry.d.ts
777
+ /**
778
+ * Error thrown when a schema operation fails
779
+ */
780
+ declare class SchemaError extends Error {
781
+ code: string;
782
+ details?: Record<string, unknown> | undefined;
783
+ constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
784
+ }
785
+ /**
786
+ * Schema Registry
787
+ *
788
+ * Manages collection and field definitions stored in D1.
789
+ * Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).
790
+ */
791
+ declare class SchemaRegistry {
792
+ private db;
793
+ constructor(db: Kysely<Database>);
794
+ /**
795
+ * List all collections
796
+ */
797
+ listCollections(): Promise<Collection[]>;
798
+ /**
799
+ * Get a collection by slug
800
+ */
801
+ getCollection(slug: string): Promise<Collection | null>;
802
+ /**
803
+ * Get a collection with all its fields
804
+ */
805
+ getCollectionWithFields(slug: string): Promise<CollectionWithFields | null>;
806
+ /**
807
+ * Create a new collection
808
+ */
809
+ createCollection(input: CreateCollectionInput): Promise<Collection>;
810
+ /**
811
+ * Update a collection
812
+ */
813
+ updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection>;
814
+ /**
815
+ * Delete a collection
816
+ */
817
+ deleteCollection(slug: string, options?: {
818
+ force?: boolean;
819
+ }): Promise<void>;
820
+ /**
821
+ * List fields for a collection
822
+ */
823
+ listFields(collectionId: string): Promise<Field[]>;
824
+ /**
825
+ * Get a field by slug within a collection
826
+ */
827
+ getField(collectionSlug: string, fieldSlug: string): Promise<Field | null>;
828
+ /**
829
+ * Create a new field
830
+ */
831
+ createField(collectionSlug: string, input: CreateFieldInput): Promise<Field>;
832
+ /**
833
+ * Update a field
834
+ */
835
+ updateField(collectionSlug: string, fieldSlug: string, input: UpdateFieldInput): Promise<Field>;
836
+ /**
837
+ * Rebuild the search index for a collection
838
+ *
839
+ * Called when searchable fields change. If search is enabled for the collection,
840
+ * this will rebuild the FTS table with the updated field list.
841
+ */
842
+ private rebuildSearchIndex;
843
+ /**
844
+ * Delete a field
845
+ */
846
+ deleteField(collectionSlug: string, fieldSlug: string): Promise<void>;
847
+ /**
848
+ * Reorder fields
849
+ */
850
+ reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void>;
851
+ /**
852
+ * Create a content table for a collection
853
+ */
854
+ private createContentTable;
855
+ /**
856
+ * Drop a content table
857
+ */
858
+ private dropContentTable;
859
+ /**
860
+ * Add a column to a content table
861
+ */
862
+ private addColumn;
863
+ /**
864
+ * Drop a column from a content table
865
+ */
866
+ private dropColumn;
867
+ /**
868
+ * Check if a collection has any content
869
+ */
870
+ private collectionHasContent;
871
+ /**
872
+ * Get table name for a collection
873
+ */
874
+ private getTableName;
875
+ /**
876
+ * Get column name for a field
877
+ */
878
+ private getColumnName;
879
+ /**
880
+ * Validate a slug
881
+ */
882
+ private validateSlug;
883
+ /**
884
+ * Format a default value for SQL.
885
+ *
886
+ * SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant
887
+ * expression — parameterized values cannot be used here. We manually escape
888
+ * single quotes and coerce types to ensure the output is safe.
889
+ *
890
+ * INTEGER/REAL values are coerced through `Number()` which can only produce
891
+ * digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.
892
+ * TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).
893
+ */
894
+ private formatDefaultValue;
895
+ /**
896
+ * Get empty default for a field type
897
+ */
898
+ private getEmptyDefault;
899
+ /**
900
+ * Map a collection row to a Collection object
901
+ */
902
+ private mapCollectionRow;
903
+ /**
904
+ * Map a field row to a Field object
905
+ */
906
+ private mapFieldRow;
907
+ /**
908
+ * Discover orphaned content tables
909
+ *
910
+ * Finds ec_* tables that exist in the database but don't have a
911
+ * corresponding entry in _emdash_collections.
912
+ */
913
+ discoverOrphanedTables(): Promise<Array<{
914
+ slug: string;
915
+ tableName: string;
916
+ rowCount: number;
917
+ }>>;
918
+ /**
919
+ * Register an orphaned table as a collection
920
+ *
921
+ * Creates a _emdash_collections entry for an existing ec_* table.
922
+ */
923
+ registerOrphanedTable(slug: string, options?: {
924
+ label?: string;
925
+ labelSingular?: string;
926
+ description?: string;
927
+ }): Promise<Collection>;
928
+ /**
929
+ * Convert slug to human-readable label
930
+ */
931
+ private slugToLabel;
932
+ }
933
+ //#endregion
934
+ //#region src/schema/query.d.ts
935
+ /**
936
+ * Get collection metadata by slug.
937
+ *
938
+ * @example
939
+ * ```ts
940
+ * import { getCollectionInfo } from "emdash";
941
+ *
942
+ * const info = await getCollectionInfo("posts");
943
+ * if (info?.commentsEnabled) {
944
+ * // render comment UI
945
+ * }
946
+ * ```
947
+ */
948
+ declare function getCollectionInfo(slug: string): Promise<Collection | null>;
949
+ //#endregion
950
+ //#region src/sections/types.d.ts
951
+ /**
952
+ * Section source types
953
+ */
954
+ type SectionSource = "theme" | "user" | "import";
955
+ /**
956
+ * Section as returned to templates/admin
957
+ */
958
+ interface Section {
959
+ id: string;
960
+ slug: string;
961
+ title: string;
962
+ description?: string;
963
+ keywords: string[];
964
+ content: PortableTextBlock$2[];
965
+ previewUrl?: string;
966
+ source: SectionSource;
967
+ themeId?: string;
968
+ createdAt: string;
969
+ updatedAt: string;
970
+ }
971
+ /**
972
+ * Input for creating a section
973
+ */
974
+ interface CreateSectionInput {
975
+ slug: string;
976
+ title: string;
977
+ description?: string;
978
+ keywords?: string[];
979
+ content: PortableTextBlock$2[];
980
+ previewMediaId?: string;
981
+ source?: SectionSource;
982
+ themeId?: string;
983
+ }
984
+ /**
985
+ * Input for updating a section
986
+ */
987
+ interface UpdateSectionInput {
988
+ slug?: string;
989
+ title?: string;
990
+ description?: string;
991
+ keywords?: string[];
992
+ content?: PortableTextBlock$2[];
993
+ previewMediaId?: string | null;
994
+ }
995
+ /**
996
+ * Options for querying sections
997
+ */
998
+ interface GetSectionsOptions {
999
+ /** Filter by source */
1000
+ source?: SectionSource;
1001
+ /** Search title, description, keywords */
1002
+ search?: string;
1003
+ /** Limit results */
1004
+ limit?: number;
1005
+ /** Cursor for pagination */
1006
+ cursor?: string;
1007
+ }
1008
+ //#endregion
1009
+ //#region src/sections/index.d.ts
1010
+ /**
1011
+ * Get a section by slug
1012
+ *
1013
+ * @example
1014
+ * ```ts
1015
+ * import { getSection } from "emdash";
1016
+ *
1017
+ * const section = await getSection("hero-centered");
1018
+ * if (section) {
1019
+ * console.log(section.content); // Portable Text array
1020
+ * }
1021
+ * ```
1022
+ */
1023
+ declare function getSection(slug: string): Promise<Section | null>;
1024
+ /**
1025
+ * Get all sections with optional filtering
1026
+ *
1027
+ * @example
1028
+ * ```ts
1029
+ * import { getSections } from "emdash";
1030
+ *
1031
+ * // Get all theme-provided sections
1032
+ * const themeSections = await getSections({ source: "theme" });
1033
+ *
1034
+ * // Search sections
1035
+ * const results = await getSections({ search: "pricing" });
1036
+ * ```
1037
+ */
1038
+ declare function getSections(options?: GetSectionsOptions): Promise<FindManyResult<Section>>;
1039
+ //#endregion
1040
+ //#region src/plugins/sandbox/types.d.ts
1041
+ /**
1042
+ * Resource limits for sandboxed plugins.
1043
+ * Enforced by the sandbox runtime (e.g., Worker Loader).
1044
+ */
1045
+ interface ResourceLimits {
1046
+ /** CPU time per invocation in milliseconds (default: 50ms) */
1047
+ cpuMs?: number;
1048
+ /** Memory limit in MB (default: 128MB) */
1049
+ memoryMb?: number;
1050
+ /** Maximum subrequests per invocation (default: 10) */
1051
+ subrequests?: number;
1052
+ /** Wall-clock time limit in milliseconds (default: 30000ms) */
1053
+ wallTimeMs?: number;
1054
+ }
1055
+ /**
1056
+ * Storage interface for loading plugin code.
1057
+ * Could be R2, local filesystem, or any other storage backend.
1058
+ */
1059
+ interface PluginCodeStorage {
1060
+ /** Get plugin bundle code by path */
1061
+ get(path: string): Promise<string | null>;
1062
+ /** Check if a bundle exists */
1063
+ exists(path: string): Promise<boolean>;
1064
+ }
1065
+ /**
1066
+ * Serialized email message for sandbox RPC transport.
1067
+ * Matches the core EmailMessage type but uses only serializable fields.
1068
+ */
1069
+ interface SandboxEmailMessage {
1070
+ to: string;
1071
+ subject: string;
1072
+ text: string;
1073
+ html?: string;
1074
+ }
1075
+ /**
1076
+ * Callback for sending email from a sandboxed plugin.
1077
+ * The sandbox runner wires this up from the EmailPipeline.
1078
+ *
1079
+ * @param message - The email message to send
1080
+ * @param pluginId - The sending plugin's ID (used as source)
1081
+ */
1082
+ type SandboxEmailSendCallback = (message: SandboxEmailMessage, pluginId: string) => Promise<void>;
1083
+ /**
1084
+ * Options for creating a sandbox runner
1085
+ */
1086
+ interface SandboxOptions {
1087
+ /** Storage interface for loading plugin code */
1088
+ storage?: PluginCodeStorage;
1089
+ /** Database for bridge operations */
1090
+ db: Kysely<Database>;
1091
+ /** Default resource limits */
1092
+ limits?: ResourceLimits;
1093
+ /** Site info for plugin context (injected into wrapper at generation time) */
1094
+ siteInfo?: {
1095
+ name: string;
1096
+ url: string;
1097
+ locale: string;
1098
+ };
1099
+ /** Email send callback, wired from the EmailPipeline by the runtime */
1100
+ emailSend?: SandboxEmailSendCallback;
1101
+ }
1102
+ /**
1103
+ * A sandboxed plugin instance.
1104
+ * Provides methods to invoke hooks and routes in the isolated environment.
1105
+ */
1106
+ interface SandboxedPlugin {
1107
+ /** Unique identifier: `${manifest.id}:${manifest.version}` */
1108
+ readonly id: string;
1109
+ /**
1110
+ * Invoke a hook in the sandboxed plugin.
1111
+ *
1112
+ * @param hookName - Name of the hook (e.g., "content:beforeSave")
1113
+ * @param event - Event data to pass to the hook
1114
+ * @returns Hook result (transformed content, void, etc.)
1115
+ */
1116
+ invokeHook(hookName: string, event: unknown): Promise<unknown>;
1117
+ /**
1118
+ * Invoke an API route in the sandboxed plugin.
1119
+ *
1120
+ * @param routeName - Name of the route
1121
+ * @param input - Validated input data
1122
+ * @param request - Serialized request info for context
1123
+ * @returns Route response data
1124
+ */
1125
+ invokeRoute(routeName: string, input: unknown, request: SerializedRequest): Promise<unknown>;
1126
+ /**
1127
+ * Terminate the sandboxed plugin.
1128
+ * Releases resources and prevents further invocations.
1129
+ */
1130
+ terminate(): Promise<void>;
1131
+ }
1132
+ /**
1133
+ * Serialized request for RPC transport.
1134
+ * Worker Loader can't pass Request objects directly.
1135
+ */
1136
+ interface SerializedRequest {
1137
+ url: string;
1138
+ method: string;
1139
+ headers: Record<string, string>;
1140
+ /** Normalized request metadata extracted before RPC serialization */
1141
+ meta: RequestMeta;
1142
+ }
1143
+ /**
1144
+ * Sandbox runner interface.
1145
+ * Platform adapters implement this to provide plugin isolation.
1146
+ */
1147
+ interface SandboxRunner {
1148
+ /**
1149
+ * Check if sandboxing is available on this platform.
1150
+ * Returns false for platforms that don't support isolation.
1151
+ */
1152
+ isAvailable(): boolean;
1153
+ /**
1154
+ * Load a sandboxed plugin from code.
1155
+ *
1156
+ * @param manifest - Plugin manifest with metadata and capabilities
1157
+ * @param code - The bundled plugin JavaScript code
1158
+ * @returns A sandboxed plugin instance
1159
+ * @throws If sandboxing is not available or plugin can't be loaded
1160
+ */
1161
+ load(manifest: PluginManifest, code: string): Promise<SandboxedPlugin>;
1162
+ /**
1163
+ * Set the email send callback for sandboxed plugins.
1164
+ * Called after the EmailPipeline is created, since the pipeline
1165
+ * doesn't exist when the sandbox runner is constructed.
1166
+ */
1167
+ setEmailSend(callback: SandboxEmailSendCallback | null): void;
1168
+ /**
1169
+ * Terminate all loaded sandboxed plugins.
1170
+ * Called during shutdown or when reconfiguring.
1171
+ */
1172
+ terminateAll(): Promise<void>;
1173
+ }
1174
+ /**
1175
+ * Factory function type for creating sandbox runners.
1176
+ * Exported by platform adapters (e.g., @emdash-cms/adapter-cloudflare/sandbox).
1177
+ *
1178
+ * @example
1179
+ * ```typescript
1180
+ * // In @emdash-cms/adapter-cloudflare/sandbox.ts
1181
+ * export const createSandboxRunner: SandboxRunnerFactory = (options) => {
1182
+ * return new CloudflareSandboxRunner(options);
1183
+ * };
1184
+ * ```
1185
+ */
1186
+ type SandboxRunnerFactory = (options: SandboxOptions) => SandboxRunner;
1187
+ //#endregion
1188
+ //#region src/content/converters/types.d.ts
1189
+ /**
1190
+ * Portable Text Types
1191
+ *
1192
+ * Defines the structure of Portable Text blocks used in EmDash.
1193
+ */
1194
+ /**
1195
+ * Base span (inline text)
1196
+ */
1197
+ interface PortableTextSpan {
1198
+ _type: "span";
1199
+ _key: string;
1200
+ text: string;
1201
+ marks?: string[];
1202
+ }
1203
+ /**
1204
+ * Mark definition (bold, italic, link, etc.)
1205
+ */
1206
+ interface PortableTextMarkDef {
1207
+ _type: string;
1208
+ _key: string;
1209
+ [key: string]: unknown;
1210
+ }
1211
+ /**
1212
+ * Link mark definition
1213
+ */
1214
+ interface PortableTextLinkMark extends PortableTextMarkDef {
1215
+ _type: "link";
1216
+ href: string;
1217
+ blank?: boolean;
1218
+ }
1219
+ /**
1220
+ * Text block (paragraph, heading, etc.)
1221
+ */
1222
+ interface PortableTextTextBlock {
1223
+ _type: "block";
1224
+ _key: string;
1225
+ style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote";
1226
+ listItem?: "bullet" | "number";
1227
+ level?: number;
1228
+ children: PortableTextSpan[];
1229
+ markDefs?: PortableTextMarkDef[];
1230
+ }
1231
+ /**
1232
+ * Image block
1233
+ */
1234
+ interface PortableTextImageBlock {
1235
+ _type: "image";
1236
+ _key: string;
1237
+ asset: {
1238
+ _ref: string;
1239
+ url?: string; /** Provider ID for external media (e.g., "cloudflare-images") */
1240
+ provider?: string;
1241
+ };
1242
+ alt?: string;
1243
+ caption?: string;
1244
+ /** Original image width */
1245
+ width?: number;
1246
+ /** Original image height */
1247
+ height?: number;
1248
+ /** Display width for this instance (overrides original) */
1249
+ displayWidth?: number;
1250
+ /** Display height for this instance (overrides original) */
1251
+ displayHeight?: number;
1252
+ }
1253
+ /**
1254
+ * Code block
1255
+ */
1256
+ interface PortableTextCodeBlock {
1257
+ _type: "code";
1258
+ _key: string;
1259
+ code: string;
1260
+ language?: string;
1261
+ filename?: string;
1262
+ }
1263
+ /**
1264
+ * Unknown/custom block (preserved for plugin compatibility)
1265
+ */
1266
+ interface PortableTextUnknownBlock {
1267
+ _type: string;
1268
+ _key: string;
1269
+ [key: string]: unknown;
1270
+ }
1271
+ /**
1272
+ * Any Portable Text block
1273
+ */
1274
+ type PortableTextBlock$1 = PortableTextTextBlock | PortableTextImageBlock | PortableTextCodeBlock | PortableTextUnknownBlock;
1275
+ /**
1276
+ * ProseMirror JSON types (simplified for TipTap)
1277
+ */
1278
+ interface ProseMirrorMark {
1279
+ type: string;
1280
+ attrs?: Record<string, unknown>;
1281
+ }
1282
+ interface ProseMirrorNode {
1283
+ type: string;
1284
+ attrs?: Record<string, unknown>;
1285
+ content?: ProseMirrorNode[];
1286
+ marks?: ProseMirrorMark[];
1287
+ text?: string;
1288
+ }
1289
+ interface ProseMirrorDocument {
1290
+ type: "doc";
1291
+ content: ProseMirrorNode[];
1292
+ }
1293
+ //#endregion
1294
+ //#region src/content/converters/prosemirror-to-portable-text.d.ts
1295
+ /**
1296
+ * Convert ProseMirror document to Portable Text
1297
+ */
1298
+ declare function prosemirrorToPortableText(doc: ProseMirrorDocument): PortableTextBlock$1[];
1299
+ //#endregion
1300
+ //#region src/content/converters/portable-text-to-prosemirror.d.ts
1301
+ /**
1302
+ * Convert Portable Text to ProseMirror document
1303
+ */
1304
+ declare function portableTextToProsemirror(blocks: PortableTextBlock$1[]): ProseMirrorDocument;
1305
+ //#endregion
1306
+ //#region src/utils/hash.d.ts
1307
+ /**
1308
+ * SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
1309
+ * For cache invalidation / ETags — not for security.
1310
+ */
1311
+ declare function hashString(content: string): Promise<string>;
1312
+ /**
1313
+ * Compute content hash using Web Crypto API
1314
+ *
1315
+ * Uses SHA-1 which is the fastest option in SubtleCrypto.
1316
+ * SHA-1 is cryptographically weak but fine for content deduplication
1317
+ * where we only need to detect identical files, not resist attacks.
1318
+ *
1319
+ * Returns hex string prefixed with "sha1:" for future-proofing
1320
+ */
1321
+ declare function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string>;
1322
+ //#endregion
1323
+ //#region src/utils/url.d.ts
1324
+ /**
1325
+ * URL scheme validation utilities
1326
+ *
1327
+ * Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
1328
+ * by allowlisting known-safe schemes before rendering into href attributes.
1329
+ */
1330
+ /**
1331
+ * Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
1332
+ *
1333
+ * Use this at the render layer as the primary defense against XSS via
1334
+ * dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
1335
+ *
1336
+ * @example
1337
+ * ```ts
1338
+ * sanitizeHref("https://example.com") // "https://example.com"
1339
+ * sanitizeHref("/about") // "/about"
1340
+ * sanitizeHref("#section") // "#section"
1341
+ * sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
1342
+ * sanitizeHref("javascript:alert(1)") // "#"
1343
+ * sanitizeHref("data:text/html,<script>") // "#"
1344
+ * sanitizeHref("") // "#"
1345
+ * ```
1346
+ */
1347
+ declare function sanitizeHref(url: string | undefined | null): string;
1348
+ /**
1349
+ * Returns true if the URL uses a safe scheme for rendering in href attributes.
1350
+ */
1351
+ declare function isSafeHref(url: string): boolean;
1352
+ //#endregion
1353
+ //#region src/visual-editing/editable.d.ts
1354
+ /**
1355
+ * Visual editing annotation system
1356
+ *
1357
+ * Creates Proxy objects that emit data-emdash-ref attributes when spread onto elements.
1358
+ */
1359
+ interface CMSAnnotation {
1360
+ collection: string;
1361
+ id: string;
1362
+ field?: string;
1363
+ /** Entry status — only present on entry-level annotations (not field-level) */
1364
+ status?: string;
1365
+ /** Whether the entry has unpublished draft changes */
1366
+ hasDraft?: boolean;
1367
+ }
1368
+ /** The shape returned when spreading an edit annotation onto an element */
1369
+ interface FieldAnnotation {
1370
+ "data-emdash-ref": string;
1371
+ }
1372
+ interface EditableOptions {
1373
+ /** Entry status: "draft", "published", "scheduled" */
1374
+ status?: string;
1375
+ /** true when draftRevisionId exists and differs from liveRevisionId */
1376
+ hasDraft?: boolean;
1377
+ }
1378
+ /**
1379
+ * Create an editable proxy for an entry.
1380
+ *
1381
+ * Usage:
1382
+ * - `{...entry.edit}` - entry-level annotation (includes status/hasDraft)
1383
+ * - `{...entry.edit.title}` - field-level annotation
1384
+ * - `{...entry.edit['nested.field']}` - nested field (bracket notation)
1385
+ */
1386
+ declare function createEditable(collection: string, id: string, options?: EditableOptions): EditProxy;
1387
+ /**
1388
+ * Create a noop proxy for production mode.
1389
+ * Spreading this produces no attributes.
1390
+ */
1391
+ declare function createNoop(): EditProxy;
1392
+ /**
1393
+ * Visual editing proxy type.
1394
+ *
1395
+ * Spread directly onto elements for entry-level annotations: `{...entry.edit}`
1396
+ * Access a field for field-level annotations: `{...entry.edit.title}`
1397
+ *
1398
+ * In production, spreading produces no attributes (noop).
1399
+ */
1400
+ type EditProxy = {
1401
+ readonly [field: string]: Partial<FieldAnnotation>;
1402
+ };
1403
+ //#endregion
1404
+ //#region src/query.d.ts
1405
+ /**
1406
+ * Collection type registry for type-safe queries.
1407
+ *
1408
+ * This interface is extended by the generated emdash-env.d.ts file
1409
+ * to provide type inference for collection names and their data shapes.
1410
+ *
1411
+ * @example
1412
+ * ```ts
1413
+ * // In emdash-env.d.ts (generated):
1414
+ * declare module "emdash" {
1415
+ * interface EmDashCollections {
1416
+ * posts: { title: string; content: PortableTextBlock[]; };
1417
+ * pages: { title: string; body: PortableTextBlock[]; };
1418
+ * }
1419
+ * }
1420
+ *
1421
+ * // Then in your code:
1422
+ * const { entries } = await getEmDashCollection("posts");
1423
+ * // entries[0].data.title is typed as string
1424
+ * ```
1425
+ */
1426
+ interface EmDashCollections {}
1427
+ /**
1428
+ * Helper type to infer the data type for a collection.
1429
+ * Returns the registered type if known, otherwise falls back to Record<string, unknown>.
1430
+ */
1431
+ type InferCollectionData<T extends string> = T extends keyof EmDashCollections ? EmDashCollections[T] : Record<string, unknown>;
1432
+ /**
1433
+ * Sort direction
1434
+ */
1435
+ type SortDirection$1 = "asc" | "desc";
1436
+ /**
1437
+ * Order by specification - field name to direction
1438
+ * @example { created_at: "desc" } - Sort by created_at descending
1439
+ * @example { title: "asc" } - Sort by title ascending
1440
+ * @example { published_at: "desc", title: "asc" } - Multi-field sort
1441
+ */
1442
+ type OrderBySpec$1 = Record<string, SortDirection$1>;
1443
+ interface CollectionFilter$1 {
1444
+ status?: "draft" | "published" | "archived";
1445
+ limit?: number;
1446
+ /**
1447
+ * Opaque cursor for keyset pagination.
1448
+ * Pass the `nextCursor` value from a previous result to fetch the next page.
1449
+ * @example
1450
+ * ```ts
1451
+ * const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
1452
+ * const { entries, nextCursor } = await getEmDashCollection("posts", {
1453
+ * limit: 10,
1454
+ * cursor,
1455
+ * });
1456
+ * ```
1457
+ */
1458
+ cursor?: string;
1459
+ /**
1460
+ * Filter by field values or taxonomy terms
1461
+ * @example { category: 'news' } - Filter by taxonomy term
1462
+ * @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
1463
+ */
1464
+ where?: Record<string, string | string[]>;
1465
+ /**
1466
+ * Order results by field(s)
1467
+ * @default { created_at: "desc" }
1468
+ * @example { created_at: "desc" } - Sort by created_at descending (default)
1469
+ * @example { title: "asc" } - Sort by title ascending
1470
+ * @example { published_at: "desc", title: "asc" } - Multi-field sort
1471
+ */
1472
+ orderBy?: OrderBySpec$1;
1473
+ /**
1474
+ * Filter by locale. When set, only returns entries in this locale.
1475
+ * Only relevant when i18n is configured.
1476
+ * @example "en" — English entries only
1477
+ * @example "fr" — French entries only
1478
+ */
1479
+ locale?: string;
1480
+ }
1481
+ interface ContentEntry<T = Record<string, unknown>> {
1482
+ id: string;
1483
+ data: T;
1484
+ /** Visual editing annotations. Spread onto elements: {...entry.edit.title} */
1485
+ edit: EditProxy;
1486
+ }
1487
+ /** Cache hint returned by the content loader for route caching */
1488
+ interface CacheHint {
1489
+ tags?: string[];
1490
+ lastModified?: Date;
1491
+ }
1492
+ /**
1493
+ * Result from getEmDashCollection
1494
+ */
1495
+ interface CollectionResult<T> {
1496
+ /** The entries (empty array if error or none found) */
1497
+ entries: ContentEntry<T>[];
1498
+ /** Error if the query failed */
1499
+ error?: Error;
1500
+ /** Cache hint for route caching (pass to Astro.cache.set()) */
1501
+ cacheHint: CacheHint;
1502
+ /**
1503
+ * Opaque cursor for the next page.
1504
+ * Undefined when there are no more results.
1505
+ * Pass this as `cursor` in the next query to get the next page.
1506
+ */
1507
+ nextCursor?: string;
1508
+ }
1509
+ /**
1510
+ * Result from getEmDashEntry
1511
+ */
1512
+ interface EntryResult<T> {
1513
+ /** The entry, or null if not found */
1514
+ entry: ContentEntry<T> | null;
1515
+ /** Error if the query failed (not set for "not found", only for actual errors) */
1516
+ error?: Error;
1517
+ /** Whether we're in preview mode (valid token was provided) */
1518
+ isPreview: boolean;
1519
+ /** Set when a fallback locale was used instead of the requested locale */
1520
+ fallbackLocale?: string;
1521
+ /** Cache hint for route caching (pass to Astro.cache.set()) */
1522
+ cacheHint: CacheHint;
1523
+ }
1524
+ /** Edit metadata attached to PT arrays in edit mode */
1525
+ interface EditFieldMeta {
1526
+ collection: string;
1527
+ id: string;
1528
+ field: string;
1529
+ }
1530
+ /**
1531
+ * Read edit metadata from a value (returns undefined if not tagged).
1532
+ * Uses Object.getOwnPropertyDescriptor to access Symbol-keyed property
1533
+ * without an unsafe type assertion.
1534
+ */
1535
+ declare function getEditMeta(value: unknown): EditFieldMeta | undefined;
1536
+ /**
1537
+ * Get all entries of a content type
1538
+ *
1539
+ * Returns { entries, error } for graceful error handling.
1540
+ *
1541
+ * When emdash-env.d.ts is generated, the collection name will be
1542
+ * type-checked and the return type will be inferred automatically.
1543
+ *
1544
+ * @example
1545
+ * ```ts
1546
+ * import { getEmDashCollection } from "emdash";
1547
+ *
1548
+ * const { entries: posts, error } = await getEmDashCollection("posts");
1549
+ * if (error) {
1550
+ * console.error("Failed to load posts:", error);
1551
+ * return;
1552
+ * }
1553
+ * // posts[0].data.title is typed (if emdash-env.d.ts exists)
1554
+ *
1555
+ * // With filters
1556
+ * const { entries: drafts } = await getEmDashCollection("posts", { status: "draft" });
1557
+ * ```
1558
+ */
1559
+ declare function getEmDashCollection<T extends string, D = InferCollectionData<T>>(type: T, filter?: CollectionFilter$1): Promise<CollectionResult<D>>;
1560
+ /**
1561
+ * Get a single entry by type and ID/slug
1562
+ *
1563
+ * Returns { entry, error, isPreview } for graceful error handling.
1564
+ * - entry is null if not found (not an error)
1565
+ * - error is set only for actual errors (db issues, etc.)
1566
+ *
1567
+ * Preview mode is detected automatically from request context (ALS).
1568
+ * When the URL has a valid `_preview` token, the middleware sets preview
1569
+ * context and this function serves draft revision data if available.
1570
+ *
1571
+ * @example
1572
+ * ```ts
1573
+ * import { getEmDashEntry } from "emdash";
1574
+ *
1575
+ * // Simple usage — preview just works via middleware
1576
+ * const { entry: post, isPreview, error } = await getEmDashEntry("posts", "my-slug");
1577
+ * if (!post) return Astro.redirect("/404");
1578
+ * ```
1579
+ */
1580
+ declare function getEmDashEntry<T extends string, D = InferCollectionData<T>>(type: T, id: string, options?: {
1581
+ locale?: string;
1582
+ }): Promise<EntryResult<D>>;
1583
+ /**
1584
+ * Translation summary for a single locale variant
1585
+ */
1586
+ interface TranslationSummary {
1587
+ /** Content item ID */
1588
+ id: string;
1589
+ /** Locale code (e.g. "en", "fr") */
1590
+ locale: string;
1591
+ /** URL slug */
1592
+ slug: string | null;
1593
+ /** Current status */
1594
+ status: string;
1595
+ }
1596
+ /**
1597
+ * Result from getTranslations
1598
+ */
1599
+ interface TranslationsResult {
1600
+ /** The translation group ID (shared across locales) */
1601
+ translationGroup: string;
1602
+ /** All locale variants in this group */
1603
+ translations: TranslationSummary[];
1604
+ /** Error if the query failed */
1605
+ error?: Error;
1606
+ }
1607
+ /**
1608
+ * Get all translations of a content item.
1609
+ *
1610
+ * Given a content entry, returns all locale variants that share the same
1611
+ * translation group. This is useful for building language switcher UI.
1612
+ *
1613
+ * @example
1614
+ * ```ts
1615
+ * import { getEmDashEntry, getTranslations } from "emdash";
1616
+ *
1617
+ * const { entry: post } = await getEmDashEntry("posts", "hello-world", { locale: "en" });
1618
+ * const { translations } = await getTranslations("posts", post.data.id);
1619
+ * // translations = [{ id: "...", locale: "en", slug: "hello-world", status: "published" }, ...]
1620
+ * ```
1621
+ */
1622
+ declare function getTranslations(type: string, id: string): Promise<TranslationsResult>;
1623
+ /**
1624
+ * Result from resolveEmDashPath
1625
+ */
1626
+ interface ResolvePathResult<T = Record<string, unknown>> {
1627
+ /** The matched entry */
1628
+ entry: ContentEntry<T>;
1629
+ /** The collection slug that matched */
1630
+ collection: string;
1631
+ /** Extracted parameters from the URL pattern (e.g. { slug: "my-post" }) */
1632
+ params: Record<string, string>;
1633
+ }
1634
+ /**
1635
+ * Resolve a URL path to a content entry by matching against collection URL patterns.
1636
+ *
1637
+ * Loads all collections with a `urlPattern` set, converts each pattern to a regex,
1638
+ * and tests the given path. On match, extracts the slug and fetches the entry.
1639
+ *
1640
+ * @example
1641
+ * ```ts
1642
+ * import { resolveEmDashPath } from "emdash";
1643
+ *
1644
+ * // Given pages with urlPattern "/{slug}" and posts with "/blog/{slug}":
1645
+ * const result = await resolveEmDashPath("/blog/hello-world");
1646
+ * if (result) {
1647
+ * console.log(result.collection); // "posts"
1648
+ * console.log(result.params.slug); // "hello-world"
1649
+ * console.log(result.entry.data); // post data
1650
+ * }
1651
+ * ```
1652
+ */
1653
+ declare function resolveEmDashPath<T = Record<string, unknown>>(path: string): Promise<ResolvePathResult<T> | null>;
1654
+ //#endregion
1655
+ //#region src/i18n/config.d.ts
1656
+ /**
1657
+ * EmDash i18n Configuration
1658
+ *
1659
+ * Reads locale configuration from the virtual module (sourced from Astro config).
1660
+ * Initialized during runtime startup, then available via getI18nConfig().
1661
+ */
1662
+ interface I18nConfig {
1663
+ defaultLocale: string;
1664
+ locales: string[];
1665
+ fallback?: Record<string, string>;
1666
+ prefixDefaultLocale?: boolean;
1667
+ }
1668
+ /**
1669
+ * Get the current i18n config.
1670
+ * Returns null if i18n is not configured.
1671
+ */
1672
+ declare function getI18nConfig(): I18nConfig | null;
1673
+ /**
1674
+ * Check if i18n is enabled.
1675
+ * Returns true when multiple locales are configured.
1676
+ */
1677
+ declare function isI18nEnabled(): boolean;
1678
+ /**
1679
+ * Resolve fallback locale chain for a given locale.
1680
+ * Returns array of locales to try, from most preferred to least.
1681
+ * Always ends with defaultLocale.
1682
+ */
1683
+ declare function getFallbackChain(locale: string): string[];
1684
+ //#endregion
1685
+ //#region src/loader.d.ts
1686
+ /**
1687
+ * Entry data type - generic object
1688
+ */
1689
+ type EntryData = Record<string, unknown>;
1690
+ /**
1691
+ * Sort direction
1692
+ */
1693
+ type SortDirection = "asc" | "desc";
1694
+ /**
1695
+ * Order by specification - field name to direction
1696
+ * @example { created_at: "desc" } - Sort by created_at descending
1697
+ * @example { title: "asc" } - Sort by title ascending
1698
+ */
1699
+ type OrderBySpec = Record<string, SortDirection>;
1700
+ /**
1701
+ * Filter for loadCollection - type is required
1702
+ */
1703
+ interface CollectionFilter {
1704
+ type: string;
1705
+ status?: "draft" | "published" | "archived";
1706
+ limit?: number;
1707
+ /**
1708
+ * Opaque cursor for keyset pagination.
1709
+ * Pass the `nextCursor` value from a previous result to fetch the next page.
1710
+ */
1711
+ cursor?: string;
1712
+ /**
1713
+ * Filter by field values or taxonomy terms
1714
+ */
1715
+ where?: Record<string, string | string[]>;
1716
+ /**
1717
+ * Order results by field(s)
1718
+ * @default { created_at: "desc" }
1719
+ */
1720
+ orderBy?: OrderBySpec;
1721
+ /**
1722
+ * Filter by locale (e.g. 'en', 'fr').
1723
+ * When set, only returns content in this locale.
1724
+ */
1725
+ locale?: string;
1726
+ }
1727
+ /**
1728
+ * Filter for loadEntry - type and id are required
1729
+ */
1730
+ interface EntryFilter {
1731
+ type: string;
1732
+ id: string;
1733
+ /**
1734
+ * When set, fetch content data from this revision instead of the content table.
1735
+ * Used by preview mode to serve draft revision data.
1736
+ */
1737
+ revisionId?: string;
1738
+ /**
1739
+ * Locale to scope slug lookup. Only affects slug resolution;
1740
+ * IDs are globally unique and always resolve regardless of locale.
1741
+ */
1742
+ locale?: string;
1743
+ }
1744
+ /**
1745
+ * Get the database instance. Used by query wrapper functions and middleware.
1746
+ *
1747
+ * Checks the ALS request context first — if a per-request DB override is set
1748
+ * (e.g. by DO preview middleware), it takes precedence over the module-level
1749
+ * cached instance. This allows preview mode to route queries to an isolated
1750
+ * Durable Object database without modifying any calling code.
1751
+ *
1752
+ * Initializes the default database on first call using config from virtual module.
1753
+ */
1754
+ declare function getDb(): Promise<Kysely<Database>>;
1755
+ /**
1756
+ * Create an EmDash Live Collections loader
1757
+ *
1758
+ * This loader handles ALL content types in a single Astro collection.
1759
+ * Use `getEmDashCollection()` and `getEmDashEntry()` to query
1760
+ * specific content types.
1761
+ *
1762
+ * Database is configured in astro.config.mjs via the emdash() integration.
1763
+ *
1764
+ * @example
1765
+ * ```ts
1766
+ * // src/live.config.ts
1767
+ * import { defineLiveCollection } from "astro:content";
1768
+ * import { emdashLoader } from "emdash";
1769
+ *
1770
+ * export const collections = {
1771
+ * emdash: defineLiveCollection({
1772
+ * loader: emdashLoader(),
1773
+ * }),
1774
+ * };
1775
+ * ```
1776
+ */
1777
+ declare function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFilter>;
1778
+ //#endregion
1779
+ //#region src/cli/wxr/parser.d.ts
1780
+ /**
1781
+ * Parsed WordPress export data
1782
+ */
1783
+ interface WxrData {
1784
+ /** Site metadata */
1785
+ site: WxrSite;
1786
+ /** Posts (including custom post types) */
1787
+ posts: WxrPost[];
1788
+ /** Media attachments */
1789
+ attachments: WxrAttachment[];
1790
+ /** Categories */
1791
+ categories: WxrCategory[];
1792
+ /** Tags */
1793
+ tags: WxrTag[];
1794
+ /** Authors */
1795
+ authors: WxrAuthor[];
1796
+ /** All taxonomy terms (including custom taxonomies and nav_menu) */
1797
+ terms: WxrTerm[];
1798
+ /** Parsed navigation menus */
1799
+ navMenus: WxrNavMenu[];
1800
+ }
1801
+ interface WxrSite {
1802
+ title?: string;
1803
+ link?: string;
1804
+ description?: string;
1805
+ language?: string;
1806
+ baseSiteUrl?: string;
1807
+ baseBlogUrl?: string;
1808
+ }
1809
+ interface WxrPost {
1810
+ id?: number;
1811
+ title?: string;
1812
+ link?: string;
1813
+ pubDate?: string;
1814
+ creator?: string;
1815
+ guid?: string;
1816
+ description?: string;
1817
+ content?: string;
1818
+ excerpt?: string;
1819
+ postDate?: string;
1820
+ postDateGmt?: string;
1821
+ postModified?: string;
1822
+ postModifiedGmt?: string;
1823
+ commentStatus?: string;
1824
+ pingStatus?: string;
1825
+ status?: string;
1826
+ postType?: string;
1827
+ postName?: string;
1828
+ postPassword?: string;
1829
+ isSticky?: boolean;
1830
+ /** Parent post ID for hierarchical content (pages) */
1831
+ postParent?: number;
1832
+ /** Menu order for sorting */
1833
+ menuOrder?: number;
1834
+ categories: string[];
1835
+ tags: string[];
1836
+ /** Custom taxonomy assignments beyond categories/tags */
1837
+ customTaxonomies?: Map<string, string[]>;
1838
+ meta: Map<string, string>;
1839
+ }
1840
+ interface WxrAttachment {
1841
+ id?: number;
1842
+ title?: string;
1843
+ url?: string;
1844
+ postDate?: string;
1845
+ meta: Map<string, string>;
1846
+ }
1847
+ interface WxrCategory {
1848
+ id?: number;
1849
+ nicename?: string;
1850
+ name?: string;
1851
+ parent?: string;
1852
+ description?: string;
1853
+ }
1854
+ interface WxrTag {
1855
+ id?: number;
1856
+ slug?: string;
1857
+ name?: string;
1858
+ description?: string;
1859
+ }
1860
+ /**
1861
+ * Generic taxonomy term (categories, tags, nav_menu, custom taxonomies)
1862
+ */
1863
+ interface WxrTerm {
1864
+ id: number;
1865
+ taxonomy: string;
1866
+ slug: string;
1867
+ name: string;
1868
+ parent?: string;
1869
+ description?: string;
1870
+ }
1871
+ /**
1872
+ * Navigation menu structure
1873
+ */
1874
+ interface WxrNavMenu {
1875
+ id: number;
1876
+ name: string;
1877
+ label: string;
1878
+ items: WxrNavMenuItem[];
1879
+ }
1880
+ /**
1881
+ * Navigation menu item
1882
+ */
1883
+ interface WxrNavMenuItem {
1884
+ id: number;
1885
+ menuId: number;
1886
+ parentId?: number;
1887
+ sortOrder: number;
1888
+ type: "custom" | "post_type" | "taxonomy";
1889
+ objectType?: string;
1890
+ objectId?: number;
1891
+ url?: string;
1892
+ title: string;
1893
+ target?: string;
1894
+ classes?: string;
1895
+ }
1896
+ interface WxrAuthor {
1897
+ id?: number;
1898
+ login?: string;
1899
+ email?: string;
1900
+ displayName?: string;
1901
+ firstName?: string;
1902
+ lastName?: string;
1903
+ }
1904
+ /**
1905
+ * Parse a WordPress WXR export file
1906
+ */
1907
+ declare function parseWxr(stream: Readable): Promise<WxrData>;
1908
+ /**
1909
+ * Parse a WordPress WXR export from a string
1910
+ *
1911
+ * Uses the non-streaming SAX parser API for compatibility with
1912
+ * environments that don't have Node.js streams (e.g., Cloudflare Workers).
1913
+ */
1914
+ declare function parseWxrString(xml: string): Promise<WxrData>;
1915
+ //#endregion
1916
+ //#region src/plugins/define-plugin.d.ts
1917
+ /**
1918
+ * Define an EmDash plugin.
1919
+ *
1920
+ * **Standard format** -- the canonical format for plugins that work in both
1921
+ * trusted and sandboxed modes. No id/version -- those come from the descriptor.
1922
+ *
1923
+ * @example
1924
+ * ```typescript
1925
+ * import { definePlugin } from "emdash";
1926
+ *
1927
+ * export default definePlugin({
1928
+ * hooks: {
1929
+ * "content:afterSave": {
1930
+ * handler: async (event, ctx) => {
1931
+ * await ctx.kv.set("lastSave", Date.now());
1932
+ * },
1933
+ * },
1934
+ * },
1935
+ * routes: {
1936
+ * status: {
1937
+ * handler: async (routeCtx, ctx) => ({ ok: true }),
1938
+ * },
1939
+ * },
1940
+ * });
1941
+ * ```
1942
+ *
1943
+ * **Native format** -- for plugins that need React admin, direct DB access,
1944
+ * or other capabilities not available in the sandbox.
1945
+ *
1946
+ * @example
1947
+ * ```typescript
1948
+ * import { definePlugin } from "emdash";
1949
+ *
1950
+ * export default definePlugin({
1951
+ * id: "my-plugin",
1952
+ * version: "1.0.0",
1953
+ * capabilities: ["read:content"],
1954
+ * hooks: {
1955
+ * "content:beforeSave": async (event, ctx) => {
1956
+ * ctx.log.info("Saving content", { collection: event.collection });
1957
+ * return event.content;
1958
+ * }
1959
+ * },
1960
+ * routes: {
1961
+ * "sync": {
1962
+ * handler: async (ctx) => {
1963
+ * return { status: "ok" };
1964
+ * }
1965
+ * }
1966
+ * }
1967
+ * });
1968
+ * ```
1969
+ */
1970
+ declare function definePlugin<TStorage extends PluginStorageConfig>(definition: PluginDefinition<TStorage>): ResolvedPlugin<TStorage>;
1971
+ declare function definePlugin(definition: StandardPluginDefinition): StandardPluginDefinition;
1972
+ //#endregion
1973
+ //#region src/auth/types.d.ts
1974
+ /**
1975
+ * Auth Provider Types
1976
+ *
1977
+ * Defines the interfaces for pluggable authentication providers.
1978
+ * Providers like Cloudflare Access implement these interfaces.
1979
+ */
1980
+ /**
1981
+ * Result of authenticating a request via an external auth provider
1982
+ */
1983
+ interface AuthResult {
1984
+ /** User's email address */
1985
+ email: string;
1986
+ /** User's display name */
1987
+ name: string;
1988
+ /** Resolved role level (e.g., 50 for Admin, 30 for Editor) */
1989
+ role: number;
1990
+ /** Provider-specific subject ID */
1991
+ subject?: string;
1992
+ /** Additional provider-specific data */
1993
+ metadata?: Record<string, unknown>;
1994
+ }
1995
+ /**
1996
+ * Auth descriptor - returned by auth adapter functions (e.g., access())
1997
+ *
1998
+ * Similar to DatabaseDescriptor and StorageDescriptor, this allows
1999
+ * auth providers to be configured at build time and loaded at runtime.
2000
+ */
2001
+ interface AuthDescriptor {
2002
+ /**
2003
+ * Auth provider type identifier
2004
+ * @example "cloudflare-access", "okta", "auth0"
2005
+ */
2006
+ type: string;
2007
+ /**
2008
+ * Module specifier to import at runtime
2009
+ * The module must export an `authenticate` function.
2010
+ * @example "@emdash-cms/cloudflare/auth"
2011
+ */
2012
+ entrypoint: string;
2013
+ /**
2014
+ * Provider-specific configuration (JSON-serializable)
2015
+ */
2016
+ config: unknown;
2017
+ }
2018
+ /**
2019
+ * Auth provider module interface
2020
+ *
2021
+ * Modules specified by AuthDescriptor.entrypoint must export
2022
+ * an `authenticate` function matching this signature.
2023
+ */
2024
+ interface AuthProviderModule {
2025
+ /**
2026
+ * Authenticate a request using the provider
2027
+ *
2028
+ * @param request - The incoming HTTP request
2029
+ * @param config - Provider-specific configuration from AuthDescriptor
2030
+ * @returns Authentication result if valid, throws if invalid
2031
+ */
2032
+ authenticate(request: Request, config: unknown): Promise<AuthResult>;
2033
+ }
2034
+ /**
2035
+ * Configuration options common to external auth providers
2036
+ */
2037
+ interface ExternalAuthConfig {
2038
+ /**
2039
+ * Automatically create EmDash users on first login
2040
+ * @default true
2041
+ */
2042
+ autoProvision?: boolean;
2043
+ /**
2044
+ * Role level for users not matching any group in roleMapping
2045
+ * @default 30 (Editor)
2046
+ */
2047
+ defaultRole?: number;
2048
+ /**
2049
+ * Update user's role on each login based on current IdP groups
2050
+ * When false, role is only set on first provisioning
2051
+ * @default false
2052
+ */
2053
+ syncRoles?: boolean;
2054
+ /**
2055
+ * Map IdP group names to EmDash role levels
2056
+ * First match wins if user is in multiple groups
2057
+ *
2058
+ * @example
2059
+ * ```ts
2060
+ * roleMapping: {
2061
+ * "Admins": 50, // Admin
2062
+ * "Developers": 40, // Developer
2063
+ * "Content Team": 30, // Editor
2064
+ * }
2065
+ * ```
2066
+ */
2067
+ roleMapping?: Record<string, number>;
2068
+ }
2069
+ //#endregion
2070
+ //#region src/astro/storage/types.d.ts
2071
+ /**
2072
+ * Serializable storage configuration descriptor
2073
+ */
2074
+ interface StorageDescriptor {
2075
+ /** Module path exporting createStorage function */
2076
+ entrypoint: string;
2077
+ /** Serializable config passed to createStorage at runtime */
2078
+ config: unknown;
2079
+ }
2080
+ /**
2081
+ * S3-compatible storage configuration
2082
+ */
2083
+ interface S3StorageConfig {
2084
+ /** S3 endpoint URL */
2085
+ endpoint: string;
2086
+ /** Bucket name */
2087
+ bucket: string;
2088
+ /** Access key ID */
2089
+ accessKeyId: string;
2090
+ /** Secret access key */
2091
+ secretAccessKey: string;
2092
+ /** Optional region (defaults to "auto") */
2093
+ region?: string;
2094
+ /** Optional public URL prefix for CDN */
2095
+ publicUrl?: string;
2096
+ }
2097
+ /**
2098
+ * Local filesystem storage configuration
2099
+ */
2100
+ interface LocalStorageConfig {
2101
+ /** Directory path for storing files */
2102
+ directory: string;
2103
+ /** Base URL for serving files */
2104
+ baseUrl: string;
2105
+ }
2106
+ //#endregion
2107
+ //#region src/astro/integration/runtime.d.ts
2108
+ /**
2109
+ * Admin page definition (copied from plugins/types to avoid circular deps)
2110
+ */
2111
+ interface PluginAdminPage {
2112
+ path: string;
2113
+ label: string;
2114
+ icon?: string;
2115
+ }
2116
+ /**
2117
+ * Dashboard widget definition (copied from plugins/types to avoid circular deps)
2118
+ */
2119
+ interface PluginDashboardWidget {
2120
+ id: string;
2121
+ size?: "full" | "half" | "third";
2122
+ title?: string;
2123
+ }
2124
+ /**
2125
+ * Plugin descriptor - returned by plugin factory functions
2126
+ *
2127
+ * Contains all static metadata needed for manifest and admin UI,
2128
+ * plus the entrypoint for runtime instantiation.
2129
+ *
2130
+ * @example
2131
+ * ```ts
2132
+ * export function myPlugin(options?: MyPluginOptions): PluginDescriptor {
2133
+ * return {
2134
+ * id: "my-plugin",
2135
+ * version: "1.0.0",
2136
+ * entrypoint: "@my-org/emdash-plugin-foo",
2137
+ * options: options ?? {},
2138
+ * adminEntry: "@my-org/emdash-plugin-foo/admin",
2139
+ * adminPages: [{ path: "/settings", label: "Settings" }],
2140
+ * };
2141
+ * }
2142
+ * ```
2143
+ */
2144
+ /**
2145
+ * Storage collection declaration for sandboxed plugins
2146
+ */
2147
+ interface StorageCollectionDeclaration {
2148
+ indexes?: string[];
2149
+ uniqueIndexes?: string[];
2150
+ }
2151
+ interface PluginDescriptor<TOptions = Record<string, unknown>> {
2152
+ /** Unique plugin identifier */
2153
+ id: string;
2154
+ /** Plugin version (semver) */
2155
+ version: string;
2156
+ /** Module specifier to import (e.g., "@emdash-cms/plugin-api-test") */
2157
+ entrypoint: string;
2158
+ /**
2159
+ * Options to pass to createPlugin(). Native format only.
2160
+ * Standard-format plugins configure themselves via KV settings
2161
+ * and Block Kit admin pages -- not constructor options.
2162
+ */
2163
+ options?: TOptions;
2164
+ /**
2165
+ * Plugin format. Determines how the entrypoint is loaded:
2166
+ * - `"standard"` -- exports `definePlugin({ hooks, routes })` as default.
2167
+ * Wrapped with `adaptSandboxEntry` for in-process execution. Can run in both
2168
+ * `plugins: []` (in-process) and `sandboxed: []` (isolate).
2169
+ * - `"native"` -- exports `createPlugin(options)` returning a `ResolvedPlugin`.
2170
+ * Can only run in `plugins: []`. Cannot be sandboxed or published to marketplace.
2171
+ *
2172
+ * Defaults to `"native"` when unset.
2173
+ *
2174
+ */
2175
+ format?: "standard" | "native";
2176
+ /** Admin UI module specifier (e.g., "@emdash-cms/plugin-audit-log/admin") */
2177
+ adminEntry?: string;
2178
+ /** Module specifier for site-side Astro rendering components (must export `blockComponents`) */
2179
+ componentsEntry?: string;
2180
+ /** Admin pages for navigation */
2181
+ adminPages?: PluginAdminPage[];
2182
+ /** Dashboard widgets */
2183
+ adminWidgets?: PluginDashboardWidget[];
2184
+ /**
2185
+ * Capabilities the plugin requests.
2186
+ * For standard-format plugins, capabilities are enforced in both trusted and
2187
+ * sandboxed modes via the PluginContextFactory.
2188
+ */
2189
+ capabilities?: string[];
2190
+ /**
2191
+ * Allowed hosts for network:fetch capability
2192
+ * Supports wildcards like "*.example.com"
2193
+ */
2194
+ allowedHosts?: string[];
2195
+ /**
2196
+ * Storage collections the plugin declares
2197
+ * Sandboxed plugins can only access declared collections.
2198
+ */
2199
+ storage?: Record<string, StorageCollectionDeclaration>;
2200
+ }
2201
+ /**
2202
+ * Sandboxed plugin descriptor - same format as PluginDescriptor
2203
+ *
2204
+ * These run in isolated V8 isolates via Worker Loader on Cloudflare.
2205
+ * The `entrypoint` is resolved to a file and bundled at build time.
2206
+ */
2207
+ type SandboxedPluginDescriptor<TOptions = Record<string, unknown>> = PluginDescriptor<TOptions>;
2208
+ interface EmDashConfig {
2209
+ /**
2210
+ * Database configuration
2211
+ *
2212
+ * Use one of the adapter functions:
2213
+ * - `sqlite({ url: "file:./data.db" })` - Local SQLite
2214
+ * - `libsql({ url: "...", authToken: "..." })` - Turso/libSQL
2215
+ * - `d1({ binding: "DB" })` - Cloudflare D1
2216
+ *
2217
+ * @example
2218
+ * ```ts
2219
+ * import { sqlite } from "emdash/db";
2220
+ *
2221
+ * emdash({
2222
+ * database: sqlite({ url: "file:./data.db" }),
2223
+ * })
2224
+ * ```
2225
+ */
2226
+ database?: DatabaseDescriptor;
2227
+ /**
2228
+ * Storage configuration (for media)
2229
+ */
2230
+ storage?: StorageDescriptor;
2231
+ /**
2232
+ * Trusted plugins to load (run in main isolate)
2233
+ *
2234
+ * @example
2235
+ * ```ts
2236
+ * import { auditLogPlugin } from "@emdash-cms/plugin-audit-log";
2237
+ * import { webhookNotifierPlugin } from "@emdash-cms/plugin-webhook-notifier";
2238
+ *
2239
+ * emdash({
2240
+ * plugins: [
2241
+ * auditLogPlugin(),
2242
+ * webhookNotifierPlugin({ url: "https://example.com/webhook" }),
2243
+ * ],
2244
+ * })
2245
+ * ```
2246
+ */
2247
+ plugins?: PluginDescriptor[];
2248
+ /**
2249
+ * Sandboxed plugins to load (run in isolated V8 isolates)
2250
+ *
2251
+ * Only works on Cloudflare with Worker Loader enabled.
2252
+ * Uses the same format as `plugins` - the difference is where they run.
2253
+ *
2254
+ * @example
2255
+ * ```ts
2256
+ * import { untrustedPlugin } from "some-third-party-plugin";
2257
+ *
2258
+ * emdash({
2259
+ * plugins: [trustedPlugin()], // runs in host
2260
+ * sandboxed: [untrustedPlugin()], // runs in isolate
2261
+ * sandboxRunner: "@emdash-cms/sandbox-cloudflare",
2262
+ * })
2263
+ * ```
2264
+ */
2265
+ sandboxed?: SandboxedPluginDescriptor[];
2266
+ /**
2267
+ * Module that exports the sandbox runner factory.
2268
+ * Required if using sandboxed plugins.
2269
+ *
2270
+ * @example
2271
+ * ```ts
2272
+ * emdash({
2273
+ * sandboxRunner: "@emdash-cms/sandbox-cloudflare",
2274
+ * })
2275
+ * ```
2276
+ */
2277
+ sandboxRunner?: string;
2278
+ /**
2279
+ * Authentication configuration
2280
+ *
2281
+ * Use an auth adapter function from a platform package:
2282
+ * - `access({ teamDomain: "..." })` from `@emdash-cms/cloudflare`
2283
+ *
2284
+ * When an external auth provider is configured, passkey auth is disabled.
2285
+ *
2286
+ * @example
2287
+ * ```ts
2288
+ * import { access } from "@emdash-cms/cloudflare";
2289
+ *
2290
+ * emdash({
2291
+ * auth: access({
2292
+ * teamDomain: "myteam.cloudflareaccess.com",
2293
+ * audience: "abc123...",
2294
+ * roleMapping: {
2295
+ * "Admins": 50,
2296
+ * "Editors": 30,
2297
+ * },
2298
+ * }),
2299
+ * })
2300
+ * ```
2301
+ */
2302
+ auth?: AuthDescriptor;
2303
+ /**
2304
+ * Enable the MCP (Model Context Protocol) server endpoint.
2305
+ *
2306
+ * When enabled, exposes an MCP Streamable HTTP server at
2307
+ * `/_emdash/api/mcp` that allows AI agents and tools to interact
2308
+ * with the CMS using the standardized MCP protocol.
2309
+ *
2310
+ * Authentication is handled by the existing EmDash auth middleware —
2311
+ * agents must authenticate with an API token or session cookie.
2312
+ *
2313
+ * @default false
2314
+ *
2315
+ * @example
2316
+ * ```ts
2317
+ * emdash({
2318
+ * mcp: true,
2319
+ * })
2320
+ * ```
2321
+ */
2322
+ mcp?: boolean;
2323
+ /**
2324
+ * Plugin marketplace URL
2325
+ *
2326
+ * When set, enables the marketplace features: browse, install, update,
2327
+ * and uninstall plugins from a remote marketplace.
2328
+ *
2329
+ * Must be an HTTPS URL in production, or localhost/127.0.0.1 in dev.
2330
+ * Requires `sandboxRunner` to be configured (marketplace plugins run sandboxed).
2331
+ *
2332
+ * @example
2333
+ * ```ts
2334
+ * emdash({
2335
+ * marketplace: "https://marketplace.emdashcms.com",
2336
+ * sandboxRunner: "@emdash-cms/sandbox-cloudflare",
2337
+ * })
2338
+ * ```
2339
+ */
2340
+ marketplace?: string;
2341
+ /**
2342
+ * Enable playground mode for ephemeral "try EmDash" sites.
2343
+ *
2344
+ * When set, the integration injects a playground middleware (order: "pre")
2345
+ * that runs BEFORE the normal EmDash middleware chain. It creates an
2346
+ * isolated Durable Object database per session, runs migrations, applies
2347
+ * the seed, creates an anonymous admin user, and sets the DB in ALS.
2348
+ * By the time the runtime middleware runs, the database is fully ready.
2349
+ *
2350
+ * Setup and auth middleware are skipped (the playground handles both).
2351
+ *
2352
+ * Requires `@emdash-cms/cloudflare` as a dependency and a DO binding
2353
+ * in wrangler.jsonc.
2354
+ *
2355
+ * @example
2356
+ * ```ts
2357
+ * emdash({
2358
+ * database: playgroundDatabase({ binding: "PLAYGROUND_DB" }),
2359
+ * playground: {
2360
+ * middlewareEntrypoint: "@emdash-cms/cloudflare/db/playground-middleware",
2361
+ * },
2362
+ * })
2363
+ * ```
2364
+ */
2365
+ playground?: {
2366
+ /** Module path for the playground middleware. */middlewareEntrypoint: string;
2367
+ };
2368
+ /**
2369
+ * Media providers for browsing and uploading media
2370
+ *
2371
+ * The local media provider (using storage adapter) is available by default.
2372
+ * Additional providers can be added for external services like Unsplash,
2373
+ * Cloudinary, Mux, Cloudflare Images, etc.
2374
+ *
2375
+ * @example
2376
+ * ```ts
2377
+ * import { cloudflareImages, cloudflareStream } from "@emdash-cms/cloudflare";
2378
+ * import { unsplash } from "@emdash-cms/provider-unsplash";
2379
+ *
2380
+ * emdash({
2381
+ * mediaProviders: [
2382
+ * cloudflareImages({ accountId: "..." }),
2383
+ * cloudflareStream({ accountId: "..." }),
2384
+ * unsplash({ accessKey: "..." }),
2385
+ * ],
2386
+ * })
2387
+ * ```
2388
+ */
2389
+ mediaProviders?: MediaProviderDescriptor[];
2390
+ }
2391
+ /**
2392
+ * Get stored config from global
2393
+ * This is set by the virtual module at build time
2394
+ */
2395
+ declare function getStoredConfig(): EmDashConfig | null;
2396
+ declare global {
2397
+ var __emdashConfig: EmDashConfig | undefined;
2398
+ } //# sourceMappingURL=runtime.d.ts.map
2399
+ //#endregion
2400
+ //#region src/plugins/manifest-schema.d.ts
2401
+ /**
2402
+ * Zod schema matching the PluginManifest interface from types.ts.
2403
+ *
2404
+ * Every JSON.parse of a manifest.json should validate through this.
2405
+ */
2406
+ declare const pluginManifestSchema: z$1.ZodObject<{
2407
+ id: z$1.ZodString;
2408
+ version: z$1.ZodString;
2409
+ capabilities: z$1.ZodArray<z$1.ZodEnum<{
2410
+ "network:fetch": "network:fetch";
2411
+ "network:fetch:any": "network:fetch:any";
2412
+ "read:content": "read:content";
2413
+ "write:content": "write:content";
2414
+ "read:media": "read:media";
2415
+ "write:media": "write:media";
2416
+ "read:users": "read:users";
2417
+ "email:send": "email:send";
2418
+ "email:provide": "email:provide";
2419
+ "email:intercept": "email:intercept";
2420
+ "page:inject": "page:inject";
2421
+ }>>;
2422
+ allowedHosts: z$1.ZodArray<z$1.ZodString>;
2423
+ storage: z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
2424
+ indexes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>;
2425
+ uniqueIndexes: z$1.ZodOptional<z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>>;
2426
+ }, z$1.core.$strip>>;
2427
+ hooks: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodEnum<{
2428
+ "plugin:install": "plugin:install";
2429
+ "plugin:activate": "plugin:activate";
2430
+ "plugin:deactivate": "plugin:deactivate";
2431
+ "plugin:uninstall": "plugin:uninstall";
2432
+ "content:beforeSave": "content:beforeSave";
2433
+ "content:afterSave": "content:afterSave";
2434
+ "content:beforeDelete": "content:beforeDelete";
2435
+ "content:afterDelete": "content:afterDelete";
2436
+ "media:beforeUpload": "media:beforeUpload";
2437
+ "media:afterUpload": "media:afterUpload";
2438
+ cron: "cron";
2439
+ "email:beforeSend": "email:beforeSend";
2440
+ "email:deliver": "email:deliver";
2441
+ "email:afterSend": "email:afterSend";
2442
+ "comment:beforeCreate": "comment:beforeCreate";
2443
+ "comment:moderate": "comment:moderate";
2444
+ "comment:afterCreate": "comment:afterCreate";
2445
+ "comment:afterModerate": "comment:afterModerate";
2446
+ "page:metadata": "page:metadata";
2447
+ "page:fragments": "page:fragments";
2448
+ }>, z$1.ZodObject<{
2449
+ name: z$1.ZodEnum<{
2450
+ "plugin:install": "plugin:install";
2451
+ "plugin:activate": "plugin:activate";
2452
+ "plugin:deactivate": "plugin:deactivate";
2453
+ "plugin:uninstall": "plugin:uninstall";
2454
+ "content:beforeSave": "content:beforeSave";
2455
+ "content:afterSave": "content:afterSave";
2456
+ "content:beforeDelete": "content:beforeDelete";
2457
+ "content:afterDelete": "content:afterDelete";
2458
+ "media:beforeUpload": "media:beforeUpload";
2459
+ "media:afterUpload": "media:afterUpload";
2460
+ cron: "cron";
2461
+ "email:beforeSend": "email:beforeSend";
2462
+ "email:deliver": "email:deliver";
2463
+ "email:afterSend": "email:afterSend";
2464
+ "comment:beforeCreate": "comment:beforeCreate";
2465
+ "comment:moderate": "comment:moderate";
2466
+ "comment:afterCreate": "comment:afterCreate";
2467
+ "comment:afterModerate": "comment:afterModerate";
2468
+ "page:metadata": "page:metadata";
2469
+ "page:fragments": "page:fragments";
2470
+ }>;
2471
+ exclusive: z$1.ZodOptional<z$1.ZodBoolean>;
2472
+ priority: z$1.ZodOptional<z$1.ZodNumber>;
2473
+ timeout: z$1.ZodOptional<z$1.ZodNumber>;
2474
+ }, z$1.core.$strip>]>>;
2475
+ routes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodObject<{
2476
+ name: z$1.ZodString;
2477
+ public: z$1.ZodOptional<z$1.ZodBoolean>;
2478
+ }, z$1.core.$strip>]>>;
2479
+ admin: z$1.ZodObject<{
2480
+ entry: z$1.ZodOptional<z$1.ZodString>;
2481
+ settingsSchema: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{
2482
+ type: z$1.ZodLiteral<"string">;
2483
+ default: z$1.ZodOptional<z$1.ZodString>;
2484
+ multiline: z$1.ZodOptional<z$1.ZodBoolean>;
2485
+ label: z$1.ZodString;
2486
+ description: z$1.ZodOptional<z$1.ZodString>;
2487
+ }, z$1.core.$strip>, z$1.ZodObject<{
2488
+ type: z$1.ZodLiteral<"number">;
2489
+ default: z$1.ZodOptional<z$1.ZodNumber>;
2490
+ min: z$1.ZodOptional<z$1.ZodNumber>;
2491
+ max: z$1.ZodOptional<z$1.ZodNumber>;
2492
+ label: z$1.ZodString;
2493
+ description: z$1.ZodOptional<z$1.ZodString>;
2494
+ }, z$1.core.$strip>, z$1.ZodObject<{
2495
+ type: z$1.ZodLiteral<"boolean">;
2496
+ default: z$1.ZodOptional<z$1.ZodBoolean>;
2497
+ label: z$1.ZodString;
2498
+ description: z$1.ZodOptional<z$1.ZodString>;
2499
+ }, z$1.core.$strip>, z$1.ZodObject<{
2500
+ type: z$1.ZodLiteral<"select">;
2501
+ options: z$1.ZodArray<z$1.ZodObject<{
2502
+ value: z$1.ZodString;
2503
+ label: z$1.ZodString;
2504
+ }, z$1.core.$strip>>;
2505
+ default: z$1.ZodOptional<z$1.ZodString>;
2506
+ label: z$1.ZodString;
2507
+ description: z$1.ZodOptional<z$1.ZodString>;
2508
+ }, z$1.core.$strip>, z$1.ZodObject<{
2509
+ type: z$1.ZodLiteral<"secret">;
2510
+ label: z$1.ZodString;
2511
+ description: z$1.ZodOptional<z$1.ZodString>;
2512
+ }, z$1.core.$strip>], "type">>>;
2513
+ pages: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2514
+ path: z$1.ZodString;
2515
+ label: z$1.ZodString;
2516
+ icon: z$1.ZodOptional<z$1.ZodString>;
2517
+ }, z$1.core.$strip>>>;
2518
+ widgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2519
+ id: z$1.ZodString;
2520
+ size: z$1.ZodOptional<z$1.ZodEnum<{
2521
+ full: "full";
2522
+ half: "half";
2523
+ third: "third";
2524
+ }>>;
2525
+ title: z$1.ZodOptional<z$1.ZodString>;
2526
+ }, z$1.core.$strip>>>;
2527
+ fieldWidgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2528
+ name: z$1.ZodString;
2529
+ label: z$1.ZodString;
2530
+ fieldTypes: z$1.ZodArray<z$1.ZodEnum<{
2531
+ string: "string";
2532
+ number: "number";
2533
+ boolean: "boolean";
2534
+ text: "text";
2535
+ integer: "integer";
2536
+ datetime: "datetime";
2537
+ select: "select";
2538
+ multiSelect: "multiSelect";
2539
+ portableText: "portableText";
2540
+ image: "image";
2541
+ file: "file";
2542
+ reference: "reference";
2543
+ json: "json";
2544
+ slug: "slug";
2545
+ }>>;
2546
+ elements: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2547
+ type: z$1.ZodString;
2548
+ action_id: z$1.ZodString;
2549
+ label: z$1.ZodOptional<z$1.ZodString>;
2550
+ }, z$1.core.$loose>>>;
2551
+ }, z$1.core.$strip>>>;
2552
+ }, z$1.core.$strip>;
2553
+ }, z$1.core.$strip>;
2554
+ type ValidatedPluginManifest = z$1.infer<typeof pluginManifestSchema>;
2555
+ //#endregion
2556
+ //#region src/plugins/hooks.d.ts
2557
+ type HookNameV2 = "plugin:install" | "plugin:activate" | "plugin:deactivate" | "plugin:uninstall" | "content:beforeSave" | "content:afterSave" | "content:beforeDelete" | "content:afterDelete" | "media:beforeUpload" | "media:afterUpload" | "cron" | "email:beforeSend" | "email:deliver" | "email:afterSend" | "comment:beforeCreate" | "comment:moderate" | "comment:afterCreate" | "comment:afterModerate" | "page:metadata" | "page:fragments";
2558
+ /**
2559
+ * Hook execution result
2560
+ */
2561
+ interface HookResult<T> {
2562
+ success: boolean;
2563
+ value?: T;
2564
+ error?: Error;
2565
+ pluginId: string;
2566
+ duration: number;
2567
+ }
2568
+ /**
2569
+ * Hook pipeline for executing hooks in order
2570
+ */
2571
+ declare class HookPipeline {
2572
+ private hooks;
2573
+ private pluginMap;
2574
+ private contextFactory;
2575
+ /** Stored so setContextFactory can merge incrementally. */
2576
+ private contextFactoryOptions;
2577
+ /** Hook names where at least one handler declared exclusive: true */
2578
+ private exclusiveHookNames;
2579
+ /**
2580
+ * Selected provider plugin ID for each exclusive hook.
2581
+ * Set by the PluginManager after resolution.
2582
+ */
2583
+ private exclusiveSelections;
2584
+ constructor(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions);
2585
+ /**
2586
+ * Set or update the context factory options.
2587
+ *
2588
+ * When called on a pipeline that already has a factory, the new options
2589
+ * are merged on top of the existing ones so that callers don't need to
2590
+ * repeat every field (e.g. adding `cronReschedule` without losing
2591
+ * `storage` / `getUploadUrl`).
2592
+ */
2593
+ setContextFactory(options: Partial<PluginContextFactoryOptions>): void;
2594
+ /**
2595
+ * Get context for a plugin
2596
+ */
2597
+ private getContext;
2598
+ /**
2599
+ * Get typed hooks for a specific hook name.
2600
+ * The internal map stores ResolvedHook<unknown>, but we know each name
2601
+ * maps to a specific handler type via HookHandlerMap.
2602
+ *
2603
+ * Exclusive hooks that have a selected provider are filtered out — they
2604
+ * should only run via invokeExclusiveHook(), not in the regular pipeline.
2605
+ */
2606
+ private getTypedHooks;
2607
+ /**
2608
+ * Register all hooks from plugins.
2609
+ *
2610
+ * Registers each hook name individually to preserve type safety. The
2611
+ * internal map stores ResolvedHook<unknown> since it's keyed by string,
2612
+ * but getTypedHooks() restores the correct handler type on retrieval.
2613
+ */
2614
+ private registerPlugins;
2615
+ /**
2616
+ * Maps hook names to the capability required to register them.
2617
+ *
2618
+ * Hooks not listed here have no capability requirement (e.g. lifecycle
2619
+ * hooks, cron). Any plugin declaring a listed hook without the required
2620
+ * capability will have that hook silently skipped at registration time.
2621
+ */
2622
+ private static readonly HOOK_REQUIRED_CAPABILITY;
2623
+ /**
2624
+ * Register a single plugin's hook by name
2625
+ */
2626
+ private registerPluginHook;
2627
+ /**
2628
+ * Register a single hook
2629
+ */
2630
+ private registerHook;
2631
+ /**
2632
+ * Sort hooks by priority and dependencies
2633
+ */
2634
+ private sortHooks;
2635
+ /**
2636
+ * Execute a hook with timeout
2637
+ */
2638
+ private executeWithTimeout;
2639
+ /**
2640
+ * Run plugin:install hooks
2641
+ */
2642
+ runPluginInstall(pluginId: string): Promise<HookResult<void>[]>;
2643
+ /**
2644
+ * Run plugin:activate hooks
2645
+ */
2646
+ runPluginActivate(pluginId: string): Promise<HookResult<void>[]>;
2647
+ /**
2648
+ * Run plugin:deactivate hooks
2649
+ */
2650
+ runPluginDeactivate(pluginId: string): Promise<HookResult<void>[]>;
2651
+ /**
2652
+ * Run plugin:uninstall hooks
2653
+ */
2654
+ runPluginUninstall(pluginId: string, deleteData: boolean): Promise<HookResult<void>[]>;
2655
+ private runLifecycleHook;
2656
+ /**
2657
+ * Run content:beforeSave hooks
2658
+ * Returns modified content from the pipeline
2659
+ */
2660
+ runContentBeforeSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<{
2661
+ content: Record<string, unknown>;
2662
+ results: HookResult<Record<string, unknown>>[];
2663
+ }>;
2664
+ /**
2665
+ * Run content:afterSave hooks
2666
+ */
2667
+ runContentAfterSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<HookResult<void>[]>;
2668
+ /**
2669
+ * Run content:beforeDelete hooks
2670
+ * Returns whether deletion is allowed
2671
+ */
2672
+ runContentBeforeDelete(id: string, collection: string): Promise<{
2673
+ allowed: boolean;
2674
+ results: HookResult<boolean>[];
2675
+ }>;
2676
+ /**
2677
+ * Run content:afterDelete hooks
2678
+ */
2679
+ runContentAfterDelete(id: string, collection: string): Promise<HookResult<void>[]>;
2680
+ /**
2681
+ * Run media:beforeUpload hooks
2682
+ */
2683
+ runMediaBeforeUpload(file: {
2684
+ name: string;
2685
+ type: string;
2686
+ size: number;
2687
+ }): Promise<{
2688
+ file: {
2689
+ name: string;
2690
+ type: string;
2691
+ size: number;
2692
+ };
2693
+ results: HookResult<{
2694
+ name: string;
2695
+ type: string;
2696
+ size: number;
2697
+ }>[];
2698
+ }>;
2699
+ /**
2700
+ * Run media:afterUpload hooks
2701
+ */
2702
+ runMediaAfterUpload(media: {
2703
+ id: string;
2704
+ filename: string;
2705
+ mimeType: string;
2706
+ size: number | null;
2707
+ url: string;
2708
+ createdAt: string;
2709
+ }): Promise<HookResult<void>[]>;
2710
+ /**
2711
+ * Invoke the cron hook for a specific plugin.
2712
+ *
2713
+ * Unlike other hooks which broadcast to all plugins, the cron hook is
2714
+ * dispatched only to the target plugin — the one that owns the task.
2715
+ */
2716
+ invokeCronHook(pluginId: string, event: CronEvent): Promise<HookResult<void>>;
2717
+ /**
2718
+ * Run email:beforeSend hooks (middleware pipeline).
2719
+ *
2720
+ * Each handler receives the message and returns a modified message or
2721
+ * `false` to cancel delivery. The pipeline chains message transformations —
2722
+ * each handler receives the output of the previous one.
2723
+ */
2724
+ runEmailBeforeSend(message: EmailMessage, source: string): Promise<{
2725
+ message: EmailMessage | false;
2726
+ results: HookResult<EmailMessage | false>[];
2727
+ }>;
2728
+ /**
2729
+ * Run email:afterSend hooks (fire-and-forget).
2730
+ *
2731
+ * Errors are logged but don't propagate — they don't affect the caller.
2732
+ */
2733
+ runEmailAfterSend(message: EmailMessage, source: string): Promise<HookResult<void>[]>;
2734
+ /**
2735
+ * Run comment:beforeCreate hooks (middleware pipeline).
2736
+ *
2737
+ * Each handler receives the event and returns a modified event or
2738
+ * `false` to reject the comment. The pipeline chains transformations —
2739
+ * each handler receives the output of the previous one.
2740
+ */
2741
+ runCommentBeforeCreate(event: CommentBeforeCreateEvent): Promise<CommentBeforeCreateEvent | false>;
2742
+ /**
2743
+ * Run comment:afterCreate hooks (fire-and-forget).
2744
+ *
2745
+ * Errors are logged but don't propagate — they don't affect the caller.
2746
+ */
2747
+ runCommentAfterCreate(event: CommentAfterCreateEvent): Promise<void>;
2748
+ /**
2749
+ * Run comment:afterModerate hooks (fire-and-forget).
2750
+ *
2751
+ * Errors are logged but don't propagate — they don't affect the caller.
2752
+ */
2753
+ runCommentAfterModerate(event: CommentAfterModerateEvent): Promise<void>;
2754
+ /**
2755
+ * Run page:metadata hooks. Each handler returns contributions that are
2756
+ * merged by the metadata collector. Errors are logged but don't propagate.
2757
+ */
2758
+ runPageMetadata(event: PageMetadataEvent): Promise<Array<{
2759
+ pluginId: string;
2760
+ contributions: PageMetadataContribution[];
2761
+ }>>;
2762
+ /**
2763
+ * Run page:fragments hooks. Only trusted plugins should be registered
2764
+ * for this hook. Errors are logged but don't propagate.
2765
+ */
2766
+ runPageFragments(event: PageFragmentEvent): Promise<Array<{
2767
+ pluginId: string;
2768
+ contributions: PageFragmentContribution[];
2769
+ }>>;
2770
+ /**
2771
+ * Check if any hooks are registered for a given name
2772
+ */
2773
+ hasHooks(name: HookNameV2): boolean;
2774
+ /**
2775
+ * Get hook count for debugging
2776
+ */
2777
+ getHookCount(name: HookNameV2): number;
2778
+ /**
2779
+ * Get all registered hook names
2780
+ */
2781
+ getRegisteredHooks(): HookNameV2[];
2782
+ /**
2783
+ * Returns hook names where at least one handler declared exclusive: true
2784
+ */
2785
+ getRegisteredExclusiveHooks(): string[];
2786
+ /**
2787
+ * Check if a hook is exclusive
2788
+ */
2789
+ isExclusiveHook(name: string): boolean;
2790
+ /**
2791
+ * Set the selected provider for an exclusive hook.
2792
+ * Called by PluginManager after resolution.
2793
+ */
2794
+ setExclusiveSelection(hookName: string, pluginId: string): void;
2795
+ /**
2796
+ * Clear the selected provider for an exclusive hook.
2797
+ */
2798
+ clearExclusiveSelection(hookName: string): void;
2799
+ /**
2800
+ * Get the selected provider for an exclusive hook (if any).
2801
+ */
2802
+ getExclusiveSelection(hookName: string): string | undefined;
2803
+ /**
2804
+ * Get all plugins that registered a handler for a given exclusive hook.
2805
+ */
2806
+ getExclusiveHookProviders(hookName: string): Array<{
2807
+ pluginId: string;
2808
+ }>;
2809
+ /**
2810
+ * Invoke an exclusive hook — dispatch only to the selected provider.
2811
+ * Returns null if no provider is selected or if the selected hook
2812
+ * is not found in the pipeline.
2813
+ *
2814
+ * This is a generic dispatch used by the email pipeline and other
2815
+ * exclusive hook consumers. The handler type is unknown — callers
2816
+ * must know the expected signature.
2817
+ *
2818
+ * Errors are isolated: a failing handler returns an error result
2819
+ * instead of propagating the exception to the caller.
2820
+ */
2821
+ invokeExclusiveHook(hookName: string, event: unknown): Promise<{
2822
+ result: unknown;
2823
+ pluginId: string;
2824
+ error?: Error;
2825
+ duration: number;
2826
+ } | null>;
2827
+ }
2828
+ /**
2829
+ * Create a hook pipeline from plugins
2830
+ */
2831
+ declare function createHookPipeline(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions): HookPipeline;
2832
+ //#endregion
2833
+ //#region src/plugins/email.d.ts
2834
+ /**
2835
+ * EmailPipeline orchestrates email delivery through the plugin hook system.
2836
+ *
2837
+ * The pipeline runs in three stages:
2838
+ * 1. email:beforeSend — middleware hooks that can transform or cancel messages
2839
+ * 2. email:deliver — exclusive hook dispatching to the selected provider
2840
+ * 3. email:afterSend — fire-and-forget hooks for logging/analytics
2841
+ */
2842
+ declare class EmailPipeline {
2843
+ private pipeline;
2844
+ constructor(pipeline: HookPipeline);
2845
+ /**
2846
+ * Replace the underlying hook pipeline.
2847
+ *
2848
+ * Called by the runtime when rebuilding the hook pipeline after a
2849
+ * plugin is enabled or disabled, so the email pipeline dispatches
2850
+ * to the current set of active hooks.
2851
+ */
2852
+ setPipeline(pipeline: HookPipeline): void;
2853
+ /**
2854
+ * Send an email through the full pipeline.
2855
+ *
2856
+ * @param message - The email to send
2857
+ * @param source - Where the email originated ("system" for auth, plugin ID for plugins)
2858
+ * @throws EmailNotConfiguredError if no provider is selected
2859
+ * @throws EmailRecursionError if called re-entrantly from within a hook
2860
+ * @throws Error if the provider handler throws
2861
+ */
2862
+ send(message: EmailMessage, source: string): Promise<void>;
2863
+ /**
2864
+ * Inner send implementation, separated from the recursion guard.
2865
+ */
2866
+ private sendInner;
2867
+ /**
2868
+ * Check if an email provider is configured and available.
2869
+ *
2870
+ * Returns true if an email:deliver provider is selected in the exclusive
2871
+ * hook system. Plugins and auth code use this to decide whether to show
2872
+ * "send invite" vs "copy invite link" UI.
2873
+ */
2874
+ isAvailable(): boolean;
2875
+ }
2876
+ //#endregion
2877
+ //#region src/plugins/context.d.ts
2878
+ /**
2879
+ * Options for creating site info
2880
+ */
2881
+ interface SiteInfoOptions {
2882
+ /** Site name from options table */
2883
+ siteName?: string;
2884
+ /** Site URL from options table or Astro config */
2885
+ siteUrl?: string;
2886
+ /** Site locale from options table */
2887
+ locale?: string;
2888
+ }
2889
+ interface PluginContextFactoryOptions {
2890
+ db: Kysely<Database>;
2891
+ /**
2892
+ * Storage backend for direct media uploads.
2893
+ * If not provided, upload() will throw.
2894
+ */
2895
+ storage?: Storage;
2896
+ /**
2897
+ * Function to generate upload URLs for media.
2898
+ * If not provided, media write operations will throw.
2899
+ */
2900
+ getUploadUrl?: (filename: string, contentType: string) => Promise<{
2901
+ uploadUrl: string;
2902
+ mediaId: string;
2903
+ }>;
2904
+ /**
2905
+ * Site information for ctx.site and ctx.url().
2906
+ * If not provided, site info will have empty defaults.
2907
+ */
2908
+ siteInfo?: SiteInfoOptions;
2909
+ /**
2910
+ * Callback to notify the cron scheduler that the next due time may have changed.
2911
+ * If not provided, ctx.cron will not be available.
2912
+ */
2913
+ cronReschedule?: () => void;
2914
+ /**
2915
+ * Email pipeline instance for ctx.email.
2916
+ * If not provided (or no provider configured), ctx.email will be undefined.
2917
+ */
2918
+ emailPipeline?: EmailPipeline;
2919
+ }
2920
+ //#endregion
2921
+ //#region src/plugins/routes.d.ts
2922
+ /**
2923
+ * Result from a route invocation
2924
+ */
2925
+ interface RouteResult<T = unknown> {
2926
+ success: boolean;
2927
+ data?: T;
2928
+ error?: {
2929
+ code: string;
2930
+ message: string;
2931
+ details?: unknown;
2932
+ };
2933
+ status: number;
2934
+ }
2935
+ /**
2936
+ * Route invocation options
2937
+ */
2938
+ interface InvokeRouteOptions {
2939
+ /** The original request */
2940
+ request: Request;
2941
+ /** Request body (already parsed) */
2942
+ body?: unknown;
2943
+ }
2944
+ /**
2945
+ * Error class for plugin routes
2946
+ * Allows plugins to return structured errors with specific HTTP status codes
2947
+ */
2948
+ declare class PluginRouteError extends Error {
2949
+ code: string;
2950
+ status: number;
2951
+ details?: unknown | undefined;
2952
+ constructor(code: string, message: string, status?: number, details?: unknown | undefined);
2953
+ /**
2954
+ * Create a bad request error (400)
2955
+ */
2956
+ static badRequest(message: string, details?: unknown): PluginRouteError;
2957
+ /**
2958
+ * Create an unauthorized error (401)
2959
+ */
2960
+ static unauthorized(message?: string): PluginRouteError;
2961
+ /**
2962
+ * Create a forbidden error (403)
2963
+ */
2964
+ static forbidden(message?: string): PluginRouteError;
2965
+ /**
2966
+ * Create a not found error (404)
2967
+ */
2968
+ static notFound(message?: string): PluginRouteError;
2969
+ /**
2970
+ * Create a conflict error (409)
2971
+ */
2972
+ static conflict(message: string, details?: unknown): PluginRouteError;
2973
+ /**
2974
+ * Create an internal error (500)
2975
+ */
2976
+ static internal(message?: string): PluginRouteError;
2977
+ }
2978
+ //#endregion
2979
+ //#region src/plugins/manager.d.ts
2980
+ /**
2981
+ * Plugin state in the manager
2982
+ */
2983
+ type PluginState = "registered" | "installed" | "active" | "inactive";
2984
+ /**
2985
+ * Plugin manager options
2986
+ */
2987
+ interface PluginManagerOptions {
2988
+ /** Database instance */
2989
+ db: Kysely<Database>;
2990
+ /** Storage backend for direct media uploads */
2991
+ storage?: Storage;
2992
+ /** Function to generate upload URLs for media */
2993
+ getUploadUrl?: (filename: string, contentType: string) => Promise<{
2994
+ uploadUrl: string;
2995
+ mediaId: string;
2996
+ }>;
2997
+ }
2998
+ /**
2999
+ * Plugin Manager v2
3000
+ *
3001
+ * Manages the full lifecycle of plugins and coordinates hooks/routes.
3002
+ */
3003
+ declare class PluginManager {
3004
+ private options;
3005
+ private plugins;
3006
+ private hookPipeline;
3007
+ private routeRegistry;
3008
+ private factoryOptions;
3009
+ private initialized;
3010
+ constructor(options: PluginManagerOptions);
3011
+ /**
3012
+ * Register a plugin definition
3013
+ * This resolves the definition and adds it to the manager, but doesn't install it
3014
+ */
3015
+ register<TStorage extends PluginStorageConfig>(definition: PluginDefinition<TStorage>): ResolvedPlugin<TStorage>;
3016
+ /**
3017
+ * Register multiple plugins
3018
+ */
3019
+ registerAll(definitions: PluginDefinition[]): void;
3020
+ /**
3021
+ * Unregister a plugin
3022
+ * Plugin must be inactive or just registered
3023
+ */
3024
+ unregister(pluginId: string): boolean;
3025
+ /**
3026
+ * Install a plugin (run install hooks, set up storage)
3027
+ */
3028
+ install(pluginId: string): Promise<HookResult<void>[]>;
3029
+ /**
3030
+ * Activate a plugin (run activate hooks, enable hooks/routes)
3031
+ */
3032
+ activate(pluginId: string): Promise<HookResult<void>[]>;
3033
+ /**
3034
+ * Deactivate a plugin (run deactivate hooks, disable hooks/routes)
3035
+ */
3036
+ deactivate(pluginId: string): Promise<HookResult<void>[]>;
3037
+ /**
3038
+ * Uninstall a plugin (run uninstall hooks, optionally delete data)
3039
+ */
3040
+ uninstall(pluginId: string, deleteData?: boolean): Promise<HookResult<void>[]>;
3041
+ /**
3042
+ * Run content:beforeSave hooks across all active plugins
3043
+ */
3044
+ runContentBeforeSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<{
3045
+ content: Record<string, unknown>;
3046
+ results: HookResult<Record<string, unknown>>[];
3047
+ }>;
3048
+ /**
3049
+ * Run content:afterSave hooks across all active plugins
3050
+ */
3051
+ runContentAfterSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<HookResult<void>[]>;
3052
+ /**
3053
+ * Run content:beforeDelete hooks across all active plugins
3054
+ */
3055
+ runContentBeforeDelete(id: string, collection: string): Promise<{
3056
+ allowed: boolean;
3057
+ results: HookResult<boolean>[];
3058
+ }>;
3059
+ /**
3060
+ * Run content:afterDelete hooks across all active plugins
3061
+ */
3062
+ runContentAfterDelete(id: string, collection: string): Promise<HookResult<void>[]>;
3063
+ /**
3064
+ * Run media:beforeUpload hooks across all active plugins
3065
+ */
3066
+ runMediaBeforeUpload(file: {
3067
+ name: string;
3068
+ type: string;
3069
+ size: number;
3070
+ }): Promise<{
3071
+ file: {
3072
+ name: string;
3073
+ type: string;
3074
+ size: number;
3075
+ };
3076
+ results: HookResult<{
3077
+ name: string;
3078
+ type: string;
3079
+ size: number;
3080
+ }>[];
3081
+ }>;
3082
+ /**
3083
+ * Run media:afterUpload hooks across all active plugins
3084
+ */
3085
+ runMediaAfterUpload(media: MediaItem$1): Promise<HookResult<void>[]>;
3086
+ /**
3087
+ * Invoke the cron hook for a specific plugin (per-plugin dispatch).
3088
+ * Used as the InvokeCronHookFn callback for CronExecutor.
3089
+ */
3090
+ invokeCronHook(pluginId: string, event: CronEvent): Promise<void>;
3091
+ /**
3092
+ * Invoke a plugin route
3093
+ */
3094
+ invokeRoute(pluginId: string, routeName: string, options: InvokeRouteOptions): Promise<RouteResult>;
3095
+ /**
3096
+ * Get all routes for a plugin
3097
+ */
3098
+ getPluginRoutes(pluginId: string): string[];
3099
+ /**
3100
+ * Get a plugin by ID
3101
+ */
3102
+ getPlugin(pluginId: string): ResolvedPlugin | undefined;
3103
+ /**
3104
+ * Get plugin state
3105
+ */
3106
+ getPluginState(pluginId: string): PluginState | undefined;
3107
+ /**
3108
+ * Get all registered plugins
3109
+ */
3110
+ getAllPlugins(): Array<{
3111
+ plugin: ResolvedPlugin;
3112
+ state: PluginState;
3113
+ }>;
3114
+ /**
3115
+ * Get all active plugins
3116
+ */
3117
+ getActivePlugins(): ResolvedPlugin[];
3118
+ /**
3119
+ * Check if a plugin exists
3120
+ */
3121
+ hasPlugin(pluginId: string): boolean;
3122
+ /**
3123
+ * Check if a plugin is active
3124
+ */
3125
+ isActive(pluginId: string): boolean;
3126
+ /**
3127
+ * Get all plugins that registered a handler for an exclusive hook.
3128
+ */
3129
+ getExclusiveHookProviders(hookName: string): Array<{
3130
+ pluginId: string;
3131
+ pluginName: string;
3132
+ }>;
3133
+ /**
3134
+ * Read the selected provider for an exclusive hook from the options table.
3135
+ */
3136
+ getExclusiveHookSelection(hookName: string): Promise<string | null>;
3137
+ /**
3138
+ * Set the selected provider for an exclusive hook in the options table.
3139
+ * Pass null to clear the selection.
3140
+ */
3141
+ setExclusiveHookSelection(hookName: string, pluginId: string | null): Promise<void>;
3142
+ /**
3143
+ * Resolution algorithm for exclusive hooks.
3144
+ *
3145
+ * Delegates to the shared resolveExclusiveHooks() function.
3146
+ * See hooks.ts for the full algorithm description.
3147
+ */
3148
+ resolveExclusiveHooks(preferredHints?: Map<string, string[]>): Promise<void>;
3149
+ /**
3150
+ * Get all exclusive hooks with their providers and current selections.
3151
+ * Used by the admin API.
3152
+ */
3153
+ getExclusiveHooksInfo(): Promise<Array<{
3154
+ hookName: string;
3155
+ providers: Array<{
3156
+ pluginId: string;
3157
+ }>;
3158
+ selectedPluginId: string | null;
3159
+ }>>;
3160
+ /**
3161
+ * Initialize or reinitialize the hook pipeline and route registry
3162
+ */
3163
+ private ensureInitialized;
3164
+ /**
3165
+ * Force reinitialization (useful after plugin state changes)
3166
+ */
3167
+ reinitialize(): void;
3168
+ /**
3169
+ * Delete all cron tasks for a plugin.
3170
+ * Used during uninstall.
3171
+ */
3172
+ private deleteCronTasks;
3173
+ }
3174
+ /**
3175
+ * Create a plugin manager
3176
+ */
3177
+ declare function createPluginManager(options: PluginManagerOptions): PluginManager;
3178
+ //#endregion
3179
+ //#region src/plugins/sandbox/noop.d.ts
3180
+ /**
3181
+ * Error thrown when attempting to use sandboxing on an unsupported platform.
3182
+ */
3183
+ declare class SandboxNotAvailableError extends Error {
3184
+ constructor();
3185
+ }
3186
+ /**
3187
+ * No-op sandbox runner for platforms without isolation support.
3188
+ *
3189
+ * - `isAvailable()` returns false
3190
+ * - `load()` throws SandboxNotAvailableError
3191
+ * - `terminateAll()` is a no-op
3192
+ *
3193
+ * This is the default runner when no platform adapter is configured.
3194
+ */
3195
+ declare class NoopSandboxRunner implements SandboxRunner {
3196
+ /**
3197
+ * Always returns false - sandboxing is not available.
3198
+ */
3199
+ isAvailable(): boolean;
3200
+ /**
3201
+ * Always throws - can't load sandboxed plugins without isolation.
3202
+ */
3203
+ load(_manifest: PluginManifest, _code: string): Promise<SandboxedPlugin>;
3204
+ /**
3205
+ * No-op - sandboxing not available, email callback is irrelevant.
3206
+ */
3207
+ setEmailSend(): void;
3208
+ /**
3209
+ * No-op - nothing to terminate.
3210
+ */
3211
+ terminateAll(): Promise<void>;
3212
+ }
3213
+ /**
3214
+ * Create a no-op sandbox runner.
3215
+ * This is used as the default when no platform adapter is configured.
3216
+ */
3217
+ declare function createNoopSandboxRunner(_options?: SandboxOptions): SandboxRunner;
3218
+ //#endregion
3219
+ //#region src/import/types.d.ts
3220
+ /** Author info from WordPress */
3221
+ interface WpAuthorInfo {
3222
+ id?: number;
3223
+ login?: string;
3224
+ email?: string;
3225
+ displayName?: string;
3226
+ postCount: number;
3227
+ }
3228
+ /** File-based input (WXR upload) */
3229
+ interface FileInput {
3230
+ type: "file";
3231
+ file: File;
3232
+ }
3233
+ /** URL-based input (REST API probe) */
3234
+ interface UrlInput {
3235
+ type: "url";
3236
+ url: string;
3237
+ /** Optional auth token for authenticated requests */
3238
+ token?: string;
3239
+ }
3240
+ /** OAuth-based input (WordPress.com) */
3241
+ interface OAuthInput {
3242
+ type: "oauth";
3243
+ url: string;
3244
+ accessToken: string;
3245
+ /** Site ID for WordPress.com */
3246
+ siteId?: string;
3247
+ }
3248
+ type SourceInput = FileInput | UrlInput | OAuthInput;
3249
+ /** Auth requirements for an import source */
3250
+ interface SourceAuth {
3251
+ type: "oauth" | "token" | "password" | "none";
3252
+ /** OAuth provider identifier */
3253
+ provider?: string;
3254
+ /** OAuth authorization URL */
3255
+ oauthUrl?: string;
3256
+ /** Human-readable instructions */
3257
+ instructions?: string;
3258
+ }
3259
+ /** What the source can provide */
3260
+ interface SourceCapabilities {
3261
+ /** Can fetch published content without auth */
3262
+ publicContent: boolean;
3263
+ /** Can fetch drafts/private (may need auth) */
3264
+ privateContent: boolean;
3265
+ /** Can fetch all custom post types */
3266
+ customPostTypes: boolean;
3267
+ /** Can fetch all meta fields */
3268
+ allMeta: boolean;
3269
+ /** Can stream media directly */
3270
+ mediaStream: boolean;
3271
+ }
3272
+ /** Suggested next action after probe */
3273
+ type SuggestedAction = {
3274
+ type: "proceed";
3275
+ } | {
3276
+ type: "oauth";
3277
+ url: string;
3278
+ provider: string;
3279
+ } | {
3280
+ type: "upload";
3281
+ instructions: string;
3282
+ } | {
3283
+ type: "install-plugin";
3284
+ instructions: string;
3285
+ };
3286
+ /** Detected i18n/multilingual plugin info */
3287
+ interface I18nDetection {
3288
+ /** Multilingual plugin name (e.g. "wpml", "polylang") */
3289
+ plugin: string;
3290
+ /** BCP 47 default locale */
3291
+ defaultLocale: string;
3292
+ /** All configured locales */
3293
+ locales: string[];
3294
+ }
3295
+ /** Result of probing a URL for a specific source */
3296
+ interface SourceProbeResult {
3297
+ /** Which source can handle this */
3298
+ sourceId: string;
3299
+ /** Confidence level */
3300
+ confidence: "definite" | "likely" | "possible";
3301
+ /** What we detected */
3302
+ detected: {
3303
+ platform: string;
3304
+ version?: string;
3305
+ siteTitle?: string;
3306
+ siteUrl?: string;
3307
+ };
3308
+ /** What capabilities are available */
3309
+ capabilities: SourceCapabilities;
3310
+ /** What auth is needed, if any */
3311
+ auth?: SourceAuth;
3312
+ /** Suggested next step */
3313
+ suggestedAction: SuggestedAction;
3314
+ /** Preview data if available (e.g., post counts from REST API) */
3315
+ preview?: {
3316
+ posts?: number;
3317
+ pages?: number;
3318
+ media?: number;
3319
+ };
3320
+ /** Detected multilingual plugin. Absent when none detected. */
3321
+ i18n?: I18nDetection;
3322
+ }
3323
+ /** Combined probe result from all sources */
3324
+ interface ProbeResult {
3325
+ url: string;
3326
+ isWordPress: boolean;
3327
+ /** Best matching source (highest confidence) */
3328
+ bestMatch: SourceProbeResult | null;
3329
+ /** All matching sources */
3330
+ allMatches: SourceProbeResult[];
3331
+ }
3332
+ /** Field definition for import */
3333
+ interface ImportFieldDef {
3334
+ slug: string;
3335
+ label: string;
3336
+ type: string;
3337
+ required: boolean;
3338
+ searchable?: boolean;
3339
+ }
3340
+ /** Field compatibility with existing schema */
3341
+ type FieldCompatibility = "compatible" | "type_mismatch" | "missing";
3342
+ /** Schema status for a collection */
3343
+ interface CollectionSchemaStatus {
3344
+ exists: boolean;
3345
+ fieldStatus: Record<string, {
3346
+ status: FieldCompatibility;
3347
+ existingType?: string;
3348
+ requiredType: string;
3349
+ }>;
3350
+ canImport: boolean;
3351
+ reason?: string;
3352
+ }
3353
+ /** Analysis of a single post type */
3354
+ interface PostTypeAnalysis {
3355
+ name: string;
3356
+ count: number;
3357
+ suggestedCollection: string;
3358
+ requiredFields: ImportFieldDef[];
3359
+ schemaStatus: CollectionSchemaStatus;
3360
+ }
3361
+ /** Attachment/media info */
3362
+ interface AttachmentInfo {
3363
+ id?: number;
3364
+ title?: string;
3365
+ url?: string;
3366
+ filename?: string;
3367
+ mimeType?: string;
3368
+ alt?: string;
3369
+ caption?: string;
3370
+ width?: number;
3371
+ height?: number;
3372
+ }
3373
+ /** Navigation menu analysis */
3374
+ interface NavMenuAnalysis {
3375
+ /** Menu name/slug */
3376
+ name: string;
3377
+ /** Menu display label */
3378
+ label: string;
3379
+ /** Number of items in this menu */
3380
+ itemCount: number;
3381
+ }
3382
+ /** Custom taxonomy analysis */
3383
+ interface TaxonomyAnalysis {
3384
+ /** Taxonomy slug (e.g., 'genre', 'portfolio_category') */
3385
+ slug: string;
3386
+ /** Number of terms in this taxonomy */
3387
+ termCount: number;
3388
+ /** Sample term names */
3389
+ sampleTerms: string[];
3390
+ }
3391
+ /** Reusable block analysis (wp_block post type) */
3392
+ interface ReusableBlockAnalysis {
3393
+ /** Original WP ID */
3394
+ id: number;
3395
+ /** Block title */
3396
+ title: string;
3397
+ /** Block slug */
3398
+ slug: string;
3399
+ }
3400
+ /** Normalized analysis result - same format for all sources */
3401
+ interface ImportAnalysis {
3402
+ /** Source that produced this analysis */
3403
+ sourceId: string;
3404
+ site: {
3405
+ title: string;
3406
+ url: string;
3407
+ };
3408
+ postTypes: PostTypeAnalysis[];
3409
+ attachments: {
3410
+ count: number;
3411
+ items: AttachmentInfo[];
3412
+ };
3413
+ categories: number;
3414
+ tags: number;
3415
+ authors: WpAuthorInfo[];
3416
+ /** Navigation menus found in the export */
3417
+ navMenus?: NavMenuAnalysis[];
3418
+ /** Custom taxonomies (beyond categories/tags) */
3419
+ customTaxonomies?: TaxonomyAnalysis[];
3420
+ /** Reusable blocks (wp_block post type) - will be imported as sections */
3421
+ reusableBlocks?: ReusableBlockAnalysis[];
3422
+ /** Source-specific custom fields analysis */
3423
+ customFields?: Array<{
3424
+ key: string;
3425
+ count: number;
3426
+ samples: string[];
3427
+ suggestedField: string;
3428
+ suggestedType: "string" | "number" | "boolean" | "date" | "json";
3429
+ isInternal: boolean;
3430
+ }>;
3431
+ /** Detected multilingual plugin. Absent when none detected. */
3432
+ i18n?: I18nDetection;
3433
+ }
3434
+ /** Normalized content item - produced by all sources */
3435
+ interface NormalizedItem {
3436
+ /** Original ID from source */
3437
+ sourceId: string | number;
3438
+ /** WordPress post type */
3439
+ postType: string;
3440
+ /** Content status */
3441
+ status: "publish" | "draft" | "pending" | "private" | "future";
3442
+ /** URL slug */
3443
+ slug: string;
3444
+ /** Title */
3445
+ title: string;
3446
+ /** Content as Portable Text (already converted) */
3447
+ content: PortableTextBlock[];
3448
+ /** Excerpt/summary */
3449
+ excerpt?: string;
3450
+ /** Publication date */
3451
+ date: Date;
3452
+ /** Last modified date */
3453
+ modified?: Date;
3454
+ /** Author identifier */
3455
+ author?: string;
3456
+ /** Category slugs */
3457
+ categories?: string[];
3458
+ /** Tag slugs */
3459
+ tags?: string[];
3460
+ /** Custom meta fields */
3461
+ meta?: Record<string, unknown>;
3462
+ /** Featured image URL */
3463
+ featuredImage?: string;
3464
+ /** Parent post ID (for hierarchical content like pages) */
3465
+ parentId?: string | number;
3466
+ /** Menu order for sorting */
3467
+ menuOrder?: number;
3468
+ /** Custom taxonomy assignments beyond categories/tags */
3469
+ customTaxonomies?: Record<string, string[]>;
3470
+ /** BCP 47 locale code. When omitted, defaults to defaultLocale. */
3471
+ locale?: string;
3472
+ /**
3473
+ * Source-side translation group ID (opaque string from the origin system).
3474
+ * Items sharing the same translationGroup are linked as translations.
3475
+ * Resolved to an EmDash translation_group ULID during execute.
3476
+ */
3477
+ translationGroup?: string;
3478
+ }
3479
+ /** Post type mapping configuration */
3480
+ interface PostTypeMapping {
3481
+ enabled: boolean;
3482
+ collection: string;
3483
+ }
3484
+ /** Import configuration */
3485
+ interface ImportConfig {
3486
+ postTypeMappings: Record<string, PostTypeMapping>;
3487
+ skipExisting?: boolean;
3488
+ }
3489
+ /** Options for fetching content */
3490
+ interface FetchOptions {
3491
+ /** Post types to fetch */
3492
+ postTypes: string[];
3493
+ /** Whether to include drafts */
3494
+ includeDrafts?: boolean;
3495
+ /** Limit number of items (for testing) */
3496
+ limit?: number;
3497
+ }
3498
+ /** Import result */
3499
+ interface ImportResult {
3500
+ success: boolean;
3501
+ imported: number;
3502
+ skipped: number;
3503
+ errors: Array<{
3504
+ title: string;
3505
+ error: string;
3506
+ }>;
3507
+ byCollection: Record<string, number>;
3508
+ }
3509
+ /**
3510
+ * An import source provides content from an external system.
3511
+ * All sources produce the same normalized analysis and content format.
3512
+ */
3513
+ interface ImportSource {
3514
+ /** Unique identifier */
3515
+ id: string;
3516
+ /** Display name */
3517
+ name: string;
3518
+ /** Description for UI */
3519
+ description: string;
3520
+ /** Icon identifier */
3521
+ icon: "upload" | "globe" | "wordpress" | "plug";
3522
+ /** Whether this source requires a file upload */
3523
+ requiresFile?: boolean;
3524
+ /** Whether this source can probe URLs */
3525
+ canProbe?: boolean;
3526
+ /**
3527
+ * Probe a URL to see if this source can handle it.
3528
+ * Returns null if not applicable.
3529
+ */
3530
+ probe?(url: string): Promise<SourceProbeResult | null>;
3531
+ /**
3532
+ * Analyze content from this source.
3533
+ * Returns normalized ImportAnalysis.
3534
+ */
3535
+ analyze(input: SourceInput, context: ImportContext): Promise<ImportAnalysis>;
3536
+ /**
3537
+ * Stream content items for import.
3538
+ * Yields normalized content items.
3539
+ */
3540
+ fetchContent(input: SourceInput, options: FetchOptions): AsyncGenerator<NormalizedItem>;
3541
+ /**
3542
+ * Fetch a media item's data.
3543
+ * Used for media import.
3544
+ */
3545
+ fetchMedia?(url: string, input: SourceInput): Promise<Blob>;
3546
+ }
3547
+ /** Context passed to import sources */
3548
+ interface ImportContext {
3549
+ /** Database connection for schema checks */
3550
+ db?: unknown;
3551
+ /** Function to check existing collections */
3552
+ getExistingCollections?: () => Promise<Map<string, {
3553
+ slug: string;
3554
+ fields: Map<string, {
3555
+ type: string;
3556
+ }>;
3557
+ }>>;
3558
+ }
3559
+ //#endregion
3560
+ //#region src/import/sections.d.ts
3561
+ /**
3562
+ * Result of sections import operation
3563
+ */
3564
+ interface SectionsImportResult {
3565
+ /** Number of sections created */
3566
+ sectionsCreated: number;
3567
+ /** Number of sections skipped (already exist) */
3568
+ sectionsSkipped: number;
3569
+ /** Errors encountered during import */
3570
+ errors: Array<{
3571
+ title: string;
3572
+ error: string;
3573
+ }>;
3574
+ }
3575
+ /**
3576
+ * Import reusable blocks (wp_block post type) from WXR as sections
3577
+ *
3578
+ * @param posts - All posts from WXR (will filter to wp_block)
3579
+ * @param db - Database connection
3580
+ * @returns Import result with counts
3581
+ */
3582
+ declare function importReusableBlocksAsSections(posts: WxrPost[], db: Kysely<Database>): Promise<SectionsImportResult>;
3583
+ //#endregion
3584
+ //#region src/import/registry.d.ts
3585
+ /**
3586
+ * Register an import source
3587
+ */
3588
+ declare function registerSource(source: ImportSource): void;
3589
+ /**
3590
+ * Get a source by ID
3591
+ */
3592
+ declare function getSource(id: string): ImportSource | undefined;
3593
+ /**
3594
+ * Get all registered sources
3595
+ */
3596
+ declare function getAllSources(): ImportSource[];
3597
+ /**
3598
+ * Get sources that can handle file uploads
3599
+ */
3600
+ declare function getFileSources(): ImportSource[];
3601
+ /**
3602
+ * Get sources that can probe URLs
3603
+ */
3604
+ declare function getUrlSources(): ImportSource[];
3605
+ /**
3606
+ * Probe a URL against all registered sources
3607
+ *
3608
+ * Returns probe results sorted by confidence (definite > likely > possible)
3609
+ */
3610
+ declare function probeUrl(url: string): Promise<ProbeResult>;
3611
+ /**
3612
+ * Clear all registered sources (useful for testing)
3613
+ */
3614
+ declare function clearSources(): void;
3615
+ //#endregion
3616
+ //#region src/import/sources/wxr.d.ts
3617
+ declare const wxrSource: ImportSource;
3618
+ //#endregion
3619
+ //#region src/import/sources/wordpress-rest.d.ts
3620
+ declare const wordpressRestSource: ImportSource;
3621
+ //#endregion
3622
+ //#region src/preview/tokens.d.ts
3623
+ /**
3624
+ * Preview token generation and verification
3625
+ *
3626
+ * Tokens are compact, URL-safe, and HMAC-signed.
3627
+ * Format: base64url(JSON payload).base64url(HMAC signature)
3628
+ *
3629
+ * Payload: { cid: contentId, exp: expiryTimestamp, iat: issuedAt }
3630
+ */
3631
+ /**
3632
+ * Preview token payload
3633
+ */
3634
+ interface PreviewTokenPayload {
3635
+ /** Content ID in format "collection:id" (e.g., "posts:abc123") */
3636
+ cid: string;
3637
+ /** Expiry timestamp (seconds since epoch) */
3638
+ exp: number;
3639
+ /** Issued at timestamp (seconds since epoch) */
3640
+ iat: number;
3641
+ }
3642
+ /**
3643
+ * Options for generating a preview token
3644
+ */
3645
+ interface GeneratePreviewTokenOptions {
3646
+ /** Content ID in format "collection:id" */
3647
+ contentId: string;
3648
+ /** How long the token is valid. Accepts "1h", "30m", "1d", or seconds as number. Default: "1h" */
3649
+ expiresIn?: string | number;
3650
+ /** Secret key for signing. Should be from environment variable. */
3651
+ secret: string;
3652
+ }
3653
+ /**
3654
+ * Generate a preview token for content
3655
+ *
3656
+ * @example
3657
+ * ```ts
3658
+ * const token = await generatePreviewToken({
3659
+ * contentId: "posts:abc123",
3660
+ * expiresIn: "1h",
3661
+ * secret: process.env.PREVIEW_SECRET!,
3662
+ * });
3663
+ * ```
3664
+ */
3665
+ declare function generatePreviewToken(options: GeneratePreviewTokenOptions): Promise<string>;
3666
+ /**
3667
+ * Result of verifying a preview token
3668
+ */
3669
+ type VerifyPreviewTokenResult = {
3670
+ valid: true;
3671
+ payload: PreviewTokenPayload;
3672
+ } | {
3673
+ valid: false;
3674
+ error: "invalid" | "expired" | "malformed" | "none";
3675
+ };
3676
+ /**
3677
+ * Options for verifyPreviewToken
3678
+ */
3679
+ type VerifyPreviewTokenOptions = {
3680
+ /** Secret key for verifying tokens */secret: string;
3681
+ } & ({
3682
+ url: URL;
3683
+ } | {
3684
+ /** Preview token string (can be null) */token: string | null | undefined;
3685
+ });
3686
+ /**
3687
+ * Verify a preview token and return the payload
3688
+ *
3689
+ * @example
3690
+ * ```ts
3691
+ * // With URL (extracts _preview query param)
3692
+ * const result = await verifyPreviewToken({
3693
+ * url: Astro.url,
3694
+ * secret: import.meta.env.PREVIEW_SECRET,
3695
+ * });
3696
+ *
3697
+ * // With token directly
3698
+ * const result = await verifyPreviewToken({
3699
+ * token: someToken,
3700
+ * secret: import.meta.env.PREVIEW_SECRET,
3701
+ * });
3702
+ *
3703
+ * if (result.valid) {
3704
+ * console.log(result.payload.cid); // "posts:abc123"
3705
+ * }
3706
+ * ```
3707
+ */
3708
+ declare function verifyPreviewToken(options: VerifyPreviewTokenOptions): Promise<VerifyPreviewTokenResult>;
3709
+ /**
3710
+ * Parse a content ID into collection and id
3711
+ */
3712
+ declare function parseContentId(contentId: string): {
3713
+ collection: string;
3714
+ id: string;
3715
+ };
3716
+ //#endregion
3717
+ //#region src/preview/urls.d.ts
3718
+ /**
3719
+ * Preview URL generation
3720
+ *
3721
+ * Creates preview URLs that include a signed token for accessing draft content.
3722
+ */
3723
+ /**
3724
+ * Options for generating a preview URL
3725
+ */
3726
+ interface GetPreviewUrlOptions {
3727
+ /** Collection slug (e.g., "posts") */
3728
+ collection: string;
3729
+ /** Content ID or slug */
3730
+ id: string;
3731
+ /** Secret key for signing the token */
3732
+ secret: string;
3733
+ /** How long the preview URL is valid. Default: "1h" */
3734
+ expiresIn?: string | number;
3735
+ /** Base URL of the site. If not provided, returns a relative URL. */
3736
+ baseUrl?: string;
3737
+ /** Custom path pattern. Use {collection} and {id} as placeholders. Default: "/{collection}/{id}" */
3738
+ pathPattern?: string;
3739
+ }
3740
+ /**
3741
+ * Generate a preview URL for content
3742
+ *
3743
+ * The URL includes a `_preview` query parameter with a signed token.
3744
+ *
3745
+ * @example
3746
+ * ```ts
3747
+ * const url = await getPreviewUrl({
3748
+ * collection: "posts",
3749
+ * id: "hello-world",
3750
+ * secret: process.env.PREVIEW_SECRET!,
3751
+ * });
3752
+ * // Returns: /posts/hello-world?_preview=eyJj...
3753
+ *
3754
+ * // With base URL:
3755
+ * const fullUrl = await getPreviewUrl({
3756
+ * collection: "posts",
3757
+ * id: "hello-world",
3758
+ * secret: process.env.PREVIEW_SECRET!,
3759
+ * baseUrl: "https://example.com",
3760
+ * });
3761
+ * // Returns: https://example.com/posts/hello-world?_preview=eyJj...
3762
+ *
3763
+ * // Custom path pattern:
3764
+ * const customUrl = await getPreviewUrl({
3765
+ * collection: "posts",
3766
+ * id: "hello-world",
3767
+ * secret: process.env.PREVIEW_SECRET!,
3768
+ * pathPattern: "/blog/{id}",
3769
+ * });
3770
+ * // Returns: /blog/hello-world?_preview=eyJj...
3771
+ * ```
3772
+ */
3773
+ declare function getPreviewUrl(options: GetPreviewUrlOptions): Promise<string>;
3774
+ /**
3775
+ * Build a preview URL from a token (when you already have the token)
3776
+ *
3777
+ * @example
3778
+ * ```ts
3779
+ * const url = buildPreviewUrl({
3780
+ * path: "/posts/hello-world",
3781
+ * token: existingToken,
3782
+ * });
3783
+ * ```
3784
+ */
3785
+ declare function buildPreviewUrl(options: {
3786
+ path: string;
3787
+ token: string;
3788
+ baseUrl?: string;
3789
+ }): string;
3790
+ //#endregion
3791
+ //#region src/preview/helpers.d.ts
3792
+ /**
3793
+ * Preview helpers for Astro pages
3794
+ */
3795
+ /**
3796
+ * Check if a request is a preview request
3797
+ *
3798
+ * @example
3799
+ * ```ts
3800
+ * const isPreview = isPreviewRequest(Astro.url);
3801
+ * ```
3802
+ */
3803
+ declare function isPreviewRequest(url: URL): boolean;
3804
+ /**
3805
+ * Get the preview token from a URL
3806
+ *
3807
+ * @example
3808
+ * ```ts
3809
+ * const token = getPreviewToken(Astro.url);
3810
+ * ```
3811
+ */
3812
+ declare function getPreviewToken(url: URL): string | null;
3813
+ //#endregion
3814
+ //#region src/settings/index.d.ts
3815
+ /**
3816
+ * Get a single site setting by key
3817
+ *
3818
+ * Returns `undefined` if the setting has not been configured.
3819
+ * For media settings (logo, favicon), the URL is resolved automatically.
3820
+ *
3821
+ * @param key - The setting key (e.g., "title", "logo", "social")
3822
+ * @returns The setting value, or undefined if not set
3823
+ *
3824
+ * @example
3825
+ * ```ts
3826
+ * import { getSiteSetting } from "emdash";
3827
+ *
3828
+ * const title = await getSiteSetting("title");
3829
+ * const logo = await getSiteSetting("logo");
3830
+ * console.log(logo?.url); // Resolved URL
3831
+ * ```
3832
+ */
3833
+ declare function getSiteSetting<K extends SiteSettingKey>(key: K): Promise<SiteSettings[K] | undefined>;
3834
+ /**
3835
+ * Get all site settings
3836
+ *
3837
+ * Returns all configured settings. Unset values are undefined.
3838
+ * Media references (logo/favicon) are resolved to include URLs.
3839
+ *
3840
+ * @example
3841
+ * ```ts
3842
+ * import { getSiteSettings } from "emdash";
3843
+ *
3844
+ * const settings = await getSiteSettings();
3845
+ * console.log(settings.title); // "My Site"
3846
+ * console.log(settings.logo?.url); // "/_emdash/api/media/file/abc123"
3847
+ * ```
3848
+ */
3849
+ declare function getSiteSettings(): Promise<Partial<SiteSettings>>;
3850
+ /**
3851
+ * Set site settings (internal function used by admin API)
3852
+ *
3853
+ * Merges provided settings with existing ones. Only provided fields are updated.
3854
+ * Media references should include just the mediaId; URLs are resolved on read.
3855
+ *
3856
+ * @param settings - Partial settings object with values to update
3857
+ * @param db - Kysely database instance
3858
+ * @returns Promise that resolves when settings are saved
3859
+ *
3860
+ * @internal
3861
+ *
3862
+ * @example
3863
+ * ```ts
3864
+ * // Update multiple settings at once
3865
+ * await setSiteSettings({
3866
+ * title: "My Site",
3867
+ * tagline: "Welcome",
3868
+ * logo: { mediaId: "med_123", alt: "Logo" }
3869
+ * }, db);
3870
+ * ```
3871
+ */
3872
+ declare function setSiteSettings(settings: Partial<SiteSettings>, db: Kysely<Database>): Promise<void>;
3873
+ //#endregion
3874
+ //#region src/comments/query.d.ts
3875
+ interface GetCommentsOptions {
3876
+ collection: string;
3877
+ contentId: string;
3878
+ threaded?: boolean;
3879
+ }
3880
+ interface GetCommentsResult {
3881
+ items: PublicComment[];
3882
+ total: number;
3883
+ }
3884
+ /**
3885
+ * Get approved comments for a content item.
3886
+ *
3887
+ * @example
3888
+ * ```ts
3889
+ * import { getComments } from "emdash";
3890
+ *
3891
+ * const { items, total } = await getComments({
3892
+ * collection: "posts",
3893
+ * contentId: post.id,
3894
+ * threaded: true,
3895
+ * });
3896
+ * ```
3897
+ */
3898
+ declare function getComments(options: GetCommentsOptions): Promise<GetCommentsResult>;
3899
+ /**
3900
+ * Get the count of approved comments for a content item.
3901
+ *
3902
+ * @example
3903
+ * ```ts
3904
+ * import { getCommentCount } from "emdash";
3905
+ *
3906
+ * const count = await getCommentCount("posts", post.id);
3907
+ * ```
3908
+ */
3909
+ declare function getCommentCount(collection: string, contentId: string): Promise<number>;
3910
+ //#endregion
3911
+ //#region src/menus/types.d.ts
3912
+ /**
3913
+ * Menu item types
3914
+ */
3915
+ type MenuItemType = string;
3916
+ /**
3917
+ * Menu item as returned to templates (with resolved URL)
3918
+ */
3919
+ interface MenuItem {
3920
+ id: string;
3921
+ label: string;
3922
+ url: string;
3923
+ target?: string;
3924
+ titleAttr?: string;
3925
+ cssClasses?: string;
3926
+ children: MenuItem[];
3927
+ }
3928
+ /**
3929
+ * Menu as returned to templates
3930
+ */
3931
+ interface Menu {
3932
+ id: string;
3933
+ name: string;
3934
+ label: string;
3935
+ items: MenuItem[];
3936
+ }
3937
+ /**
3938
+ * Input for creating a menu item
3939
+ */
3940
+ interface CreateMenuItemInput {
3941
+ type: MenuItemType;
3942
+ label: string;
3943
+ referenceCollection?: string;
3944
+ referenceId?: string;
3945
+ customUrl?: string;
3946
+ target?: string;
3947
+ titleAttr?: string;
3948
+ cssClasses?: string;
3949
+ parentId?: string;
3950
+ sortOrder?: number;
3951
+ }
3952
+ /**
3953
+ * Input for updating a menu item
3954
+ */
3955
+ interface UpdateMenuItemInput {
3956
+ label?: string;
3957
+ customUrl?: string;
3958
+ target?: string;
3959
+ titleAttr?: string;
3960
+ cssClasses?: string;
3961
+ parentId?: string | null;
3962
+ sortOrder?: number;
3963
+ }
3964
+ /**
3965
+ * Input for creating a menu
3966
+ */
3967
+ interface CreateMenuInput {
3968
+ name: string;
3969
+ label: string;
3970
+ }
3971
+ /**
3972
+ * Input for updating a menu
3973
+ */
3974
+ interface UpdateMenuInput {
3975
+ label?: string;
3976
+ }
3977
+ /**
3978
+ * Input for reordering menu items
3979
+ */
3980
+ interface ReorderMenuItemsInput {
3981
+ items: Array<{
3982
+ id: string;
3983
+ parentId: string | null;
3984
+ sortOrder: number;
3985
+ }>;
3986
+ }
3987
+ //#endregion
3988
+ //#region src/menus/index.d.ts
3989
+ /**
3990
+ * Get menu by name with resolved URLs
3991
+ *
3992
+ * @example
3993
+ * ```ts
3994
+ * import { getMenu } from "emdash";
3995
+ *
3996
+ * const menu = await getMenu("primary");
3997
+ * if (menu) {
3998
+ * console.log(menu.items); // Array of MenuItem with resolved URLs
3999
+ * }
4000
+ * ```
4001
+ */
4002
+ declare function getMenu(name: string): Promise<Menu | null>;
4003
+ /**
4004
+ * Get all menus (without items - for admin list)
4005
+ *
4006
+ * @example
4007
+ * ```ts
4008
+ * import { getMenus } from "emdash";
4009
+ *
4010
+ * const menus = await getMenus();
4011
+ * console.log(menus); // [{ id, name, label }]
4012
+ * ```
4013
+ */
4014
+ declare function getMenus(): Promise<Array<{
4015
+ id: string;
4016
+ name: string;
4017
+ label: string;
4018
+ }>>;
4019
+ //#endregion
4020
+ //#region src/bylines/index.d.ts
4021
+ /**
4022
+ * Get a byline by ID.
4023
+ *
4024
+ * @example
4025
+ * ```ts
4026
+ * import { getByline } from "emdash";
4027
+ *
4028
+ * const byline = await getByline("01HXYZ...");
4029
+ * if (byline) {
4030
+ * console.log(byline.displayName);
4031
+ * }
4032
+ * ```
4033
+ */
4034
+ declare function getByline(id: string): Promise<BylineSummary | null>;
4035
+ /**
4036
+ * Get a byline by slug.
4037
+ *
4038
+ * @example
4039
+ * ```ts
4040
+ * import { getBylineBySlug } from "emdash";
4041
+ *
4042
+ * const byline = await getBylineBySlug("jane-doe");
4043
+ * if (byline) {
4044
+ * console.log(byline.displayName); // "Jane Doe"
4045
+ * }
4046
+ * ```
4047
+ */
4048
+ declare function getBylineBySlug(slug: string): Promise<BylineSummary | null>;
4049
+ //#endregion
4050
+ //#region src/taxonomies/types.d.ts
4051
+ /**
4052
+ * Taxonomy types for EmDash CMS
4053
+ */
4054
+ /**
4055
+ * Taxonomy definition - describes a taxonomy like "category" or "tag"
4056
+ */
4057
+ interface TaxonomyDef {
4058
+ id: string;
4059
+ name: string;
4060
+ label: string;
4061
+ labelSingular?: string;
4062
+ hierarchical: boolean;
4063
+ collections: string[];
4064
+ }
4065
+ /**
4066
+ * Taxonomy term - a specific term within a taxonomy (e.g., "News" in "category")
4067
+ */
4068
+ interface TaxonomyTerm {
4069
+ id: string;
4070
+ name: string;
4071
+ slug: string;
4072
+ label: string;
4073
+ parentId?: string;
4074
+ description?: string;
4075
+ children: TaxonomyTerm[];
4076
+ count?: number;
4077
+ }
4078
+ /**
4079
+ * Flat version for DB row
4080
+ */
4081
+ interface TaxonomyTermRow {
4082
+ id: string;
4083
+ name: string;
4084
+ slug: string;
4085
+ label: string;
4086
+ parent_id: string | null;
4087
+ data: string | null;
4088
+ }
4089
+ /**
4090
+ * Input for creating a term
4091
+ */
4092
+ interface CreateTermInput {
4093
+ slug: string;
4094
+ label: string;
4095
+ parentId?: string;
4096
+ description?: string;
4097
+ }
4098
+ /**
4099
+ * Input for updating a term
4100
+ */
4101
+ interface UpdateTermInput {
4102
+ slug?: string;
4103
+ label?: string;
4104
+ parentId?: string | null;
4105
+ description?: string;
4106
+ }
4107
+ //#endregion
4108
+ //#region src/taxonomies/index.d.ts
4109
+ /**
4110
+ * Get all taxonomy definitions
4111
+ */
4112
+ declare function getTaxonomyDefs(): Promise<TaxonomyDef[]>;
4113
+ /**
4114
+ * Get a single taxonomy definition by name
4115
+ */
4116
+ declare function getTaxonomyDef(name: string): Promise<TaxonomyDef | null>;
4117
+ /**
4118
+ * Get all terms for a taxonomy (as tree for hierarchical, flat for tags)
4119
+ */
4120
+ declare function getTaxonomyTerms(taxonomyName: string): Promise<TaxonomyTerm[]>;
4121
+ /**
4122
+ * Get a single term by taxonomy and slug
4123
+ */
4124
+ declare function getTerm(taxonomyName: string, slug: string): Promise<TaxonomyTerm | null>;
4125
+ /**
4126
+ * Get terms assigned to an entry
4127
+ */
4128
+ declare function getEntryTerms(collection: string, entryId: string, taxonomyName?: string): Promise<TaxonomyTerm[]>;
4129
+ /**
4130
+ * Get terms for multiple entries in a single query (batched API)
4131
+ *
4132
+ * This is more efficient than calling getEntryTerms for each entry
4133
+ * when you need terms for a list of entries.
4134
+ *
4135
+ * @param collection - The collection type (e.g., "posts")
4136
+ * @param entryIds - Array of entry IDs
4137
+ * @param taxonomyName - The taxonomy name (e.g., "categories")
4138
+ * @returns Map from entry ID to array of terms
4139
+ */
4140
+ declare function getTermsForEntries(collection: string, entryIds: string[], taxonomyName: string): Promise<Map<string, TaxonomyTerm[]>>;
4141
+ /**
4142
+ * Get entries by term (wraps getEmDashCollection)
4143
+ */
4144
+ declare function getEntriesByTerm(collection: string, taxonomyName: string, termSlug: string): Promise<Array<{
4145
+ id: string;
4146
+ data: Record<string, unknown>;
4147
+ }>>;
4148
+ //#endregion
4149
+ //#region src/widgets/types.d.ts
4150
+ type WidgetType = "content" | "menu" | "component";
4151
+ interface Widget {
4152
+ id: string;
4153
+ type: WidgetType;
4154
+ title?: string;
4155
+ content?: PortableTextBlock$2[];
4156
+ menuName?: string;
4157
+ componentId?: string;
4158
+ componentProps?: Record<string, unknown>;
4159
+ }
4160
+ interface WidgetArea {
4161
+ id: string;
4162
+ name: string;
4163
+ label: string;
4164
+ description?: string;
4165
+ widgets: Widget[];
4166
+ }
4167
+ interface WidgetComponentDef {
4168
+ id: string;
4169
+ label: string;
4170
+ description?: string;
4171
+ props: Record<string, PropDef>;
4172
+ }
4173
+ interface PropDef {
4174
+ type: "string" | "number" | "boolean" | "select";
4175
+ label: string;
4176
+ default?: unknown;
4177
+ options?: Array<{
4178
+ value: string;
4179
+ label: string;
4180
+ }>;
4181
+ }
4182
+ interface CreateWidgetAreaInput {
4183
+ name: string;
4184
+ label: string;
4185
+ description?: string;
4186
+ }
4187
+ interface CreateWidgetInput {
4188
+ type: WidgetType;
4189
+ title?: string;
4190
+ content?: PortableTextBlock$2[];
4191
+ menuName?: string;
4192
+ componentId?: string;
4193
+ componentProps?: Record<string, unknown>;
4194
+ }
4195
+ interface UpdateWidgetInput extends Partial<CreateWidgetInput> {}
4196
+ interface ReorderWidgetsInput {
4197
+ widgetIds: string[];
4198
+ }
4199
+ //#endregion
4200
+ //#region src/widgets/index.d.ts
4201
+ /**
4202
+ * Get a widget area by name, with all its widgets
4203
+ */
4204
+ declare function getWidgetArea(name: string): Promise<WidgetArea | null>;
4205
+ /**
4206
+ * Get all widget areas with their widgets
4207
+ */
4208
+ declare function getWidgetAreas(): Promise<WidgetArea[]>;
4209
+ /**
4210
+ * Get available widget components (for admin UI)
4211
+ */
4212
+ declare function getWidgetComponents(): WidgetComponentDef[];
4213
+ //#endregion
4214
+ //#region src/search/types.d.ts
4215
+ /**
4216
+ * Search Types
4217
+ *
4218
+ * Type definitions for the EmDash search system.
4219
+ */
4220
+ /**
4221
+ * Search configuration for a collection
4222
+ */
4223
+ interface SearchConfig {
4224
+ /** Whether search is enabled for this collection */
4225
+ enabled: boolean;
4226
+ /** Field weights for ranking (higher = more important) */
4227
+ weights?: Record<string, number>;
4228
+ }
4229
+ /**
4230
+ * Options for search queries
4231
+ */
4232
+ interface SearchOptions {
4233
+ /** Collections to search (defaults to all searchable collections) */
4234
+ collections?: string[];
4235
+ /** Filter by content status (defaults to 'published') */
4236
+ status?: string;
4237
+ /** Filter by locale (omit to search all locales) */
4238
+ locale?: string;
4239
+ /** Maximum results to return (defaults to 20) */
4240
+ limit?: number;
4241
+ /** Pagination cursor */
4242
+ cursor?: string;
4243
+ }
4244
+ /**
4245
+ * Options for collection-specific search
4246
+ */
4247
+ interface CollectionSearchOptions {
4248
+ /** Filter by content status (defaults to 'published') */
4249
+ status?: string;
4250
+ /** Filter by locale (omit to search all locales) */
4251
+ locale?: string;
4252
+ /** Maximum results to return (defaults to 20) */
4253
+ limit?: number;
4254
+ /** Pagination cursor */
4255
+ cursor?: string;
4256
+ }
4257
+ /**
4258
+ * A single search result
4259
+ */
4260
+ interface SearchResult {
4261
+ /** Collection the result belongs to */
4262
+ collection: string;
4263
+ /** Entry ID */
4264
+ id: string;
4265
+ /** Entry slug */
4266
+ slug: string | null;
4267
+ /** Content locale */
4268
+ locale: string;
4269
+ /** Entry title (if available) */
4270
+ title?: string;
4271
+ /** Highlighted snippet showing match context */
4272
+ snippet?: string;
4273
+ /** Relevance score (higher = more relevant) */
4274
+ score: number;
4275
+ }
4276
+ /**
4277
+ * Response from a search query
4278
+ */
4279
+ interface SearchResponse {
4280
+ /** Search results */
4281
+ items: SearchResult[];
4282
+ /** Cursor for next page of results */
4283
+ nextCursor?: string;
4284
+ }
4285
+ /**
4286
+ * Options for suggestion/autocomplete queries
4287
+ */
4288
+ interface SuggestOptions {
4289
+ /** Collections to search (defaults to all searchable collections) */
4290
+ collections?: string[];
4291
+ /** Filter by locale (omit to search all locales) */
4292
+ locale?: string;
4293
+ /** Maximum suggestions to return (defaults to 5) */
4294
+ limit?: number;
4295
+ }
4296
+ /**
4297
+ * A single suggestion result
4298
+ */
4299
+ interface Suggestion {
4300
+ /** Collection the suggestion belongs to */
4301
+ collection: string;
4302
+ /** Entry ID */
4303
+ id: string;
4304
+ /** Entry title */
4305
+ title: string;
4306
+ }
4307
+ /**
4308
+ * Search index statistics
4309
+ */
4310
+ interface SearchStats {
4311
+ collections: Record<string, {
4312
+ /** Number of indexed entries */indexed: number; /** When the index was last rebuilt */
4313
+ lastRebuilt?: string;
4314
+ }>;
4315
+ }
4316
+ //#endregion
4317
+ //#region src/search/fts-manager.d.ts
4318
+ /**
4319
+ * FTS5 Manager
4320
+ *
4321
+ * Handles creation, deletion, and management of FTS5 virtual tables
4322
+ * for full-text search on content collections.
4323
+ */
4324
+ declare class FTSManager {
4325
+ private db;
4326
+ constructor(db: Kysely<Database>);
4327
+ /**
4328
+ * Validate a collection slug and its searchable field names.
4329
+ * Must be called before any raw SQL interpolation.
4330
+ */
4331
+ private validateInputs;
4332
+ /**
4333
+ * Get the FTS table name for a collection
4334
+ * Uses _emdash_ prefix to clearly mark as internal/system table
4335
+ */
4336
+ getFtsTableName(collectionSlug: string): string;
4337
+ /**
4338
+ * Get the content table name for a collection
4339
+ */
4340
+ getContentTableName(collectionSlug: string): string;
4341
+ /**
4342
+ * Check if an FTS table exists for a collection
4343
+ */
4344
+ ftsTableExists(collectionSlug: string): Promise<boolean>;
4345
+ /**
4346
+ * Create an FTS5 virtual table for a collection.
4347
+ * FTS5 is SQLite-only; on other dialects this is a no-op.
4348
+ *
4349
+ * @param collectionSlug - The collection slug
4350
+ * @param searchableFields - Array of field names to index
4351
+ * @param weights - Optional field weights for ranking
4352
+ */
4353
+ createFtsTable(collectionSlug: string, searchableFields: string[], _weights?: Record<string, number>): Promise<void>;
4354
+ /**
4355
+ * Create triggers to keep FTS table in sync with content table
4356
+ */
4357
+ private createTriggers;
4358
+ /**
4359
+ * Drop triggers for a collection
4360
+ */
4361
+ private dropTriggers;
4362
+ /**
4363
+ * Drop the FTS table and triggers for a collection
4364
+ */
4365
+ dropFtsTable(collectionSlug: string): Promise<void>;
4366
+ /**
4367
+ * Rebuild the FTS index for a collection
4368
+ *
4369
+ * This is useful after bulk imports or if the index gets out of sync.
4370
+ */
4371
+ rebuildIndex(collectionSlug: string, searchableFields: string[], weights?: Record<string, number>): Promise<void>;
4372
+ /**
4373
+ * Populate the FTS table from existing content
4374
+ */
4375
+ populateFromContent(collectionSlug: string, searchableFields: string[]): Promise<void>;
4376
+ /**
4377
+ * Get the search configuration for a collection
4378
+ */
4379
+ getSearchConfig(collectionSlug: string): Promise<SearchConfig | null>;
4380
+ /**
4381
+ * Update the search configuration for a collection
4382
+ */
4383
+ setSearchConfig(collectionSlug: string, config: SearchConfig): Promise<void>;
4384
+ /**
4385
+ * Get searchable fields for a collection
4386
+ */
4387
+ getSearchableFields(collectionSlug: string): Promise<string[]>;
4388
+ /**
4389
+ * Enable search for a collection
4390
+ *
4391
+ * Creates the FTS table and triggers, and populates from existing content.
4392
+ */
4393
+ enableSearch(collectionSlug: string, options?: {
4394
+ weights?: Record<string, number>;
4395
+ }): Promise<void>;
4396
+ /**
4397
+ * Disable search for a collection
4398
+ *
4399
+ * Drops the FTS table and triggers.
4400
+ */
4401
+ disableSearch(collectionSlug: string): Promise<void>;
4402
+ /**
4403
+ * Get index statistics for a collection
4404
+ */
4405
+ getIndexStats(collectionSlug: string): Promise<{
4406
+ indexed: number;
4407
+ lastRebuilt?: string;
4408
+ } | null>;
4409
+ /**
4410
+ * Verify FTS index integrity and rebuild if corrupted.
4411
+ *
4412
+ * Checks for two corruption indicators:
4413
+ * 1. Row count mismatch between content table and FTS table
4414
+ * 2. FTS5 integrity-check failure (catches shadow table inconsistencies)
4415
+ *
4416
+ * Returns true if the index was rebuilt, false if it was healthy.
4417
+ */
4418
+ verifyAndRepairIndex(collectionSlug: string): Promise<boolean>;
4419
+ /**
4420
+ * Verify and repair FTS indexes for all search-enabled collections.
4421
+ *
4422
+ * Intended to run at startup to auto-heal any corruption from
4423
+ * previous process crashes.
4424
+ */
4425
+ verifyAndRepairAll(): Promise<number>;
4426
+ }
4427
+ //#endregion
4428
+ //#region src/search/query.d.ts
4429
+ /**
4430
+ * Search across multiple collections
4431
+ *
4432
+ * Public API that auto-injects the database.
4433
+ *
4434
+ * @param query - Search query (FTS5 syntax supported)
4435
+ * @param options - Search options
4436
+ * @returns Search results with pagination
4437
+ *
4438
+ * @example
4439
+ * ```typescript
4440
+ * import { search } from "emdash";
4441
+ *
4442
+ * const results = await search("hello world", {
4443
+ * collections: ["posts", "pages"],
4444
+ * limit: 20
4445
+ * });
4446
+ * ```
4447
+ */
4448
+ declare function search(query: string, options?: SearchOptions): Promise<SearchResponse>;
4449
+ /**
4450
+ * Search across multiple collections (with explicit db)
4451
+ *
4452
+ * @internal Use `search()` in templates. This variant is for admin routes
4453
+ * that already have a database handle.
4454
+ *
4455
+ * @param db - Kysely database instance
4456
+ * @param query - Search query (FTS5 syntax supported)
4457
+ * @param options - Search options
4458
+ * @returns Search results with pagination
4459
+ */
4460
+ declare function searchWithDb(db: Kysely<Database>, query: string, options?: SearchOptions): Promise<SearchResponse>;
4461
+ /**
4462
+ * Search within a single collection
4463
+ *
4464
+ * @param db - Kysely database instance
4465
+ * @param collection - Collection slug
4466
+ * @param query - Search query (FTS5 syntax supported)
4467
+ * @param options - Search options
4468
+ * @returns Search results with pagination
4469
+ *
4470
+ * @example
4471
+ * ```typescript
4472
+ * const results = await searchCollection(db, "posts", "hello world", {
4473
+ * limit: 10
4474
+ * });
4475
+ * ```
4476
+ */
4477
+ declare function searchCollection(db: Kysely<Database>, collection: string, query: string, options?: CollectionSearchOptions): Promise<SearchResponse>;
4478
+ /**
4479
+ * Get search suggestions for autocomplete
4480
+ *
4481
+ * @param db - Kysely database instance
4482
+ * @param query - Partial search query
4483
+ * @param options - Suggestion options
4484
+ * @returns Array of suggestions
4485
+ */
4486
+ declare function getSuggestions(db: Kysely<Database>, query: string, options?: SuggestOptions): Promise<Suggestion[]>;
4487
+ /**
4488
+ * Get search statistics for all collections
4489
+ */
4490
+ declare function getSearchStats(db: Kysely<Database>): Promise<SearchStats>;
4491
+ //#endregion
4492
+ //#region src/search/text-extraction.d.ts
4493
+ /**
4494
+ * Extract plain text from Portable Text blocks
4495
+ *
4496
+ * Uses @portabletext/toolkit's toPlainText for standard blocks,
4497
+ * plus extracts text from custom block types (code, images with alt/caption).
4498
+ *
4499
+ * @param blocks - Array of Portable Text blocks (or a JSON string)
4500
+ * @returns Plain text content
4501
+ *
4502
+ * @example
4503
+ * ```typescript
4504
+ * const text = extractPlainText([
4505
+ * {
4506
+ * _type: "block",
4507
+ * _key: "abc",
4508
+ * children: [{ _type: "span", _key: "s1", text: "Hello World" }]
4509
+ * }
4510
+ * ]);
4511
+ * // Returns: "Hello World"
4512
+ * ```
4513
+ */
4514
+ declare function extractPlainText(blocks: PortableTextBlock$1[] | string | null | undefined): string;
4515
+ /**
4516
+ * Extract searchable text from a content entry
4517
+ *
4518
+ * Extracts text from specified fields, handling both plain text and Portable Text.
4519
+ *
4520
+ * @param entry - Content entry data
4521
+ * @param fields - Field names to extract text from
4522
+ * @returns Object mapping field names to extracted text
4523
+ */
4524
+ declare function extractSearchableFields(entry: Record<string, unknown>, fields: string[]): Record<string, string>;
4525
+ //#endregion
4526
+ export { GetCommentsOptions as $, CMSAnnotation as $n, handleContentCreate as $r, PluginManager as $t, getEntryTerms as A, MediaItem as Ai, EntryFilter as An, GetSectionsOptions as Ar, FetchOptions as At, UpdateTermInput as B, ContentEntry as Bn, handleMediaDelete as Br, OAuthInput as Bt, ReorderWidgetsInput as C, image as Ci, WxrPost as Cn, SandboxRunner as Cr, getSource as Ct, WidgetComponentDef as D, ImageValue as Di, parseWxrString as Dn, getSection as Dr, importReusableBlocksAsSections as Dt, WidgetArea as E, FileValue as Ei, parseWxr as En, SerializedRequest as Er, registerSource as Et, getTermsForEntries as F, getI18nConfig as Fn, SchemaError as Fr, ImportContext as Ft, CreateMenuInput as G, ResolvePathResult as Gn, RevisionResponse as Gr, SourceCapabilities as Gt, getBylineBySlug as H, EmDashCollections as Hn, handleMediaList as Hr, PostTypeMapping as Ht, CreateTermInput as I, isI18nEnabled as In, SchemaRegistry as Ir, ImportFieldDef as It, MenuItem as J, getEditMeta as Jn, handleRevisionRestore as Jr, SuggestedAction as Jt, CreateMenuItemInput as K, TranslationSummary as Kn, handleRevisionGet as Kr, SourceInput as Kt, TaxonomyDef as L, CacheHint as Ln, MediaListResponse as Lr, ImportResult as Lt, getTaxonomyDefs as M, ContentRepository as Mi, getDb as Mn, SectionSource as Mr, FileInput as Mt, getTaxonomyTerms as N, DatabaseConfig as Ni, I18nConfig as Nn, UpdateSectionInput as Nr, ImportAnalysis as Nt, WidgetType as O, PortableTextBlock$2 as Oi, CollectionFilter as On, getSections as Or, AttachmentInfo as Ot, getTerm as P, EmDashDatabaseError as Pi, getFallbackChain as Pn, getCollectionInfo as Pr, ImportConfig as Pt, UpdateMenuItemInput as Q, resolveEmDashPath as Qn, handleContentCountTrashed as Qr, createNoopSandboxRunner as Qt, TaxonomyTerm as R, CollectionFilter$1 as Rn, MediaResponse as Rr, ImportSource as Rt, PropDef as S, reference as Si, WxrData as Sn, SandboxOptions as Sr, getFileSources as St, Widget as T, FieldUIHints as Ti, WxrTag as Tn, SandboxedPlugin as Tr, probeUrl as Tt, getMenu as U, EntryResult as Un, handleMediaUpdate as Ur, ProbeResult as Ut, getByline as V, EditFieldMeta as Vn, handleMediaGet as Vr, PostTypeAnalysis as Vt, getMenus as W, InferCollectionData as Wn, RevisionListResponse as Wr, SourceAuth as Wt, ReorderMenuItemsInput as X, getEmDashEntry as Xn, handleContentCompare as Xr, NoopSandboxRunner as Xt, MenuItemType as Y, getEmDashCollection as Yn, generateManifest as Yr, UrlInput as Yt, UpdateMenuInput as Z, getTranslations as Zn, handleContentCountScheduled as Zr, SandboxNotAvailableError as Zt, getWidgetArea as _, ContentResponse as _i, ExternalAuthConfig as _n, ProseMirrorDocument as _r, verifyPreviewToken as _t, search as a, handleContentList as ai, createHookPipeline as an, sanitizeHref as ar, setSiteSettings as at, CreateWidgetAreaInput as b, ManifestResponse as bi, WxrAuthor as bn, SandboxEmailMessage as br, clearSources as bt, FTSManager as c, handleContentPublish as ci, EmDashConfig as cn, portableTextToProsemirror as cr, GetPreviewUrlOptions as ct, SearchOptions as d, handleContentTranslations as di, LocalStorageConfig as dn, PortableTextImageBlock as dr, GeneratePreviewTokenOptions as dt, handleContentDelete as ei, createPluginManager as en, EditProxy as er, GetCommentsResult as et, SearchResponse as f, handleContentUnpublish as fi, S3StorageConfig as fn, PortableTextLinkMark as fr, PreviewTokenPayload as ft, Suggestion as g, ContentListResponse as gi, AuthResult as gn, PortableTextUnknownBlock as gr, parseContentId as gt, SuggestOptions as h, ApiContext as hi, AuthProviderModule as hn, PortableTextTextBlock as hr, generatePreviewToken as ht, getSuggestions as i, handleContentGetIncludingTrashed as ii, HookResult as in, isSafeHref as ir, getSiteSettings as it, getTaxonomyDef as j, MediaRepository as ji, emdashLoader as jn, Section as jr, FieldCompatibility as jt, getEntriesByTerm as k, CreateMediaInput as ki, EntryData as kn, CreateSectionInput as kr, CollectionSchemaStatus as kt, CollectionSearchOptions as l, handleContentRestore as li, PluginDescriptor as ln, prosemirrorToPortableText as lr, buildPreviewUrl as lt, SearchStats as m, handleContentUpdate as mi, AuthDescriptor as mn, PortableTextSpan as mr, VerifyPreviewTokenResult as mt, extractSearchableFields as n, handleContentDuplicate as ni, EmailPipeline as nn, createEditable as nr, getComments as nt, searchCollection as o, handleContentListTrashed as oi, ValidatedPluginManifest as on, computeContentHash as or, getPreviewToken as ot, SearchResult as p, handleContentUnschedule as pi, StorageDescriptor as pn, PortableTextMarkDef as pr, VerifyPreviewTokenOptions as pt, Menu as q, TranslationsResult as qn, handleRevisionList as qr, SourceProbeResult as qt, getSearchStats as r, handleContentGet as ri, HookPipeline as rn, createNoop as rr, getSiteSetting as rt, searchWithDb as s, handleContentPermanentDelete as si, pluginManifestSchema as sn, hashString as sr, isPreviewRequest as st, extractPlainText as t, handleContentDiscardDraft as ti, PluginRouteError as tn, FieldAnnotation as tr, getCommentCount as tt, SearchConfig as u, handleContentSchedule as ui, getStoredConfig as un, PortableTextCodeBlock as ur, getPreviewUrl as ut, getWidgetAreas as v, FieldDescriptor as vi, definePlugin as vn, ProseMirrorMark as vr, wordpressRestSource as vt, UpdateWidgetInput as w, FieldDefinition as wi, WxrSite as wn, SandboxRunnerFactory as wr, getUrlSources as wt, CreateWidgetInput as x, portableText as xi, WxrCategory as xn, SandboxEmailSendCallback as xr, getAllSources as xt, getWidgetComponents as y, ListResponse as yi, WxrAttachment as yn, ProseMirrorNode as yr, wxrSource as yt, TaxonomyTermRow as z, CollectionResult as zn, handleMediaCreate as zr, NormalizedItem as zt };
4527
+ //# sourceMappingURL=index-C1xF3OGh.d.mts.map