dineway 0.1.48 → 0.2.0

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 (420) hide show
  1. package/dist/{activity-events-C9u37D5z.mjs → activity-events-y6eT8UW6.mjs} +6 -38
  2. package/dist/actor-CrObAPV0.mjs +37 -0
  3. package/dist/after-BfniwgIf.mjs +9 -0
  4. package/dist/{allowed-origins-DhipQNLb.mjs → allowed-origins-_oeyP6x-.mjs} +1 -1
  5. package/dist/api/route-utils.d.mts +10 -10
  6. package/dist/api/route-utils.mjs +17 -14
  7. package/dist/api/schemas/index.d.mts +2 -2
  8. package/dist/api/schemas/index.mjs +5 -4
  9. package/dist/{api-Eiy8_zVZ.mjs → api-ByrU2q-Z.mjs} +61 -37
  10. package/dist/{api-tokens-DtvdtIkm.mjs → api-tokens-CjVMQT-X.mjs} +6 -2
  11. package/dist/{apply-CX3no7XE.mjs → apply-bZswmZPm.mjs} +117 -77
  12. package/dist/astro/image-endpoint.d.mts +7 -0
  13. package/dist/astro/image-endpoint.mjs +54 -0
  14. package/dist/astro/index.d.mts +35 -11
  15. package/dist/astro/index.mjs +157 -23
  16. package/dist/astro/integration/shims/use-sync-external-store-with-selector.js +71 -0
  17. package/dist/astro/integration/shims/use-sync-external-store.js +1 -0
  18. package/dist/astro/middleware/auth.d.mts +10 -10
  19. package/dist/astro/middleware/auth.mjs +42 -24
  20. package/dist/astro/middleware/redirect.mjs +14 -5
  21. package/dist/astro/middleware/request-context.mjs +9 -6
  22. package/dist/astro/middleware/seed.d.mts +1 -1
  23. package/dist/astro/middleware/seed.mjs +2 -2
  24. package/dist/astro/middleware/setup.mjs +1 -1
  25. package/dist/astro/middleware.mjs +334 -193
  26. package/dist/astro/routes/admin.astro +6 -1
  27. package/dist/astro/routes/api/admin/allowed-domains/_domain_.mjs +7 -6
  28. package/dist/astro/routes/api/admin/allowed-domains/index.mjs +7 -6
  29. package/dist/astro/routes/api/admin/api-tokens/_id_.mjs +4 -4
  30. package/dist/astro/routes/api/admin/api-tokens/index.mjs +6 -6
  31. package/dist/astro/routes/api/admin/briefing.mjs +22 -18
  32. package/dist/astro/routes/api/admin/byline-fields/_slug_/usage.mjs +4 -4
  33. package/dist/astro/routes/api/admin/byline-fields/_slug_.mjs +9 -8
  34. package/dist/astro/routes/api/admin/byline-fields/index.mjs +9 -8
  35. package/dist/astro/routes/api/admin/byline-fields/reorder.mjs +9 -8
  36. package/dist/astro/routes/api/admin/bylines/_id_/index.mjs +18 -15
  37. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +18 -15
  38. package/dist/astro/routes/api/admin/bylines/index.mjs +18 -15
  39. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +15 -13
  40. package/dist/astro/routes/api/admin/comments/_id_.mjs +7 -6
  41. package/dist/astro/routes/api/admin/comments/bulk.mjs +12 -10
  42. package/dist/astro/routes/api/admin/comments/counts.mjs +7 -6
  43. package/dist/astro/routes/api/admin/comments/index.mjs +12 -10
  44. package/dist/astro/routes/api/admin/context/_id_/history.mjs +27 -25
  45. package/dist/astro/routes/api/admin/context/_id_/index.mjs +27 -25
  46. package/dist/astro/routes/api/admin/context/_id_/review.mjs +32 -29
  47. package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +32 -29
  48. package/dist/astro/routes/api/admin/context/diff.mjs +31 -28
  49. package/dist/astro/routes/api/admin/context/index.mjs +32 -29
  50. package/dist/astro/routes/api/admin/context/stale.mjs +31 -28
  51. package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +27 -25
  52. package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +31 -28
  53. package/dist/astro/routes/api/admin/hitl-requests/index.mjs +31 -28
  54. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +28 -26
  55. package/dist/astro/routes/api/admin/hooks/exclusive/index.mjs +3 -3
  56. package/dist/astro/routes/api/admin/oauth-clients/_id_.mjs +6 -6
  57. package/dist/astro/routes/api/admin/oauth-clients/index.mjs +6 -6
  58. package/dist/astro/routes/api/admin/plugins/_id_/disable.mjs +56 -52
  59. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +56 -52
  60. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +48 -44
  61. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +54 -50
  62. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +53 -49
  63. package/dist/astro/routes/api/admin/plugins/index.mjs +48 -44
  64. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/icon.mjs +2 -2
  65. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +47 -43
  66. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +53 -49
  67. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +47 -43
  68. package/dist/astro/routes/api/admin/plugins/updates.mjs +47 -43
  69. package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +6 -6
  70. package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +32 -28
  71. package/dist/astro/routes/api/admin/review-requests/index.mjs +11 -10
  72. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +47 -43
  73. package/dist/astro/routes/api/admin/themes/marketplace/_id_/thumbnail.mjs +2 -2
  74. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +47 -43
  75. package/dist/astro/routes/api/admin/users/_id_/disable.mjs +3 -3
  76. package/dist/astro/routes/api/admin/users/_id_/enable.mjs +2 -2
  77. package/dist/astro/routes/api/admin/users/_id_/index.mjs +8 -7
  78. package/dist/astro/routes/api/admin/users/_id_/send-recovery.mjs +4 -4
  79. package/dist/astro/routes/api/admin/users/index.mjs +7 -6
  80. package/dist/astro/routes/api/auth/dev-bypass.mjs +4 -4
  81. package/dist/astro/routes/api/auth/invite/accept.mjs +2 -2
  82. package/dist/astro/routes/api/auth/invite/complete.mjs +12 -11
  83. package/dist/astro/routes/api/auth/invite/index.mjs +9 -8
  84. package/dist/astro/routes/api/auth/invite/register-options.mjs +11 -10
  85. package/dist/astro/routes/api/auth/logout.mjs +2 -2
  86. package/dist/astro/routes/api/auth/magic-link/send.mjs +11 -10
  87. package/dist/astro/routes/api/auth/magic-link/verify.mjs +3 -3
  88. package/dist/astro/routes/api/auth/me.mjs +10 -9
  89. package/dist/astro/routes/api/auth/mode.mjs +1 -1
  90. package/dist/astro/routes/api/auth/oauth/_provider_/callback.mjs +3 -3
  91. package/dist/astro/routes/api/auth/oauth/_provider_.mjs +2 -2
  92. package/dist/astro/routes/api/auth/passkey/_id_.mjs +6 -5
  93. package/dist/astro/routes/api/auth/passkey/index.mjs +1 -1
  94. package/dist/astro/routes/api/auth/passkey/options.mjs +12 -11
  95. package/dist/astro/routes/api/auth/passkey/register/options.mjs +10 -9
  96. package/dist/astro/routes/api/auth/passkey/register/verify.mjs +11 -10
  97. package/dist/astro/routes/api/auth/passkey/verify.mjs +11 -10
  98. package/dist/astro/routes/api/auth/setup-token/index.mjs +6 -6
  99. package/dist/astro/routes/api/auth/setup-token/verify.mjs +2 -2
  100. package/dist/astro/routes/api/auth/signup/complete.mjs +12 -11
  101. package/dist/astro/routes/api/auth/signup/request.mjs +11 -10
  102. package/dist/astro/routes/api/auth/signup/verify.mjs +2 -2
  103. package/dist/astro/routes/api/comments/_collection_/_contentId_/index.mjs +16 -14
  104. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.d.mts +8 -0
  105. package/dist/astro/routes/api/comments/_collection_/_contentId_/reactions.mjs +160 -0
  106. package/dist/astro/routes/api/content/_collection_/_id_/compare.mjs +2 -2
  107. package/dist/astro/routes/api/content/_collection_/_id_/discard-draft.mjs +6 -6
  108. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +6 -6
  109. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +6 -6
  110. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +12 -11
  111. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +11 -10
  112. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +6 -6
  113. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  114. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +11 -10
  115. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +17 -15
  116. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  117. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +6 -6
  118. package/dist/astro/routes/api/content/_collection_/_id_.mjs +11 -10
  119. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  120. package/dist/astro/routes/api/content/_collection_/index.mjs +11 -10
  121. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -6
  122. package/dist/astro/routes/api/dashboard.mjs +10 -9
  123. package/dist/astro/routes/api/dev/emails.mjs +2 -2
  124. package/dist/astro/routes/api/health.mjs +1 -1
  125. package/dist/astro/routes/api/import/probe.d.mts +3 -3
  126. package/dist/astro/routes/api/import/probe.mjs +23 -11
  127. package/dist/astro/routes/api/import/wordpress/analyze.mjs +9 -6
  128. package/dist/astro/routes/api/import/wordpress/execute.d.mts +19 -1
  129. package/dist/astro/routes/api/import/wordpress/execute.mjs +85 -38
  130. package/dist/astro/routes/api/import/wordpress/media.d.mts +13 -1
  131. package/dist/astro/routes/api/import/wordpress/media.mjs +20 -14
  132. package/dist/astro/routes/api/import/wordpress/prepare.mjs +36 -33
  133. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +18 -1
  134. package/dist/astro/routes/api/import/wordpress/rewrite-urls.mjs +121 -101
  135. package/dist/astro/routes/api/import/wordpress-plugin/analyze.d.mts +1 -1
  136. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +25 -13
  137. package/dist/astro/routes/api/import/wordpress-plugin/callback.mjs +1 -1
  138. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +56 -2
  139. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +284 -56
  140. package/dist/astro/routes/api/manifest.mjs +14 -5
  141. package/dist/astro/routes/api/mcp.mjs +266 -70
  142. package/dist/astro/routes/api/media/_id_/confirm.mjs +39 -11
  143. package/dist/astro/routes/api/media/_id_.mjs +11 -7
  144. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  145. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  146. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  147. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  148. package/dist/astro/routes/api/media/upload-url.mjs +12 -11
  149. package/dist/astro/routes/api/media.mjs +28 -35
  150. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +32 -29
  151. package/dist/astro/routes/api/menus/_name_/items.mjs +32 -29
  152. package/dist/astro/routes/api/menus/_name_/reorder.mjs +32 -29
  153. package/dist/astro/routes/api/menus/_name_/translations.mjs +32 -29
  154. package/dist/astro/routes/api/menus/_name_.mjs +32 -29
  155. package/dist/astro/routes/api/menus/index.mjs +32 -29
  156. package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
  157. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  158. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  159. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  160. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  161. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  162. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  163. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  164. package/dist/astro/routes/api/openapi.json.mjs +4 -3
  165. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +30 -30
  166. package/dist/astro/routes/api/redirects/404s/index.mjs +12 -11
  167. package/dist/astro/routes/api/redirects/404s/summary.mjs +12 -11
  168. package/dist/astro/routes/api/redirects/_id_.mjs +33 -30
  169. package/dist/astro/routes/api/redirects/index.mjs +33 -30
  170. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  171. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
  172. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +48 -44
  173. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +48 -44
  174. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +48 -44
  175. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +48 -44
  176. package/dist/astro/routes/api/schema/collections/index.mjs +48 -44
  177. package/dist/astro/routes/api/schema/index.mjs +13 -14
  178. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +47 -43
  179. package/dist/astro/routes/api/schema/orphans/index.mjs +47 -43
  180. package/dist/astro/routes/api/search/enable.mjs +12 -11
  181. package/dist/astro/routes/api/search/index.mjs +11 -10
  182. package/dist/astro/routes/api/search/rebuild.mjs +12 -11
  183. package/dist/astro/routes/api/search/stats.mjs +7 -7
  184. package/dist/astro/routes/api/search/suggest.mjs +11 -10
  185. package/dist/astro/routes/api/sections/_slug_.mjs +32 -29
  186. package/dist/astro/routes/api/sections/index.mjs +32 -29
  187. package/dist/astro/routes/api/settings/email.mjs +4 -4
  188. package/dist/astro/routes/api/settings.mjs +32 -29
  189. package/dist/astro/routes/api/setup/admin-verify.mjs +14 -13
  190. package/dist/astro/routes/api/setup/admin.mjs +12 -11
  191. package/dist/astro/routes/api/setup/dev-bypass.mjs +32 -26
  192. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  193. package/dist/astro/routes/api/setup/index.mjs +30 -26
  194. package/dist/astro/routes/api/setup/status.mjs +3 -3
  195. package/dist/astro/routes/api/snapshot.mjs +9 -8
  196. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +35 -32
  197. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +35 -32
  198. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +35 -32
  199. package/dist/astro/routes/api/taxonomies/index.mjs +35 -32
  200. package/dist/astro/routes/api/themes/preview.mjs +6 -6
  201. package/dist/astro/routes/api/typegen.mjs +4 -4
  202. package/dist/astro/routes/api/well-known/auth.mjs +3 -3
  203. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
  204. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
  205. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +31 -28
  206. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +32 -29
  207. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +32 -29
  208. package/dist/astro/routes/api/widget-areas/_name_.mjs +29 -27
  209. package/dist/astro/routes/api/widget-areas/index.mjs +32 -29
  210. package/dist/astro/routes/api/widget-components.mjs +2 -2
  211. package/dist/astro/routes/robots.txt.mjs +9 -8
  212. package/dist/astro/routes/sitemap-_collection_.xml.mjs +24 -15
  213. package/dist/astro/routes/sitemap.xml.mjs +10 -9
  214. package/dist/astro/session-driver.d.mts +1 -1
  215. package/dist/astro/session-driver.mjs +3 -3
  216. package/dist/astro/types.d.mts +21 -13
  217. package/dist/{audit-D1cbG7xH.mjs → audit-ByVKIwWF.mjs} +1 -1
  218. package/dist/auth/providers/github.d.mts +1 -1
  219. package/dist/auth/providers/google.d.mts +1 -1
  220. package/dist/{auth-control-guard-Dr14I98m.mjs → auth-control-guard-CqeUmQsv.mjs} +1 -1
  221. package/dist/{authorize-BLO0m7fW.mjs → authorize-CcBxcHtz.mjs} +1 -1
  222. package/dist/{briefing-CObXGOGz.mjs → briefing-BJaJI8dm.mjs} +2 -1
  223. package/dist/{briefing-gKWiGLt1.mjs → briefing-CawZ59CY.mjs} +90 -28
  224. package/dist/bundle-7C_DpkEq.mjs +602 -0
  225. package/dist/{byline-1ntDwv8c.mjs → byline-e51-fWRs.mjs} +30 -62
  226. package/dist/{byline-fields-BX7rWKNU.d.mts → byline-fields-CUvbslGc.d.mts} +49 -6
  227. package/dist/{byline-fields-C9_iaPaM.mjs → byline-fields-D-N5qVIG.mjs} +1 -1
  228. package/dist/{byline-fields-B-ZkoVft.mjs → byline-fields-DOJO16Gm.mjs} +3 -3
  229. package/dist/{byline-registry-CUSvkasJ.mjs → byline-registry-87nNnYl4.mjs} +2 -2
  230. package/dist/{bylines-bC15ZqAv.mjs → bylines-CMQNCNFh.mjs} +9 -3
  231. package/dist/{bylines-DtxChhN_.mjs → bylines-y4LO-dTj.mjs} +5 -5
  232. package/dist/{cache-DbKyr60Q.mjs → cache-C-FNTFYK.mjs} +2 -2
  233. package/dist/{chunks-C5zp2xir.mjs → chunks-CxBt-GxR.mjs} +1 -1
  234. package/dist/cli/index.mjs +820 -1276
  235. package/dist/client/external-auth-headers.d.mts +1 -1
  236. package/dist/client/index.d.mts +1 -1
  237. package/dist/client/index.mjs +2 -1
  238. package/dist/{comment-CXDOQ93N.mjs → comment-DlA4iChg.mjs} +13 -3
  239. package/dist/comment-reaction-DfFao1ST.mjs +58 -0
  240. package/dist/{comments-hK-rdzJ9.mjs → comments-DApFGMsP.mjs} +1 -1
  241. package/dist/{content-QaryevFO.mjs → content-Bh4BDjv8.mjs} +51 -34
  242. package/dist/content-refresh-CgutSUfO.mjs +1576 -0
  243. package/dist/{context-CoYb_fvK.mjs → context-C5W3G18y.mjs} +111 -50
  244. package/dist/{context-DBL1ib4v.mjs → context-CK4ym2Sf.mjs} +2 -2
  245. package/dist/{context-route-helpers-CYQVmbIm.mjs → context-route-helpers-MASyGgWf.mjs} +2 -1
  246. package/dist/{cron-DxCAU_Sn.mjs → cron-cKcNTix_.mjs} +7 -3
  247. package/dist/{dashboard-DNlqsknJ.mjs → dashboard-DQkVT7Ei.mjs} +4 -4
  248. package/dist/db/index.d.mts +3 -3
  249. package/dist/db/index.mjs +1 -1
  250. package/dist/db/libsql.d.mts +1 -1
  251. package/dist/db/postgres.d.mts +1 -1
  252. package/dist/db/sqlite.d.mts +1 -1
  253. package/dist/{device-flow-DygsFPGL.mjs → device-flow-BnqRH-T9.mjs} +5 -5
  254. package/dist/{placeholder-BDo81Is5.mjs → enrich-DIFIFA8O.mjs} +36 -9
  255. package/dist/{error-DCSuUAZW.mjs → error-CytFlgcd.mjs} +5 -0
  256. package/dist/field-defs-cache-DRNdhBJv.mjs +49 -0
  257. package/dist/{fts-manager-CIZlScg5.mjs → fts-manager-Crzypjqu.mjs} +1 -1
  258. package/dist/hitl-Hw1RmWOq.mjs +677 -0
  259. package/dist/{hitl-requests-CGQwOEiq.mjs → hitl-requests-B4Vbcmaq.mjs} +2 -2
  260. package/dist/{hitl-route-helpers-GSDLNPpN.mjs → hitl-route-helpers-hEVzvP8l.mjs} +5 -4
  261. package/dist/import-Bh9biJfx.mjs +1354 -0
  262. package/dist/{index-CwRuZ-u8.d.mts → index-D4y6NGiy.d.mts} +75 -3
  263. package/dist/index.d.mts +17 -16
  264. package/dist/index.mjs +81 -69
  265. package/dist/{jsonld-DZ67souc.d.mts → jsonld-Dq0gsnOH.d.mts} +8 -4
  266. package/dist/{load-xE01Jm0V.mjs → load-DmYeniXl.mjs} +1 -1
  267. package/dist/{loader-tg63WSY2.mjs → loader-CjWqjweO.mjs} +117 -31
  268. package/dist/{manifest-schema-qh2P7RDX.mjs → manifest-schema-BxVPYMJR.mjs} +34 -1
  269. package/dist/mcp-reviewed-executor-TwVbMzG6.mjs +555 -0
  270. package/dist/media/image-endpoint.d.mts +32 -0
  271. package/dist/media/image-endpoint.mjs +111 -0
  272. package/dist/media/index.d.mts +27 -2
  273. package/dist/media/index.mjs +5 -3
  274. package/dist/media/local-runtime.d.mts +16 -11
  275. package/dist/media/local-runtime.mjs +10 -8
  276. package/dist/{media-DUAjMfvR.mjs → media-DMj0grzC.mjs} +3 -1
  277. package/dist/{media-allowlist-BsXkT9RK.mjs → media-allowlist-BlVCSzHx.mjs} +1 -1
  278. package/dist/media-url-lEKSrpr9.mjs +20 -0
  279. package/dist/{menus-WpFRMXjz.mjs → menus-TaW1gKnk.mjs} +19 -5
  280. package/dist/{menus-DU1eZqw_.mjs → menus-xvsnVZXw.mjs} +80 -15
  281. package/dist/{normalize-DUnoXAa9.mjs → normalize-5ek_z7de.mjs} +8 -1
  282. package/dist/{oauth-authorization-D-1p52Je.mjs → oauth-authorization-DiaGvRVz.mjs} +5 -5
  283. package/dist/{oauth-clients-CzeMGyUU.mjs → oauth-clients-Dl9E8dEM.mjs} +2 -2
  284. package/dist/object-cache/memory.d.mts +14 -0
  285. package/dist/object-cache/memory.mjs +55 -0
  286. package/dist/object-cache-D51qOseS.mjs +419 -0
  287. package/dist/page/index.d.mts +4 -3
  288. package/dist/page/index.mjs +2 -2
  289. package/dist/{parse-CneSgl7-.mjs → parse-CbymENaR.mjs} +1 -1
  290. package/dist/{parser-DxfsARXL.mjs → parser-C1nYd-81.mjs} +151 -9
  291. package/dist/{placeholder-CXfoCtCd.d.mts → placeholder-uvNRZBX9.d.mts} +12 -4
  292. package/dist/plugin-utils.d.mts +9 -9
  293. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  294. package/dist/plugins/adapt-sandbox-entry.mjs +11 -2
  295. package/dist/{plugins-C57YQi4l.mjs → plugins-BolVa-tl.mjs} +832 -64
  296. package/dist/{transport-LSdZVXHF.mjs → portable-text-dA_UlJwW.mjs} +1 -134
  297. package/dist/{preview-D5rvDhRt.mjs → preview-vSVg6fwG.mjs} +4 -3
  298. package/dist/process-cache-7xgAO9JY.mjs +106 -0
  299. package/dist/{provider-loader-9it4vd6L.d.mts → provider-loader-MD8zAbnH.d.mts} +1 -1
  300. package/dist/{public-url-DLUM5OOv.mjs → public-url-BEz_sM9n.mjs} +24 -18
  301. package/dist/{public-url-B5HaoGzj.d.mts → public-url-gsp3oUbu.d.mts} +5 -4
  302. package/dist/{query-BYc3oruA.mjs → query-CfRCdaL3.mjs} +281 -76
  303. package/dist/{query-DKEwzobh.mjs → query-jaAmw8E1.mjs} +11 -6
  304. package/dist/{rate-limit-i0G3IAOX.mjs → rate-limit-ZLdyWoZF.mjs} +2 -2
  305. package/dist/{redirect-C2zXRj3c.mjs → redirect-BAjt4Z6b.mjs} +2 -2
  306. package/dist/{redirects-YZo_znWG.mjs → redirects-BTdwpQtE.mjs} +47 -24
  307. package/dist/{redirects-ocRJmQHP.mjs → redirects-CA-xylPG.mjs} +19 -11
  308. package/dist/{registry-CTkbIDB9.mjs → registry-CtyVedcN.mjs} +130 -77
  309. package/dist/request-context.d.mts +2 -0
  310. package/dist/{request-meta-DAb6xaP9.mjs → request-meta-CUypToDJ.mjs} +1 -1
  311. package/dist/{review-requests-C0un5kdV.mjs → review-requests-C9Ff11Vq.mjs} +1 -1
  312. package/dist/{review-requests-gGMyYYhy.mjs → review-requests-DUyEmtmG.mjs} +1 -1
  313. package/dist/{runner-D4FL9usy.d.mts → runner-1tC2tIRV.d.mts} +1 -1
  314. package/dist/runner-DB7CRfOF.mjs +6740 -0
  315. package/dist/{runtime-DEWQpZ-4.d.mts → runtime-BOeiQsCv.d.mts} +2028 -1564
  316. package/dist/runtime.d.mts +10 -10
  317. package/dist/runtime.mjs +4 -4
  318. package/dist/schema-DXdYj4R3.mjs +8 -0
  319. package/dist/{search-axGQ1KY3.mjs → search-DSaLgEFI.mjs} +5 -3
  320. package/dist/{secrets-062Izo8i.mjs → secrets-CDZo2k8L.mjs} +15 -12
  321. package/dist/{sections-OLKgXL10.mjs → sections-PVVXHGfp.mjs} +2 -2
  322. package/dist/seed/index.d.mts +2 -2
  323. package/dist/seed/index.mjs +22 -19
  324. package/dist/seo/index.d.mts +1 -1
  325. package/dist/seo/index.mjs +3 -12
  326. package/dist/{seo-Cd45Po8L.mjs → seo-CQG3GCHQ.mjs} +5 -2
  327. package/dist/{seo-contributions-CqVvReEj.mjs → seo-contributions-C1EnikHB.mjs} +11 -3
  328. package/dist/{seo-5lJOtB5J.mjs → seo-qa7Dn0jK.mjs} +22 -4
  329. package/dist/{service-Bwad8s5h.mjs → service-DiN4ZuPp.mjs} +2 -2
  330. package/dist/session-user-CAKImna3.mjs +22 -0
  331. package/dist/{settings-yLjz_I4T.mjs → settings-BbqgHWpU.mjs} +28 -55
  332. package/dist/{settings-lAHjaUit.mjs → settings-i4VPP8bT.mjs} +2 -2
  333. package/dist/{setup-complete--PradA4R.mjs → setup-complete-B8fl-mjV.mjs} +1 -1
  334. package/dist/{site-activity-D7Xyropw.mjs → site-activity-Dy3FROs0.mjs} +1 -1
  335. package/dist/{site-context-DaN9Z91j.mjs → site-context-DQiL8Fl5.mjs} +23 -652
  336. package/dist/{site-url-DpGZo9Z6.mjs → site-url-BML3GQYm.mjs} +1 -1
  337. package/dist/status-DANd8ERo.mjs +21 -0
  338. package/dist/storage/local.d.mts +1 -1
  339. package/dist/storage/local.mjs +1 -1
  340. package/dist/storage/s3.d.mts +1 -1
  341. package/dist/storage/s3.mjs +1 -1
  342. package/dist/{taxonomies-uXVEoQso.mjs → taxonomies-9s-v03H-.mjs} +36 -29
  343. package/dist/taxonomies-DRiixp_E.mjs +443 -0
  344. package/dist/{taxonomy-CBmkmMuU.mjs → taxonomy-Dvsw6BOs.mjs} +44 -9
  345. package/dist/{tokens-CjSgb0AC.mjs → tokens-1RK1n6ED.mjs} +1 -1
  346. package/dist/transport-BNmCqLu7.mjs +134 -0
  347. package/dist/types-4garmdWa.mjs +66 -0
  348. package/dist/{types-DSPGWjxO.d.mts → types-C8XW6L19.d.mts} +225 -4
  349. package/dist/{types-GaCtZ1k9.d.mts → types-CDpH6MA4.d.mts} +18 -0
  350. package/dist/{types-DRIKLmJI.d.mts → types-C_ly5eTp.d.mts} +17 -2
  351. package/dist/types-DF7ZuGGk.d.mts +118 -0
  352. package/dist/types-DU0bU2Wu.d.mts +2392 -0
  353. package/dist/{types-CwawBUTa.d.mts → types-DW_-sFyz.d.mts} +2 -1
  354. package/dist/{types-DfuD0Afl.mjs → types-Dq1qT19x.mjs} +2 -2
  355. package/dist/ui/server-runtime.d.mts +15 -15
  356. package/dist/ui/server-runtime.mjs +25 -21
  357. package/dist/url-Cac7a9QZ.mjs +33 -0
  358. package/dist/{user-DtNmjNYt.mjs → user-BIZPzCb9.mjs} +2 -2
  359. package/dist/{utils-wv-zvC-Y.mjs → utils-CMDhr5Xd.mjs} +129 -7
  360. package/dist/{validate-BMs11tan.d.mts → validate-CZvb-BKB.d.mts} +10 -7
  361. package/dist/{validate-7SYRbz2f.mjs → validate-DNs0pTSc.mjs} +11 -6
  362. package/dist/version-BTvfRGc6.mjs +6 -0
  363. package/dist/{widgets-DR8EHuRO.mjs → widgets-f0ibZUIq.mjs} +46 -43
  364. package/dist/{wordpress-slugs-Dvhxh4cl.mjs → wordpress-slugs-BhHJX8XE.mjs} +1 -1
  365. package/dist/{zod-generator-BS9-umbk.mjs → zod-generator-B7TMjyFJ.mjs} +41 -13
  366. package/package.json +31 -8
  367. package/src/components/Block.astro +50 -0
  368. package/src/components/Comments.astro +143 -1
  369. package/src/components/DinewayHead.astro +19 -2
  370. package/src/components/DinewayImage.astro +66 -33
  371. package/src/components/DinewayMedia.astro +1 -2
  372. package/src/components/Image.astro +85 -40
  373. package/src/components/InlinePortableTextEditor.tsx +12 -2
  374. package/src/components/JsonLdScript.astro +9 -0
  375. package/src/components/LiveSearch.astro +40 -4
  376. package/src/components/index.ts +4 -0
  377. package/src/components/live-search-routing.ts +30 -0
  378. package/src/components/portable-text-text-align.ts +15 -0
  379. package/src/ui.ts +2 -0
  380. package/dist/entity-aliases-Egjmqc7I.mjs +0 -51
  381. package/dist/import-CvHY6sf5.mjs +0 -684
  382. package/dist/runner-B-tbV751.mjs +0 -2741
  383. package/dist/schema-B6zyB-Xn.mjs +0 -8
  384. package/dist/taxonomies-CNOGeC-3.mjs +0 -327
  385. package/dist/types-eu5UDgHN.d.mts +0 -652
  386. package/dist/version-xlzMSXF2.mjs +0 -6
  387. /package/dist/{adapters-OQCImOL7.d.mts → adapters-NVSs4UH7.d.mts} +0 -0
  388. /package/dist/{api-tokens-CYUoFGo7.mjs → api-tokens-2r7OWi_I.mjs} +0 -0
  389. /package/dist/{base64-C1Q9yr0B.mjs → base64-F8-DUraK.mjs} +0 -0
  390. /package/dist/{challenge-store-CRSz-Xim.mjs → challenge-store-Bjlepa2E.mjs} +0 -0
  391. /package/dist/{components--pg6zBvu.mjs → components-Bclf98Be.mjs} +0 -0
  392. /package/dist/{context-types-DQh_XKkn.mjs → context-types-DqTo6C79.mjs} +0 -0
  393. /package/dist/{default-B6iaLvP7.mjs → default--K40jqm0.mjs} +0 -0
  394. /package/dist/{email-console-BOVqIYpB.mjs → email-console-ChgKFO8-.mjs} +0 -0
  395. /package/dist/{escape-BDgouFFY.mjs → escape-Bd4P_xKg.mjs} +0 -0
  396. /package/dist/{experimental-workflows-Dh4DUoD_.mjs → experimental-workflows-BMsUnIAw.mjs} +0 -0
  397. /package/dist/{mime-8pAB8-77.mjs → mime-CA7Lgovc.mjs} +0 -0
  398. /package/dist/{mode-CpyEz8pe.mjs → mode-C4CIyjtR.mjs} +0 -0
  399. /package/dist/{oauth-state-store-qncPB_IU.mjs → oauth-state-store-CNoXafF7.mjs} +0 -0
  400. /package/dist/{oauth-user-lookup-BFjWF8wK.mjs → oauth-user-lookup-Ygw4bNyt.mjs} +0 -0
  401. /package/dist/{options-BvJoSSJR.mjs → options-DQPTH5n0.mjs} +0 -0
  402. /package/dist/{passkey-config-DzHQK90v.mjs → passkey-config-BUwu8BA3.mjs} +0 -0
  403. /package/dist/{patterns-r-0n824Y.mjs → patterns-BhAvqO0S.mjs} +0 -0
  404. /package/dist/{provider-loader-DzUxejk7.mjs → provider-loader-D0w9dqjm.mjs} +0 -0
  405. /package/dist/{redirect-BjIBtDWY.mjs → redirect-wphRBv4y.mjs} +0 -0
  406. /package/dist/{request-cache-CYMbwZc6.mjs → request-cache-D9GQBxMP.mjs} +0 -0
  407. /package/dist/{resolve-DTuDyYKs.mjs → resolve-Cb6Dbz-C.mjs} +0 -0
  408. /package/dist/{setup-nonce-pyGfc9hV.mjs → setup-nonce-CoyjILvW.mjs} +0 -0
  409. /package/dist/{sidecar-client-mJxwayYN.mjs → sidecar-client-C3mqXg4C.mjs} +0 -0
  410. /package/dist/{slugify-BzGxlOFx.mjs → slugify-KSsVD_D3.mjs} +0 -0
  411. /package/dist/{ssrf-DiKqWd3N.mjs → ssrf-DWe8jwAp.mjs} +0 -0
  412. /package/dist/{transaction-CShMWIej.mjs → transaction-C2EOMTJA.mjs} +0 -0
  413. /package/dist/{transport-BnsNxh2l.d.mts → transport-CcJu3Co8.d.mts} +0 -0
  414. /package/dist/{trusted-proxy-BgIIcbsN.mjs → trusted-proxy-DTXQ2IMv.mjs} +0 -0
  415. /package/dist/{types-BO8TGjS8.mjs → types-B3t5cxhU.mjs} +0 -0
  416. /package/dist/{types-nP9vGUFq.d.mts → types-C46EvNdc.d.mts} +0 -0
  417. /package/dist/{types-Cg276-3z.mjs → types-C5CVgwsV.mjs} +0 -0
  418. /package/dist/{types-DZpT-PnG.d.mts → types-POH8PQZh.d.mts} +0 -0
  419. /package/dist/{types-Dryvv7LH.d.mts → types-Rc3gQqqw.d.mts} +0 -0
  420. /package/dist/{url-w7Mp5qAD.mjs → url-CpyFDFpO.mjs} +0 -0
@@ -1,16 +1,18 @@
1
- import { _ as UpdateFieldInput, f as FieldValidation, g as UpdateCollectionInput, i as CollectionWithFields, o as CreateCollectionInput, s as CreateFieldInput, t as Collection, u as Field } from "./types-CwawBUTa.mjs";
2
- import { f as UpdateContentInput, i as ContentItem, l as FindManyOptions, o as ContentSeoInput, r as ContentDateField, s as CreateContentInput, t as BylineSummary, u as FindManyResult } from "./types-DRIKLmJI.mjs";
3
- import { t as Database } from "./types-eu5UDgHN.mjs";
4
- import { A as PageMetadataContribution, B as PluginDefinition, D as PageFragmentContribution, H as PluginManifest, J as RequestMeta, O as PageFragmentEvent, W as PluginStorageConfig, X as ResolvedPlugin, a as CommentAfterModerateEvent, g as EmailMessage, h as CronEvent, j as PageMetadataEvent, r as CommentAfterCreateEvent, s as CommentBeforeCreateEvent, tt as StandardPluginDefinition, w as MediaItem$1 } from "./types-DSPGWjxO.mjs";
5
- import { r as AuthProviderDescriptor, t as AuthDescriptor } from "./types-Dryvv7LH.mjs";
6
- import { t as DatabaseDescriptor } from "./adapters-OQCImOL7.mjs";
7
- import { _ as MediaValue, m as MediaProviderDescriptor } from "./placeholder-CXfoCtCd.mjs";
8
- import { S as ContentBylineInput } from "./index-CwRuZ-u8.mjs";
9
- import { d as Storage } from "./types-DZpT-PnG.mjs";
10
- import { i as SiteSettings, r as SiteSettingKey } from "./types-nP9vGUFq.mjs";
11
- import { Kysely } from "kysely";
1
+ import { _ as UpdateFieldInput, f as FieldValidation, g as UpdateCollectionInput, i as CollectionWithFields, o as CreateCollectionInput, s as CreateFieldInput, t as Collection, u as Field } from "./types-DW_-sFyz.mjs";
2
+ import { f as UpdateContentInput, i as ContentItem, l as FindManyOptions, o as ContentSeoInput, r as ContentDateField, s as CreateContentInput, t as BylineSummary, u as FindManyResult } from "./types-C_ly5eTp.mjs";
3
+ import { t as Database } from "./types-DU0bU2Wu.mjs";
4
+ import { A as PageMetadataContribution, D as PageFragmentContribution, Dt as StandardPluginDefinition, F as PluginActor, G as PluginManifest, J as PluginMcpCommandTool, O as PageFragmentEvent, U as PluginDefinition, V as PluginCapability, X as PluginMcpExecutionContext, _ as FieldWidgetConfig, a as CommentAfterModerateEvent, at as PluginMcpTargetAuthorizer$1, et as PluginMcpResource, g as EmailMessage, gt as PortableTextBlockConfig, h as CronEvent, ht as PluginTargetScope, j as PageMetadataEvent, mt as PluginStorageConfig, ot as PluginMcpTool, r as CommentAfterCreateEvent, s as CommentBeforeCreateEvent, w as MediaItem$1, xt as ResolvedPlugin, yt as RequestMeta } from "./types-C8XW6L19.mjs";
5
+ import { d as Storage } from "./types-POH8PQZh.mjs";
6
+ import { r as AuthProviderDescriptor, t as AuthDescriptor } from "./types-Rc3gQqqw.mjs";
7
+ import { t as DatabaseDescriptor } from "./adapters-NVSs4UH7.mjs";
8
+ import { _ as MediaValue, m as MediaProviderDescriptor } from "./placeholder-uvNRZBX9.mjs";
9
+ import { r as ObjectCacheDescriptor } from "./types-DF7ZuGGk.mjs";
10
+ import { E as ContentBylineInput } from "./index-D4y6NGiy.mjs";
11
+ import { i as SiteSettings, r as SiteSettingKey } from "./types-C46EvNdc.mjs";
12
+ import { Dialect, Kysely, Transaction } from "kysely";
12
13
  import { z } from "astro/zod";
13
14
  import { z as z$1 } from "zod";
15
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
16
  import { LiveLoader } from "astro/loaders";
15
17
  import { MiddlewareHandler } from "astro";
16
18
 
@@ -227,6 +229,139 @@ interface DatabaseConfig {
227
229
  authToken?: string;
228
230
  }
229
231
  //#endregion
232
+ //#region src/loader.d.ts
233
+ /**
234
+ * Entry data type - generic object
235
+ */
236
+ type EntryData = Record<string, unknown>;
237
+ /**
238
+ * Sort direction
239
+ */
240
+ type SortDirection$1 = "asc" | "desc";
241
+ /**
242
+ * Order by specification - field name to direction
243
+ * @example { created_at: "desc" } - Sort by created_at descending
244
+ * @example { title: "asc" } - Sort by title ascending
245
+ */
246
+ type OrderBySpec$1 = Record<string, SortDirection$1>;
247
+ /**
248
+ * Range filter for comparison operators on field values.
249
+ * ISO 8601 timestamps sort lexicographically in the same order as time.
250
+ */
251
+ interface WhereRange {
252
+ gt?: string;
253
+ gte?: string;
254
+ lt?: string;
255
+ lte?: string;
256
+ }
257
+ type WhereValue = string | string[] | WhereRange;
258
+ /**
259
+ * Fields shared by every collection filter, independent of pagination mode.
260
+ */
261
+ interface CollectionFilterBase$1 {
262
+ type: string;
263
+ status?: "draft" | "published" | "archived";
264
+ limit?: number;
265
+ /**
266
+ * Filter by field values, taxonomy terms, byline credits, or ranges.
267
+ *
268
+ * Taxonomy names are detected automatically and filtered by term.
269
+ * The reserved `byline` key filters by byline credit in any position,
270
+ * not just the primary credit. Other keys are treated as content table
271
+ * column filters.
272
+ */
273
+ where?: Record<string, WhereValue>;
274
+ /** Case-insensitive substring search across the provided columns. */
275
+ q?: string;
276
+ searchColumns?: string[];
277
+ /**
278
+ * Order results by field(s)
279
+ * @default { created_at: "desc" }
280
+ */
281
+ orderBy?: OrderBySpec$1;
282
+ /**
283
+ * Filter by locale (e.g. 'en', 'fr').
284
+ * When set, only returns content in this locale.
285
+ */
286
+ locale?: string;
287
+ }
288
+ /** Keyset-paginated collection filter. Cannot also carry an offset. */
289
+ interface CursorCollectionFilter$1 extends CollectionFilterBase$1 {
290
+ /**
291
+ * Opaque cursor for keyset pagination.
292
+ * Pass the `nextCursor` value from a previous result to fetch the next page.
293
+ */
294
+ cursor?: string;
295
+ offset?: never;
296
+ }
297
+ /** Offset-paginated collection filter. Cannot also carry a cursor. */
298
+ interface OffsetCollectionFilter$1 extends CollectionFilterBase$1 {
299
+ /**
300
+ * Skip this many rows before returning results. Use with `limit` for numbered
301
+ * archives, for example `offset = (page - 1) * perPage`.
302
+ */
303
+ offset?: number;
304
+ cursor?: never;
305
+ }
306
+ /**
307
+ * Filter for loadCollection - type is required.
308
+ *
309
+ * Cursor and offset are mutually exclusive pagination modes. Runtime callers
310
+ * that supply both are treated as cursor-paginated so the two skips do not stack.
311
+ */
312
+ type CollectionFilter$1 = CursorCollectionFilter$1 | OffsetCollectionFilter$1;
313
+ /**
314
+ * Filter for loadEntry - type and id are required
315
+ */
316
+ interface EntryFilter {
317
+ type: string;
318
+ id: string;
319
+ /**
320
+ * When set, fetch content data from this revision instead of the content table.
321
+ * Used by preview mode to serve draft revision data.
322
+ */
323
+ revisionId?: string;
324
+ /**
325
+ * Locale to scope slug lookup. Only affects slug resolution;
326
+ * IDs are globally unique and always resolve regardless of locale.
327
+ */
328
+ locale?: string;
329
+ }
330
+ /**
331
+ * Get the database instance. Used by query wrapper functions and middleware.
332
+ *
333
+ * Checks the ALS request context first — if a per-request DB override is set
334
+ * (e.g. by preview or playground middleware), it takes precedence over the
335
+ * module-level cached instance. This allows preview flows to route queries
336
+ * to an isolated session database without modifying any calling code.
337
+ *
338
+ * Initializes the default database on first call using config from virtual module.
339
+ */
340
+ declare function getDb(): Promise<Kysely<Database>>;
341
+ /**
342
+ * Create a Dineway Live Collections loader
343
+ *
344
+ * This loader handles ALL content types in a single Astro collection.
345
+ * Use `getDinewayCollection()` and `getDinewayEntry()` to query
346
+ * specific content types.
347
+ *
348
+ * Database is configured in astro.config.mjs via the dineway() integration.
349
+ *
350
+ * @example
351
+ * ```ts
352
+ * // src/live.config.ts
353
+ * import { defineLiveCollection } from "astro:content";
354
+ * import { dinewayLoader } from "dineway";
355
+ *
356
+ * export const collections = {
357
+ * dineway: defineLiveCollection({
358
+ * loader: dinewayLoader(),
359
+ * }),
360
+ * };
361
+ * ```
362
+ */
363
+ declare function dinewayLoader(): LiveLoader<EntryData, EntryFilter, CollectionFilter$1>;
364
+ //#endregion
230
365
  //#region src/database/repositories/content.d.ts
231
366
  /**
232
367
  * Repository for content CRUD operations
@@ -301,7 +436,7 @@ declare class ContentRepository {
301
436
  /**
302
437
  * Restore content from trash
303
438
  */
304
- restore(type: string, id: string): Promise<boolean>;
439
+ restore(type: string, id: string): Promise<ContentItem | null>;
305
440
  /**
306
441
  * Permanently delete a soft-deleted content row.
307
442
  */
@@ -490,6 +625,8 @@ declare class MediaRepository {
490
625
  width?: number;
491
626
  height?: number;
492
627
  size?: number;
628
+ blurhash?: string;
629
+ dominantColor?: string;
493
630
  }): Promise<MediaItem | null>;
494
631
  /**
495
632
  * Mark upload as failed
@@ -561,6 +698,7 @@ interface PublicComment {
561
698
  isRegisteredUser: boolean;
562
699
  body: string;
563
700
  createdAt: string;
701
+ reactions?: Record<string, number>;
564
702
  replies?: PublicComment[];
565
703
  }
566
704
  //#endregion
@@ -806,12 +944,14 @@ declare function handleContentDuplicate(db: Kysely<Database>, collection: string
806
944
  */
807
945
  declare function handleContentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
808
946
  deleted: true;
947
+ id: string;
809
948
  }>>;
810
949
  /**
811
950
  * Restore content item from trash
812
951
  */
813
952
  declare function handleContentRestore(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
814
953
  restored: true;
954
+ item: ContentItem;
815
955
  }>>;
816
956
  /**
817
957
  * Permanently delete content item (cannot be undone).
@@ -819,6 +959,7 @@ declare function handleContentRestore(db: Kysely<Database>, collection: string,
819
959
  */
820
960
  declare function handleContentPermanentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
821
961
  deleted: true;
962
+ id: string;
822
963
  }>>;
823
964
  /**
824
965
  * List trashed content items
@@ -895,392 +1036,443 @@ declare function handleContentTranslations(db: Kysely<Database>, collection: str
895
1036
  }>;
896
1037
  }>>;
897
1038
  //#endregion
898
- //#region src/api/handlers/manifest.d.ts
899
- interface CollectionDefinition {
900
- schema: {
901
- _def?: {
902
- shape?: () => Record<string, unknown>;
903
- };
904
- shape?: Record<string, unknown>;
905
- };
906
- admin: {
907
- label: string;
908
- labelSingular?: string;
909
- supports?: string[];
910
- };
911
- }
912
- type CollectionMap = Record<string, CollectionDefinition>;
1039
+ //#region src/plugins/email.d.ts
913
1040
  /**
914
- * Generate admin manifest from collections
1041
+ * EmailPipeline orchestrates email delivery through the plugin hook system.
1042
+ *
1043
+ * The pipeline runs in three stages:
1044
+ * 1. email:beforeSend — middleware hooks that can transform or cancel messages
1045
+ * 2. email:deliver — exclusive hook dispatching to the selected provider
1046
+ * 3. email:afterSend — fire-and-forget hooks for logging/analytics
915
1047
  */
916
- declare function generateManifest(collections: CollectionMap, plugins?: Record<string, {
917
- adminPages?: Array<{
918
- path: string;
919
- component: string;
920
- }>;
921
- widgets?: string[];
922
- }>): Promise<ManifestResponse>;
1048
+ declare class EmailPipeline {
1049
+ private pipeline;
1050
+ constructor(pipeline: HookPipeline);
1051
+ /**
1052
+ * Replace the underlying hook pipeline.
1053
+ *
1054
+ * Called by the runtime when rebuilding the hook pipeline after a
1055
+ * plugin is enabled or disabled, so the email pipeline dispatches
1056
+ * to the current set of active hooks.
1057
+ */
1058
+ setPipeline(pipeline: HookPipeline): void;
1059
+ /**
1060
+ * Send an email through the full pipeline.
1061
+ *
1062
+ * @param message - The email to send
1063
+ * @param source - Where the email originated ("system" for auth, plugin ID for plugins)
1064
+ * @throws EmailNotConfiguredError if no provider is selected
1065
+ * @throws EmailRecursionError if called re-entrantly from within a hook
1066
+ * @throws Error if the provider handler throws
1067
+ */
1068
+ send(message: EmailMessage, source: string): Promise<void>;
1069
+ /**
1070
+ * Inner send implementation, separated from the recursion guard.
1071
+ */
1072
+ private sendInner;
1073
+ /**
1074
+ * Check if an email provider is configured and available.
1075
+ *
1076
+ * Returns true if an email:deliver provider is selected in the exclusive
1077
+ * hook system. Plugins and auth code use this to decide whether to show
1078
+ * "send invite" vs "copy invite link" UI.
1079
+ */
1080
+ isAvailable(): boolean;
1081
+ }
923
1082
  //#endregion
924
- //#region src/api/handlers/revision.d.ts
925
- interface RevisionListResponse {
926
- items: Revision[];
927
- total: number;
1083
+ //#region src/plugins/context.d.ts
1084
+ /**
1085
+ * Options for creating site info
1086
+ */
1087
+ interface SiteInfoOptions {
1088
+ /** Site name from options table */
1089
+ siteName?: string;
1090
+ /** Site URL from options table or Astro config */
1091
+ siteUrl?: string;
1092
+ /** Site locale from options table */
1093
+ locale?: string;
928
1094
  }
929
- interface RevisionResponse {
930
- item: Revision;
1095
+ interface PluginContextFactoryOptions {
1096
+ db: Kysely<Database>;
1097
+ /**
1098
+ * Resolver for the current database connection. When omitted, `db` is used.
1099
+ * Runtime code provides this so plugin hooks and routes honor request-scoped
1100
+ * database overrides from preview/playground sidecars.
1101
+ */
1102
+ getDb?: () => Kysely<Database>;
1103
+ /**
1104
+ * Storage backend for direct media uploads.
1105
+ * If not provided, upload() will throw.
1106
+ */
1107
+ storage?: Storage;
1108
+ /**
1109
+ * Function to generate upload URLs for media.
1110
+ * If not provided, media write operations will throw.
1111
+ */
1112
+ getUploadUrl?: (filename: string, contentType: string) => Promise<{
1113
+ uploadUrl: string;
1114
+ mediaId: string;
1115
+ }>;
1116
+ /**
1117
+ * Site information for ctx.site and ctx.url().
1118
+ * If not provided, site info will have empty defaults.
1119
+ */
1120
+ siteInfo?: SiteInfoOptions;
1121
+ /**
1122
+ * Callback to notify the cron scheduler that the next due time may have changed.
1123
+ * If not provided, ctx.cron will not be available.
1124
+ */
1125
+ cronReschedule?: () => void;
1126
+ /**
1127
+ * Email pipeline instance for ctx.email.
1128
+ * If not provided (or no provider configured), ctx.email will be undefined.
1129
+ */
1130
+ emailPipeline?: EmailPipeline;
1131
+ /**
1132
+ * Trusted reverse-proxy headers for request metadata IP extraction.
1133
+ */
1134
+ trustedProxyHeaders?: string[];
931
1135
  }
1136
+ //#endregion
1137
+ //#region src/plugins/hooks.d.ts
1138
+ type HookNameV2 = "plugin:install" | "plugin:activate" | "plugin:deactivate" | "plugin:uninstall" | "content:beforeSave" | "content:afterSave" | "content:beforeDelete" | "content:afterDelete" | "content:afterPublish" | "content:afterUnpublish" | "content:afterRestore" | "content:afterSchedule" | "content:afterUnschedule" | "media:beforeUpload" | "media:afterUpload" | "cron" | "email:beforeSend" | "email:deliver" | "email:afterSend" | "comment:beforeCreate" | "comment:moderate" | "comment:afterCreate" | "comment:afterModerate" | "page:metadata" | "page:fragments";
932
1139
  /**
933
- * List revisions for a content entry
1140
+ * Hook execution result
934
1141
  */
935
- declare function handleRevisionList(db: Kysely<Database>, collection: string, entryId: string, params?: {
936
- limit?: number;
937
- }): Promise<ApiResult<RevisionListResponse>>;
1142
+ interface HookResult<T> {
1143
+ success: boolean;
1144
+ value?: T;
1145
+ error?: Error;
1146
+ pluginId: string;
1147
+ duration: number;
1148
+ }
938
1149
  /**
939
- * Get a specific revision
1150
+ * Hook pipeline for executing hooks in order
940
1151
  */
941
- declare function handleRevisionGet(db: Kysely<Database>, revisionId: string): Promise<ApiResult<RevisionResponse>>;
942
- /**
943
- * Restore a revision (updates content to this revision's data and creates new revision)
944
- */
945
- declare function handleRevisionRestore(db: Kysely<Database>, revisionId: string, callerUserId: string): Promise<ApiResult<ContentResponse>>;
946
- //#endregion
947
- //#region src/api/handlers/media.d.ts
948
- interface MediaListResponse {
949
- items: MediaItem[];
950
- nextCursor?: string;
951
- }
952
- interface MediaResponse {
953
- item: MediaItem;
954
- }
955
- /**
956
- * List media items
957
- */
958
- declare function handleMediaList(db: Kysely<Database>, params: {
959
- cursor?: string;
960
- limit?: number;
961
- mimeType?: string | readonly string[];
962
- q?: string;
963
- }): Promise<ApiResult<MediaListResponse>>;
964
- /**
965
- * Get single media item
966
- */
967
- declare function handleMediaGet(db: Kysely<Database>, id: string): Promise<ApiResult<MediaResponse>>;
968
- /**
969
- * Create media item (after file upload)
970
- */
971
- declare function handleMediaCreate(db: Kysely<Database>, input: {
972
- filename: string;
973
- mimeType: string;
974
- size?: number;
975
- width?: number;
976
- height?: number;
977
- alt?: string;
978
- storageKey: string;
979
- contentHash?: string;
980
- blurhash?: string;
981
- dominantColor?: string;
982
- authorId?: string;
983
- }): Promise<ApiResult<MediaResponse>>;
984
- /**
985
- * Update media metadata
986
- */
987
- declare function handleMediaUpdate(db: Kysely<Database>, id: string, input: {
988
- alt?: string;
989
- caption?: string;
990
- width?: number;
991
- height?: number;
992
- }): Promise<ApiResult<MediaResponse>>;
993
- /**
994
- * Delete media item
995
- */
996
- declare function handleMediaDelete(db: Kysely<Database>, id: string): Promise<ApiResult<{
997
- deleted: true;
998
- }>>;
999
- //#endregion
1000
- //#region src/schema/registry.d.ts
1001
- /**
1002
- * Error thrown when a schema operation fails
1003
- */
1004
- declare class SchemaError extends Error {
1005
- code: string;
1006
- details?: Record<string, unknown> | undefined;
1007
- constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
1008
- }
1009
- /**
1010
- * Schema Registry
1011
- *
1012
- * Manages collection and field definitions stored in the database.
1013
- * Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).
1014
- */
1015
- declare class SchemaRegistry {
1016
- private db;
1017
- constructor(db: Kysely<Database>);
1152
+ declare class HookPipeline {
1153
+ private hooks;
1154
+ private pluginMap;
1155
+ private contextFactory;
1156
+ /** Stored so setContextFactory can merge incrementally. */
1157
+ private contextFactoryOptions;
1158
+ /** Hook names where at least one handler declared exclusive: true */
1159
+ private exclusiveHookNames;
1018
1160
  /**
1019
- * List all collections
1161
+ * Selected provider plugin ID for each exclusive hook.
1162
+ * Set by the PluginManager after resolution.
1020
1163
  */
1021
- listCollections(): Promise<Collection[]>;
1164
+ private exclusiveSelections;
1165
+ constructor(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions);
1022
1166
  /**
1023
- * List all collections with their fields using bounded query shapes.
1167
+ * Set or update the context factory options.
1168
+ *
1169
+ * When called on a pipeline that already has a factory, the new options
1170
+ * are merged on top of the existing ones so that callers don't need to
1171
+ * repeat every field (e.g. adding `cronReschedule` without losing
1172
+ * `storage` / `getUploadUrl`).
1024
1173
  */
1025
- listCollectionsWithFields(): Promise<CollectionWithFields[]>;
1174
+ setContextFactory(options: Partial<PluginContextFactoryOptions>): void;
1026
1175
  /**
1027
- * Get a collection by slug
1176
+ * Get context for a plugin
1028
1177
  */
1029
- getCollection(slug: string): Promise<Collection | null>;
1178
+ private getContext;
1030
1179
  /**
1031
- * Get a collection with all its fields
1180
+ * Get typed hooks for a specific hook name.
1181
+ * The internal map stores ResolvedHook<unknown>, but we know each name
1182
+ * maps to a specific handler type via HookHandlerMap.
1183
+ *
1184
+ * Exclusive hooks that have a selected provider are filtered out — they
1185
+ * should only run via invokeExclusiveHook(), not in the regular pipeline.
1032
1186
  */
1033
- getCollectionWithFields(slug: string): Promise<CollectionWithFields | null>;
1187
+ private getTypedHooks;
1034
1188
  /**
1035
- * Create a new collection
1189
+ * Register all hooks from plugins.
1190
+ *
1191
+ * Registers each hook name individually to preserve type safety. The
1192
+ * internal map stores ResolvedHook<unknown> since it's keyed by string,
1193
+ * but getTypedHooks() restores the correct handler type on retrieval.
1036
1194
  */
1037
- createCollection(input: CreateCollectionInput): Promise<Collection>;
1195
+ private registerPlugins;
1038
1196
  /**
1039
- * Update a collection
1197
+ * Maps hook names to the capability required to register them.
1198
+ *
1199
+ * Hooks not listed here have no capability requirement (e.g. lifecycle
1200
+ * hooks, cron). Any plugin declaring a listed hook without the required
1201
+ * capability will have that hook silently skipped at registration time.
1040
1202
  */
1041
- updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection>;
1042
- private validateUrlPattern;
1043
- private checkLabelUniqueness;
1044
- private checkUrlPatternUniqueness;
1203
+ private static readonly HOOK_REQUIRED_CAPABILITY;
1045
1204
  /**
1046
- * Delete a collection
1205
+ * Register a single plugin's hook by name
1047
1206
  */
1048
- deleteCollection(slug: string, options?: {
1049
- force?: boolean;
1050
- }): Promise<void>;
1207
+ private registerPluginHook;
1051
1208
  /**
1052
- * List fields for a collection
1209
+ * Register a single hook
1053
1210
  */
1054
- listFields(collectionId: string): Promise<Field[]>;
1211
+ private registerHook;
1055
1212
  /**
1056
- * Get a field by slug within a collection
1213
+ * Sort hooks by priority and dependencies
1057
1214
  */
1058
- getField(collectionSlug: string, fieldSlug: string): Promise<Field | null>;
1215
+ private sortHooks;
1059
1216
  /**
1060
- * Create a new field
1217
+ * Execute a hook with timeout
1061
1218
  */
1062
- createField(collectionSlug: string, input: CreateFieldInput): Promise<Field>;
1219
+ private executeWithTimeout;
1063
1220
  /**
1064
- * Ensure the content table for an existing collection exists.
1065
- *
1066
- * This repairs interrupted schema creation where the metadata row exists but
1067
- * the physical `ec_*` table was not created.
1221
+ * Run plugin:install hooks
1068
1222
  */
1069
- ensureCollectionContentTable(collectionSlug: string): Promise<boolean>;
1223
+ runPluginInstall(pluginId: string): Promise<HookResult<void>[]>;
1070
1224
  /**
1071
- * Ensure the physical column for an existing field exists on its content table.
1072
- *
1073
- * This repairs interrupted field creation where `_dineway_fields` was written
1074
- * but `ALTER TABLE ec_* ADD COLUMN` did not complete.
1225
+ * Run plugin:activate hooks
1075
1226
  */
1076
- ensureFieldColumn(collectionSlug: string, fieldSlug: string): Promise<boolean>;
1227
+ runPluginActivate(pluginId: string): Promise<HookResult<void>[]>;
1077
1228
  /**
1078
- * Update a field
1229
+ * Run plugin:deactivate hooks
1079
1230
  */
1080
- updateField(collectionSlug: string, fieldSlug: string, input: UpdateFieldInput): Promise<Field>;
1231
+ runPluginDeactivate(pluginId: string): Promise<HookResult<void>[]>;
1081
1232
  /**
1082
- * Synchronize an existing FTS index with the collection's current state.
1083
- *
1084
- * Schema writes must not first-time enable FTS. Initial enablement stays in
1085
- * explicit seed/import/admin flows where FTS failures can be handled deliberately.
1233
+ * Run plugin:uninstall hooks
1086
1234
  */
1087
- private syncSearchState;
1235
+ runPluginUninstall(pluginId: string, deleteData: boolean): Promise<HookResult<void>[]>;
1236
+ private runLifecycleHook;
1088
1237
  /**
1089
- * Delete a field
1238
+ * Run content:beforeSave hooks
1239
+ * Returns modified content from the pipeline
1090
1240
  */
1091
- deleteField(collectionSlug: string, fieldSlug: string): Promise<void>;
1241
+ runContentBeforeSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<{
1242
+ content: Record<string, unknown>;
1243
+ results: HookResult<Record<string, unknown>>[];
1244
+ }>;
1092
1245
  /**
1093
- * Reorder fields
1246
+ * Run content:afterSave hooks
1094
1247
  */
1095
- reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void>;
1248
+ runContentAfterSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<HookResult<void>[]>;
1096
1249
  /**
1097
- * Create a content table for a collection
1250
+ * Run content:beforeDelete hooks
1251
+ * Returns whether deletion is allowed
1098
1252
  */
1099
- private createContentTable;
1253
+ runContentBeforeDelete(id: string, collection: string): Promise<{
1254
+ allowed: boolean;
1255
+ results: HookResult<boolean>[];
1256
+ }>;
1100
1257
  /**
1101
- * Drop a content table
1258
+ * Run content:afterDelete hooks
1102
1259
  */
1103
- private dropContentTable;
1260
+ runContentAfterDelete(id: string, collection: string, permanent: boolean): Promise<HookResult<void>[]>;
1104
1261
  /**
1105
- * Add a column to a content table
1262
+ * Run content:afterPublish hooks (fire-and-forget).
1106
1263
  */
1107
- private addColumn;
1264
+ runContentAfterPublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1108
1265
  /**
1109
- * Drop a column from a content table
1266
+ * Run content:afterUnpublish hooks (fire-and-forget).
1110
1267
  */
1111
- private dropColumn;
1268
+ runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1112
1269
  /**
1113
- * Check if a collection has any content
1270
+ * Run content:afterRestore hooks (fire-and-forget).
1114
1271
  */
1115
- private collectionHasContent;
1272
+ runContentAfterRestore(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1116
1273
  /**
1117
- * Get table name for a collection
1274
+ * Run content:afterSchedule hooks (fire-and-forget).
1118
1275
  */
1119
- private getTableName;
1276
+ runContentAfterSchedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1120
1277
  /**
1121
- * Get column name for a field
1278
+ * Run content:afterUnschedule hooks (fire-and-forget).
1122
1279
  */
1123
- private getColumnName;
1280
+ runContentAfterUnschedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1281
+ private runContentStateChangeHook;
1124
1282
  /**
1125
- * Validate a slug
1283
+ * Run media:beforeUpload hooks
1126
1284
  */
1127
- private validateSlug;
1285
+ runMediaBeforeUpload(file: {
1286
+ name: string;
1287
+ type: string;
1288
+ size: number;
1289
+ }): Promise<{
1290
+ file: {
1291
+ name: string;
1292
+ type: string;
1293
+ size: number;
1294
+ };
1295
+ results: HookResult<{
1296
+ name: string;
1297
+ type: string;
1298
+ size: number;
1299
+ }>[];
1300
+ }>;
1128
1301
  /**
1129
- * Format a default value for SQL.
1130
- *
1131
- * SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant
1132
- * expression — parameterized values cannot be used here. We manually escape
1133
- * single quotes and coerce types to ensure the output is safe.
1134
- *
1135
- * INTEGER/REAL values are coerced through `Number()` which can only produce
1136
- * digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.
1137
- * TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).
1302
+ * Run media:afterUpload hooks
1138
1303
  */
1139
- private formatDefaultValue;
1304
+ runMediaAfterUpload(media: {
1305
+ id: string;
1306
+ filename: string;
1307
+ mimeType: string;
1308
+ size: number | null;
1309
+ url: string;
1310
+ createdAt: string;
1311
+ }): Promise<HookResult<void>[]>;
1140
1312
  /**
1141
- * Get empty default for a field type
1313
+ * Invoke the cron hook for a specific plugin.
1314
+ *
1315
+ * Unlike other hooks which broadcast to all plugins, the cron hook is
1316
+ * dispatched only to the target plugin — the one that owns the task.
1142
1317
  */
1143
- private getEmptyDefault;
1318
+ invokeCronHook(pluginId: string, event: CronEvent): Promise<HookResult<void>>;
1144
1319
  /**
1145
- * Map a collection row to a Collection object
1320
+ * Run email:beforeSend hooks (middleware pipeline).
1321
+ *
1322
+ * Each handler receives the message and returns a modified message or
1323
+ * `false` to cancel delivery. The pipeline chains message transformations —
1324
+ * each handler receives the output of the previous one.
1146
1325
  */
1147
- private mapCollectionRow;
1326
+ runEmailBeforeSend(message: EmailMessage, source: string): Promise<{
1327
+ message: EmailMessage | false;
1328
+ results: HookResult<EmailMessage | false>[];
1329
+ }>;
1148
1330
  /**
1149
- * Map a field row to a Field object
1331
+ * Run email:afterSend hooks (fire-and-forget).
1332
+ *
1333
+ * Errors are logged but don't propagate — they don't affect the caller.
1150
1334
  */
1151
- private mapFieldRow;
1335
+ runEmailAfterSend(message: EmailMessage, source: string): Promise<HookResult<void>[]>;
1152
1336
  /**
1153
- * Discover orphaned content tables
1337
+ * Run comment:beforeCreate hooks (middleware pipeline).
1154
1338
  *
1155
- * Finds ec_* tables that exist in the database but don't have a
1156
- * corresponding entry in _dineway_collections.
1339
+ * Each handler receives the event and returns a modified event or
1340
+ * `false` to reject the comment. The pipeline chains transformations —
1341
+ * each handler receives the output of the previous one.
1157
1342
  */
1158
- discoverOrphanedTables(): Promise<Array<{
1159
- slug: string;
1160
- tableName: string;
1161
- rowCount: number;
1162
- }>>;
1343
+ runCommentBeforeCreate(event: CommentBeforeCreateEvent): Promise<CommentBeforeCreateEvent | false>;
1163
1344
  /**
1164
- * Register an orphaned table as a collection
1345
+ * Run comment:afterCreate hooks (fire-and-forget).
1165
1346
  *
1166
- * Creates a _dineway_collections entry for an existing ec_* table.
1347
+ * Errors are logged but don't propagate — they don't affect the caller.
1167
1348
  */
1168
- registerOrphanedTable(slug: string, options?: {
1169
- label?: string;
1170
- labelSingular?: string;
1171
- description?: string;
1172
- }): Promise<Collection>;
1349
+ runCommentAfterCreate(event: CommentAfterCreateEvent): Promise<void>;
1173
1350
  /**
1174
- * Convert slug to human-readable label
1351
+ * Run comment:afterModerate hooks (fire-and-forget).
1352
+ *
1353
+ * Errors are logged but don't propagate — they don't affect the caller.
1175
1354
  */
1176
- private slugToLabel;
1355
+ runCommentAfterModerate(event: CommentAfterModerateEvent): Promise<void>;
1356
+ /**
1357
+ * Run page:metadata hooks. Each handler returns contributions that are
1358
+ * merged by the metadata collector. Errors are logged but don't propagate.
1359
+ */
1360
+ runPageMetadata(event: PageMetadataEvent): Promise<Array<{
1361
+ pluginId: string;
1362
+ contributions: PageMetadataContribution[];
1363
+ }>>;
1364
+ /**
1365
+ * Run page:fragments hooks. Only trusted plugins should be registered
1366
+ * for this hook. Errors are logged but don't propagate.
1367
+ */
1368
+ runPageFragments(event: PageFragmentEvent): Promise<Array<{
1369
+ pluginId: string;
1370
+ contributions: PageFragmentContribution[];
1371
+ }>>;
1372
+ /**
1373
+ * Check if any hooks are registered for a given name
1374
+ */
1375
+ hasHooks(name: HookNameV2): boolean;
1376
+ /**
1377
+ * Get hook count for debugging
1378
+ */
1379
+ getHookCount(name: HookNameV2): number;
1380
+ /**
1381
+ * Get all registered hook names
1382
+ */
1383
+ getRegisteredHooks(): HookNameV2[];
1384
+ /**
1385
+ * Returns hook names where at least one handler declared exclusive: true
1386
+ */
1387
+ getRegisteredExclusiveHooks(): string[];
1388
+ /**
1389
+ * Check if a hook is exclusive
1390
+ */
1391
+ isExclusiveHook(name: string): boolean;
1392
+ /**
1393
+ * Set the selected provider for an exclusive hook.
1394
+ * Called by PluginManager after resolution.
1395
+ */
1396
+ setExclusiveSelection(hookName: string, pluginId: string): void;
1397
+ /**
1398
+ * Clear the selected provider for an exclusive hook.
1399
+ */
1400
+ clearExclusiveSelection(hookName: string): void;
1401
+ /**
1402
+ * Get the selected provider for an exclusive hook (if any).
1403
+ */
1404
+ getExclusiveSelection(hookName: string): string | undefined;
1405
+ /**
1406
+ * Get all plugins that registered a handler for a given exclusive hook.
1407
+ */
1408
+ getExclusiveHookProviders(hookName: string): Array<{
1409
+ pluginId: string;
1410
+ }>;
1411
+ /**
1412
+ * Get all plugins that registered a non-exclusive handler for a given hook,
1413
+ * preserving priority order. This partitions with getExclusiveHookProviders().
1414
+ */
1415
+ getHookProviders(hookName: string): Array<{
1416
+ pluginId: string;
1417
+ }>;
1418
+ /**
1419
+ * Invoke an exclusive hook — dispatch only to the selected provider.
1420
+ * Returns null if no provider is selected or if the selected hook
1421
+ * is not found in the pipeline.
1422
+ *
1423
+ * This is a generic dispatch used by the email pipeline and other
1424
+ * exclusive hook consumers. The handler type is unknown — callers
1425
+ * must know the expected signature.
1426
+ *
1427
+ * Errors are isolated: a failing handler returns an error result
1428
+ * instead of propagating the exception to the caller.
1429
+ */
1430
+ invokeExclusiveHook(hookName: string, event: unknown): Promise<{
1431
+ result: unknown;
1432
+ pluginId: string;
1433
+ error?: Error;
1434
+ duration: number;
1435
+ } | null>;
1177
1436
  }
1178
- //#endregion
1179
- //#region src/schema/query.d.ts
1180
1437
  /**
1181
- * Get collection metadata by slug.
1182
- *
1183
- * @example
1184
- * ```ts
1185
- * import { getCollectionInfo } from "dineway";
1186
- *
1187
- * const info = await getCollectionInfo("posts");
1188
- * if (info?.commentsEnabled) {
1189
- * // render comment UI
1190
- * }
1191
- * ```
1438
+ * Create a hook pipeline from plugins
1192
1439
  */
1193
- declare function getCollectionInfo(slug: string): Promise<Collection | null>;
1440
+ declare function createHookPipeline(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions): HookPipeline;
1194
1441
  //#endregion
1195
- //#region src/sections/types.d.ts
1196
- /**
1197
- * Section source types
1198
- */
1199
- type SectionSource = "theme" | "user" | "import";
1200
- /**
1201
- * Section as returned to templates/admin
1202
- */
1203
- interface Section {
1204
- id: string;
1205
- slug: string;
1206
- title: string;
1207
- description?: string;
1208
- keywords: string[];
1209
- content: PortableTextBlock$1[];
1210
- previewUrl?: string;
1211
- source: SectionSource;
1212
- themeId?: string;
1213
- createdAt: string;
1214
- updatedAt: string;
1215
- }
1216
- /**
1217
- * Input for creating a section
1218
- */
1219
- interface CreateSectionInput {
1220
- slug: string;
1221
- title: string;
1222
- description?: string;
1223
- keywords?: string[];
1224
- content: PortableTextBlock$1[];
1225
- previewMediaId?: string;
1226
- source?: SectionSource;
1227
- themeId?: string;
1228
- }
1229
- /**
1230
- * Input for updating a section
1231
- */
1232
- interface UpdateSectionInput {
1233
- slug?: string;
1234
- title?: string;
1235
- description?: string;
1236
- keywords?: string[];
1237
- content?: PortableTextBlock$1[];
1238
- previewMediaId?: string | null;
1239
- }
1240
- /**
1241
- * Options for querying sections
1242
- */
1243
- interface GetSectionsOptions {
1244
- /** Filter by source */
1245
- source?: SectionSource;
1246
- /** Search title, description, keywords */
1247
- search?: string;
1248
- /** Limit results */
1249
- limit?: number;
1250
- /** Cursor for pagination */
1251
- cursor?: string;
1442
+ //#region src/plugins/mcp.d.ts
1443
+ interface RegisteredPluginMcpTool {
1444
+ pluginId: string;
1445
+ pluginVersion: string;
1446
+ tool: PluginMcpTool;
1447
+ authorizeTarget?: PluginMcpTargetAuthorizer$1;
1252
1448
  }
1253
- //#endregion
1254
- //#region src/sections/index.d.ts
1255
- /**
1256
- * Get a section by slug
1257
- *
1258
- * @example
1259
- * ```ts
1260
- * import { getSection } from "dineway";
1261
- *
1262
- * const section = await getSection("hero-centered");
1263
- * if (section) {
1264
- * console.log(section.content); // Portable Text array
1265
- * }
1266
- * ```
1267
- */
1268
- declare function getSection(slug: string): Promise<Section | null>;
1269
- /**
1270
- * Get all sections with optional filtering
1271
- *
1272
- * @example
1273
- * ```ts
1274
- * import { getSections } from "dineway";
1275
- *
1276
- * // Get all theme-provided sections
1277
- * const themeSections = await getSections({ source: "theme" });
1278
- *
1279
- * // Search sections
1280
- * const results = await getSections({ search: "pricing" });
1281
- * ```
1282
- */
1283
- declare function getSections(options?: GetSectionsOptions): Promise<FindManyResult<Section>>;
1449
+ interface RegisteredPluginMcpResource {
1450
+ pluginId: string;
1451
+ pluginVersion: string;
1452
+ resource: PluginMcpResource;
1453
+ authorizeTarget?: PluginMcpTargetAuthorizer$1;
1454
+ }
1455
+ interface PluginMcpRegistry {
1456
+ tools: RegisteredPluginMcpTool[];
1457
+ resources: RegisteredPluginMcpResource[];
1458
+ }
1459
+ interface PluginMcpTargetAuthorizationRequest {
1460
+ restaurantPermission: string;
1461
+ target: PluginTargetScope;
1462
+ context: PluginMcpExecutionContext;
1463
+ }
1464
+ type PluginMcpTargetAuthorizer = (request: PluginMcpTargetAuthorizationRequest) => Promise<void>;
1465
+ interface PluginMcpReviewMetadata {
1466
+ hitlRequestId?: string;
1467
+ quickActionHash?: string;
1468
+ }
1469
+ interface PluginMcpCommandExecutionRequest {
1470
+ target?: PluginTargetScope;
1471
+ review: PluginMcpReviewMetadata;
1472
+ }
1473
+ type PluginMcpCommandExecutor = (command: RegisteredPluginMcpTool & {
1474
+ tool: PluginMcpCommandTool;
1475
+ }, input: Record<string, unknown>, context: PluginMcpExecutionContext, request: PluginMcpCommandExecutionRequest) => Promise<Record<string, unknown>>;
1284
1476
  //#endregion
1285
1477
  //#region src/plugins/sandbox/types.d.ts
1286
1478
  /**
@@ -1384,6 +1576,8 @@ interface SerializedRequest {
1384
1576
  headers: Record<string, string>;
1385
1577
  /** Normalized request metadata extracted before RPC serialization */
1386
1578
  meta: RequestMeta;
1579
+ /** Safe authenticated actor metadata; null for unauthenticated public routes. */
1580
+ actor?: PluginActor | null;
1387
1581
  }
1388
1582
  /**
1389
1583
  * Sandbox runner interface.
@@ -1430,1429 +1624,1654 @@ interface SandboxRunner {
1430
1624
  */
1431
1625
  type SandboxRunnerFactory = (options: SandboxOptions) => SandboxRunner;
1432
1626
  //#endregion
1433
- //#region src/content/converters/types.d.ts
1434
- /**
1435
- * Portable Text Types
1436
- *
1437
- * Defines the structure of Portable Text blocks used in Dineway.
1438
- */
1627
+ //#region src/plugins/routes.d.ts
1439
1628
  /**
1440
- * Base span (inline text)
1629
+ * Result from a route invocation
1441
1630
  */
1442
- interface PortableTextSpan {
1443
- _type: "span";
1444
- _key: string;
1445
- text: string;
1446
- marks?: string[];
1631
+ interface RouteResult<T = unknown> {
1632
+ success: boolean;
1633
+ data?: T;
1634
+ error?: {
1635
+ code: string;
1636
+ message: string;
1637
+ details?: unknown;
1638
+ };
1639
+ status: number;
1447
1640
  }
1448
1641
  /**
1449
- * Mark definition (bold, italic, link, etc.)
1642
+ * Route invocation options
1450
1643
  */
1451
- interface PortableTextMarkDef {
1452
- _type: string;
1453
- _key: string;
1454
- [key: string]: unknown;
1644
+ interface InvokeRouteOptions {
1645
+ /** The original request */
1646
+ request: Request;
1647
+ /** Request body (already parsed) */
1648
+ body?: unknown;
1649
+ /** Exact request bytes for routes that declare body: "raw". */
1650
+ rawBody?: Uint8Array;
1651
+ /** Normalized authenticated actor supplied by the core route boundary. */
1652
+ actor?: PluginActor | null;
1455
1653
  }
1456
1654
  /**
1457
- * Link mark definition
1655
+ * Error class for plugin routes
1656
+ * Allows plugins to return structured errors with specific HTTP status codes
1458
1657
  */
1459
- interface PortableTextLinkMark extends PortableTextMarkDef {
1460
- _type: "link";
1461
- href: string;
1462
- blank?: boolean;
1658
+ declare class PluginRouteError extends Error {
1659
+ code: string;
1660
+ status: number;
1661
+ details?: unknown | undefined;
1662
+ constructor(code: string, message: string, status?: number, details?: unknown | undefined);
1663
+ /**
1664
+ * Create a bad request error (400)
1665
+ */
1666
+ static badRequest(message: string, details?: unknown): PluginRouteError;
1667
+ /**
1668
+ * Create an unauthorized error (401)
1669
+ */
1670
+ static unauthorized(message?: string): PluginRouteError;
1671
+ /**
1672
+ * Create a forbidden error (403)
1673
+ */
1674
+ static forbidden(message?: string): PluginRouteError;
1675
+ /**
1676
+ * Create a not found error (404)
1677
+ */
1678
+ static notFound(message?: string): PluginRouteError;
1679
+ /**
1680
+ * Create a conflict error (409)
1681
+ */
1682
+ static conflict(message: string, details?: unknown): PluginRouteError;
1683
+ /**
1684
+ * Create an internal error (500)
1685
+ */
1686
+ static internal(message?: string): PluginRouteError;
1463
1687
  }
1464
- /**
1465
- * Text block (paragraph, heading, etc.)
1466
- */
1467
- interface PortableTextTextBlock {
1468
- _type: "block";
1469
- _key: string;
1470
- style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote";
1471
- listItem?: "bullet" | "number";
1472
- level?: number;
1473
- children: PortableTextSpan[];
1474
- markDefs?: PortableTextMarkDef[];
1688
+ //#endregion
1689
+ //#region src/plugins/sandbox/runtime-options.d.ts
1690
+ interface SandboxRunnerRuntimeOptions extends SandboxOptions {
1691
+ mediaStorage?: Storage;
1692
+ cronReschedule?: () => void;
1475
1693
  }
1694
+ //#endregion
1695
+ //#region src/dineway-runtime.d.ts
1476
1696
  /**
1477
- * Image block
1697
+ * Sandboxed plugin entry from virtual module
1478
1698
  */
1479
- interface PortableTextImageBlock {
1480
- _type: "image";
1481
- _key: string;
1482
- asset: {
1483
- _ref: string;
1484
- url?: string; /** Provider ID for external media (e.g., "image-cdn") */
1485
- provider?: string;
1699
+ interface SandboxedPluginEntry {
1700
+ id: string;
1701
+ version: string;
1702
+ options: Record<string, unknown>;
1703
+ code: string;
1704
+ /** Capabilities the plugin requests */
1705
+ capabilities: PluginCapability[];
1706
+ /** Allowed hosts for network:request */
1707
+ allowedHosts: string[];
1708
+ /** Declared storage collections */
1709
+ storage: PluginStorageConfig;
1710
+ /** Admin pages */
1711
+ adminPages?: Array<{
1712
+ path: string;
1713
+ label?: string;
1714
+ icon?: string;
1715
+ }>;
1716
+ /** Dashboard widgets */
1717
+ adminWidgets?: Array<{
1718
+ id: string;
1719
+ title?: string;
1720
+ size?: string;
1721
+ }>;
1722
+ /** Portable Text block types contributed to the editor through declarative Block Kit. */
1723
+ portableTextBlocks?: PortableTextBlockConfig[];
1724
+ /** Field widget types contributed for schema-field editing UIs. */
1725
+ fieldWidgets?: FieldWidgetConfig[];
1726
+ /** Admin entry module */
1727
+ adminEntry?: string;
1728
+ /**
1729
+ * Exclusive hooks this plugin should be auto-selected for.
1730
+ * Weaker than an existing admin DB selection — config order wins when no selection exists.
1731
+ */
1732
+ preferred?: string[];
1733
+ }
1734
+ //#endregion
1735
+ //#region src/api/handlers/manifest.d.ts
1736
+ interface CollectionDefinition {
1737
+ schema: {
1738
+ _def?: {
1739
+ shape?: () => Record<string, unknown>;
1740
+ };
1741
+ shape?: Record<string, unknown>;
1742
+ };
1743
+ admin: {
1744
+ label: string;
1745
+ labelSingular?: string;
1746
+ supports?: string[];
1486
1747
  };
1487
- alt?: string;
1488
- caption?: string;
1489
- /** Original image width */
1490
- width?: number;
1491
- /** Original image height */
1492
- height?: number;
1493
- /** Display width for this instance (overrides original) */
1494
- displayWidth?: number;
1495
- /** Display height for this instance (overrides original) */
1496
- displayHeight?: number;
1497
1748
  }
1749
+ type CollectionMap = Record<string, CollectionDefinition>;
1498
1750
  /**
1499
- * Code block
1751
+ * Generate admin manifest from collections
1500
1752
  */
1501
- interface PortableTextCodeBlock {
1502
- _type: "code";
1503
- _key: string;
1504
- code: string;
1505
- language?: string;
1506
- filename?: string;
1753
+ declare function generateManifest(collections: CollectionMap, plugins?: Record<string, {
1754
+ adminPages?: Array<{
1755
+ path: string;
1756
+ component: string;
1757
+ }>;
1758
+ widgets?: string[];
1759
+ }>): Promise<ManifestResponse>;
1760
+ //#endregion
1761
+ //#region src/api/handlers/revision.d.ts
1762
+ interface RevisionListResponse {
1763
+ items: Revision[];
1764
+ total: number;
1507
1765
  }
1508
- /**
1509
- * HTML block (raw HTML content)
1510
- */
1511
- interface PortableTextHtmlBlock {
1512
- _type: "htmlBlock";
1513
- _key: string;
1514
- html: string;
1766
+ interface RevisionResponse {
1767
+ item: Revision;
1515
1768
  }
1516
1769
  /**
1517
- * Unknown/custom block (preserved for plugin compatibility)
1770
+ * List revisions for a content entry
1518
1771
  */
1519
- interface PortableTextUnknownBlock {
1520
- _type: string;
1521
- _key: string;
1522
- [key: string]: unknown;
1523
- }
1772
+ declare function handleRevisionList(db: Kysely<Database>, collection: string, entryId: string, params?: {
1773
+ limit?: number;
1774
+ }): Promise<ApiResult<RevisionListResponse>>;
1524
1775
  /**
1525
- * Any Portable Text block
1776
+ * Get a specific revision
1526
1777
  */
1527
- type PortableTextBlock = PortableTextTextBlock | PortableTextImageBlock | PortableTextCodeBlock | PortableTextHtmlBlock | PortableTextUnknownBlock;
1778
+ declare function handleRevisionGet(db: Kysely<Database>, revisionId: string): Promise<ApiResult<RevisionResponse>>;
1528
1779
  /**
1529
- * ProseMirror JSON types (simplified for TipTap)
1780
+ * Restore a revision (updates content to this revision's data and creates new revision)
1530
1781
  */
1531
- interface ProseMirrorMark {
1532
- type: string;
1533
- attrs?: Record<string, unknown>;
1534
- }
1535
- interface ProseMirrorNode {
1536
- type: string;
1537
- attrs?: Record<string, unknown>;
1538
- content?: ProseMirrorNode[];
1539
- marks?: ProseMirrorMark[];
1540
- text?: string;
1782
+ declare function handleRevisionRestore(db: Kysely<Database>, revisionId: string, callerUserId: string): Promise<ApiResult<ContentResponse>>;
1783
+ //#endregion
1784
+ //#region src/api/handlers/media.d.ts
1785
+ interface MediaListResponse {
1786
+ items: MediaItem[];
1787
+ nextCursor?: string;
1541
1788
  }
1542
- interface ProseMirrorDocument {
1543
- type: "doc";
1544
- content: ProseMirrorNode[];
1789
+ interface MediaResponse {
1790
+ item: MediaItem;
1545
1791
  }
1546
- //#endregion
1547
- //#region src/content/converters/prosemirror-to-portable-text.d.ts
1548
1792
  /**
1549
- * Convert ProseMirror document to Portable Text
1793
+ * List media items
1550
1794
  */
1551
- declare function prosemirrorToPortableText(doc: ProseMirrorDocument): PortableTextBlock[];
1552
- //#endregion
1553
- //#region src/content/converters/portable-text-to-prosemirror.d.ts
1795
+ declare function handleMediaList(db: Kysely<Database>, params: {
1796
+ cursor?: string;
1797
+ limit?: number;
1798
+ mimeType?: string | readonly string[];
1799
+ q?: string;
1800
+ }): Promise<ApiResult<MediaListResponse>>;
1554
1801
  /**
1555
- * Convert Portable Text to ProseMirror document
1802
+ * Get single media item
1556
1803
  */
1557
- declare function portableTextToProsemirror(blocks: PortableTextBlock[]): ProseMirrorDocument;
1558
- //#endregion
1559
- //#region src/utils/hash.d.ts
1804
+ declare function handleMediaGet(db: Kysely<Database>, id: string): Promise<ApiResult<MediaResponse>>;
1560
1805
  /**
1561
- * SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
1562
- * For cache invalidation / ETags — not for security.
1806
+ * Create media item (after file upload)
1563
1807
  */
1564
- declare function hashString(content: string): Promise<string>;
1808
+ declare function handleMediaCreate(db: Kysely<Database>, input: {
1809
+ filename: string;
1810
+ mimeType: string;
1811
+ size?: number;
1812
+ width?: number;
1813
+ height?: number;
1814
+ alt?: string;
1815
+ storageKey: string;
1816
+ contentHash?: string;
1817
+ blurhash?: string;
1818
+ dominantColor?: string;
1819
+ authorId?: string;
1820
+ }): Promise<ApiResult<MediaResponse>>;
1565
1821
  /**
1566
- * Compute content hash using Web Crypto API
1567
- *
1568
- * Uses SHA-1 which is the fastest option in SubtleCrypto.
1569
- * SHA-1 is cryptographically weak but fine for content deduplication
1570
- * where we only need to detect identical files, not resist attacks.
1571
- *
1572
- * Returns hex string prefixed with "sha1:" for future-proofing
1822
+ * Update media metadata
1573
1823
  */
1574
- declare function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string>;
1824
+ declare function handleMediaUpdate(db: Kysely<Database>, id: string, input: {
1825
+ alt?: string;
1826
+ caption?: string;
1827
+ width?: number;
1828
+ height?: number;
1829
+ }): Promise<ApiResult<MediaResponse>>;
1830
+ /**
1831
+ * Delete media item
1832
+ */
1833
+ declare function handleMediaDelete(db: Kysely<Database>, id: string): Promise<ApiResult<{
1834
+ deleted: true;
1835
+ }>>;
1575
1836
  //#endregion
1576
- //#region src/utils/url.d.ts
1837
+ //#region src/schema/registry.d.ts
1577
1838
  /**
1578
- * URL scheme validation utilities
1579
- *
1580
- * Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
1581
- * by allowlisting known-safe schemes before rendering into href attributes.
1839
+ * Error thrown when a schema operation fails
1582
1840
  */
1841
+ declare class SchemaError extends Error {
1842
+ code: string;
1843
+ details?: Record<string, unknown> | undefined;
1844
+ constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
1845
+ }
1583
1846
  /**
1584
- * Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
1585
- *
1586
- * Use this at the render layer as the primary defense against XSS via
1587
- * dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
1847
+ * Schema Registry
1588
1848
  *
1589
- * @example
1590
- * ```ts
1591
- * sanitizeHref("https://example.com") // "https://example.com"
1592
- * sanitizeHref("/about") // "/about"
1593
- * sanitizeHref("#section") // "#section"
1594
- * sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
1595
- * sanitizeHref("javascript:alert(1)") // "#"
1596
- * sanitizeHref("data:text/html,<script>") // "#"
1597
- * sanitizeHref("") // "#"
1598
- * ```
1599
- */
1600
- declare function sanitizeHref(url: string | undefined | null): string;
1601
- /**
1602
- * Returns true if the URL uses a safe scheme for rendering in href attributes.
1603
- */
1604
- declare function isSafeHref(url: string): boolean;
1605
- //#endregion
1606
- //#region src/loader.d.ts
1607
- /**
1608
- * Entry data type - generic object
1609
- */
1610
- type EntryData = Record<string, unknown>;
1611
- /**
1612
- * Sort direction
1613
- */
1614
- type SortDirection$1 = "asc" | "desc";
1615
- /**
1616
- * Order by specification - field name to direction
1617
- * @example { created_at: "desc" } - Sort by created_at descending
1618
- * @example { title: "asc" } - Sort by title ascending
1619
- */
1620
- type OrderBySpec$1 = Record<string, SortDirection$1>;
1621
- /**
1622
- * Range filter for comparison operators on field values.
1623
- * ISO 8601 timestamps sort lexicographically in the same order as time.
1624
- */
1625
- interface WhereRange {
1626
- gt?: string;
1627
- gte?: string;
1628
- lt?: string;
1629
- lte?: string;
1630
- }
1631
- type WhereValue = string | string[] | WhereRange;
1632
- /**
1633
- * Filter for loadCollection - type is required
1849
+ * Manages collection and field definitions stored in the database.
1850
+ * Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).
1634
1851
  */
1635
- interface CollectionFilter$1 {
1636
- type: string;
1637
- status?: "draft" | "published" | "archived";
1638
- limit?: number;
1852
+ declare class SchemaRegistry {
1853
+ private db;
1854
+ constructor(db: Kysely<Database>);
1639
1855
  /**
1640
- * Opaque cursor for keyset pagination.
1641
- * Pass the `nextCursor` value from a previous result to fetch the next page.
1856
+ * List all collections
1642
1857
  */
1643
- cursor?: string;
1858
+ listCollections(): Promise<Collection[]>;
1644
1859
  /**
1645
- * Filter by field values, taxonomy terms, byline credits, or ranges.
1860
+ * List all collections with their fields using bounded query shapes.
1861
+ */
1862
+ listCollectionsWithFields(): Promise<CollectionWithFields[]>;
1863
+ /**
1864
+ * Get a collection by slug
1865
+ */
1866
+ getCollection(slug: string): Promise<Collection | null>;
1867
+ /**
1868
+ * Get a collection with all its fields
1869
+ */
1870
+ getCollectionWithFields(slug: string): Promise<CollectionWithFields | null>;
1871
+ /**
1872
+ * Create a new collection
1873
+ */
1874
+ createCollection(input: CreateCollectionInput): Promise<Collection>;
1875
+ /**
1876
+ * Update a collection
1877
+ */
1878
+ updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection>;
1879
+ private validateUrlPattern;
1880
+ private checkLabelUniqueness;
1881
+ private checkUrlPatternUniqueness;
1882
+ /**
1883
+ * Delete a collection
1884
+ */
1885
+ deleteCollection(slug: string, options?: {
1886
+ force?: boolean;
1887
+ }): Promise<void>;
1888
+ /**
1889
+ * List fields for a collection
1890
+ */
1891
+ listFields(collectionId: string): Promise<Field[]>;
1892
+ /**
1893
+ * Get a field by slug within a collection
1894
+ */
1895
+ getField(collectionSlug: string, fieldSlug: string): Promise<Field | null>;
1896
+ /**
1897
+ * Create a new field
1898
+ */
1899
+ createField(collectionSlug: string, input: CreateFieldInput): Promise<Field>;
1900
+ /**
1901
+ * Ensure the content table for an existing collection exists.
1646
1902
  *
1647
- * Taxonomy names are detected automatically and filtered by term.
1648
- * The reserved `byline` key filters by byline credit in any position,
1649
- * not just the primary credit. Other keys are treated as content table
1650
- * column filters.
1903
+ * This repairs interrupted schema creation where the metadata row exists but
1904
+ * the physical `ec_*` table was not created.
1651
1905
  */
1652
- where?: Record<string, WhereValue>;
1653
- /** Case-insensitive substring search across the provided columns. */
1654
- q?: string;
1655
- searchColumns?: string[];
1906
+ ensureCollectionContentTable(collectionSlug: string): Promise<boolean>;
1656
1907
  /**
1657
- * Order results by field(s)
1658
- * @default { created_at: "desc" }
1908
+ * Ensure the physical column for an existing field exists on its content table.
1909
+ *
1910
+ * This repairs interrupted field creation where `_dineway_fields` was written
1911
+ * but `ALTER TABLE ec_* ADD COLUMN` did not complete.
1659
1912
  */
1660
- orderBy?: OrderBySpec$1;
1913
+ ensureFieldColumn(collectionSlug: string, fieldSlug: string): Promise<boolean>;
1661
1914
  /**
1662
- * Filter by locale (e.g. 'en', 'fr').
1663
- * When set, only returns content in this locale.
1915
+ * Update a field
1664
1916
  */
1665
- locale?: string;
1666
- }
1667
- /**
1668
- * Filter for loadEntry - type and id are required
1669
- */
1670
- interface EntryFilter {
1671
- type: string;
1672
- id: string;
1917
+ updateField(collectionSlug: string, fieldSlug: string, input: UpdateFieldInput): Promise<Field>;
1673
1918
  /**
1674
- * When set, fetch content data from this revision instead of the content table.
1675
- * Used by preview mode to serve draft revision data.
1919
+ * Synchronize an existing FTS index with the collection's current state.
1920
+ *
1921
+ * Schema writes must not first-time enable FTS. Initial enablement stays in
1922
+ * explicit seed/import/admin flows where FTS failures can be handled deliberately.
1676
1923
  */
1677
- revisionId?: string;
1924
+ private syncSearchState;
1678
1925
  /**
1679
- * Locale to scope slug lookup. Only affects slug resolution;
1680
- * IDs are globally unique and always resolve regardless of locale.
1926
+ * Delete a field
1681
1927
  */
1682
- locale?: string;
1928
+ deleteField(collectionSlug: string, fieldSlug: string): Promise<void>;
1929
+ /**
1930
+ * Reorder fields
1931
+ */
1932
+ reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void>;
1933
+ /**
1934
+ * Create a content table for a collection
1935
+ */
1936
+ private createContentTable;
1937
+ /**
1938
+ * Drop a content table
1939
+ */
1940
+ private dropContentTable;
1941
+ /**
1942
+ * Add a column to a content table
1943
+ */
1944
+ private addColumn;
1945
+ /**
1946
+ * Drop a column from a content table
1947
+ */
1948
+ private dropColumn;
1949
+ /**
1950
+ * Check if a collection has any content
1951
+ */
1952
+ private collectionHasContent;
1953
+ /**
1954
+ * Get table name for a collection
1955
+ */
1956
+ private getTableName;
1957
+ /**
1958
+ * Get column name for a field
1959
+ */
1960
+ private getColumnName;
1961
+ /**
1962
+ * Validate a slug
1963
+ */
1964
+ private validateSlug;
1965
+ /**
1966
+ * Format a default value for SQL.
1967
+ *
1968
+ * SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant
1969
+ * expression — parameterized values cannot be used here. We manually escape
1970
+ * single quotes and coerce types to ensure the output is safe.
1971
+ *
1972
+ * INTEGER/REAL values are coerced through `Number()` which can only produce
1973
+ * digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.
1974
+ * TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).
1975
+ */
1976
+ private formatDefaultValue;
1977
+ /**
1978
+ * Get empty default for a field type
1979
+ */
1980
+ private getEmptyDefault;
1981
+ /**
1982
+ * Map a collection row to a Collection object
1983
+ */
1984
+ private mapCollectionRow;
1985
+ /**
1986
+ * Map a field row to a Field object
1987
+ */
1988
+ private mapFieldRow;
1989
+ /**
1990
+ * Discover orphaned content tables
1991
+ *
1992
+ * Finds ec_* tables that exist in the database but don't have a
1993
+ * corresponding entry in _dineway_collections.
1994
+ */
1995
+ discoverOrphanedTables(): Promise<Array<{
1996
+ slug: string;
1997
+ tableName: string;
1998
+ rowCount: number;
1999
+ }>>;
2000
+ /**
2001
+ * Register an orphaned table as a collection
2002
+ *
2003
+ * Creates a _dineway_collections entry for an existing ec_* table.
2004
+ */
2005
+ registerOrphanedTable(slug: string, options?: {
2006
+ label?: string;
2007
+ labelSingular?: string;
2008
+ description?: string;
2009
+ }): Promise<Collection>;
2010
+ /**
2011
+ * Convert slug to human-readable label
2012
+ */
2013
+ private slugToLabel;
1683
2014
  }
2015
+ //#endregion
2016
+ //#region src/schema/query.d.ts
1684
2017
  /**
1685
- * Get the database instance. Used by query wrapper functions and middleware.
1686
- *
1687
- * Checks the ALS request context first — if a per-request DB override is set
1688
- * (e.g. by preview or playground middleware), it takes precedence over the
1689
- * module-level cached instance. This allows preview flows to route queries
1690
- * to an isolated session database without modifying any calling code.
1691
- *
1692
- * Initializes the default database on first call using config from virtual module.
1693
- */
1694
- declare function getDb(): Promise<Kysely<Database>>;
1695
- /**
1696
- * Create a Dineway Live Collections loader
1697
- *
1698
- * This loader handles ALL content types in a single Astro collection.
1699
- * Use `getDinewayCollection()` and `getDinewayEntry()` to query
1700
- * specific content types.
1701
- *
1702
- * Database is configured in astro.config.mjs via the dineway() integration.
2018
+ * Get collection metadata by slug.
1703
2019
  *
1704
2020
  * @example
1705
2021
  * ```ts
1706
- * // src/live.config.ts
1707
- * import { defineLiveCollection } from "astro:content";
1708
- * import { dinewayLoader } from "dineway";
2022
+ * import { getCollectionInfo } from "dineway";
1709
2023
  *
1710
- * export const collections = {
1711
- * dineway: defineLiveCollection({
1712
- * loader: dinewayLoader(),
1713
- * }),
1714
- * };
1715
- * ```
1716
- */
1717
- declare function dinewayLoader(): LiveLoader<EntryData, EntryFilter, CollectionFilter$1>;
2024
+ * const info = await getCollectionInfo("posts");
2025
+ * if (info?.commentsEnabled) {
2026
+ * // render comment UI
2027
+ * }
2028
+ * ```
2029
+ */
2030
+ declare function getCollectionInfo(slug: string): Promise<Collection | null>;
1718
2031
  //#endregion
1719
- //#region src/visual-editing/editable.d.ts
2032
+ //#region src/sections/types.d.ts
1720
2033
  /**
1721
- * Visual editing annotation system
1722
- *
1723
- * Creates Proxy objects that emit data-dineway-ref attributes when spread onto elements.
2034
+ * Section source types
1724
2035
  */
1725
- interface CMSAnnotation {
1726
- collection: string;
2036
+ type SectionSource = "theme" | "user" | "import";
2037
+ /**
2038
+ * Section as returned to templates/admin
2039
+ */
2040
+ interface Section {
1727
2041
  id: string;
1728
- field?: string;
1729
- /** Entry status — only present on entry-level annotations (not field-level) */
1730
- status?: string;
1731
- /** Whether the entry has unpublished draft changes */
1732
- hasDraft?: boolean;
1733
- }
1734
- /** The shape returned when spreading an edit annotation onto an element */
1735
- interface FieldAnnotation {
1736
- "data-dineway-ref": string;
2042
+ slug: string;
2043
+ title: string;
2044
+ description?: string;
2045
+ keywords: string[];
2046
+ content: PortableTextBlock$1[];
2047
+ previewUrl?: string;
2048
+ source: SectionSource;
2049
+ themeId?: string;
2050
+ createdAt: string;
2051
+ updatedAt: string;
1737
2052
  }
1738
- interface EditableOptions {
1739
- /** Entry status: "draft", "published", "scheduled" */
1740
- status?: string;
1741
- /** true when draftRevisionId exists and differs from liveRevisionId */
1742
- hasDraft?: boolean;
2053
+ /**
2054
+ * Input for creating a section
2055
+ */
2056
+ interface CreateSectionInput {
2057
+ slug: string;
2058
+ title: string;
2059
+ description?: string;
2060
+ keywords?: string[];
2061
+ content: PortableTextBlock$1[];
2062
+ previewMediaId?: string;
2063
+ source?: SectionSource;
2064
+ themeId?: string;
1743
2065
  }
1744
2066
  /**
1745
- * Create an editable proxy for an entry.
1746
- *
1747
- * Usage:
1748
- * - `{...entry.edit}` - entry-level annotation (includes status/hasDraft)
1749
- * - `{...entry.edit.title}` - field-level annotation
1750
- * - `{...entry.edit['nested.field']}` - nested field (bracket notation)
2067
+ * Input for updating a section
1751
2068
  */
1752
- declare function createEditable(collection: string, id: string, options?: EditableOptions): EditProxy;
2069
+ interface UpdateSectionInput {
2070
+ slug?: string;
2071
+ title?: string;
2072
+ description?: string;
2073
+ keywords?: string[];
2074
+ content?: PortableTextBlock$1[];
2075
+ previewMediaId?: string | null;
2076
+ }
1753
2077
  /**
1754
- * Create a noop proxy for production mode.
1755
- * Spreading this produces no attributes.
2078
+ * Options for querying sections
1756
2079
  */
1757
- declare function createNoop(): EditProxy;
2080
+ interface GetSectionsOptions {
2081
+ /** Filter by source */
2082
+ source?: SectionSource;
2083
+ /** Search title, description, keywords */
2084
+ search?: string;
2085
+ /** Limit results */
2086
+ limit?: number;
2087
+ /** Cursor for pagination */
2088
+ cursor?: string;
2089
+ }
2090
+ //#endregion
2091
+ //#region src/sections/index.d.ts
1758
2092
  /**
1759
- * Visual editing proxy type.
2093
+ * Get a section by slug
1760
2094
  *
1761
- * Spread directly onto elements for entry-level annotations: `{...entry.edit}`
1762
- * Access a field for field-level annotations: `{...entry.edit.title}`
2095
+ * @example
2096
+ * ```ts
2097
+ * import { getSection } from "dineway";
1763
2098
  *
1764
- * In production, spreading produces no attributes (noop).
2099
+ * const section = await getSection("hero-centered");
2100
+ * if (section) {
2101
+ * console.log(section.content); // Portable Text array
2102
+ * }
2103
+ * ```
1765
2104
  */
1766
- type EditProxy = {
1767
- readonly [field: string]: Partial<FieldAnnotation>;
1768
- };
1769
- //#endregion
1770
- //#region src/query.d.ts
2105
+ declare function getSection(slug: string): Promise<Section | null>;
1771
2106
  /**
1772
- * Collection type registry for type-safe queries.
1773
- *
1774
- * This interface is extended by the generated dineway-env.d.ts file
1775
- * to provide type inference for collection names and their data shapes.
2107
+ * Get all sections with optional filtering
1776
2108
  *
1777
2109
  * @example
1778
2110
  * ```ts
1779
- * // In dineway-env.d.ts (generated):
1780
- * declare module "dineway" {
1781
- * interface DinewayCollections {
1782
- * posts: { title: string; content: PortableTextBlock[]; };
1783
- * pages: { title: string; body: PortableTextBlock[]; };
1784
- * }
1785
- * }
2111
+ * import { getSections } from "dineway";
1786
2112
  *
1787
- * // Then in your code:
1788
- * const { entries } = await getDinewayCollection("posts");
1789
- * // entries[0].data.title is typed as string
2113
+ * // Get all theme-provided sections
2114
+ * const themeSections = await getSections({ source: "theme" });
2115
+ *
2116
+ * // Search sections
2117
+ * const results = await getSections({ search: "pricing" });
1790
2118
  * ```
1791
2119
  */
1792
- interface DinewayCollections {}
2120
+ declare function getSections(options?: GetSectionsOptions): Promise<FindManyResult<Section>>;
2121
+ //#endregion
2122
+ //#region src/content/converters/types.d.ts
1793
2123
  /**
1794
- * Helper type to infer the data type for a collection.
1795
- * Returns the registered type if known, otherwise falls back to Record<string, unknown>.
2124
+ * Portable Text Types
2125
+ *
2126
+ * Defines the structure of Portable Text blocks used in Dineway.
1796
2127
  */
1797
- type InferCollectionData<T extends string> = T extends keyof DinewayCollections ? DinewayCollections[T] : Record<string, unknown>;
1798
2128
  /**
1799
- * Sort direction
2129
+ * Base span (inline text)
1800
2130
  */
1801
- type SortDirection = "asc" | "desc";
2131
+ interface PortableTextSpan {
2132
+ _type: "span";
2133
+ _key: string;
2134
+ text: string;
2135
+ marks?: string[];
2136
+ }
1802
2137
  /**
1803
- * Order by specification - field name to direction
1804
- * @example { created_at: "desc" } - Sort by created_at descending
1805
- * @example { title: "asc" } - Sort by title ascending
1806
- * @example { published_at: "desc", title: "asc" } - Multi-field sort
2138
+ * Mark definition (bold, italic, link, etc.)
1807
2139
  */
1808
- type OrderBySpec = Record<string, SortDirection>;
1809
- interface CollectionFilter {
1810
- status?: "draft" | "published" | "archived";
1811
- limit?: number;
1812
- /**
1813
- * Opaque cursor for keyset pagination.
1814
- * Pass the `nextCursor` value from a previous result to fetch the next page.
1815
- * @example
1816
- * ```ts
1817
- * const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
1818
- * const { entries, nextCursor } = await getDinewayCollection("posts", {
1819
- * limit: 10,
1820
- * cursor,
1821
- * });
1822
- * ```
1823
- */
1824
- cursor?: string;
1825
- /**
1826
- * Filter by field values, taxonomy terms, byline credits, or ranges.
1827
- *
1828
- * Taxonomy names are detected automatically and filtered by term.
1829
- * The reserved `byline` key filters by byline credit in any position,
1830
- * not just the primary credit. It accepts one or more byline translation
1831
- * groups, or concrete byline row IDs.
1832
- * Other keys are treated as content table column filters.
1833
- *
1834
- * @example { category: 'news' } - Filter by taxonomy term
1835
- * @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
1836
- * @example { byline: '01HXYZ...' } - Entries credited to a byline (any position)
1837
- * @example { byline: ['01HXYZ...', '01HABC...'] } - Credited to any of these bylines (OR)
1838
- * @example { series: 'main' } - Exact match on a content field
1839
- * @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - Date range
1840
- */
1841
- where?: Record<string, WhereValue>;
1842
- /**
1843
- * Case-insensitive substring search across selected content fields.
1844
- *
1845
- * `searchColumns` must contain concrete field slugs or system column names.
1846
- * When `q` is present without `searchColumns`, no search condition is applied.
1847
- */
1848
- q?: string;
1849
- searchColumns?: string[];
1850
- /**
1851
- * Order results by field(s)
1852
- * @default { created_at: "desc" }
1853
- * @example { created_at: "desc" } - Sort by created_at descending (default)
1854
- * @example { title: "asc" } - Sort by title ascending
1855
- * @example { published_at: "desc", title: "asc" } - Multi-field sort
1856
- */
1857
- orderBy?: OrderBySpec;
1858
- /**
1859
- * Filter by locale. When set, only returns entries in this locale.
1860
- * Only relevant when i18n is configured.
1861
- * @example "en" — English entries only
1862
- * @example "fr" — French entries only
1863
- */
1864
- locale?: string;
1865
- }
1866
- interface ContentEntry<T = Record<string, unknown>> {
1867
- id: string;
1868
- data: T;
1869
- /** Visual editing annotations. Spread onto elements: {...entry.edit.title} */
1870
- edit: EditProxy;
1871
- }
1872
- /** Cache hint returned by the content loader for route caching */
1873
- interface CacheHint {
1874
- tags?: string[];
1875
- lastModified?: Date;
2140
+ interface PortableTextMarkDef {
2141
+ _type: string;
2142
+ _key: string;
2143
+ [key: string]: unknown;
1876
2144
  }
1877
2145
  /**
1878
- * Result from getDinewayCollection
2146
+ * Link mark definition
1879
2147
  */
1880
- interface CollectionResult<T> {
1881
- /** The entries (empty array if error or none found) */
1882
- entries: ContentEntry<T>[];
1883
- /** Error if the query failed */
1884
- error?: Error;
1885
- /** Cache hint for route caching (pass to Astro.cache.set()) */
1886
- cacheHint: CacheHint;
1887
- /**
1888
- * Opaque cursor for the next page.
1889
- * Undefined when there are no more results.
1890
- * Pass this as `cursor` in the next query to get the next page.
1891
- */
1892
- nextCursor?: string;
1893
- /**
1894
- * Total number of entries matching the current filter, excluding cursor and limit.
1895
- */
1896
- total?: number;
2148
+ interface PortableTextLinkMark extends PortableTextMarkDef {
2149
+ _type: "link";
2150
+ href: string;
2151
+ blank?: boolean;
1897
2152
  }
1898
2153
  /**
1899
- * Result from getDinewayEntry
2154
+ * Text block (paragraph, heading, etc.)
1900
2155
  */
1901
- interface EntryResult<T> {
1902
- /** The entry, or null if not found */
1903
- entry: ContentEntry<T> | null;
1904
- /** Error if the query failed (not set for "not found", only for actual errors) */
1905
- error?: Error;
1906
- /** Whether we're in preview mode (valid token was provided) */
1907
- isPreview: boolean;
1908
- /** Set when a fallback locale was used instead of the requested locale */
1909
- fallbackLocale?: string;
1910
- /** Cache hint for route caching (pass to Astro.cache.set()) */
1911
- cacheHint: CacheHint;
1912
- }
1913
- /** Edit metadata attached to PT arrays in edit mode */
1914
- interface EditFieldMeta {
1915
- collection: string;
1916
- id: string;
1917
- field: string;
2156
+ interface PortableTextTextBlock {
2157
+ _type: "block";
2158
+ _key: string;
2159
+ style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote";
2160
+ listItem?: "bullet" | "number";
2161
+ level?: number;
2162
+ children: PortableTextSpan[];
2163
+ markDefs?: PortableTextMarkDef[];
2164
+ textAlign?: "left" | "center" | "right" | "justify";
1918
2165
  }
1919
2166
  /**
1920
- * Read edit metadata from a value (returns undefined if not tagged).
1921
- * Uses Object.getOwnPropertyDescriptor to access Symbol-keyed property
1922
- * without an unsafe type assertion.
2167
+ * Image block
1923
2168
  */
1924
- declare function getEditMeta(value: unknown): EditFieldMeta | undefined;
2169
+ interface PortableTextImageBlock {
2170
+ _type: "image";
2171
+ _key: string;
2172
+ asset: {
2173
+ _ref: string;
2174
+ url?: string; /** Provider ID for external media (e.g., "image-cdn") */
2175
+ provider?: string;
2176
+ };
2177
+ alt?: string;
2178
+ caption?: string;
2179
+ /** Original image width */
2180
+ width?: number;
2181
+ /** Original image height */
2182
+ height?: number;
2183
+ /** Display width for this instance (overrides original) */
2184
+ displayWidth?: number;
2185
+ /** Display height for this instance (overrides original) */
2186
+ displayHeight?: number;
2187
+ }
1925
2188
  /**
1926
- * Get all entries of a content type
1927
- *
1928
- * Returns { entries, error } for graceful error handling.
1929
- *
1930
- * When dineway-env.d.ts is generated, the collection name will be
1931
- * type-checked and the return type will be inferred automatically.
1932
- *
1933
- * @example
1934
- * ```ts
1935
- * import { getDinewayCollection } from "dineway";
1936
- *
1937
- * const { entries: posts, error } = await getDinewayCollection("posts");
1938
- * if (error) {
1939
- * console.error("Failed to load posts:", error);
1940
- * return;
1941
- * }
1942
- * // posts[0].data.title is typed (if dineway-env.d.ts exists)
1943
- *
1944
- * // With filters
1945
- * const { entries: drafts } = await getDinewayCollection("posts", { status: "draft" });
1946
- * ```
2189
+ * Code block
1947
2190
  */
1948
- declare function getDinewayCollection<T extends string, D = InferCollectionData<T>>(type: T, filter?: CollectionFilter): Promise<CollectionResult<D>>;
2191
+ interface PortableTextCodeBlock {
2192
+ _type: "code";
2193
+ _key: string;
2194
+ code: string;
2195
+ language?: string;
2196
+ filename?: string;
2197
+ }
1949
2198
  /**
1950
- * Get a single entry by type and ID/slug
1951
- *
1952
- * Returns { entry, error, isPreview } for graceful error handling.
1953
- * - entry is null if not found (not an error)
1954
- * - error is set only for actual errors (db issues, etc.)
1955
- *
1956
- * Preview mode is detected automatically from request context (ALS).
1957
- * When the URL has a valid `_preview` token, the middleware sets preview
1958
- * context and this function serves draft revision data if available.
1959
- *
1960
- * @example
1961
- * ```ts
1962
- * import { getDinewayEntry } from "dineway";
1963
- *
1964
- * // Simple usage — preview just works via middleware
1965
- * const { entry: post, isPreview, error } = await getDinewayEntry("posts", "my-slug");
1966
- * if (!post) return Astro.redirect("/404");
1967
- * ```
2199
+ * HTML block (raw HTML content)
1968
2200
  */
1969
- declare function getDinewayEntry<T extends string, D = InferCollectionData<T>>(type: T, id: string, options?: {
1970
- locale?: string;
1971
- }): Promise<EntryResult<D>>;
2201
+ interface PortableTextHtmlBlock {
2202
+ _type: "htmlBlock";
2203
+ _key: string;
2204
+ html: string;
2205
+ }
1972
2206
  /**
1973
- * Translation summary for a single locale variant
2207
+ * Unknown/custom block (preserved for plugin compatibility)
1974
2208
  */
1975
- interface TranslationSummary {
1976
- /** Content item ID */
1977
- id: string;
1978
- /** Locale code (e.g. "en", "fr") */
1979
- locale: string;
1980
- /** URL slug */
1981
- slug: string | null;
1982
- /** Current status */
1983
- status: string;
2209
+ interface PortableTextUnknownBlock {
2210
+ _type: string;
2211
+ _key: string;
2212
+ [key: string]: unknown;
1984
2213
  }
1985
2214
  /**
1986
- * Result from getTranslations
2215
+ * Any Portable Text block
1987
2216
  */
1988
- interface TranslationsResult {
1989
- /** The translation group ID (shared across locales) */
1990
- translationGroup: string;
1991
- /** All locale variants in this group */
1992
- translations: TranslationSummary[];
1993
- /** Error if the query failed */
1994
- error?: Error;
2217
+ type PortableTextBlock = PortableTextTextBlock | PortableTextImageBlock | PortableTextCodeBlock | PortableTextHtmlBlock | PortableTextUnknownBlock;
2218
+ /**
2219
+ * ProseMirror JSON types (simplified for TipTap)
2220
+ */
2221
+ interface ProseMirrorMark {
2222
+ type: string;
2223
+ attrs?: Record<string, unknown>;
2224
+ }
2225
+ interface ProseMirrorNode {
2226
+ type: string;
2227
+ attrs?: Record<string, unknown>;
2228
+ content?: ProseMirrorNode[];
2229
+ marks?: ProseMirrorMark[];
2230
+ text?: string;
1995
2231
  }
2232
+ interface ProseMirrorDocument {
2233
+ type: "doc";
2234
+ content: ProseMirrorNode[];
2235
+ }
2236
+ //#endregion
2237
+ //#region src/content/converters/prosemirror-to-portable-text.d.ts
1996
2238
  /**
1997
- * Get all translations of a content item.
1998
- *
1999
- * Given a content entry, returns all locale variants that share the same
2000
- * translation group. This is useful for building language switcher UI.
2001
- *
2002
- * @example
2003
- * ```ts
2004
- * import { getDinewayEntry, getTranslations } from "dineway";
2005
- *
2006
- * const { entry: post } = await getDinewayEntry("posts", "hello-world", { locale: "en" });
2007
- * const { translations } = await getTranslations("posts", post.data.id);
2008
- * // translations = [{ id: "...", locale: "en", slug: "hello-world", status: "published" }, ...]
2009
- * ```
2239
+ * Convert ProseMirror document to Portable Text
2010
2240
  */
2011
- declare function getTranslations(type: string, id: string): Promise<TranslationsResult>;
2241
+ declare function prosemirrorToPortableText(doc: ProseMirrorDocument): PortableTextBlock[];
2242
+ //#endregion
2243
+ //#region src/content/converters/portable-text-to-prosemirror.d.ts
2012
2244
  /**
2013
- * Result from resolveDinewayPath
2245
+ * Convert Portable Text to ProseMirror document
2014
2246
  */
2015
- interface ResolvePathResult<T = Record<string, unknown>> {
2016
- /** The matched entry */
2017
- entry: ContentEntry<T>;
2018
- /** The collection slug that matched */
2019
- collection: string;
2020
- /** Extracted parameters from the URL pattern (e.g. { slug: "my-post" }) */
2021
- params: Record<string, string>;
2022
- }
2247
+ declare function portableTextToProsemirror(blocks: PortableTextBlock[]): ProseMirrorDocument;
2248
+ //#endregion
2249
+ //#region src/utils/hash.d.ts
2023
2250
  /**
2024
- * Resolve a URL path to a content entry by matching against collection URL patterns.
2025
- *
2026
- * Loads all collections with a `urlPattern` set, converts each pattern to a regex,
2027
- * and tests the given path. On match, extracts the slug and fetches the entry.
2251
+ * SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
2252
+ * For cache invalidation / ETags — not for security.
2253
+ */
2254
+ declare function hashString(content: string): Promise<string>;
2255
+ /**
2256
+ * Compute content hash using Web Crypto API
2028
2257
  *
2029
- * @example
2030
- * ```ts
2031
- * import { resolveDinewayPath } from "dineway";
2258
+ * Uses SHA-1 which is the fastest option in SubtleCrypto.
2259
+ * SHA-1 is cryptographically weak but fine for content deduplication
2260
+ * where we only need to detect identical files, not resist attacks.
2032
2261
  *
2033
- * // Given pages with urlPattern "/{slug}" and posts with "/blog/{slug}":
2034
- * const result = await resolveDinewayPath("/blog/hello-world");
2035
- * if (result) {
2036
- * console.log(result.collection); // "posts"
2037
- * console.log(result.params.slug); // "hello-world"
2038
- * console.log(result.entry.data); // post data
2039
- * }
2040
- * ```
2262
+ * Returns hex string prefixed with "sha1:" for future-proofing
2041
2263
  */
2042
- declare function resolveDinewayPath<T = Record<string, unknown>>(path: string): Promise<ResolvePathResult<T> | null>;
2264
+ declare function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string>;
2043
2265
  //#endregion
2044
- //#region src/after.d.ts
2266
+ //#region src/utils/url.d.ts
2045
2267
  /**
2046
- * Defer work past the current synchronous path.
2268
+ * URL scheme validation utilities
2047
2269
  *
2048
- * Use this for best-effort bookkeeping that should not block runtime
2049
- * initialization or response handling. Node keeps the process alive for
2050
- * pending work; callers that need stronger durability should await their own
2051
- * operation instead of using this helper.
2270
+ * Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
2271
+ * by allowlisting known-safe schemes before rendering into href attributes.
2052
2272
  */
2053
- type AfterCallback = () => void | Promise<void>;
2054
- declare function after(fn: AfterCallback): void;
2055
- //#endregion
2056
- //#region src/i18n/config.d.ts
2057
2273
  /**
2058
- * Dineway i18n Configuration
2274
+ * Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
2059
2275
  *
2060
- * Reads locale configuration from the virtual module (sourced from Astro config).
2061
- * Initialized during runtime startup, then available via getI18nConfig().
2276
+ * Use this at the render layer as the primary defense against XSS via
2277
+ * dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
2278
+ *
2279
+ * @example
2280
+ * ```ts
2281
+ * sanitizeHref("https://example.com") // "https://example.com"
2282
+ * sanitizeHref("/about") // "/about"
2283
+ * sanitizeHref("#section") // "#section"
2284
+ * sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
2285
+ * sanitizeHref("javascript:alert(1)") // "#"
2286
+ * sanitizeHref("data:text/html,<script>") // "#"
2287
+ * sanitizeHref("") // "#"
2288
+ * ```
2062
2289
  */
2063
- interface I18nConfig {
2064
- defaultLocale: string;
2065
- locales: string[];
2066
- fallback?: Record<string, string>;
2067
- prefixDefaultLocale?: boolean;
2068
- }
2290
+ declare function sanitizeHref(url: string | undefined | null): string;
2069
2291
  /**
2070
- * Get the current i18n config.
2071
- * Returns null if i18n is not configured.
2292
+ * Returns true if the URL uses a safe scheme for rendering in href attributes.
2072
2293
  */
2073
- declare function getI18nConfig(): I18nConfig | null;
2294
+ declare function isSafeHref(url: string): boolean;
2295
+ //#endregion
2296
+ //#region src/auth/rate-limit.d.ts
2074
2297
  /**
2075
- * Check if i18n is enabled.
2076
- * Returns true when multiple locales are configured.
2298
+ * Result of a rate limit check.
2077
2299
  */
2078
- declare function isI18nEnabled(): boolean;
2300
+ interface RateLimitResult {
2301
+ /** Whether the request is allowed (within limit). */
2302
+ allowed: boolean;
2303
+ /** Current request count in this window. */
2304
+ count: number;
2305
+ /** Maximum requests allowed in this window. */
2306
+ limit: number;
2307
+ }
2079
2308
  /**
2080
- * Resolve fallback locale chain for a given locale.
2081
- * Returns array of locales to try, from most preferred to least.
2082
- * Always ends with defaultLocale.
2309
+ * Check (and increment) the rate limit for a given IP + endpoint.
2310
+ *
2311
+ * If `ip` is null (no trusted IP available), rate limiting is skipped
2312
+ * and the request is allowed. There's no meaningful key to rate limit
2313
+ * on when the IP is unknown.
2314
+ *
2315
+ * Returns whether the request is allowed. The counter is always
2316
+ * incremented — even when the limit is exceeded — so that repeated
2317
+ * abuse doesn't reset the window.
2318
+ *
2319
+ * Piggybacks cleanup of expired entries with a 1% probability
2320
+ * to prevent unbounded table growth.
2083
2321
  */
2084
- declare function getFallbackChain(locale: string): string[];
2322
+ declare function checkRateLimit(db: Kysely<Database>, ip: string | null, endpoint: string, maxRequests: number, windowSeconds: number): Promise<RateLimitResult>;
2085
2323
  //#endregion
2086
- //#region src/preview/sidecar-client.d.ts
2087
- /**
2088
- * Preview sidecar protocol helpers.
2089
- *
2090
- * These utilities define the signed URL and snapshot-auth contract shared
2091
- * by preview sidecars and the source site serving snapshot exports.
2092
- */
2093
- interface PreviewSidecarSignature {
2094
- source: string;
2095
- exp: number;
2096
- sig: string;
2097
- }
2098
- interface PreviewSidecarClient {
2099
- signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
2100
- buildSnapshotSignatureHeader(signature: PreviewSidecarSignature): string;
2101
- }
2102
- declare function signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
2103
- declare function buildPreviewSignatureHeader(signature: PreviewSidecarSignature): string;
2104
- declare function parsePreviewSignatureHeader(header: string): PreviewSidecarSignature | null;
2105
- declare function verifyPreviewSignature(source: string, exp: number, sig: string, secret: string): Promise<boolean>;
2106
- declare const defaultPreviewSidecarClient: PreviewSidecarClient;
2107
- //#endregion
2108
- //#region src/preview/session-database-factory.d.ts
2109
- interface SessionDatabaseInfo {
2110
- id: string;
2111
- dbPath: string;
2112
- createdAt: number;
2324
+ //#region src/security/guest-access-tokens.d.ts
2325
+ interface GuestAccessTokenClaims {
2326
+ version: 1;
2327
+ tokenId: string;
2328
+ purpose: string;
2329
+ subjectType: string;
2330
+ subjectId: string;
2331
+ locationId: string;
2332
+ issuedAt: number;
2113
2333
  expiresAt: number;
2114
- lastTouchedAt: number;
2115
- }
2116
- interface SessionDatabaseHandle {
2117
- created: boolean;
2118
- session: SessionDatabaseInfo;
2119
- db: Kysely<Database>;
2120
- close(): Promise<void>;
2121
- }
2122
- interface SessionCleanupResult {
2123
- removedSessionIds: string[];
2124
- removedPaths: string[];
2125
2334
  }
2126
- interface SessionOpenOptions {
2127
- id: string;
2335
+ interface IssueGuestAccessTokenOptions {
2336
+ secret: string;
2337
+ purpose: string;
2338
+ subjectType: string;
2339
+ subjectId: string;
2340
+ locationId: string;
2341
+ /** Reuses an already persisted identifier to reconstruct the exact same capability. */
2342
+ tokenId?: string;
2343
+ expiresIn?: string | number;
2128
2344
  now?: number;
2129
2345
  }
2130
- interface SessionOpenOrCreateOptions extends SessionOpenOptions {
2131
- ttlMs: number;
2132
- }
2133
- interface SessionDatabaseFactory {
2134
- open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
2135
- openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
2136
- destroy(id: string): Promise<boolean>;
2137
- cleanup(now?: number): Promise<SessionCleanupResult>;
2138
- close(): Promise<void>;
2346
+ interface IssuedGuestAccessToken {
2347
+ token: string;
2348
+ tokenHash: string;
2349
+ claims: GuestAccessTokenClaims;
2350
+ }
2351
+ interface GuestAccessExpectedScope {
2352
+ purpose: string;
2353
+ subjectType: string;
2354
+ subjectId?: string;
2355
+ locationId?: string;
2356
+ }
2357
+ interface VerifyGuestAccessTokenOptions {
2358
+ token: string | null | undefined;
2359
+ /** Primary secret first, followed by retained rotation secrets. */
2360
+ secrets: string | readonly string[];
2361
+ expected: GuestAccessExpectedScope;
2362
+ now?: number;
2139
2363
  }
2140
- interface FileSessionDatabaseFactoryOptions {
2141
- rootDir: string;
2142
- maxDiskBytes?: number;
2143
- registryFileName?: string;
2144
- sessionsDirName?: string;
2364
+ type VerifyGuestAccessTokenResult = {
2365
+ valid: true;
2366
+ claims: GuestAccessTokenClaims;
2367
+ tokenHash: string;
2368
+ } | {
2369
+ valid: false;
2370
+ error: "none" | "malformed" | "invalid" | "expired" | "scope_mismatch";
2371
+ };
2372
+ declare class GuestAccessTokenConfigurationError extends Error {
2373
+ readonly code: "INVALID_GUEST_TOKEN_SECRET" | "INVALID_GUEST_TOKEN_INPUT";
2374
+ readonly name = "GuestAccessTokenConfigurationError";
2375
+ constructor(message: string, code: "INVALID_GUEST_TOKEN_SECRET" | "INVALID_GUEST_TOKEN_INPUT");
2145
2376
  }
2146
- declare class SessionDatabaseLimitError extends Error {
2147
- constructor(message?: string);
2377
+ /**
2378
+ * Issues an expiring capability for one guest purpose and one restaurant target.
2379
+ * Persist only tokenHash/tokenId and revocation metadata; never persist or log token.
2380
+ */
2381
+ declare function issueGuestAccessToken(options: IssueGuestAccessTokenOptions): Promise<IssuedGuestAccessToken>;
2382
+ /**
2383
+ * Verifies signature, expiry, and the caller-declared purpose/target scope.
2384
+ * A valid result still requires the plugin to check its revocation record by tokenHash.
2385
+ */
2386
+ declare function verifyGuestAccessToken(options: VerifyGuestAccessTokenOptions): Promise<VerifyGuestAccessTokenResult>;
2387
+ /** Returns the non-reversible identifier stored for revocation and lookup. */
2388
+ declare function hashGuestAccessToken(token: string): Promise<string>;
2389
+ //#endregion
2390
+ //#region src/visual-editing/editable.d.ts
2391
+ /**
2392
+ * Visual editing annotation system
2393
+ *
2394
+ * Creates Proxy objects that emit data-dineway-ref attributes when spread onto elements.
2395
+ */
2396
+ interface CMSAnnotation {
2397
+ collection: string;
2398
+ id: string;
2399
+ field?: string;
2400
+ /** Entry status — only present on entry-level annotations (not field-level) */
2401
+ status?: string;
2402
+ /** Whether the entry has unpublished draft changes */
2403
+ hasDraft?: boolean;
2148
2404
  }
2149
- declare class FileSessionDatabaseFactory implements SessionDatabaseFactory {
2150
- private readonly options;
2151
- private readonly registry;
2152
- private readonly sessionsDir;
2153
- private readonly maxDiskBytes;
2154
- constructor(options: FileSessionDatabaseFactoryOptions);
2155
- open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
2156
- openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
2157
- destroy(id: string): Promise<boolean>;
2158
- cleanup(now?: number): Promise<SessionCleanupResult>;
2159
- close(): Promise<void>;
2160
- private createHandle;
2161
- private getSessionRow;
2162
- private toSessionInfo;
2163
- private deleteSession;
2164
- private getActiveDiskBytes;
2165
- private getDbPath;
2166
- private getManagedPaths;
2167
- private listSessionRows;
2168
- private listDbPathRows;
2405
+ /** The shape returned when spreading an edit annotation onto an element */
2406
+ interface FieldAnnotation {
2407
+ "data-dineway-ref": string;
2169
2408
  }
2170
- //#endregion
2171
- //#region src/preview/middleware.d.ts
2172
- interface FilePreviewMiddlewareConfig {
2173
- rootDir?: string;
2174
- secret: string;
2175
- ttlSeconds?: number;
2176
- cookieName?: string;
2177
- snapshotPath?: string;
2178
- maxSessionDiskBytes?: number;
2179
- sessionFactory?: SessionDatabaseFactory;
2180
- fetch?: typeof globalThis.fetch;
2409
+ interface EditableOptions {
2410
+ /** Entry status: "draft", "published", "scheduled" */
2411
+ status?: string;
2412
+ /** true when draftRevisionId exists and differs from liveRevisionId */
2413
+ hasDraft?: boolean;
2181
2414
  }
2182
- declare function createFilePreviewMiddleware(config: FilePreviewMiddlewareConfig): MiddlewareHandler;
2183
- //#endregion
2184
- //#region src/plugins/define-plugin.d.ts
2185
2415
  /**
2186
- * Define a Dineway plugin.
2416
+ * Create an editable proxy for an entry.
2187
2417
  *
2188
- * **Standard format** -- the canonical format for plugins that work in both
2189
- * trusted and sandboxed modes. No id/version -- those come from the descriptor.
2418
+ * Usage:
2419
+ * - `{...entry.edit}` - entry-level annotation (includes status/hasDraft)
2420
+ * - `{...entry.edit.title}` - field-level annotation
2421
+ * - `{...entry.edit['nested.field']}` - nested field (bracket notation)
2422
+ */
2423
+ declare function createEditable(collection: string, id: string, options?: EditableOptions): EditProxy;
2424
+ /**
2425
+ * Create a noop proxy for production mode.
2426
+ * Spreading this produces no attributes.
2427
+ */
2428
+ declare function createNoop(): EditProxy;
2429
+ /**
2430
+ * Visual editing proxy type.
2190
2431
  *
2191
- * @example
2192
- * ```typescript
2193
- * import { definePlugin } from "dineway";
2432
+ * Spread directly onto elements for entry-level annotations: `{...entry.edit}`
2433
+ * Access a field for field-level annotations: `{...entry.edit.title}`
2194
2434
  *
2195
- * export default definePlugin({
2196
- * hooks: {
2197
- * "content:afterSave": {
2198
- * handler: async (event, ctx) => {
2199
- * await ctx.kv.set("lastSave", Date.now());
2200
- * },
2201
- * },
2202
- * },
2203
- * routes: {
2204
- * status: {
2205
- * handler: async (routeCtx, ctx) => ({ ok: true }),
2206
- * },
2207
- * },
2208
- * });
2209
- * ```
2435
+ * In production, spreading produces no attributes (noop).
2436
+ */
2437
+ type EditProxy = {
2438
+ readonly [field: string]: Partial<FieldAnnotation>;
2439
+ };
2440
+ //#endregion
2441
+ //#region src/query.d.ts
2442
+ /**
2443
+ * Collection type registry for type-safe queries.
2210
2444
  *
2211
- * **Native format** -- for plugins that need React admin, direct DB access,
2212
- * or other capabilities not available in the sandbox.
2445
+ * This interface is extended by the generated dineway-env.d.ts file
2446
+ * to provide type inference for collection names and their data shapes.
2213
2447
  *
2214
2448
  * @example
2215
- * ```typescript
2216
- * import { definePlugin } from "dineway";
2217
- *
2218
- * export default definePlugin({
2219
- * id: "my-plugin",
2220
- * version: "1.0.0",
2221
- * capabilities: ["content:read"],
2222
- * hooks: {
2223
- * "content:beforeSave": async (event, ctx) => {
2224
- * ctx.log.info("Saving content", { collection: event.collection });
2225
- * return event.content;
2226
- * }
2227
- * },
2228
- * routes: {
2229
- * "sync": {
2230
- * handler: async (ctx) => {
2231
- * return { status: "ok" };
2232
- * }
2233
- * }
2449
+ * ```ts
2450
+ * // In dineway-env.d.ts (generated):
2451
+ * declare module "dineway" {
2452
+ * interface DinewayCollections {
2453
+ * posts: { title: string; content: PortableTextBlock[]; };
2454
+ * pages: { title: string; body: PortableTextBlock[]; };
2234
2455
  * }
2235
- * });
2456
+ * }
2457
+ *
2458
+ * // Then in your code:
2459
+ * const { entries } = await getDinewayCollection("posts");
2460
+ * // entries[0].data.title is typed as string
2236
2461
  * ```
2237
2462
  */
2238
- declare function definePlugin<TStorage extends PluginStorageConfig>(definition: PluginDefinition<TStorage>): ResolvedPlugin<TStorage>;
2239
- declare function definePlugin(definition: StandardPluginDefinition): StandardPluginDefinition;
2240
- //#endregion
2241
- //#region src/plugins/manifest-schema.d.ts
2463
+ interface DinewayCollections {}
2242
2464
  /**
2243
- * Zod schema matching the PluginManifest interface from types.ts.
2244
- *
2245
- * Every JSON.parse of a manifest.json should validate through this.
2465
+ * Helper type to infer the data type for a collection.
2466
+ * Returns the registered type if known, otherwise falls back to Record<string, unknown>.
2246
2467
  */
2247
- declare const pluginManifestSchema: z$1.ZodObject<{
2248
- id: z$1.ZodString;
2249
- version: z$1.ZodString;
2250
- capabilities: z$1.ZodArray<z$1.ZodEnum<{
2251
- "network:request": "network:request";
2252
- "network:request:unrestricted": "network:request:unrestricted";
2253
- "content:read": "content:read";
2254
- "content:write": "content:write";
2255
- "media:read": "media:read";
2256
- "media:write": "media:write";
2257
- "users:read": "users:read";
2258
- "email:send": "email:send";
2259
- "hooks.email-transport:register": "hooks.email-transport:register";
2260
- "hooks.email-events:register": "hooks.email-events:register";
2261
- "hooks.page-fragments:register": "hooks.page-fragments:register";
2262
- }>>;
2263
- allowedHosts: z$1.ZodArray<z$1.ZodString>;
2264
- storage: z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
2265
- indexes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>;
2266
- uniqueIndexes: z$1.ZodOptional<z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>>;
2267
- }, z$1.core.$strip>>;
2268
- hooks: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodEnum<{
2269
- "plugin:install": "plugin:install";
2270
- "plugin:activate": "plugin:activate";
2271
- "plugin:deactivate": "plugin:deactivate";
2272
- "plugin:uninstall": "plugin:uninstall";
2273
- "content:beforeSave": "content:beforeSave";
2274
- "content:afterSave": "content:afterSave";
2275
- "content:beforeDelete": "content:beforeDelete";
2276
- "content:afterDelete": "content:afterDelete";
2277
- "content:afterPublish": "content:afterPublish";
2278
- "content:afterUnpublish": "content:afterUnpublish";
2279
- "media:beforeUpload": "media:beforeUpload";
2280
- "media:afterUpload": "media:afterUpload";
2281
- cron: "cron";
2282
- "email:beforeSend": "email:beforeSend";
2283
- "email:deliver": "email:deliver";
2284
- "email:afterSend": "email:afterSend";
2285
- "comment:beforeCreate": "comment:beforeCreate";
2286
- "comment:moderate": "comment:moderate";
2287
- "comment:afterCreate": "comment:afterCreate";
2288
- "comment:afterModerate": "comment:afterModerate";
2289
- "page:metadata": "page:metadata";
2290
- "page:fragments": "page:fragments";
2291
- }>, z$1.ZodObject<{
2292
- name: z$1.ZodEnum<{
2293
- "plugin:install": "plugin:install";
2294
- "plugin:activate": "plugin:activate";
2295
- "plugin:deactivate": "plugin:deactivate";
2296
- "plugin:uninstall": "plugin:uninstall";
2297
- "content:beforeSave": "content:beforeSave";
2298
- "content:afterSave": "content:afterSave";
2299
- "content:beforeDelete": "content:beforeDelete";
2300
- "content:afterDelete": "content:afterDelete";
2301
- "content:afterPublish": "content:afterPublish";
2302
- "content:afterUnpublish": "content:afterUnpublish";
2303
- "media:beforeUpload": "media:beforeUpload";
2304
- "media:afterUpload": "media:afterUpload";
2305
- cron: "cron";
2306
- "email:beforeSend": "email:beforeSend";
2307
- "email:deliver": "email:deliver";
2308
- "email:afterSend": "email:afterSend";
2309
- "comment:beforeCreate": "comment:beforeCreate";
2310
- "comment:moderate": "comment:moderate";
2311
- "comment:afterCreate": "comment:afterCreate";
2312
- "comment:afterModerate": "comment:afterModerate";
2313
- "page:metadata": "page:metadata";
2314
- "page:fragments": "page:fragments";
2315
- }>;
2316
- exclusive: z$1.ZodOptional<z$1.ZodBoolean>;
2317
- priority: z$1.ZodOptional<z$1.ZodNumber>;
2318
- timeout: z$1.ZodOptional<z$1.ZodNumber>;
2319
- }, z$1.core.$strip>]>>;
2320
- routes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodObject<{
2321
- name: z$1.ZodString;
2322
- public: z$1.ZodOptional<z$1.ZodBoolean>;
2323
- }, z$1.core.$strip>]>>;
2324
- admin: z$1.ZodObject<{
2325
- entry: z$1.ZodOptional<z$1.ZodString>;
2326
- settingsSchema: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{
2327
- type: z$1.ZodLiteral<"string">;
2328
- default: z$1.ZodOptional<z$1.ZodString>;
2329
- multiline: z$1.ZodOptional<z$1.ZodBoolean>;
2330
- label: z$1.ZodString;
2331
- description: z$1.ZodOptional<z$1.ZodString>;
2332
- }, z$1.core.$strip>, z$1.ZodObject<{
2333
- type: z$1.ZodLiteral<"number">;
2334
- default: z$1.ZodOptional<z$1.ZodNumber>;
2335
- min: z$1.ZodOptional<z$1.ZodNumber>;
2336
- max: z$1.ZodOptional<z$1.ZodNumber>;
2337
- label: z$1.ZodString;
2338
- description: z$1.ZodOptional<z$1.ZodString>;
2339
- }, z$1.core.$strip>, z$1.ZodObject<{
2340
- type: z$1.ZodLiteral<"boolean">;
2341
- default: z$1.ZodOptional<z$1.ZodBoolean>;
2342
- label: z$1.ZodString;
2343
- description: z$1.ZodOptional<z$1.ZodString>;
2344
- }, z$1.core.$strip>, z$1.ZodObject<{
2345
- type: z$1.ZodLiteral<"select">;
2346
- options: z$1.ZodArray<z$1.ZodObject<{
2347
- value: z$1.ZodString;
2348
- label: z$1.ZodString;
2349
- }, z$1.core.$strip>>;
2350
- default: z$1.ZodOptional<z$1.ZodString>;
2351
- label: z$1.ZodString;
2352
- description: z$1.ZodOptional<z$1.ZodString>;
2353
- }, z$1.core.$strip>, z$1.ZodObject<{
2354
- type: z$1.ZodLiteral<"secret">;
2355
- label: z$1.ZodString;
2356
- description: z$1.ZodOptional<z$1.ZodString>;
2357
- }, z$1.core.$strip>, z$1.ZodObject<{
2358
- type: z$1.ZodLiteral<"url">;
2359
- default: z$1.ZodOptional<z$1.ZodString>;
2360
- placeholder: z$1.ZodOptional<z$1.ZodString>;
2361
- label: z$1.ZodString;
2362
- description: z$1.ZodOptional<z$1.ZodString>;
2363
- }, z$1.core.$strip>, z$1.ZodObject<{
2364
- type: z$1.ZodLiteral<"email">;
2365
- default: z$1.ZodOptional<z$1.ZodString>;
2366
- placeholder: z$1.ZodOptional<z$1.ZodString>;
2367
- label: z$1.ZodString;
2368
- description: z$1.ZodOptional<z$1.ZodString>;
2369
- }, z$1.core.$strip>], "type">>>;
2370
- pages: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2371
- path: z$1.ZodString;
2372
- label: z$1.ZodString;
2373
- icon: z$1.ZodOptional<z$1.ZodString>;
2374
- }, z$1.core.$strip>>>;
2375
- widgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2376
- id: z$1.ZodString;
2377
- size: z$1.ZodOptional<z$1.ZodEnum<{
2378
- full: "full";
2379
- half: "half";
2380
- third: "third";
2381
- }>>;
2382
- title: z$1.ZodOptional<z$1.ZodString>;
2383
- }, z$1.core.$strip>>>;
2384
- fieldWidgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2385
- name: z$1.ZodString;
2386
- label: z$1.ZodString;
2387
- fieldTypes: z$1.ZodArray<z$1.ZodEnum<{
2388
- string: "string";
2389
- number: "number";
2390
- boolean: "boolean";
2391
- file: "file";
2392
- slug: "slug";
2393
- text: "text";
2394
- integer: "integer";
2395
- datetime: "datetime";
2396
- select: "select";
2397
- multiSelect: "multiSelect";
2398
- portableText: "portableText";
2399
- image: "image";
2400
- reference: "reference";
2401
- json: "json";
2402
- repeater: "repeater";
2403
- }>>;
2404
- elements: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
2405
- type: z$1.ZodString;
2406
- action_id: z$1.ZodString;
2407
- label: z$1.ZodOptional<z$1.ZodString>;
2408
- }, z$1.core.$loose>>>;
2409
- }, z$1.core.$strip>>>;
2410
- }, z$1.core.$strip>;
2411
- }, z$1.core.$strip>;
2412
- type ValidatedPluginManifest = z$1.infer<typeof pluginManifestSchema>;
2413
- //#endregion
2414
- //#region src/plugins/hooks.d.ts
2415
- type HookNameV2 = "plugin:install" | "plugin:activate" | "plugin:deactivate" | "plugin:uninstall" | "content:beforeSave" | "content:afterSave" | "content:beforeDelete" | "content:afterDelete" | "content:afterPublish" | "content:afterUnpublish" | "media:beforeUpload" | "media:afterUpload" | "cron" | "email:beforeSend" | "email:deliver" | "email:afterSend" | "comment:beforeCreate" | "comment:moderate" | "comment:afterCreate" | "comment:afterModerate" | "page:metadata" | "page:fragments";
2468
+ type InferCollectionData<T extends string> = T extends keyof DinewayCollections ? DinewayCollections[T] : Record<string, unknown>;
2416
2469
  /**
2417
- * Hook execution result
2470
+ * Sort direction
2418
2471
  */
2419
- interface HookResult<T> {
2420
- success: boolean;
2421
- value?: T;
2422
- error?: Error;
2423
- pluginId: string;
2424
- duration: number;
2425
- }
2472
+ type SortDirection = "asc" | "desc";
2426
2473
  /**
2427
- * Hook pipeline for executing hooks in order
2474
+ * Order by specification - field name to direction
2475
+ * @example { created_at: "desc" } - Sort by created_at descending
2476
+ * @example { title: "asc" } - Sort by title ascending
2477
+ * @example { published_at: "desc", title: "asc" } - Multi-field sort
2428
2478
  */
2429
- declare class HookPipeline {
2430
- private hooks;
2431
- private pluginMap;
2432
- private contextFactory;
2433
- /** Stored so setContextFactory can merge incrementally. */
2434
- private contextFactoryOptions;
2435
- /** Hook names where at least one handler declared exclusive: true */
2436
- private exclusiveHookNames;
2437
- /**
2438
- * Selected provider plugin ID for each exclusive hook.
2439
- * Set by the PluginManager after resolution.
2440
- */
2441
- private exclusiveSelections;
2442
- constructor(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions);
2443
- /**
2444
- * Set or update the context factory options.
2445
- *
2446
- * When called on a pipeline that already has a factory, the new options
2447
- * are merged on top of the existing ones so that callers don't need to
2448
- * repeat every field (e.g. adding `cronReschedule` without losing
2449
- * `storage` / `getUploadUrl`).
2450
- */
2451
- setContextFactory(options: Partial<PluginContextFactoryOptions>): void;
2452
- /**
2453
- * Get context for a plugin
2454
- */
2455
- private getContext;
2479
+ type OrderBySpec = Record<string, SortDirection>;
2480
+ /**
2481
+ * Fields shared by every collection query, independent of pagination mode.
2482
+ */
2483
+ interface CollectionFilterBase {
2484
+ status?: "draft" | "published" | "archived";
2485
+ limit?: number;
2456
2486
  /**
2457
- * Get typed hooks for a specific hook name.
2458
- * The internal map stores ResolvedHook<unknown>, but we know each name
2459
- * maps to a specific handler type via HookHandlerMap.
2487
+ * Filter by field values, taxonomy terms, byline credits, or ranges.
2460
2488
  *
2461
- * Exclusive hooks that have a selected provider are filtered out — they
2462
- * should only run via invokeExclusiveHook(), not in the regular pipeline.
2463
- */
2464
- private getTypedHooks;
2465
- /**
2466
- * Register all hooks from plugins.
2489
+ * Taxonomy names are detected automatically and filtered by term.
2490
+ * The reserved `byline` key filters by byline credit in any position,
2491
+ * not just the primary credit. It accepts one or more byline translation
2492
+ * groups, or concrete byline row IDs.
2493
+ * Other keys are treated as content table column filters.
2467
2494
  *
2468
- * Registers each hook name individually to preserve type safety. The
2469
- * internal map stores ResolvedHook<unknown> since it's keyed by string,
2470
- * but getTypedHooks() restores the correct handler type on retrieval.
2495
+ * @example { category: 'news' } - Filter by taxonomy term
2496
+ * @example { category: ['news', 'featured'] } - Filter by multiple terms (OR)
2497
+ * @example { byline: '01HXYZ...' } - Entries credited to a byline (any position)
2498
+ * @example { byline: ['01HXYZ...', '01HABC...'] } - Credited to any of these bylines (OR)
2499
+ * @example { series: 'main' } - Exact match on a content field
2500
+ * @example { published_at: { gte: '2024-01-01', lt: '2025-01-01' } } - Date range
2471
2501
  */
2472
- private registerPlugins;
2502
+ where?: Record<string, WhereValue>;
2473
2503
  /**
2474
- * Maps hook names to the capability required to register them.
2504
+ * Case-insensitive substring search across selected content fields.
2475
2505
  *
2476
- * Hooks not listed here have no capability requirement (e.g. lifecycle
2477
- * hooks, cron). Any plugin declaring a listed hook without the required
2478
- * capability will have that hook silently skipped at registration time.
2479
- */
2480
- private static readonly HOOK_REQUIRED_CAPABILITY;
2481
- /**
2482
- * Register a single plugin's hook by name
2483
- */
2484
- private registerPluginHook;
2485
- /**
2486
- * Register a single hook
2487
- */
2488
- private registerHook;
2489
- /**
2490
- * Sort hooks by priority and dependencies
2506
+ * `searchColumns` must contain concrete field slugs or system column names.
2507
+ * When `q` is present without `searchColumns`, no search condition is applied.
2491
2508
  */
2492
- private sortHooks;
2509
+ q?: string;
2510
+ searchColumns?: string[];
2493
2511
  /**
2494
- * Execute a hook with timeout
2512
+ * Order results by field(s)
2513
+ * @default { created_at: "desc" }
2514
+ * @example { created_at: "desc" } - Sort by created_at descending (default)
2515
+ * @example { title: "asc" } - Sort by title ascending
2516
+ * @example { published_at: "desc", title: "asc" } - Multi-field sort
2495
2517
  */
2496
- private executeWithTimeout;
2518
+ orderBy?: OrderBySpec;
2497
2519
  /**
2498
- * Run plugin:install hooks
2520
+ * Filter by locale. When set, only returns entries in this locale.
2521
+ * Only relevant when i18n is configured.
2522
+ * @example "en" — English entries only
2523
+ * @example "fr" — French entries only
2499
2524
  */
2500
- runPluginInstall(pluginId: string): Promise<HookResult<void>[]>;
2525
+ locale?: string;
2526
+ }
2527
+ /** Keyset-paginated query filter. Cannot also carry an offset. */
2528
+ interface CursorCollectionFilter extends CollectionFilterBase {
2501
2529
  /**
2502
- * Run plugin:activate hooks
2530
+ * Opaque cursor for keyset pagination.
2531
+ * Pass the `nextCursor` value from a previous result to fetch the next page.
2532
+ * @example
2533
+ * ```ts
2534
+ * const cursor = Astro.url.searchParams.get("cursor") ?? undefined;
2535
+ * const { entries, nextCursor } = await getDinewayCollection("posts", {
2536
+ * limit: 10,
2537
+ * cursor,
2538
+ * });
2539
+ * ```
2503
2540
  */
2504
- runPluginActivate(pluginId: string): Promise<HookResult<void>[]>;
2541
+ cursor?: string;
2542
+ offset?: never;
2543
+ }
2544
+ /** Offset-paginated query filter. Cannot also carry a cursor. */
2545
+ interface OffsetCollectionFilter extends CollectionFilterBase {
2505
2546
  /**
2506
- * Run plugin:deactivate hooks
2547
+ * Skip this many entries before returning results. Use with `limit` for
2548
+ * numbered archive routes, for example `offset = (page - 1) * perPage`.
2507
2549
  */
2508
- runPluginDeactivate(pluginId: string): Promise<HookResult<void>[]>;
2509
- /**
2510
- * Run plugin:uninstall hooks
2511
- */
2512
- runPluginUninstall(pluginId: string, deleteData: boolean): Promise<HookResult<void>[]>;
2513
- private runLifecycleHook;
2514
- /**
2515
- * Run content:beforeSave hooks
2516
- * Returns modified content from the pipeline
2517
- */
2518
- runContentBeforeSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<{
2519
- content: Record<string, unknown>;
2520
- results: HookResult<Record<string, unknown>>[];
2521
- }>;
2522
- /**
2523
- * Run content:afterSave hooks
2524
- */
2525
- runContentAfterSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<HookResult<void>[]>;
2526
- /**
2527
- * Run content:beforeDelete hooks
2528
- * Returns whether deletion is allowed
2529
- */
2530
- runContentBeforeDelete(id: string, collection: string): Promise<{
2531
- allowed: boolean;
2532
- results: HookResult<boolean>[];
2533
- }>;
2534
- /**
2535
- * Run content:afterDelete hooks
2536
- */
2537
- runContentAfterDelete(id: string, collection: string, permanent: boolean): Promise<HookResult<void>[]>;
2538
- /**
2539
- * Run content:afterPublish hooks (fire-and-forget).
2540
- */
2541
- runContentAfterPublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
2542
- /**
2543
- * Run content:afterUnpublish hooks (fire-and-forget).
2544
- */
2545
- runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
2546
- /**
2547
- * Run media:beforeUpload hooks
2548
- */
2549
- runMediaBeforeUpload(file: {
2550
- name: string;
2551
- type: string;
2552
- size: number;
2553
- }): Promise<{
2554
- file: {
2555
- name: string;
2556
- type: string;
2557
- size: number;
2558
- };
2559
- results: HookResult<{
2560
- name: string;
2561
- type: string;
2562
- size: number;
2563
- }>[];
2564
- }>;
2565
- /**
2566
- * Run media:afterUpload hooks
2567
- */
2568
- runMediaAfterUpload(media: {
2569
- id: string;
2570
- filename: string;
2571
- mimeType: string;
2572
- size: number | null;
2573
- url: string;
2574
- createdAt: string;
2575
- }): Promise<HookResult<void>[]>;
2576
- /**
2577
- * Invoke the cron hook for a specific plugin.
2578
- *
2579
- * Unlike other hooks which broadcast to all plugins, the cron hook is
2580
- * dispatched only to the target plugin — the one that owns the task.
2581
- */
2582
- invokeCronHook(pluginId: string, event: CronEvent): Promise<HookResult<void>>;
2583
- /**
2584
- * Run email:beforeSend hooks (middleware pipeline).
2585
- *
2586
- * Each handler receives the message and returns a modified message or
2587
- * `false` to cancel delivery. The pipeline chains message transformations —
2588
- * each handler receives the output of the previous one.
2589
- */
2590
- runEmailBeforeSend(message: EmailMessage, source: string): Promise<{
2591
- message: EmailMessage | false;
2592
- results: HookResult<EmailMessage | false>[];
2593
- }>;
2594
- /**
2595
- * Run email:afterSend hooks (fire-and-forget).
2596
- *
2597
- * Errors are logged but don't propagate — they don't affect the caller.
2598
- */
2599
- runEmailAfterSend(message: EmailMessage, source: string): Promise<HookResult<void>[]>;
2600
- /**
2601
- * Run comment:beforeCreate hooks (middleware pipeline).
2602
- *
2603
- * Each handler receives the event and returns a modified event or
2604
- * `false` to reject the comment. The pipeline chains transformations —
2605
- * each handler receives the output of the previous one.
2606
- */
2607
- runCommentBeforeCreate(event: CommentBeforeCreateEvent): Promise<CommentBeforeCreateEvent | false>;
2608
- /**
2609
- * Run comment:afterCreate hooks (fire-and-forget).
2610
- *
2611
- * Errors are logged but don't propagate — they don't affect the caller.
2612
- */
2613
- runCommentAfterCreate(event: CommentAfterCreateEvent): Promise<void>;
2614
- /**
2615
- * Run comment:afterModerate hooks (fire-and-forget).
2616
- *
2617
- * Errors are logged but don't propagate — they don't affect the caller.
2618
- */
2619
- runCommentAfterModerate(event: CommentAfterModerateEvent): Promise<void>;
2620
- /**
2621
- * Run page:metadata hooks. Each handler returns contributions that are
2622
- * merged by the metadata collector. Errors are logged but don't propagate.
2623
- */
2624
- runPageMetadata(event: PageMetadataEvent): Promise<Array<{
2625
- pluginId: string;
2626
- contributions: PageMetadataContribution[];
2627
- }>>;
2628
- /**
2629
- * Run page:fragments hooks. Only trusted plugins should be registered
2630
- * for this hook. Errors are logged but don't propagate.
2631
- */
2632
- runPageFragments(event: PageFragmentEvent): Promise<Array<{
2633
- pluginId: string;
2634
- contributions: PageFragmentContribution[];
2635
- }>>;
2636
- /**
2637
- * Check if any hooks are registered for a given name
2638
- */
2639
- hasHooks(name: HookNameV2): boolean;
2640
- /**
2641
- * Get hook count for debugging
2642
- */
2643
- getHookCount(name: HookNameV2): number;
2644
- /**
2645
- * Get all registered hook names
2646
- */
2647
- getRegisteredHooks(): HookNameV2[];
2648
- /**
2649
- * Returns hook names where at least one handler declared exclusive: true
2650
- */
2651
- getRegisteredExclusiveHooks(): string[];
2652
- /**
2653
- * Check if a hook is exclusive
2654
- */
2655
- isExclusiveHook(name: string): boolean;
2656
- /**
2657
- * Set the selected provider for an exclusive hook.
2658
- * Called by PluginManager after resolution.
2659
- */
2660
- setExclusiveSelection(hookName: string, pluginId: string): void;
2661
- /**
2662
- * Clear the selected provider for an exclusive hook.
2663
- */
2664
- clearExclusiveSelection(hookName: string): void;
2665
- /**
2666
- * Get the selected provider for an exclusive hook (if any).
2667
- */
2668
- getExclusiveSelection(hookName: string): string | undefined;
2550
+ offset?: number;
2551
+ cursor?: never;
2552
+ }
2553
+ type CollectionFilter = CursorCollectionFilter | OffsetCollectionFilter;
2554
+ interface ContentEntry<T = Record<string, unknown>> {
2555
+ id: string;
2556
+ data: T;
2557
+ /** Visual editing annotations. Spread onto elements: {...entry.edit.title} */
2558
+ edit: EditProxy;
2559
+ }
2560
+ /** Cache hint returned by the content loader for route caching */
2561
+ interface CacheHint {
2562
+ tags?: string[];
2563
+ lastModified?: Date;
2564
+ }
2565
+ /**
2566
+ * Result from getDinewayCollection
2567
+ */
2568
+ interface CollectionResult<T> {
2569
+ /** The entries (empty array if error or none found) */
2570
+ entries: ContentEntry<T>[];
2571
+ /** Error if the query failed */
2572
+ error?: Error;
2573
+ /** Cache hint for route caching (pass to Astro.cache.set()) */
2574
+ cacheHint: CacheHint;
2669
2575
  /**
2670
- * Get all plugins that registered a handler for a given exclusive hook.
2576
+ * Opaque cursor for the next page.
2577
+ * Undefined when there are no more results.
2578
+ * Pass this as `cursor` in the next query to get the next page.
2671
2579
  */
2672
- getExclusiveHookProviders(hookName: string): Array<{
2673
- pluginId: string;
2674
- }>;
2580
+ nextCursor?: string;
2675
2581
  /**
2676
- * Get all plugins that registered a non-exclusive handler for a given hook,
2677
- * preserving priority order. This partitions with getExclusiveHookProviders().
2582
+ * Whether more entries exist beyond this page. Set whenever `limit` is
2583
+ * provided, including offset-paginated numbered archives.
2678
2584
  */
2679
- getHookProviders(hookName: string): Array<{
2680
- pluginId: string;
2681
- }>;
2585
+ hasMore?: boolean;
2682
2586
  /**
2683
- * Invoke an exclusive hook — dispatch only to the selected provider.
2684
- * Returns null if no provider is selected or if the selected hook
2685
- * is not found in the pipeline.
2686
- *
2687
- * This is a generic dispatch used by the email pipeline and other
2688
- * exclusive hook consumers. The handler type is unknown — callers
2689
- * must know the expected signature.
2690
- *
2691
- * Errors are isolated: a failing handler returns an error result
2692
- * instead of propagating the exception to the caller.
2587
+ * Total number of entries matching the current filter, excluding cursor and limit.
2693
2588
  */
2694
- invokeExclusiveHook(hookName: string, event: unknown): Promise<{
2695
- result: unknown;
2696
- pluginId: string;
2697
- error?: Error;
2698
- duration: number;
2699
- } | null>;
2589
+ total?: number;
2700
2590
  }
2701
2591
  /**
2702
- * Create a hook pipeline from plugins
2592
+ * Result from getDinewayEntry
2703
2593
  */
2704
- declare function createHookPipeline(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions): HookPipeline;
2705
- //#endregion
2706
- //#region src/plugins/email.d.ts
2594
+ interface EntryResult<T> {
2595
+ /** The entry, or null if not found */
2596
+ entry: ContentEntry<T> | null;
2597
+ /** Error if the query failed (not set for "not found", only for actual errors) */
2598
+ error?: Error;
2599
+ /** Whether we're in preview mode (valid token was provided) */
2600
+ isPreview: boolean;
2601
+ /** Set when a fallback locale was used instead of the requested locale */
2602
+ fallbackLocale?: string;
2603
+ /** Cache hint for route caching (pass to Astro.cache.set()) */
2604
+ cacheHint: CacheHint;
2605
+ }
2606
+ /** Edit metadata attached to PT arrays in edit mode */
2607
+ interface EditFieldMeta {
2608
+ collection: string;
2609
+ id: string;
2610
+ field: string;
2611
+ }
2707
2612
  /**
2708
- * EmailPipeline orchestrates email delivery through the plugin hook system.
2709
- *
2710
- * The pipeline runs in three stages:
2711
- * 1. email:beforeSend — middleware hooks that can transform or cancel messages
2712
- * 2. email:deliver — exclusive hook dispatching to the selected provider
2713
- * 3. email:afterSend — fire-and-forget hooks for logging/analytics
2613
+ * Read edit metadata from a value (returns undefined if not tagged).
2614
+ * Uses Object.getOwnPropertyDescriptor to access Symbol-keyed property
2615
+ * without an unsafe type assertion.
2714
2616
  */
2715
- declare class EmailPipeline {
2716
- private pipeline;
2717
- constructor(pipeline: HookPipeline);
2718
- /**
2719
- * Replace the underlying hook pipeline.
2720
- *
2721
- * Called by the runtime when rebuilding the hook pipeline after a
2722
- * plugin is enabled or disabled, so the email pipeline dispatches
2723
- * to the current set of active hooks.
2724
- */
2725
- setPipeline(pipeline: HookPipeline): void;
2726
- /**
2727
- * Send an email through the full pipeline.
2728
- *
2729
- * @param message - The email to send
2730
- * @param source - Where the email originated ("system" for auth, plugin ID for plugins)
2731
- * @throws EmailNotConfiguredError if no provider is selected
2732
- * @throws EmailRecursionError if called re-entrantly from within a hook
2733
- * @throws Error if the provider handler throws
2734
- */
2735
- send(message: EmailMessage, source: string): Promise<void>;
2736
- /**
2737
- * Inner send implementation, separated from the recursion guard.
2738
- */
2739
- private sendInner;
2740
- /**
2741
- * Check if an email provider is configured and available.
2742
- *
2743
- * Returns true if an email:deliver provider is selected in the exclusive
2744
- * hook system. Plugins and auth code use this to decide whether to show
2745
- * "send invite" vs "copy invite link" UI.
2746
- */
2747
- isAvailable(): boolean;
2617
+ declare function getEditMeta(value: unknown): EditFieldMeta | undefined;
2618
+ /**
2619
+ * Get all entries of a content type
2620
+ *
2621
+ * Returns { entries, error } for graceful error handling.
2622
+ *
2623
+ * When dineway-env.d.ts is generated, the collection name will be
2624
+ * type-checked and the return type will be inferred automatically.
2625
+ *
2626
+ * @example
2627
+ * ```ts
2628
+ * import { getDinewayCollection } from "dineway";
2629
+ *
2630
+ * const { entries: posts, error } = await getDinewayCollection("posts");
2631
+ * if (error) {
2632
+ * console.error("Failed to load posts:", error);
2633
+ * return;
2634
+ * }
2635
+ * // posts[0].data.title is typed (if dineway-env.d.ts exists)
2636
+ *
2637
+ * // With filters
2638
+ * const { entries: drafts } = await getDinewayCollection("posts", { status: "draft" });
2639
+ * ```
2640
+ */
2641
+ declare function getDinewayCollection<T extends string, D = InferCollectionData<T>>(type: T, filter?: CollectionFilter): Promise<CollectionResult<D>>;
2642
+ /**
2643
+ * Get a single entry by type and ID/slug
2644
+ *
2645
+ * Returns { entry, error, isPreview } for graceful error handling.
2646
+ * - entry is null if not found (not an error)
2647
+ * - error is set only for actual errors (db issues, etc.)
2648
+ *
2649
+ * Preview mode is detected automatically from request context (ALS).
2650
+ * When the URL has a valid `_preview` token, the middleware sets preview
2651
+ * context and this function serves draft revision data if available.
2652
+ *
2653
+ * @example
2654
+ * ```ts
2655
+ * import { getDinewayEntry } from "dineway";
2656
+ *
2657
+ * // Simple usage — preview just works via middleware
2658
+ * const { entry: post, isPreview, error } = await getDinewayEntry("posts", "my-slug");
2659
+ * if (!post) return Astro.redirect("/404");
2660
+ * ```
2661
+ */
2662
+ declare function getDinewayEntry<T extends string, D = InferCollectionData<T>>(type: T, id: string, options?: {
2663
+ locale?: string;
2664
+ }): Promise<EntryResult<D>>;
2665
+ /**
2666
+ * Translation summary for a single locale variant
2667
+ */
2668
+ interface TranslationSummary {
2669
+ /** Content item ID */
2670
+ id: string;
2671
+ /** Locale code (e.g. "en", "fr") */
2672
+ locale: string;
2673
+ /** URL slug */
2674
+ slug: string | null;
2675
+ /** Current status */
2676
+ status: string;
2677
+ }
2678
+ /**
2679
+ * Result from getTranslations
2680
+ */
2681
+ interface TranslationsResult {
2682
+ /** The translation group ID (shared across locales) */
2683
+ translationGroup: string;
2684
+ /** All locale variants in this group */
2685
+ translations: TranslationSummary[];
2686
+ /** Error if the query failed */
2687
+ error?: Error;
2748
2688
  }
2689
+ /**
2690
+ * Get all translations of a content item.
2691
+ *
2692
+ * Given a content entry, returns all locale variants that share the same
2693
+ * translation group. This is useful for building language switcher UI.
2694
+ *
2695
+ * @example
2696
+ * ```ts
2697
+ * import { getDinewayEntry, getTranslations } from "dineway";
2698
+ *
2699
+ * const { entry: post } = await getDinewayEntry("posts", "hello-world", { locale: "en" });
2700
+ * const { translations } = await getTranslations("posts", post.data.id);
2701
+ * // translations = [{ id: "...", locale: "en", slug: "hello-world", status: "published" }, ...]
2702
+ * ```
2703
+ */
2704
+ declare function getTranslations(type: string, id: string): Promise<TranslationsResult>;
2705
+ /**
2706
+ * Result from resolveDinewayPath
2707
+ */
2708
+ interface ResolvePathResult<T = Record<string, unknown>> {
2709
+ /** The matched entry */
2710
+ entry: ContentEntry<T>;
2711
+ /** The collection slug that matched */
2712
+ collection: string;
2713
+ /** Extracted parameters from the URL pattern (e.g. { slug: "my-post" }) */
2714
+ params: Record<string, string>;
2715
+ }
2716
+ /**
2717
+ * Resolve a URL path to a content entry by matching against collection URL patterns.
2718
+ *
2719
+ * Loads all collections with a `urlPattern` set, converts each pattern to a regex,
2720
+ * and tests the given path. On match, extracts the slug and fetches the entry.
2721
+ *
2722
+ * @example
2723
+ * ```ts
2724
+ * import { resolveDinewayPath } from "dineway";
2725
+ *
2726
+ * // Given pages with urlPattern "/{slug}" and posts with "/blog/{slug}":
2727
+ * const result = await resolveDinewayPath("/blog/hello-world");
2728
+ * if (result) {
2729
+ * console.log(result.collection); // "posts"
2730
+ * console.log(result.params.slug); // "hello-world"
2731
+ * console.log(result.entry.data); // post data
2732
+ * }
2733
+ * ```
2734
+ */
2735
+ declare function resolveDinewayPath<T = Record<string, unknown>>(path: string): Promise<ResolvePathResult<T> | null>;
2736
+ //#endregion
2737
+ //#region src/after.d.ts
2738
+ /**
2739
+ * Defer work past the current synchronous path.
2740
+ *
2741
+ * Use this for best-effort bookkeeping that should not block runtime
2742
+ * initialization or response handling. Node keeps the process alive for
2743
+ * pending work; callers that need stronger durability should await their own
2744
+ * operation instead of using this helper.
2745
+ */
2746
+ type AfterCallback = () => void | Promise<void>;
2747
+ declare function after(fn: AfterCallback): void;
2748
+ //#endregion
2749
+ //#region src/object-cache/index.d.ts
2750
+ /** Options for {@link cachedQuery}. */
2751
+ interface CachedQueryOptions<T> {
2752
+ /**
2753
+ * Invalidation namespace(s). A single string for self-contained data
2754
+ * (`settings`, `menus`), or several when the cached value depends on data
2755
+ * owned by other namespaces — e.g. a content entry hydrates bylines and
2756
+ * taxonomy terms, so it caches under
2757
+ * `[content:posts, "bylines", "taxonomies"]` and is invalidated when *any*
2758
+ * of them is bumped. Every namespace's epoch is folded into the key.
2759
+ */
2760
+ namespace: string | readonly string[];
2761
+ /** Stable, fully-qualifying cache key *within* the namespace. */
2762
+ key: string;
2763
+ /** Loader run on a miss (or when caching is disabled/bypassed). */
2764
+ load: () => Promise<T>;
2765
+ /** TTL override in seconds. Falls back to the configured `defaultTtl`. */
2766
+ ttl?: number;
2767
+ /**
2768
+ * Predicate gating whether a freshly-loaded value is stored. Defaults to
2769
+ * always-cache. Use it to skip caching error/empty sentinels.
2770
+ */
2771
+ cacheable?: (value: T) => boolean;
2772
+ }
2773
+ /**
2774
+ * Distributed read-through cache around `load`.
2775
+ *
2776
+ * `T` must be the value as it should be *stored* — i.e. JSON-serializable with
2777
+ * the codec's `Date` support, carrying no functions or symbol-keyed props.
2778
+ * Callers caching richer objects (content entries) reduce to a serializable
2779
+ * snapshot here and rebuild on the way out; see `query.ts`.
2780
+ *
2781
+ * On a miss or when the cache is disabled/bypassed, this is equivalent to
2782
+ * `await load()`. Backend errors never propagate: a failing `get` is a miss, a
2783
+ * failing `set` is dropped.
2784
+ */
2785
+ declare function cachedQuery<T>(options: CachedQueryOptions<T>): Promise<T>;
2786
+ /** Whether object-cache reads are active for the current request. */
2787
+ declare function isObjectCacheActive(): Promise<boolean>;
2788
+ /**
2789
+ * Invalidate every cached value in `namespace` by bumping its epoch.
2790
+ *
2791
+ * Sync and non-blocking: the local epoch is stamped immediately (so the
2792
+ * writing isolate is instantly consistent) and the backend write is deferred
2793
+ * via `after`. Other isolates pick up the new epoch within their `revalidate`
2794
+ * window. No-ops when the cache is disabled.
2795
+ */
2796
+ declare function invalidateObjectCache(namespace: string): void;
2797
+ /**
2798
+ * Fixed namespaces for data shared across collections. Content reads fold the
2799
+ * `BYLINES` and `TAXONOMIES` epochs into their keys (via {@link cachedQuery})
2800
+ * because entries hydrate byline and taxonomy-term data — so renaming an
2801
+ * author or a category correctly invalidates every cached entry that displays
2802
+ * it, without tracking which collections reference it.
2803
+ */
2804
+ declare const CacheNamespace: {
2805
+ readonly SETTINGS: "settings";
2806
+ readonly MENUS: "menus";
2807
+ readonly TAXONOMIES: "taxonomies";
2808
+ readonly BYLINES: "bylines"; /** Collection schema/metadata (label, supports, commentsEnabled, fields). */
2809
+ readonly SCHEMA: "schema"; /** Public (approved) comments. */
2810
+ readonly COMMENTS: "comments";
2811
+ };
2812
+ /** Namespace for a content collection's cached queries. */
2813
+ declare function contentNamespace(collection: string): string;
2814
+ /**
2815
+ * Namespaces a content read depends on: the collection itself plus the shared
2816
+ * byline/taxonomy data folded into each entry.
2817
+ */
2818
+ declare function contentNamespaces(collection: string): readonly string[];
2819
+ /**
2820
+ * Invalidate all cached reads (list + entry) for a content collection.
2821
+ * Call from every write path that mutates rows in `ec_<collection>`.
2822
+ */
2823
+ declare function invalidateCollectionCache(collection: string): void;
2824
+ /** Invalidate cached taxonomy definitions/terms and all content that hydrates them. */
2825
+ declare function invalidateTaxonomyObjectCache(): void;
2826
+ /** Invalidate cached bylines and all content that hydrates them. */
2827
+ declare function invalidateBylineObjectCache(): void;
2828
+ /** Invalidate cached navigation menus. */
2829
+ declare function invalidateMenuObjectCache(): void;
2830
+ /** Invalidate cached collection schema/metadata reads (e.g. getCollectionInfo). */
2831
+ declare function invalidateSchemaObjectCache(): void;
2832
+ /** Invalidate cached public comment reads. */
2833
+ declare function invalidateCommentObjectCache(): void;
2834
+ //#endregion
2835
+ //#region src/i18n/config.d.ts
2836
+ /**
2837
+ * Dineway i18n Configuration
2838
+ *
2839
+ * Reads locale configuration from the virtual module (sourced from Astro config).
2840
+ * Initialized during runtime startup, then available via getI18nConfig().
2841
+ */
2842
+ interface I18nConfig {
2843
+ defaultLocale: string;
2844
+ locales: string[];
2845
+ fallback?: Record<string, string>;
2846
+ prefixDefaultLocale?: boolean;
2847
+ }
2848
+ /**
2849
+ * Get the current i18n config.
2850
+ * Returns null if i18n is not configured.
2851
+ */
2852
+ declare function getI18nConfig(): I18nConfig | null;
2853
+ /**
2854
+ * Check if i18n is enabled.
2855
+ * Returns true when multiple locales are configured.
2856
+ */
2857
+ declare function isI18nEnabled(): boolean;
2858
+ /**
2859
+ * Resolve fallback locale chain for a given locale.
2860
+ * Returns array of locales to try, from most preferred to least.
2861
+ * Always ends with defaultLocale.
2862
+ */
2863
+ declare function getFallbackChain(locale: string): string[];
2864
+ //#endregion
2865
+ //#region src/preview/sidecar-client.d.ts
2866
+ /**
2867
+ * Preview sidecar protocol helpers.
2868
+ *
2869
+ * These utilities define the signed URL and snapshot-auth contract shared
2870
+ * by preview sidecars and the source site serving snapshot exports.
2871
+ */
2872
+ interface PreviewSidecarSignature {
2873
+ source: string;
2874
+ exp: number;
2875
+ sig: string;
2876
+ }
2877
+ interface PreviewSidecarClient {
2878
+ signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
2879
+ buildSnapshotSignatureHeader(signature: PreviewSidecarSignature): string;
2880
+ }
2881
+ declare function signPreviewUrl(previewBase: string, source: string, secret: string, ttl?: number): Promise<string>;
2882
+ declare function buildPreviewSignatureHeader(signature: PreviewSidecarSignature): string;
2883
+ declare function parsePreviewSignatureHeader(header: string): PreviewSidecarSignature | null;
2884
+ declare function verifyPreviewSignature(source: string, exp: number, sig: string, secret: string): Promise<boolean>;
2885
+ declare const defaultPreviewSidecarClient: PreviewSidecarClient;
2886
+ //#endregion
2887
+ //#region src/preview/session-database-factory.d.ts
2888
+ interface SessionDatabaseInfo {
2889
+ id: string;
2890
+ dbPath: string;
2891
+ createdAt: number;
2892
+ expiresAt: number;
2893
+ lastTouchedAt: number;
2894
+ }
2895
+ interface SessionDatabaseHandle {
2896
+ created: boolean;
2897
+ session: SessionDatabaseInfo;
2898
+ db: Kysely<Database>;
2899
+ close(): Promise<void>;
2900
+ }
2901
+ interface SessionCleanupResult {
2902
+ removedSessionIds: string[];
2903
+ removedPaths: string[];
2904
+ }
2905
+ interface SessionOpenOptions {
2906
+ id: string;
2907
+ now?: number;
2908
+ }
2909
+ interface SessionOpenOrCreateOptions extends SessionOpenOptions {
2910
+ ttlMs: number;
2911
+ }
2912
+ interface SessionDatabaseFactory {
2913
+ open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
2914
+ openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
2915
+ destroy(id: string): Promise<boolean>;
2916
+ cleanup(now?: number): Promise<SessionCleanupResult>;
2917
+ close(): Promise<void>;
2918
+ }
2919
+ interface FileSessionDatabaseFactoryOptions {
2920
+ rootDir: string;
2921
+ maxDiskBytes?: number;
2922
+ registryFileName?: string;
2923
+ sessionsDirName?: string;
2924
+ }
2925
+ declare class SessionDatabaseLimitError extends Error {
2926
+ constructor(message?: string);
2927
+ }
2928
+ declare class FileSessionDatabaseFactory implements SessionDatabaseFactory {
2929
+ private readonly options;
2930
+ private readonly registry;
2931
+ private readonly sessionsDir;
2932
+ private readonly maxDiskBytes;
2933
+ constructor(options: FileSessionDatabaseFactoryOptions);
2934
+ open(input: SessionOpenOptions): Promise<SessionDatabaseHandle | null>;
2935
+ openOrCreate(input: SessionOpenOrCreateOptions): Promise<SessionDatabaseHandle>;
2936
+ destroy(id: string): Promise<boolean>;
2937
+ cleanup(now?: number): Promise<SessionCleanupResult>;
2938
+ close(): Promise<void>;
2939
+ private createHandle;
2940
+ private getSessionRow;
2941
+ private toSessionInfo;
2942
+ private deleteSession;
2943
+ private getActiveDiskBytes;
2944
+ private getDbPath;
2945
+ private getManagedPaths;
2946
+ private listSessionRows;
2947
+ private listDbPathRows;
2948
+ }
2949
+ //#endregion
2950
+ //#region src/preview/middleware.d.ts
2951
+ interface FilePreviewMiddlewareConfig {
2952
+ rootDir?: string;
2953
+ secret: string;
2954
+ ttlSeconds?: number;
2955
+ cookieName?: string;
2956
+ snapshotPath?: string;
2957
+ maxSessionDiskBytes?: number;
2958
+ sessionFactory?: SessionDatabaseFactory;
2959
+ fetch?: typeof globalThis.fetch;
2960
+ }
2961
+ declare function createFilePreviewMiddleware(config: FilePreviewMiddlewareConfig): MiddlewareHandler;
2962
+ //#endregion
2963
+ //#region src/plugins/define-plugin.d.ts
2964
+ /**
2965
+ * Define a Dineway plugin.
2966
+ *
2967
+ * **Standard format** -- the canonical format for plugins that work in both
2968
+ * trusted and sandboxed modes. No id/version -- those come from the descriptor.
2969
+ *
2970
+ * @example
2971
+ * ```typescript
2972
+ * import { definePlugin } from "dineway";
2973
+ *
2974
+ * export default definePlugin({
2975
+ * hooks: {
2976
+ * "content:afterSave": {
2977
+ * handler: async (event, ctx) => {
2978
+ * await ctx.kv.set("lastSave", Date.now());
2979
+ * },
2980
+ * },
2981
+ * },
2982
+ * routes: {
2983
+ * status: {
2984
+ * handler: async (routeCtx, ctx) => ({ ok: true }),
2985
+ * },
2986
+ * },
2987
+ * });
2988
+ * ```
2989
+ *
2990
+ * **Native format** -- for plugins that need React admin, direct DB access,
2991
+ * or other capabilities not available in the sandbox.
2992
+ *
2993
+ * @example
2994
+ * ```typescript
2995
+ * import { definePlugin } from "dineway";
2996
+ *
2997
+ * export default definePlugin({
2998
+ * id: "my-plugin",
2999
+ * version: "1.0.0",
3000
+ * capabilities: ["content:read"],
3001
+ * hooks: {
3002
+ * "content:beforeSave": async (event, ctx) => {
3003
+ * ctx.log.info("Saving content", { collection: event.collection });
3004
+ * return event.content;
3005
+ * }
3006
+ * },
3007
+ * routes: {
3008
+ * "sync": {
3009
+ * handler: async (ctx) => {
3010
+ * return { status: "ok" };
3011
+ * }
3012
+ * }
3013
+ * }
3014
+ * });
3015
+ * ```
3016
+ */
3017
+ declare function definePlugin<TStorage extends PluginStorageConfig>(definition: PluginDefinition<TStorage>): ResolvedPlugin<TStorage>;
3018
+ declare function definePlugin(definition: StandardPluginDefinition): StandardPluginDefinition;
3019
+ //#endregion
3020
+ //#region src/plugins/manifest-schema.d.ts
3021
+ /**
3022
+ * Zod schema matching the PluginManifest interface from types.ts.
3023
+ *
3024
+ * Every JSON.parse of a manifest.json should validate through this.
3025
+ */
3026
+ declare const pluginManifestSchema: z$1.ZodObject<{
3027
+ id: z$1.ZodString;
3028
+ version: z$1.ZodString;
3029
+ declaredAccess: z$1.ZodOptional<z$1.ZodObject<{
3030
+ content: z$1.ZodOptional<z$1.ZodObject<{
3031
+ read: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3032
+ write: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3033
+ }, z$1.core.$strip>>;
3034
+ media: z$1.ZodOptional<z$1.ZodObject<{
3035
+ read: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3036
+ write: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3037
+ }, z$1.core.$strip>>;
3038
+ network: z$1.ZodOptional<z$1.ZodObject<{
3039
+ request: z$1.ZodOptional<z$1.ZodObject<{
3040
+ allowedHosts: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>;
3041
+ }, z$1.core.$strip>>;
3042
+ }, z$1.core.$strip>>;
3043
+ email: z$1.ZodOptional<z$1.ZodObject<{
3044
+ send: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3045
+ events: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3046
+ transport: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3047
+ }, z$1.core.$strip>>;
3048
+ page: z$1.ZodOptional<z$1.ZodObject<{
3049
+ fragments: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3050
+ }, z$1.core.$strip>>;
3051
+ users: z$1.ZodOptional<z$1.ZodObject<{
3052
+ read: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodUnknown>>;
3053
+ }, z$1.core.$strip>>;
3054
+ }, z$1.core.$strip>>;
3055
+ capabilities: z$1.ZodArray<z$1.ZodEnum<{
3056
+ "network:request": "network:request";
3057
+ "network:request:unrestricted": "network:request:unrestricted";
3058
+ "content:read": "content:read";
3059
+ "content:write": "content:write";
3060
+ "media:read": "media:read";
3061
+ "media:write": "media:write";
3062
+ "users:read": "users:read";
3063
+ "email:send": "email:send";
3064
+ "hooks.email-transport:register": "hooks.email-transport:register";
3065
+ "hooks.email-events:register": "hooks.email-events:register";
3066
+ "hooks.page-fragments:register": "hooks.page-fragments:register";
3067
+ }>>;
3068
+ allowedHosts: z$1.ZodArray<z$1.ZodString>;
3069
+ storage: z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
3070
+ indexes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>;
3071
+ uniqueIndexes: z$1.ZodOptional<z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodArray<z$1.ZodString>]>>>;
3072
+ }, z$1.core.$strip>>;
3073
+ hooks: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodEnum<{
3074
+ "plugin:install": "plugin:install";
3075
+ "plugin:activate": "plugin:activate";
3076
+ "plugin:deactivate": "plugin:deactivate";
3077
+ "plugin:uninstall": "plugin:uninstall";
3078
+ "content:beforeSave": "content:beforeSave";
3079
+ "content:afterSave": "content:afterSave";
3080
+ "content:beforeDelete": "content:beforeDelete";
3081
+ "content:afterDelete": "content:afterDelete";
3082
+ "content:afterPublish": "content:afterPublish";
3083
+ "content:afterUnpublish": "content:afterUnpublish";
3084
+ "content:afterRestore": "content:afterRestore";
3085
+ "content:afterSchedule": "content:afterSchedule";
3086
+ "content:afterUnschedule": "content:afterUnschedule";
3087
+ "media:beforeUpload": "media:beforeUpload";
3088
+ "media:afterUpload": "media:afterUpload";
3089
+ cron: "cron";
3090
+ "email:beforeSend": "email:beforeSend";
3091
+ "email:deliver": "email:deliver";
3092
+ "email:afterSend": "email:afterSend";
3093
+ "comment:beforeCreate": "comment:beforeCreate";
3094
+ "comment:moderate": "comment:moderate";
3095
+ "comment:afterCreate": "comment:afterCreate";
3096
+ "comment:afterModerate": "comment:afterModerate";
3097
+ "page:metadata": "page:metadata";
3098
+ "page:fragments": "page:fragments";
3099
+ }>, z$1.ZodObject<{
3100
+ name: z$1.ZodEnum<{
3101
+ "plugin:install": "plugin:install";
3102
+ "plugin:activate": "plugin:activate";
3103
+ "plugin:deactivate": "plugin:deactivate";
3104
+ "plugin:uninstall": "plugin:uninstall";
3105
+ "content:beforeSave": "content:beforeSave";
3106
+ "content:afterSave": "content:afterSave";
3107
+ "content:beforeDelete": "content:beforeDelete";
3108
+ "content:afterDelete": "content:afterDelete";
3109
+ "content:afterPublish": "content:afterPublish";
3110
+ "content:afterUnpublish": "content:afterUnpublish";
3111
+ "content:afterRestore": "content:afterRestore";
3112
+ "content:afterSchedule": "content:afterSchedule";
3113
+ "content:afterUnschedule": "content:afterUnschedule";
3114
+ "media:beforeUpload": "media:beforeUpload";
3115
+ "media:afterUpload": "media:afterUpload";
3116
+ cron: "cron";
3117
+ "email:beforeSend": "email:beforeSend";
3118
+ "email:deliver": "email:deliver";
3119
+ "email:afterSend": "email:afterSend";
3120
+ "comment:beforeCreate": "comment:beforeCreate";
3121
+ "comment:moderate": "comment:moderate";
3122
+ "comment:afterCreate": "comment:afterCreate";
3123
+ "comment:afterModerate": "comment:afterModerate";
3124
+ "page:metadata": "page:metadata";
3125
+ "page:fragments": "page:fragments";
3126
+ }>;
3127
+ exclusive: z$1.ZodOptional<z$1.ZodBoolean>;
3128
+ priority: z$1.ZodOptional<z$1.ZodNumber>;
3129
+ timeout: z$1.ZodOptional<z$1.ZodNumber>;
3130
+ }, z$1.core.$strip>]>>;
3131
+ routes: z$1.ZodArray<z$1.ZodUnion<readonly [z$1.ZodString, z$1.ZodObject<{
3132
+ name: z$1.ZodString;
3133
+ public: z$1.ZodOptional<z$1.ZodBoolean>;
3134
+ }, z$1.core.$strip>]>>;
3135
+ admin: z$1.ZodObject<{
3136
+ entry: z$1.ZodOptional<z$1.ZodString>;
3137
+ settingsSchema: z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{
3138
+ type: z$1.ZodLiteral<"string">;
3139
+ default: z$1.ZodOptional<z$1.ZodString>;
3140
+ multiline: z$1.ZodOptional<z$1.ZodBoolean>;
3141
+ label: z$1.ZodString;
3142
+ description: z$1.ZodOptional<z$1.ZodString>;
3143
+ }, z$1.core.$strip>, z$1.ZodObject<{
3144
+ type: z$1.ZodLiteral<"number">;
3145
+ default: z$1.ZodOptional<z$1.ZodNumber>;
3146
+ min: z$1.ZodOptional<z$1.ZodNumber>;
3147
+ max: z$1.ZodOptional<z$1.ZodNumber>;
3148
+ label: z$1.ZodString;
3149
+ description: z$1.ZodOptional<z$1.ZodString>;
3150
+ }, z$1.core.$strip>, z$1.ZodObject<{
3151
+ type: z$1.ZodLiteral<"boolean">;
3152
+ default: z$1.ZodOptional<z$1.ZodBoolean>;
3153
+ label: z$1.ZodString;
3154
+ description: z$1.ZodOptional<z$1.ZodString>;
3155
+ }, z$1.core.$strip>, z$1.ZodObject<{
3156
+ type: z$1.ZodLiteral<"select">;
3157
+ options: z$1.ZodArray<z$1.ZodObject<{
3158
+ value: z$1.ZodString;
3159
+ label: z$1.ZodString;
3160
+ }, z$1.core.$strip>>;
3161
+ default: z$1.ZodOptional<z$1.ZodString>;
3162
+ label: z$1.ZodString;
3163
+ description: z$1.ZodOptional<z$1.ZodString>;
3164
+ }, z$1.core.$strip>, z$1.ZodObject<{
3165
+ type: z$1.ZodLiteral<"secret">;
3166
+ label: z$1.ZodString;
3167
+ description: z$1.ZodOptional<z$1.ZodString>;
3168
+ }, z$1.core.$strip>, z$1.ZodObject<{
3169
+ type: z$1.ZodLiteral<"url">;
3170
+ default: z$1.ZodOptional<z$1.ZodString>;
3171
+ placeholder: z$1.ZodOptional<z$1.ZodString>;
3172
+ label: z$1.ZodString;
3173
+ description: z$1.ZodOptional<z$1.ZodString>;
3174
+ }, z$1.core.$strip>, z$1.ZodObject<{
3175
+ type: z$1.ZodLiteral<"email">;
3176
+ default: z$1.ZodOptional<z$1.ZodString>;
3177
+ placeholder: z$1.ZodOptional<z$1.ZodString>;
3178
+ label: z$1.ZodString;
3179
+ description: z$1.ZodOptional<z$1.ZodString>;
3180
+ }, z$1.core.$strip>], "type">>>;
3181
+ pages: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
3182
+ path: z$1.ZodString;
3183
+ label: z$1.ZodString;
3184
+ icon: z$1.ZodOptional<z$1.ZodString>;
3185
+ }, z$1.core.$strip>>>;
3186
+ widgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
3187
+ id: z$1.ZodString;
3188
+ size: z$1.ZodOptional<z$1.ZodEnum<{
3189
+ full: "full";
3190
+ half: "half";
3191
+ third: "third";
3192
+ }>>;
3193
+ title: z$1.ZodOptional<z$1.ZodString>;
3194
+ }, z$1.core.$strip>>>;
3195
+ fieldWidgets: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
3196
+ name: z$1.ZodString;
3197
+ label: z$1.ZodString;
3198
+ fieldTypes: z$1.ZodArray<z$1.ZodEnum<{
3199
+ string: "string";
3200
+ number: "number";
3201
+ boolean: "boolean";
3202
+ file: "file";
3203
+ slug: "slug";
3204
+ text: "text";
3205
+ integer: "integer";
3206
+ datetime: "datetime";
3207
+ select: "select";
3208
+ multiSelect: "multiSelect";
3209
+ portableText: "portableText";
3210
+ image: "image";
3211
+ reference: "reference";
3212
+ json: "json";
3213
+ repeater: "repeater";
3214
+ }>>;
3215
+ elements: z$1.ZodOptional<z$1.ZodArray<z$1.ZodObject<{
3216
+ type: z$1.ZodString;
3217
+ action_id: z$1.ZodString;
3218
+ label: z$1.ZodOptional<z$1.ZodString>;
3219
+ }, z$1.core.$loose>>>;
3220
+ }, z$1.core.$strip>>>;
3221
+ }, z$1.core.$strip>;
3222
+ }, z$1.core.$strip>;
3223
+ type ValidatedPluginManifest = z$1.infer<typeof pluginManifestSchema>;
2749
3224
  //#endregion
2750
- //#region src/plugins/context.d.ts
2751
- /**
2752
- * Options for creating site info
2753
- */
2754
- interface SiteInfoOptions {
2755
- /** Site name from options table */
2756
- siteName?: string;
2757
- /** Site URL from options table or Astro config */
2758
- siteUrl?: string;
2759
- /** Site locale from options table */
2760
- locale?: string;
2761
- }
2762
- interface PluginContextFactoryOptions {
2763
- db: Kysely<Database>;
2764
- /**
2765
- * Storage backend for direct media uploads.
2766
- * If not provided, upload() will throw.
2767
- */
2768
- storage?: Storage;
2769
- /**
2770
- * Function to generate upload URLs for media.
2771
- * If not provided, media write operations will throw.
2772
- */
2773
- getUploadUrl?: (filename: string, contentType: string) => Promise<{
2774
- uploadUrl: string;
2775
- mediaId: string;
2776
- }>;
2777
- /**
2778
- * Site information for ctx.site and ctx.url().
2779
- * If not provided, site info will have empty defaults.
2780
- */
2781
- siteInfo?: SiteInfoOptions;
2782
- /**
2783
- * Callback to notify the cron scheduler that the next due time may have changed.
2784
- * If not provided, ctx.cron will not be available.
2785
- */
2786
- cronReschedule?: () => void;
2787
- /**
2788
- * Email pipeline instance for ctx.email.
2789
- * If not provided (or no provider configured), ctx.email will be undefined.
2790
- */
2791
- emailPipeline?: EmailPipeline;
2792
- /**
2793
- * Trusted reverse-proxy headers for request metadata IP extraction.
2794
- */
2795
- trustedProxyHeaders?: string[];
3225
+ //#region src/config/secrets.d.ts
3226
+ interface ParsedEncryptionKey {
3227
+ kid: string;
3228
+ key: Uint8Array;
3229
+ raw: string;
3230
+ }
3231
+ interface SecretsEnv {
3232
+ DINEWAY_ENCRYPTION_KEY?: string;
3233
+ DINEWAY_PREVIEW_SECRET?: string;
3234
+ PREVIEW_SECRET?: string;
3235
+ DINEWAY_IP_SALT?: string;
3236
+ IP_SALT?: string;
2796
3237
  }
2797
3238
  //#endregion
2798
- //#region src/plugins/routes.d.ts
2799
- /**
2800
- * Result from a route invocation
2801
- */
2802
- interface RouteResult<T = unknown> {
2803
- success: boolean;
2804
- data?: T;
2805
- error?: {
2806
- code: string;
2807
- message: string;
2808
- details?: unknown;
2809
- };
2810
- status: number;
3239
+ //#region src/plugins/secrets.d.ts
3240
+ interface PluginSecretStatus {
3241
+ pluginId: string;
3242
+ name: string;
3243
+ present: true;
3244
+ fingerprint: string;
3245
+ keyId: string;
3246
+ createdAt: string;
3247
+ updatedAt: string;
2811
3248
  }
2812
- /**
2813
- * Route invocation options
2814
- */
2815
- interface InvokeRouteOptions {
2816
- /** The original request */
2817
- request: Request;
2818
- /** Request body (already parsed) */
2819
- body?: unknown;
3249
+ interface PluginSecretStoreOptions {
3250
+ env?: Pick<SecretsEnv, "DINEWAY_ENCRYPTION_KEY">;
3251
+ keys?: readonly ParsedEncryptionKey[];
2820
3252
  }
2821
3253
  /**
2822
- * Error class for plugin routes
2823
- * Allows plugins to return structured errors with specific HTTP status codes
3254
+ * Encrypted storage for trusted plugin credentials.
3255
+ *
3256
+ * Management surfaces must use set/status/list/delete and never echo the value
3257
+ * passed to set. resolveForRuntime is reserved for trusted server-side provider
3258
+ * calls and must not be exposed through plugin routes, MCP, logs, or audit data.
2824
3259
  */
2825
- declare class PluginRouteError extends Error {
2826
- code: string;
2827
- status: number;
2828
- details?: unknown | undefined;
2829
- constructor(code: string, message: string, status?: number, details?: unknown | undefined);
2830
- /**
2831
- * Create a bad request error (400)
2832
- */
2833
- static badRequest(message: string, details?: unknown): PluginRouteError;
2834
- /**
2835
- * Create an unauthorized error (401)
2836
- */
2837
- static unauthorized(message?: string): PluginRouteError;
2838
- /**
2839
- * Create a forbidden error (403)
2840
- */
2841
- static forbidden(message?: string): PluginRouteError;
2842
- /**
2843
- * Create a not found error (404)
2844
- */
2845
- static notFound(message?: string): PluginRouteError;
2846
- /**
2847
- * Create a conflict error (409)
2848
- */
2849
- static conflict(message: string, details?: unknown): PluginRouteError;
2850
- /**
2851
- * Create an internal error (500)
2852
- */
2853
- static internal(message?: string): PluginRouteError;
3260
+ declare class PluginSecretStore {
3261
+ private readonly repository;
3262
+ private readonly keysPromise;
3263
+ constructor(db: Kysely<Database> | Transaction<Database>, options?: PluginSecretStoreOptions);
3264
+ set(pluginId: string, name: string, value: string): Promise<PluginSecretStatus>;
3265
+ status(pluginId: string, name: string): Promise<PluginSecretStatus | null>;
3266
+ list(pluginId: string): Promise<PluginSecretStatus[]>;
3267
+ delete(pluginId: string, name: string): Promise<boolean>;
3268
+ resolveForRuntime(pluginId: string, name: string): Promise<string | null>;
3269
+ private requireKeys;
2854
3270
  }
2855
3271
  //#endregion
3272
+ //#region src/plugins/mcp-reviewed-executor.d.ts
3273
+ declare function createReviewedPluginMcpCommandExecutor(): PluginMcpCommandExecutor;
3274
+ //#endregion
2856
3275
  //#region src/plugins/manager.d.ts
2857
3276
  /**
2858
3277
  * Plugin state in the manager
@@ -2952,6 +3371,18 @@ declare class PluginManager {
2952
3371
  * Run content:afterUnpublish hooks across all active plugins
2953
3372
  */
2954
3373
  runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
3374
+ /**
3375
+ * Run content:afterRestore hooks across all active plugins
3376
+ */
3377
+ runContentAfterRestore(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
3378
+ /**
3379
+ * Run content:afterSchedule hooks across all active plugins
3380
+ */
3381
+ runContentAfterSchedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
3382
+ /**
3383
+ * Run content:afterUnschedule hooks across all active plugins
3384
+ */
3385
+ runContentAfterUnschedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
2955
3386
  /**
2956
3387
  * Run media:beforeUpload hooks across all active plugins
2957
3388
  */
@@ -3108,12 +3539,6 @@ declare class NoopSandboxRunner implements SandboxRunner {
3108
3539
  */
3109
3540
  declare function createNoopSandboxRunner(_options?: SandboxOptions): SandboxRunner;
3110
3541
  //#endregion
3111
- //#region src/plugins/sandbox/runtime-options.d.ts
3112
- interface SandboxRunnerRuntimeOptions extends SandboxOptions {
3113
- mediaStorage?: Storage;
3114
- cronReschedule?: () => void;
3115
- }
3116
- //#endregion
3117
3542
  //#region src/plugins/sandbox/node.d.ts
3118
3543
  declare class NodeSandboxRunner implements SandboxRunner {
3119
3544
  private readonly options;
@@ -3457,6 +3882,8 @@ interface GetCommentsOptions {
3457
3882
  collection: string;
3458
3883
  contentId: string;
3459
3884
  threaded?: boolean;
3885
+ reactions?: boolean;
3886
+ sort?: "oldest" | "best";
3460
3887
  }
3461
3888
  interface GetCommentsResult {
3462
3889
  items: PublicComment[];
@@ -3915,6 +4342,8 @@ interface Suggestion {
3915
4342
  collection: string;
3916
4343
  /** Entry ID */
3917
4344
  id: string;
4345
+ /** Entry slug, when available */
4346
+ slug?: string | null;
3918
4347
  /** Entry title */
3919
4348
  title: string;
3920
4349
  }
@@ -4262,6 +4691,13 @@ interface PluginDescriptor<TOptions = Record<string, unknown>> {
4262
4691
  adminPages?: PluginAdminPage[];
4263
4692
  /** Dashboard widgets */
4264
4693
  adminWidgets?: PluginDashboardWidget[];
4694
+ /**
4695
+ * Portable Text block types this plugin contributes to the editor.
4696
+ * Declarative Block Kit config consumed from the admin manifest.
4697
+ */
4698
+ portableTextBlocks?: PortableTextBlockConfig[];
4699
+ /** Field widget types this plugin contributes for schema-field editing UIs. */
4700
+ fieldWidgets?: FieldWidgetConfig[];
4265
4701
  /**
4266
4702
  * Capabilities the plugin requests.
4267
4703
  * For standard-format plugins, capabilities are enforced in both trusted and
@@ -4317,6 +4753,33 @@ interface DinewayConfig {
4317
4753
  * Storage configuration (for media)
4318
4754
  */
4319
4755
  storage?: StorageDescriptor;
4756
+ /**
4757
+ * Optional object cache for public query results.
4758
+ *
4759
+ * This cache is disabled by default. When configured, it sits beneath
4760
+ * request-scoped caching and above the database for anonymous, non-preview,
4761
+ * non-edit reads. Preview, visual editing, and isolated playground databases
4762
+ * bypass it so editors always see live data.
4763
+ *
4764
+ * @example
4765
+ * ```ts
4766
+ * import { memoryCache } from "dineway/astro";
4767
+ *
4768
+ * dineway({
4769
+ * objectCache: memoryCache({ defaultTtl: 600 }),
4770
+ * })
4771
+ * ```
4772
+ */
4773
+ objectCache?: ObjectCacheDescriptor;
4774
+ /**
4775
+ * Image optimization.
4776
+ *
4777
+ * By default Dineway wraps Astro's image endpoint so storage-backed media can
4778
+ * be optimized through the normal `<Image>` / `getImage` pipeline while
4779
+ * loading source bytes directly from the storage adapter. Set to `false` to
4780
+ * leave Astro's image endpoint untouched.
4781
+ */
4782
+ images?: boolean;
4320
4783
  /**
4321
4784
  * Trusted plugins to load (run in main isolate)
4322
4785
  *
@@ -4497,8 +4960,9 @@ interface DinewayConfig {
4497
4960
  * while the browser uses `https://`, which breaks WebAuthn, CSRF, OAuth, and redirect URLs.
4498
4961
  *
4499
4962
  * Set to the full origin users type in the address bar (no path), e.g.
4500
- * `https://mysite.example.com`. When not set, falls back to environment variables
4501
- * `DINEWAY_SITE_URL` > `SITE_URL`, then to the request URL's origin.
4963
+ * `https://mysite.example.com`. `DINEWAY_SITE_URL` is an explicit runtime
4964
+ * override for container deployments; otherwise this falls back to `SITE_URL`,
4965
+ * then to the request URL's origin.
4502
4966
  *
4503
4967
  * Replaces `passkeyPublicOrigin` (which only fixed passkeys).
4504
4968
  */
@@ -4614,4 +5078,4 @@ declare global {
4614
5078
  var __dinewayConfig: DinewayConfig | undefined;
4615
5079
  }
4616
5080
  //#endregion
4617
- export { CreateMenuItemInput as $, hashString as $n, handleContentList as $r, createFilePreviewMiddleware as $t, UpdateWidgetInput as A, ParseResult as Ai, ResolvePathResult as An, MediaListResponse as Ar, GeneratePreviewTokenOptions as At, getTerm as B, FieldDescriptor as Bi, FieldAnnotation as Bn, handleRevisionList as Br, SandboxNotAvailableError as Bt, getWidgetArea as C, CreateMediaInput as Ci, CollectionFilter as Cn, GetSectionsOptions as Cr, renderPreviewLoadingPage as Ct, CreateWidgetInput as D, DatabaseConfig as Di, EditFieldMeta as Dn, getCollectionInfo as Dr, GetPreviewUrlOptions as Dt, CreateWidgetAreaInput as E, ContentRepository as Ei, DinewayCollections as En, UpdateSectionInput as Er, isPreviewRequest as Et, getEntriesByTerm as F, apiSuccess as Fi, getEditMeta as Fn, handleMediaList as Fr, parseContentId as Ft, TaxonomyTermRow as G, EntryFilter as Gn, handleContentCountScheduled as Gr, EmailPipeline as Gt, CreateTermInput as H, ManifestResponse as Hi, createNoop as Hn, generateManifest as Hr, PluginManager as Ht, getEntryTerms as I, handleError as Ii, getTranslations as In, handleMediaUpdate as Ir, verifyPreviewToken as It, getBylineBySlug as J, dinewayLoader as Jn, handleContentDelete as Jr, createHookPipeline as Jt, UpdateTermInput as K, WhereRange as Kn, handleContentCountTrashed as Kr, HookPipeline as Kt, getTaxonomyDef as L, ApiContext as Li, resolveDinewayPath as Ln, RevisionListResponse as Lr, NodeSandboxRunner as Lt, WidgetArea as M, parseBody as Mi, TranslationsResult as Mn, handleMediaCreate as Mr, VerifyPreviewTokenOptions as Mt, WidgetComponentDef as N, parseQuery as Ni, getDinewayCollection as Nn, handleMediaDelete as Nr, VerifyPreviewTokenResult as Nt, PropDef as O, DinewayDatabaseError as Oi, EntryResult as On, SchemaError as Or, buildPreviewUrl as Ot, WidgetType as P, apiError as Pi, getDinewayEntry as Pn, handleMediaGet as Pr, generatePreviewToken as Pt, CreateMenuInput as Q, computeContentHash as Qn, handleContentGetIncludingTrashed as Qr, FilePreviewMiddlewareConfig as Qt, getTaxonomyDefs as R, ContentListResponse as Ri, CMSAnnotation as Rn, RevisionResponse as Rr, createNodeSandboxRunner as Rt, Suggestion as S, PublicComment as Si, CacheHint as Sn, CreateSectionInput as Sr, Snapshot as St, getWidgetComponents as T, MediaRepository as Ti, ContentEntry as Tn, SectionSource as Tr, getPreviewToken as Tt, TaxonomyDef as U, CollectionFilter$1 as Un, handleContentAuthors as Ur, createPluginManager as Ut, getTermsForEntries as V, ListResponse as Vi, createEditable as Vn, handleRevisionRestore as Vr, createNoopSandboxRunner as Vt, TaxonomyTerm as W, EntryData as Wn, handleContentCompare as Wr, PluginRouteError as Wt, getMenu as X, isSafeHref as Xn, handleContentDuplicate as Xr, pluginManifestSchema as Xt, getEntriesByByline as Y, getDb as Yn, handleContentDiscardDraft as Yr, ValidatedPluginManifest as Yt, getMenus as Z, sanitizeHref as Zn, handleContentGet as Zr, definePlugin as Zt, SearchOptions as _, ContentReference as _i, getFallbackChain as _n, SandboxRunnerFactory as _r, AppliedSnapshotMeta as _t, S3StorageConfig as a, handleContentTranslations as ai, SessionDatabaseInfo as an, PortableTextLinkMark as ar, UpdateMenuItemInput as at, SearchStats as b, RelationRepository as bi, AfterCallback as bn, getSection as br, dropSessionDatabaseTables as bt, extractSearchableFields as c, handleContentUpdate as ci, SessionOpenOrCreateOptions as cn, PortableTextTextBlock as cr, getCommentCount as ct, search as d, image as di, buildPreviewSignatureHeader as dn, ProseMirrorMark as dr, getPluginSettings as dt, handleContentListTrashed as ei, FileSessionDatabaseFactory as en, portableTextToProsemirror as er, Menu as et, searchCollection as f, FieldDefinition as fi, defaultPreviewSidecarClient as fn, ProseMirrorNode as fr, getSiteSetting as ft, SearchConfig as g, PortableTextBlock$1 as gi, I18nConfig as gn, SandboxRunner as gr, renderPreviewToolbar as gt, CollectionSearchOptions as h, ImageValue as hi, verifyPreviewSignature as hn, SandboxOptions as hr, PreviewToolbarConfig as ht, LocalStorageConfig as i, handleContentSchedule as ii, SessionDatabaseHandle as in, PortableTextImageBlock as ir, UpdateMenuInput as it, Widget as j, isParseError as ji, TranslationSummary as jn, MediaResponse as jr, PreviewTokenPayload as jt, ReorderWidgetsInput as k, OptionsRepository as ki, InferCollectionData as kn, SchemaRegistry as kr, getPreviewUrl as kt, getSearchStats as l, portableText as li, PreviewSidecarClient as ln, PortableTextUnknownBlock as lr, getComments as lt, FTSManager as m, FileValue as mi, signPreviewUrl as mn, SandboxEmailSendCallback as mr, setSiteSettings as mt, PluginDescriptor as n, handleContentPublish as ni, SessionCleanupResult as nn, PortableTextCodeBlock as nr, MenuItemType as nt, StorageDescriptor as o, handleContentUnpublish as oi, SessionDatabaseLimitError as on, PortableTextMarkDef as or, GetCommentsOptions as ot, searchWithDb as p, FieldUIHints as pi, parsePreviewSignatureHeader as pn, SandboxEmailMessage as pr, getSiteSettings as pt, getByline as q, WhereValue as qn, handleContentCreate as qr, HookResult as qt, getStoredConfig as r, handleContentRestore as ri, SessionDatabaseFactory as rn, PortableTextHtmlBlock as rr, ReorderMenuItemsInput as rt, extractPlainText as s, handleContentUnschedule as si, SessionOpenOptions as sn, PortableTextSpan as sr, GetCommentsResult as st, DinewayConfig as t, handleContentPermanentDelete as ti, FileSessionDatabaseFactoryOptions as tn, prosemirrorToPortableText as tr, MenuItem as tt, getSuggestions as u, reference as ui, PreviewSidecarSignature as un, ProseMirrorDocument as ur, getPluginSetting as ut, SearchResponse as v, CreateRelationInput as vi, getI18nConfig as vn, SandboxedPlugin as vr, ApplySnapshotToDatabaseOptions as vt, getWidgetAreas as w, MediaItem as wi, CollectionResult as wn, Section as wr, isBlockedInPreview as wt, SuggestOptions as x, UpdateRelationInput as xi, after as xn, getSections as xr, getAppliedSnapshotMeta as xt, SearchResult as y, Relation as yi, isI18nEnabled as yn, SerializedRequest as yr, applySnapshotToDatabase as yt, getTaxonomyTerms as z, ContentResponse as zi, EditProxy as zn, handleRevisionGet as zr, NoopSandboxRunner as zt };
5081
+ export { CreateMenuItemInput as $, EntryData as $i, createEditable as $n, SandboxedPluginEntry as $r, FileSessionDatabaseFactory as $t, UpdateWidgetInput as A, handleContentTranslations as Ai, invalidateTaxonomyObjectCache as An, getSection as Ar, GeneratePreviewTokenOptions as At, getTerm as B, ImageValue as Bi, EntryResult as Bn, MediaListResponse as Br, SandboxNotAvailableError as Bt, getWidgetArea as C, handleContentGetIncludingTrashed as Ci, contentNamespaces as Cn, PortableTextMarkDef as Cr, renderPreviewLoadingPage as Ct, CreateWidgetInput as D, handleContentPublish as Di, invalidateMenuObjectCache as Dn, ProseMirrorDocument as Dr, GetPreviewUrlOptions as Dt, CreateWidgetAreaInput as E, handleContentPermanentDelete as Ei, invalidateCommentObjectCache as En, PortableTextUnknownBlock as Er, isPreviewRequest as Et, getEntriesByTerm as F, reference as Fi, CollectionFilter as Fn, SectionSource as Fr, parseContentId as Ft, TaxonomyTermRow as G, RelationRepository as Gi, getDinewayCollection as Gn, handleMediaList as Gr, PluginSecretStatus as Gt, CreateTermInput as H, ContentReference as Hi, ResolvePathResult as Hn, handleMediaCreate as Hr, PluginManager as Ht, getEntryTerms as I, image as Ii, CollectionResult as In, UpdateSectionInput as Ir, verifyPreviewToken as It, getBylineBySlug as J, CreateMediaInput as Ji, getTranslations as Jn, RevisionResponse as Jr, ValidatedPluginManifest as Jt, UpdateTermInput as K, UpdateRelationInput as Ki, getDinewayEntry as Kn, handleMediaUpdate as Kr, PluginSecretStore as Kt, getTaxonomyDef as L, FieldDefinition as Li, ContentEntry as Ln, getCollectionInfo as Lr, NodeSandboxRunner as Lt, WidgetArea as M, handleContentUnschedule as Mi, AfterCallback as Mn, CreateSectionInput as Mr, VerifyPreviewTokenOptions as Mt, WidgetComponentDef as N, handleContentUpdate as Ni, after as Nn, GetSectionsOptions as Nr, VerifyPreviewTokenResult as Nt, PropDef as O, handleContentRestore as Oi, invalidateObjectCache as On, ProseMirrorMark as Or, buildPreviewUrl as Ot, WidgetType as P, portableText as Pi, CacheHint as Pn, Section as Pr, generatePreviewToken as Pt, CreateMenuInput as Q, CollectionFilter$1 as Qi, FieldAnnotation as Qn, generateManifest as Qr, createFilePreviewMiddleware as Qt, getTaxonomyDefs as R, FieldUIHints as Ri, DinewayCollections as Rn, SchemaError as Rr, createNodeSandboxRunner as Rt, Suggestion as S, handleContentGet as Si, contentNamespace as Sn, PortableTextLinkMark as Sr, Snapshot as St, getWidgetComponents as T, handleContentListTrashed as Ti, invalidateCollectionCache as Tn, PortableTextTextBlock as Tr, getPreviewToken as Tt, TaxonomyDef as U, CreateRelationInput as Ui, TranslationSummary as Un, handleMediaDelete as Ur, createPluginManager as Ut, getTermsForEntries as V, PortableTextBlock$1 as Vi, InferCollectionData as Vn, MediaResponse as Vr, createNoopSandboxRunner as Vt, TaxonomyTerm as W, Relation as Wi, TranslationsResult as Wn, handleMediaGet as Wr, createReviewedPluginMcpCommandExecutor as Wt, getMenu as X, MediaRepository as Xi, CMSAnnotation as Xn, handleRevisionList as Xr, definePlugin as Xt, getEntriesByByline as Y, MediaItem as Yi, resolveDinewayPath as Yn, handleRevisionGet as Yr, pluginManifestSchema as Yt, getMenus as Z, ContentRepository as Zi, EditProxy as Zn, handleRevisionRestore as Zr, FilePreviewMiddlewareConfig as Zt, SearchOptions as _, ContentResponse as _a, handleContentCountTrashed as _i, getI18nConfig as _n, portableTextToProsemirror as _r, AppliedSnapshotMeta as _t, S3StorageConfig as a, DatabaseConfig as aa, SandboxRunnerFactory as ai, SessionDatabaseLimitError as an, IssuedGuestAccessToken as ar, UpdateMenuItemInput as at, SearchStats as b, ManifestResponse as ba, handleContentDiscardDraft as bi, CachedQueryOptions as bn, PortableTextHtmlBlock as br, dropSessionDatabaseTables as bt, extractSearchableFields as c, ParseResult as ca, PluginMcpRegistry as ci, PreviewSidecarClient as cn, hashGuestAccessToken as cr, getCommentCount as ct, search as d, parseQuery as da, HookResult as di, defaultPreviewSidecarClient as dn, RateLimitResult as dr, getPluginSettings as dt, EntryFilter as ea, PluginRouteError as ei, FileSessionDatabaseFactoryOptions as en, createNoop as er, Menu as et, searchCollection as f, apiError as fa, createHookPipeline as fi, parsePreviewSignatureHeader as fn, checkRateLimit as fr, getSiteSetting as ft, SearchConfig as g, ContentListResponse as ga, handleContentCountScheduled as gi, getFallbackChain as gn, hashString as gr, renderPreviewToolbar as gt, CollectionSearchOptions as h, ApiContext as ha, handleContentCompare as hi, I18nConfig as hn, computeContentHash as hr, PreviewToolbarConfig as ht, LocalStorageConfig as i, getDb as ia, SandboxRunner as ii, SessionDatabaseInfo as in, IssueGuestAccessTokenOptions as ir, UpdateMenuInput as it, Widget as j, handleContentUnpublish as ji, isObjectCacheActive as jn, getSections as jr, PreviewTokenPayload as jt, ReorderWidgetsInput as k, handleContentSchedule as ki, invalidateSchemaObjectCache as kn, ProseMirrorNode as kr, getPreviewUrl as kt, getSearchStats as l, isParseError as la, PluginMcpTargetAuthorizer as li, PreviewSidecarSignature as ln, issueGuestAccessToken as lr, getComments as lt, FTSManager as m, handleError as ma, handleContentAuthors as mi, verifyPreviewSignature as mn, sanitizeHref as mr, setSiteSettings as mt, PluginDescriptor as n, WhereValue as na, SandboxEmailSendCallback as ni, SessionDatabaseFactory as nn, GuestAccessTokenClaims as nr, MenuItemType as nt, StorageDescriptor as o, DinewayDatabaseError as oa, SandboxedPlugin as oi, SessionOpenOptions as on, VerifyGuestAccessTokenOptions as or, GetCommentsOptions as ot, searchWithDb as p, apiSuccess as pa, EmailPipeline as pi, signPreviewUrl as pn, isSafeHref as pr, getSiteSettings as pt, getByline as q, PublicComment as qi, getEditMeta as qn, RevisionListResponse as qr, PluginSecretStoreOptions as qt, getStoredConfig as r, dinewayLoader as ra, SandboxOptions as ri, SessionDatabaseHandle as rn, GuestAccessTokenConfigurationError as rr, ReorderMenuItemsInput as rt, extractPlainText as s, OptionsRepository as sa, SerializedRequest as si, SessionOpenOrCreateOptions as sn, VerifyGuestAccessTokenResult as sr, GetCommentsResult as st, DinewayConfig as t, WhereRange as ta, SandboxEmailMessage as ti, SessionCleanupResult as tn, GuestAccessExpectedScope as tr, MenuItem as tt, getSuggestions as u, parseBody as ua, HookPipeline as ui, buildPreviewSignatureHeader as un, verifyGuestAccessToken as ur, getPluginSetting as ut, SearchResponse as v, FieldDescriptor as va, handleContentCreate as vi, isI18nEnabled as vn, prosemirrorToPortableText as vr, ApplySnapshotToDatabaseOptions as vt, getWidgetAreas as w, handleContentList as wi, invalidateBylineObjectCache as wn, PortableTextSpan as wr, isBlockedInPreview as wt, SuggestOptions as x, handleContentDuplicate as xi, cachedQuery as xn, PortableTextImageBlock as xr, getAppliedSnapshotMeta as xt, SearchResult as y, ListResponse as ya, handleContentDelete as yi, CacheNamespace as yn, PortableTextCodeBlock as yr, applySnapshotToDatabase as yt, getTaxonomyTerms as z, FileValue as zi, EditFieldMeta as zn, SchemaRegistry as zr, NoopSandboxRunner as zt };