dineway 0.1.49 → 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 (418) hide show
  1. package/dist/{activity-events-CwM7yxPW.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-CyGnbgBd.mjs → allowed-origins-_oeyP6x-.mjs} +1 -1
  5. package/dist/api/route-utils.d.mts +10 -10
  6. package/dist/api/route-utils.mjs +16 -13
  7. package/dist/api/schemas/index.d.mts +2 -2
  8. package/dist/api/schemas/index.mjs +5 -4
  9. package/dist/{api-BMIxRIEN.mjs → api-ByrU2q-Z.mjs} +60 -36
  10. package/dist/{api-tokens-DtvdtIkm.mjs → api-tokens-CjVMQT-X.mjs} +6 -2
  11. package/dist/{apply-D_RlTYtC.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 +13 -4
  21. package/dist/astro/middleware/request-context.mjs +8 -5
  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 +333 -192
  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 +21 -17
  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 +17 -14
  37. package/dist/astro/routes/api/admin/bylines/_id_/translations.mjs +17 -14
  38. package/dist/astro/routes/api/admin/bylines/index.mjs +17 -14
  39. package/dist/astro/routes/api/admin/comments/_id_/status.mjs +14 -12
  40. package/dist/astro/routes/api/admin/comments/_id_.mjs +6 -5
  41. package/dist/astro/routes/api/admin/comments/bulk.mjs +11 -9
  42. package/dist/astro/routes/api/admin/comments/counts.mjs +6 -5
  43. package/dist/astro/routes/api/admin/comments/index.mjs +11 -9
  44. package/dist/astro/routes/api/admin/context/_id_/history.mjs +26 -24
  45. package/dist/astro/routes/api/admin/context/_id_/index.mjs +26 -24
  46. package/dist/astro/routes/api/admin/context/_id_/review.mjs +31 -28
  47. package/dist/astro/routes/api/admin/context/_id_/supersede.mjs +31 -28
  48. package/dist/astro/routes/api/admin/context/diff.mjs +30 -27
  49. package/dist/astro/routes/api/admin/context/index.mjs +31 -28
  50. package/dist/astro/routes/api/admin/context/stale.mjs +30 -27
  51. package/dist/astro/routes/api/admin/hitl-requests/_id_/index.mjs +26 -24
  52. package/dist/astro/routes/api/admin/hitl-requests/_id_/resolve.mjs +30 -27
  53. package/dist/astro/routes/api/admin/hitl-requests/index.mjs +30 -27
  54. package/dist/astro/routes/api/admin/hooks/exclusive/_hookName_.mjs +27 -25
  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 +55 -51
  59. package/dist/astro/routes/api/admin/plugins/_id_/enable.mjs +55 -51
  60. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +47 -43
  61. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +53 -49
  62. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +52 -48
  63. package/dist/astro/routes/api/admin/plugins/index.mjs +47 -43
  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 +46 -42
  66. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +52 -48
  67. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +46 -42
  68. package/dist/astro/routes/api/admin/plugins/updates.mjs +46 -42
  69. package/dist/astro/routes/api/admin/review-requests/_id_/index.mjs +5 -5
  70. package/dist/astro/routes/api/admin/review-requests/_id_/resolve.mjs +31 -27
  71. package/dist/astro/routes/api/admin/review-requests/index.mjs +10 -9
  72. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +46 -42
  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 +46 -42
  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 +9 -8
  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 +5 -5
  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 +15 -13
  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 +5 -5
  108. package/dist/astro/routes/api/content/_collection_/_id_/duplicate.mjs +5 -5
  109. package/dist/astro/routes/api/content/_collection_/_id_/permanent.mjs +5 -5
  110. package/dist/astro/routes/api/content/_collection_/_id_/preview-url.mjs +11 -10
  111. package/dist/astro/routes/api/content/_collection_/_id_/publish.mjs +10 -9
  112. package/dist/astro/routes/api/content/_collection_/_id_/restore.mjs +5 -5
  113. package/dist/astro/routes/api/content/_collection_/_id_/revisions.mjs +2 -2
  114. package/dist/astro/routes/api/content/_collection_/_id_/schedule.mjs +10 -9
  115. package/dist/astro/routes/api/content/_collection_/_id_/terms/_taxonomy_.mjs +16 -14
  116. package/dist/astro/routes/api/content/_collection_/_id_/translations.mjs +2 -2
  117. package/dist/astro/routes/api/content/_collection_/_id_/unpublish.mjs +5 -5
  118. package/dist/astro/routes/api/content/_collection_/_id_.mjs +10 -9
  119. package/dist/astro/routes/api/content/_collection_/authors.mjs +2 -2
  120. package/dist/astro/routes/api/content/_collection_/index.mjs +10 -9
  121. package/dist/astro/routes/api/content/_collection_/trash.mjs +7 -6
  122. package/dist/astro/routes/api/dashboard.mjs +9 -8
  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 +22 -10
  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 +84 -37
  130. package/dist/astro/routes/api/import/wordpress/media.d.mts +13 -1
  131. package/dist/astro/routes/api/import/wordpress/media.mjs +19 -13
  132. package/dist/astro/routes/api/import/wordpress/prepare.mjs +35 -32
  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 +120 -100
  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 +24 -12
  137. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +56 -2
  138. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +283 -55
  139. package/dist/astro/routes/api/manifest.mjs +14 -5
  140. package/dist/astro/routes/api/mcp.mjs +265 -69
  141. package/dist/astro/routes/api/media/_id_/confirm.mjs +38 -10
  142. package/dist/astro/routes/api/media/_id_.mjs +11 -7
  143. package/dist/astro/routes/api/media/file/_...key_.mjs +1 -1
  144. package/dist/astro/routes/api/media/providers/_providerId_/_itemId_.mjs +2 -2
  145. package/dist/astro/routes/api/media/providers/_providerId_/index.mjs +2 -2
  146. package/dist/astro/routes/api/media/providers/index.mjs +2 -2
  147. package/dist/astro/routes/api/media/upload-url.mjs +11 -10
  148. package/dist/astro/routes/api/media.mjs +27 -34
  149. package/dist/astro/routes/api/menus/_name_/items/_id_.mjs +31 -28
  150. package/dist/astro/routes/api/menus/_name_/items.mjs +31 -28
  151. package/dist/astro/routes/api/menus/_name_/reorder.mjs +31 -28
  152. package/dist/astro/routes/api/menus/_name_/translations.mjs +31 -28
  153. package/dist/astro/routes/api/menus/_name_.mjs +31 -28
  154. package/dist/astro/routes/api/menus/index.mjs +31 -28
  155. package/dist/astro/routes/api/oauth/authorize.mjs +7 -7
  156. package/dist/astro/routes/api/oauth/device/authorize.mjs +6 -6
  157. package/dist/astro/routes/api/oauth/device/code.mjs +9 -9
  158. package/dist/astro/routes/api/oauth/device/token.mjs +8 -8
  159. package/dist/astro/routes/api/oauth/register.mjs +4 -4
  160. package/dist/astro/routes/api/oauth/token/refresh.mjs +6 -6
  161. package/dist/astro/routes/api/oauth/token/revoke.mjs +6 -6
  162. package/dist/astro/routes/api/oauth/token.mjs +6 -6
  163. package/dist/astro/routes/api/openapi.json.mjs +4 -3
  164. package/dist/astro/routes/api/plugins/_pluginId_/_...path_.mjs +30 -30
  165. package/dist/astro/routes/api/redirects/404s/index.mjs +11 -10
  166. package/dist/astro/routes/api/redirects/404s/summary.mjs +11 -10
  167. package/dist/astro/routes/api/redirects/_id_.mjs +32 -29
  168. package/dist/astro/routes/api/redirects/index.mjs +32 -29
  169. package/dist/astro/routes/api/revisions/_revisionId_/index.mjs +2 -2
  170. package/dist/astro/routes/api/revisions/_revisionId_/restore.mjs +2 -2
  171. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +47 -43
  172. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +47 -43
  173. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +47 -43
  174. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +47 -43
  175. package/dist/astro/routes/api/schema/collections/index.mjs +47 -43
  176. package/dist/astro/routes/api/schema/index.mjs +13 -14
  177. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +46 -42
  178. package/dist/astro/routes/api/schema/orphans/index.mjs +46 -42
  179. package/dist/astro/routes/api/search/enable.mjs +11 -10
  180. package/dist/astro/routes/api/search/index.mjs +10 -9
  181. package/dist/astro/routes/api/search/rebuild.mjs +11 -10
  182. package/dist/astro/routes/api/search/stats.mjs +6 -6
  183. package/dist/astro/routes/api/search/suggest.mjs +10 -9
  184. package/dist/astro/routes/api/sections/_slug_.mjs +31 -28
  185. package/dist/astro/routes/api/sections/index.mjs +31 -28
  186. package/dist/astro/routes/api/settings/email.mjs +4 -4
  187. package/dist/astro/routes/api/settings.mjs +31 -28
  188. package/dist/astro/routes/api/setup/admin-verify.mjs +14 -13
  189. package/dist/astro/routes/api/setup/admin.mjs +12 -11
  190. package/dist/astro/routes/api/setup/dev-bypass.mjs +31 -25
  191. package/dist/astro/routes/api/setup/dev-reset.mjs +2 -2
  192. package/dist/astro/routes/api/setup/index.mjs +29 -25
  193. package/dist/astro/routes/api/setup/status.mjs +3 -3
  194. package/dist/astro/routes/api/snapshot.mjs +8 -7
  195. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_/translations.mjs +34 -31
  196. package/dist/astro/routes/api/taxonomies/_name_/terms/_slug_.mjs +34 -31
  197. package/dist/astro/routes/api/taxonomies/_name_/terms/index.mjs +34 -31
  198. package/dist/astro/routes/api/taxonomies/index.mjs +34 -31
  199. package/dist/astro/routes/api/themes/preview.mjs +5 -5
  200. package/dist/astro/routes/api/typegen.mjs +4 -4
  201. package/dist/astro/routes/api/well-known/auth.mjs +3 -3
  202. package/dist/astro/routes/api/well-known/oauth-authorization-server.mjs +3 -3
  203. package/dist/astro/routes/api/well-known/oauth-protected-resource.mjs +3 -3
  204. package/dist/astro/routes/api/widget-areas/_name_/reorder.mjs +30 -27
  205. package/dist/astro/routes/api/widget-areas/_name_/widgets/_id_.mjs +31 -28
  206. package/dist/astro/routes/api/widget-areas/_name_/widgets.mjs +31 -28
  207. package/dist/astro/routes/api/widget-areas/_name_.mjs +28 -26
  208. package/dist/astro/routes/api/widget-areas/index.mjs +31 -28
  209. package/dist/astro/routes/api/widget-components.mjs +2 -2
  210. package/dist/astro/routes/robots.txt.mjs +8 -7
  211. package/dist/astro/routes/sitemap-_collection_.xml.mjs +23 -14
  212. package/dist/astro/routes/sitemap.xml.mjs +9 -8
  213. package/dist/astro/session-driver.d.mts +1 -1
  214. package/dist/astro/session-driver.mjs +2 -2
  215. package/dist/astro/types.d.mts +21 -13
  216. package/dist/{audit-BeNsSyfU.mjs → audit-ByVKIwWF.mjs} +1 -1
  217. package/dist/auth/providers/github.d.mts +1 -1
  218. package/dist/auth/providers/google.d.mts +1 -1
  219. package/dist/{auth-control-guard-Dr14I98m.mjs → auth-control-guard-CqeUmQsv.mjs} +1 -1
  220. package/dist/{authorize-BLO0m7fW.mjs → authorize-CcBxcHtz.mjs} +1 -1
  221. package/dist/{briefing-DJX6irto.mjs → briefing-BJaJI8dm.mjs} +2 -1
  222. package/dist/{briefing-CkTee1ex.mjs → briefing-CawZ59CY.mjs} +90 -28
  223. package/dist/bundle-7C_DpkEq.mjs +602 -0
  224. package/dist/{byline-BVC1lV6G.mjs → byline-e51-fWRs.mjs} +30 -62
  225. package/dist/{byline-fields-uJlygdzM.d.mts → byline-fields-CUvbslGc.d.mts} +80 -37
  226. package/dist/{byline-fields-Cj39WhXC.mjs → byline-fields-D-N5qVIG.mjs} +1 -1
  227. package/dist/{byline-fields-cNrLJVRs.mjs → byline-fields-DOJO16Gm.mjs} +3 -3
  228. package/dist/{byline-registry-4v6tXMNX.mjs → byline-registry-87nNnYl4.mjs} +2 -2
  229. package/dist/{bylines-LN9XISRo.mjs → bylines-CMQNCNFh.mjs} +9 -3
  230. package/dist/{bylines-DwokOFj6.mjs → bylines-y4LO-dTj.mjs} +5 -5
  231. package/dist/{cache-Bac05gBd.mjs → cache-C-FNTFYK.mjs} +2 -2
  232. package/dist/{chunks-CuUt7K50.mjs → chunks-CxBt-GxR.mjs} +1 -1
  233. package/dist/cli/index.mjs +94 -659
  234. package/dist/client/external-auth-headers.d.mts +1 -1
  235. package/dist/client/index.d.mts +1 -1
  236. package/dist/client/index.mjs +2 -1
  237. package/dist/{comment-Beue8-15.mjs → comment-DlA4iChg.mjs} +13 -3
  238. package/dist/comment-reaction-DfFao1ST.mjs +58 -0
  239. package/dist/{comments-DcjFIfqX.mjs → comments-DApFGMsP.mjs} +1 -1
  240. package/dist/{content-CBxYGWfL.mjs → content-Bh4BDjv8.mjs} +51 -34
  241. package/dist/content-refresh-CgutSUfO.mjs +1576 -0
  242. package/dist/{context-CQVNZaR8.mjs → context-C5W3G18y.mjs} +111 -50
  243. package/dist/{context-Df1xVYyr.mjs → context-CK4ym2Sf.mjs} +2 -2
  244. package/dist/{context-route-helpers-B9wj8Rmh.mjs → context-route-helpers-MASyGgWf.mjs} +2 -1
  245. package/dist/{cron-DxCAU_Sn.mjs → cron-cKcNTix_.mjs} +7 -3
  246. package/dist/{dashboard-B7ZUNuyF.mjs → dashboard-DQkVT7Ei.mjs} +4 -4
  247. package/dist/db/index.d.mts +3 -3
  248. package/dist/db/index.mjs +1 -1
  249. package/dist/db/libsql.d.mts +1 -1
  250. package/dist/db/postgres.d.mts +1 -1
  251. package/dist/db/sqlite.d.mts +1 -1
  252. package/dist/{device-flow-BZVGftqi.mjs → device-flow-BnqRH-T9.mjs} +5 -5
  253. package/dist/{placeholder-d54Qr_7n.mjs → enrich-DIFIFA8O.mjs} +36 -9
  254. package/dist/{error-DCSuUAZW.mjs → error-CytFlgcd.mjs} +5 -0
  255. package/dist/field-defs-cache-DRNdhBJv.mjs +49 -0
  256. package/dist/{fts-manager-B5l_qwrA.mjs → fts-manager-Crzypjqu.mjs} +1 -1
  257. package/dist/hitl-Hw1RmWOq.mjs +677 -0
  258. package/dist/{hitl-requests-7NlzVeUA.mjs → hitl-requests-B4Vbcmaq.mjs} +2 -2
  259. package/dist/{hitl-route-helpers-k---_H3-.mjs → hitl-route-helpers-hEVzvP8l.mjs} +5 -4
  260. package/dist/import-Bh9biJfx.mjs +1354 -0
  261. package/dist/{index-CZiWCQDp.d.mts → index-D4y6NGiy.d.mts} +75 -3
  262. package/dist/index.d.mts +17 -16
  263. package/dist/index.mjs +80 -68
  264. package/dist/{jsonld-DZ67souc.d.mts → jsonld-Dq0gsnOH.d.mts} +8 -4
  265. package/dist/{load-D9OiGr2m.mjs → load-DmYeniXl.mjs} +1 -1
  266. package/dist/{loader--GOYux8M.mjs → loader-CjWqjweO.mjs} +117 -31
  267. package/dist/{manifest-schema-qh2P7RDX.mjs → manifest-schema-BxVPYMJR.mjs} +34 -1
  268. package/dist/mcp-reviewed-executor-TwVbMzG6.mjs +555 -0
  269. package/dist/media/image-endpoint.d.mts +32 -0
  270. package/dist/media/image-endpoint.mjs +111 -0
  271. package/dist/media/index.d.mts +27 -2
  272. package/dist/media/index.mjs +5 -3
  273. package/dist/media/local-runtime.d.mts +16 -11
  274. package/dist/media/local-runtime.mjs +9 -7
  275. package/dist/{media-CbKyYukG.mjs → media-DMj0grzC.mjs} +3 -1
  276. package/dist/{media-allowlist-BYxJIcTO.mjs → media-allowlist-BlVCSzHx.mjs} +1 -1
  277. package/dist/media-url-lEKSrpr9.mjs +20 -0
  278. package/dist/{menus-BZbXf-ej.mjs → menus-TaW1gKnk.mjs} +19 -5
  279. package/dist/{menus-C7F0sCrC.mjs → menus-xvsnVZXw.mjs} +80 -15
  280. package/dist/{normalize-ByemhhfW.mjs → normalize-5ek_z7de.mjs} +8 -1
  281. package/dist/{oauth-authorization-DF-LCsIA.mjs → oauth-authorization-DiaGvRVz.mjs} +5 -5
  282. package/dist/{oauth-clients-Du-V0fEm.mjs → oauth-clients-Dl9E8dEM.mjs} +2 -2
  283. package/dist/object-cache/memory.d.mts +14 -0
  284. package/dist/object-cache/memory.mjs +55 -0
  285. package/dist/object-cache-D51qOseS.mjs +419 -0
  286. package/dist/page/index.d.mts +4 -3
  287. package/dist/page/index.mjs +2 -2
  288. package/dist/{parse-CneSgl7-.mjs → parse-CbymENaR.mjs} +1 -1
  289. package/dist/{parser-DxfsARXL.mjs → parser-C1nYd-81.mjs} +151 -9
  290. package/dist/{placeholder-CXfoCtCd.d.mts → placeholder-uvNRZBX9.d.mts} +12 -4
  291. package/dist/plugin-utils.d.mts +9 -9
  292. package/dist/plugins/adapt-sandbox-entry.d.mts +9 -9
  293. package/dist/plugins/adapt-sandbox-entry.mjs +11 -2
  294. package/dist/{plugins-DzfqRREq.mjs → plugins-BolVa-tl.mjs} +831 -63
  295. package/dist/{transport-LSdZVXHF.mjs → portable-text-dA_UlJwW.mjs} +1 -134
  296. package/dist/{preview-C-3YTX2U.mjs → preview-vSVg6fwG.mjs} +4 -3
  297. package/dist/process-cache-7xgAO9JY.mjs +106 -0
  298. package/dist/{provider-loader-9it4vd6L.d.mts → provider-loader-MD8zAbnH.d.mts} +1 -1
  299. package/dist/{public-url-B4xV4rGa.d.mts → public-url-gsp3oUbu.d.mts} +1 -1
  300. package/dist/{query-Ds0EnMFX.mjs → query-CfRCdaL3.mjs} +281 -76
  301. package/dist/{query-CZ3TH_Uu.mjs → query-jaAmw8E1.mjs} +11 -6
  302. package/dist/{rate-limit-i0G3IAOX.mjs → rate-limit-ZLdyWoZF.mjs} +2 -2
  303. package/dist/{redirect-CEACczxo.mjs → redirect-BAjt4Z6b.mjs} +2 -2
  304. package/dist/{redirects-DYj1yPxs.mjs → redirects-BTdwpQtE.mjs} +47 -24
  305. package/dist/{redirects-ocRJmQHP.mjs → redirects-CA-xylPG.mjs} +19 -11
  306. package/dist/{registry-D7HACema.mjs → registry-CtyVedcN.mjs} +130 -77
  307. package/dist/request-context.d.mts +2 -0
  308. package/dist/{request-meta-DAb6xaP9.mjs → request-meta-CUypToDJ.mjs} +1 -1
  309. package/dist/{review-requests-Qum4713s.mjs → review-requests-C9Ff11Vq.mjs} +1 -1
  310. package/dist/{review-requests-BW2NxY-l.mjs → review-requests-DUyEmtmG.mjs} +1 -1
  311. package/dist/{runner-09sTqtv0.d.mts → runner-1tC2tIRV.d.mts} +1 -1
  312. package/dist/runner-DB7CRfOF.mjs +6740 -0
  313. package/dist/{runtime-C4-2lSFg.d.mts → runtime-BOeiQsCv.d.mts} +1952 -1489
  314. package/dist/runtime.d.mts +10 -10
  315. package/dist/runtime.mjs +3 -3
  316. package/dist/schema-DXdYj4R3.mjs +8 -0
  317. package/dist/{search-Gdrqj582.mjs → search-DSaLgEFI.mjs} +5 -3
  318. package/dist/{secrets-CeGpBFV2.mjs → secrets-CDZo2k8L.mjs} +14 -11
  319. package/dist/{sections-BOjU13Y-.mjs → sections-PVVXHGfp.mjs} +2 -2
  320. package/dist/seed/index.d.mts +2 -2
  321. package/dist/seed/index.mjs +21 -18
  322. package/dist/seo/index.d.mts +1 -1
  323. package/dist/seo/index.mjs +3 -12
  324. package/dist/{seo-CLj8lS7Q.mjs → seo-CQG3GCHQ.mjs} +5 -2
  325. package/dist/{seo-contributions-CqVvReEj.mjs → seo-contributions-C1EnikHB.mjs} +11 -3
  326. package/dist/{seo-5lJOtB5J.mjs → seo-qa7Dn0jK.mjs} +22 -4
  327. package/dist/{service-jGlhrICs.mjs → service-DiN4ZuPp.mjs} +2 -2
  328. package/dist/session-user-CAKImna3.mjs +22 -0
  329. package/dist/{settings-CUXOxzsT.mjs → settings-BbqgHWpU.mjs} +28 -55
  330. package/dist/{settings-DlBsT2VS.mjs → settings-i4VPP8bT.mjs} +2 -2
  331. package/dist/{setup-complete-BRrdPYjZ.mjs → setup-complete-B8fl-mjV.mjs} +1 -1
  332. package/dist/{site-activity-DONFrMBJ.mjs → site-activity-Dy3FROs0.mjs} +1 -1
  333. package/dist/{site-context-C8Az_P_I.mjs → site-context-DQiL8Fl5.mjs} +23 -652
  334. package/dist/{site-url-DIMD68go.mjs → site-url-BML3GQYm.mjs} +1 -1
  335. package/dist/status-DANd8ERo.mjs +21 -0
  336. package/dist/storage/local.d.mts +1 -1
  337. package/dist/storage/local.mjs +1 -1
  338. package/dist/storage/s3.d.mts +1 -1
  339. package/dist/storage/s3.mjs +1 -1
  340. package/dist/{taxonomies-D9Sw4wWM.mjs → taxonomies-9s-v03H-.mjs} +36 -29
  341. package/dist/taxonomies-DRiixp_E.mjs +443 -0
  342. package/dist/{taxonomy-B169Nm6B.mjs → taxonomy-Dvsw6BOs.mjs} +44 -9
  343. package/dist/transport-BNmCqLu7.mjs +134 -0
  344. package/dist/types-4garmdWa.mjs +66 -0
  345. package/dist/{types-DSPGWjxO.d.mts → types-C8XW6L19.d.mts} +225 -4
  346. package/dist/{types-GaCtZ1k9.d.mts → types-CDpH6MA4.d.mts} +18 -0
  347. package/dist/{types-DRIKLmJI.d.mts → types-C_ly5eTp.d.mts} +17 -2
  348. package/dist/types-DF7ZuGGk.d.mts +118 -0
  349. package/dist/types-DU0bU2Wu.d.mts +2392 -0
  350. package/dist/{types-CwawBUTa.d.mts → types-DW_-sFyz.d.mts} +2 -1
  351. package/dist/{types-CSgR9nQB.mjs → types-Dq1qT19x.mjs} +1 -1
  352. package/dist/ui/server-runtime.d.mts +15 -15
  353. package/dist/ui/server-runtime.mjs +24 -20
  354. package/dist/url-Cac7a9QZ.mjs +33 -0
  355. package/dist/{user-DTLoZs16.mjs → user-BIZPzCb9.mjs} +2 -2
  356. package/dist/{utils-B8hBJ9Oz.mjs → utils-CMDhr5Xd.mjs} +129 -7
  357. package/dist/{validate-DzjCdy6v.d.mts → validate-CZvb-BKB.d.mts} +10 -7
  358. package/dist/{validate-DWmPO6oj.mjs → validate-DNs0pTSc.mjs} +11 -6
  359. package/dist/version-BTvfRGc6.mjs +6 -0
  360. package/dist/{widgets-BpJ8EpPd.mjs → widgets-f0ibZUIq.mjs} +46 -43
  361. package/dist/{wordpress-slugs-DHNR9LpG.mjs → wordpress-slugs-BhHJX8XE.mjs} +1 -1
  362. package/dist/{zod-generator-K91-g665.mjs → zod-generator-B7TMjyFJ.mjs} +41 -13
  363. package/package.json +30 -8
  364. package/src/components/Block.astro +50 -0
  365. package/src/components/Comments.astro +143 -1
  366. package/src/components/DinewayHead.astro +19 -2
  367. package/src/components/DinewayImage.astro +66 -33
  368. package/src/components/DinewayMedia.astro +1 -2
  369. package/src/components/Image.astro +85 -40
  370. package/src/components/InlinePortableTextEditor.tsx +12 -2
  371. package/src/components/JsonLdScript.astro +9 -0
  372. package/src/components/LiveSearch.astro +40 -4
  373. package/src/components/index.ts +4 -0
  374. package/src/components/live-search-routing.ts +30 -0
  375. package/src/components/portable-text-text-align.ts +15 -0
  376. package/src/ui.ts +2 -0
  377. package/dist/entity-aliases-4y93Yjuc.mjs +0 -51
  378. package/dist/import-4YBXbDkI.mjs +0 -684
  379. package/dist/runner-DzIpHGND.mjs +0 -2836
  380. package/dist/schema-Bsi-VpYv.mjs +0 -8
  381. package/dist/taxonomies-CZ-_DitR.mjs +0 -327
  382. package/dist/types-CuJOqHfM.d.mts +0 -758
  383. package/dist/version-C4gfn0PJ.mjs +0 -6
  384. /package/dist/{adapters-OQCImOL7.d.mts → adapters-NVSs4UH7.d.mts} +0 -0
  385. /package/dist/{api-tokens-CYUoFGo7.mjs → api-tokens-2r7OWi_I.mjs} +0 -0
  386. /package/dist/{challenge-store-DFxX0_15.mjs → challenge-store-Bjlepa2E.mjs} +0 -0
  387. /package/dist/{components--pg6zBvu.mjs → components-Bclf98Be.mjs} +0 -0
  388. /package/dist/{context-types-r8oFvyOq.mjs → context-types-DqTo6C79.mjs} +0 -0
  389. /package/dist/{default-B6iaLvP7.mjs → default--K40jqm0.mjs} +0 -0
  390. /package/dist/{email-console-BOVqIYpB.mjs → email-console-ChgKFO8-.mjs} +0 -0
  391. /package/dist/{escape-BDgouFFY.mjs → escape-Bd4P_xKg.mjs} +0 -0
  392. /package/dist/{experimental-workflows-CSMffP6q.mjs → experimental-workflows-BMsUnIAw.mjs} +0 -0
  393. /package/dist/{mime-CbKsKDCB.mjs → mime-CA7Lgovc.mjs} +0 -0
  394. /package/dist/{mode-CZqCF9dZ.mjs → mode-C4CIyjtR.mjs} +0 -0
  395. /package/dist/{oauth-state-store-qncPB_IU.mjs → oauth-state-store-CNoXafF7.mjs} +0 -0
  396. /package/dist/{oauth-user-lookup-BFjWF8wK.mjs → oauth-user-lookup-Ygw4bNyt.mjs} +0 -0
  397. /package/dist/{options-LsPjZlqD.mjs → options-DQPTH5n0.mjs} +0 -0
  398. /package/dist/{passkey-config-DzHQK90v.mjs → passkey-config-BUwu8BA3.mjs} +0 -0
  399. /package/dist/{patterns-DKAX6oqN.mjs → patterns-BhAvqO0S.mjs} +0 -0
  400. /package/dist/{provider-loader-DzUxejk7.mjs → provider-loader-D0w9dqjm.mjs} +0 -0
  401. /package/dist/{public-url-B_m9IwdV.mjs → public-url-BEz_sM9n.mjs} +0 -0
  402. /package/dist/{redirect-BjIBtDWY.mjs → redirect-wphRBv4y.mjs} +0 -0
  403. /package/dist/{request-cache-ho99schz.mjs → request-cache-D9GQBxMP.mjs} +0 -0
  404. /package/dist/{resolve-DTuDyYKs.mjs → resolve-Cb6Dbz-C.mjs} +0 -0
  405. /package/dist/{setup-nonce-pyGfc9hV.mjs → setup-nonce-CoyjILvW.mjs} +0 -0
  406. /package/dist/{sidecar-client-mJxwayYN.mjs → sidecar-client-C3mqXg4C.mjs} +0 -0
  407. /package/dist/{slugify-BqebcqBg.mjs → slugify-KSsVD_D3.mjs} +0 -0
  408. /package/dist/{ssrf-DiKqWd3N.mjs → ssrf-DWe8jwAp.mjs} +0 -0
  409. /package/dist/{tokens-SLmgowfd.mjs → tokens-1RK1n6ED.mjs} +0 -0
  410. /package/dist/{transaction-CFLhEOuH.mjs → transaction-C2EOMTJA.mjs} +0 -0
  411. /package/dist/{transport-BnsNxh2l.d.mts → transport-CcJu3Co8.d.mts} +0 -0
  412. /package/dist/{trusted-proxy-BgIIcbsN.mjs → trusted-proxy-DTXQ2IMv.mjs} +0 -0
  413. /package/dist/{types-CJ8DkL0q.mjs → types-B3t5cxhU.mjs} +0 -0
  414. /package/dist/{types-nP9vGUFq.d.mts → types-C46EvNdc.d.mts} +0 -0
  415. /package/dist/{types-Cg276-3z.mjs → types-C5CVgwsV.mjs} +0 -0
  416. /package/dist/{types-DZpT-PnG.d.mts → types-POH8PQZh.d.mts} +0 -0
  417. /package/dist/{types-Dryvv7LH.d.mts → types-Rc3gQqqw.d.mts} +0 -0
  418. /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-CuJOqHfM.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-CZiWCQDp.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
 
@@ -254,17 +256,12 @@ interface WhereRange {
254
256
  }
255
257
  type WhereValue = string | string[] | WhereRange;
256
258
  /**
257
- * Filter for loadCollection - type is required
259
+ * Fields shared by every collection filter, independent of pagination mode.
258
260
  */
259
- interface CollectionFilter$1 {
261
+ interface CollectionFilterBase$1 {
260
262
  type: string;
261
263
  status?: "draft" | "published" | "archived";
262
264
  limit?: number;
263
- /**
264
- * Opaque cursor for keyset pagination.
265
- * Pass the `nextCursor` value from a previous result to fetch the next page.
266
- */
267
- cursor?: string;
268
265
  /**
269
266
  * Filter by field values, taxonomy terms, byline credits, or ranges.
270
267
  *
@@ -288,6 +285,31 @@ interface CollectionFilter$1 {
288
285
  */
289
286
  locale?: string;
290
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;
291
313
  /**
292
314
  * Filter for loadEntry - type and id are required
293
315
  */
@@ -414,7 +436,7 @@ declare class ContentRepository {
414
436
  /**
415
437
  * Restore content from trash
416
438
  */
417
- restore(type: string, id: string): Promise<boolean>;
439
+ restore(type: string, id: string): Promise<ContentItem | null>;
418
440
  /**
419
441
  * Permanently delete a soft-deleted content row.
420
442
  */
@@ -603,6 +625,8 @@ declare class MediaRepository {
603
625
  width?: number;
604
626
  height?: number;
605
627
  size?: number;
628
+ blurhash?: string;
629
+ dominantColor?: string;
606
630
  }): Promise<MediaItem | null>;
607
631
  /**
608
632
  * Mark upload as failed
@@ -674,6 +698,7 @@ interface PublicComment {
674
698
  isRegisteredUser: boolean;
675
699
  body: string;
676
700
  createdAt: string;
701
+ reactions?: Record<string, number>;
677
702
  replies?: PublicComment[];
678
703
  }
679
704
  //#endregion
@@ -919,12 +944,14 @@ declare function handleContentDuplicate(db: Kysely<Database>, collection: string
919
944
  */
920
945
  declare function handleContentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
921
946
  deleted: true;
947
+ id: string;
922
948
  }>>;
923
949
  /**
924
950
  * Restore content item from trash
925
951
  */
926
952
  declare function handleContentRestore(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
927
953
  restored: true;
954
+ item: ContentItem;
928
955
  }>>;
929
956
  /**
930
957
  * Permanently delete content item (cannot be undone).
@@ -932,6 +959,7 @@ declare function handleContentRestore(db: Kysely<Database>, collection: string,
932
959
  */
933
960
  declare function handleContentPermanentDelete(db: Kysely<Database>, collection: string, id: string): Promise<ApiResult<{
934
961
  deleted: true;
962
+ id: string;
935
963
  }>>;
936
964
  /**
937
965
  * List trashed content items
@@ -1008,392 +1036,443 @@ declare function handleContentTranslations(db: Kysely<Database>, collection: str
1008
1036
  }>;
1009
1037
  }>>;
1010
1038
  //#endregion
1011
- //#region src/api/handlers/manifest.d.ts
1012
- interface CollectionDefinition {
1013
- schema: {
1014
- _def?: {
1015
- shape?: () => Record<string, unknown>;
1016
- };
1017
- shape?: Record<string, unknown>;
1018
- };
1019
- admin: {
1020
- label: string;
1021
- labelSingular?: string;
1022
- supports?: string[];
1023
- };
1024
- }
1025
- type CollectionMap = Record<string, CollectionDefinition>;
1026
- /**
1027
- * Generate admin manifest from collections
1028
- */
1029
- declare function generateManifest(collections: CollectionMap, plugins?: Record<string, {
1030
- adminPages?: Array<{
1031
- path: string;
1032
- component: string;
1033
- }>;
1034
- widgets?: string[];
1035
- }>): Promise<ManifestResponse>;
1036
- //#endregion
1037
- //#region src/api/handlers/revision.d.ts
1038
- interface RevisionListResponse {
1039
- items: Revision[];
1040
- total: number;
1041
- }
1042
- interface RevisionResponse {
1043
- item: Revision;
1044
- }
1045
- /**
1046
- * List revisions for a content entry
1047
- */
1048
- declare function handleRevisionList(db: Kysely<Database>, collection: string, entryId: string, params?: {
1049
- limit?: number;
1050
- }): Promise<ApiResult<RevisionListResponse>>;
1051
- /**
1052
- * Get a specific revision
1053
- */
1054
- declare function handleRevisionGet(db: Kysely<Database>, revisionId: string): Promise<ApiResult<RevisionResponse>>;
1055
- /**
1056
- * Restore a revision (updates content to this revision's data and creates new revision)
1057
- */
1058
- declare function handleRevisionRestore(db: Kysely<Database>, revisionId: string, callerUserId: string): Promise<ApiResult<ContentResponse>>;
1059
- //#endregion
1060
- //#region src/api/handlers/media.d.ts
1061
- interface MediaListResponse {
1062
- items: MediaItem[];
1063
- nextCursor?: string;
1064
- }
1065
- interface MediaResponse {
1066
- item: MediaItem;
1067
- }
1068
- /**
1069
- * List media items
1070
- */
1071
- declare function handleMediaList(db: Kysely<Database>, params: {
1072
- cursor?: string;
1073
- limit?: number;
1074
- mimeType?: string | readonly string[];
1075
- q?: string;
1076
- }): Promise<ApiResult<MediaListResponse>>;
1077
- /**
1078
- * Get single media item
1079
- */
1080
- declare function handleMediaGet(db: Kysely<Database>, id: string): Promise<ApiResult<MediaResponse>>;
1081
- /**
1082
- * Create media item (after file upload)
1083
- */
1084
- declare function handleMediaCreate(db: Kysely<Database>, input: {
1085
- filename: string;
1086
- mimeType: string;
1087
- size?: number;
1088
- width?: number;
1089
- height?: number;
1090
- alt?: string;
1091
- storageKey: string;
1092
- contentHash?: string;
1093
- blurhash?: string;
1094
- dominantColor?: string;
1095
- authorId?: string;
1096
- }): Promise<ApiResult<MediaResponse>>;
1097
- /**
1098
- * Update media metadata
1099
- */
1100
- declare function handleMediaUpdate(db: Kysely<Database>, id: string, input: {
1101
- alt?: string;
1102
- caption?: string;
1103
- width?: number;
1104
- height?: number;
1105
- }): Promise<ApiResult<MediaResponse>>;
1106
- /**
1107
- * Delete media item
1108
- */
1109
- declare function handleMediaDelete(db: Kysely<Database>, id: string): Promise<ApiResult<{
1110
- deleted: true;
1111
- }>>;
1112
- //#endregion
1113
- //#region src/schema/registry.d.ts
1114
- /**
1115
- * Error thrown when a schema operation fails
1116
- */
1117
- declare class SchemaError extends Error {
1118
- code: string;
1119
- details?: Record<string, unknown> | undefined;
1120
- constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
1121
- }
1039
+ //#region src/plugins/email.d.ts
1122
1040
  /**
1123
- * Schema Registry
1041
+ * EmailPipeline orchestrates email delivery through the plugin hook system.
1124
1042
  *
1125
- * Manages collection and field definitions stored in the database.
1126
- * Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).
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
1127
1047
  */
1128
- declare class SchemaRegistry {
1129
- private db;
1130
- constructor(db: Kysely<Database>);
1131
- /**
1132
- * List all collections
1133
- */
1134
- listCollections(): Promise<Collection[]>;
1135
- /**
1136
- * List all collections with their fields using bounded query shapes.
1137
- */
1138
- listCollectionsWithFields(): Promise<CollectionWithFields[]>;
1139
- /**
1140
- * Get a collection by slug
1141
- */
1142
- getCollection(slug: string): Promise<Collection | null>;
1143
- /**
1144
- * Get a collection with all its fields
1145
- */
1146
- getCollectionWithFields(slug: string): Promise<CollectionWithFields | null>;
1048
+ declare class EmailPipeline {
1049
+ private pipeline;
1050
+ constructor(pipeline: HookPipeline);
1147
1051
  /**
1148
- * Create a new collection
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.
1149
1057
  */
1150
- createCollection(input: CreateCollectionInput): Promise<Collection>;
1058
+ setPipeline(pipeline: HookPipeline): void;
1151
1059
  /**
1152
- * Update a collection
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
1153
1067
  */
1154
- updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection>;
1155
- private validateUrlPattern;
1156
- private checkLabelUniqueness;
1157
- private checkUrlPatternUniqueness;
1068
+ send(message: EmailMessage, source: string): Promise<void>;
1158
1069
  /**
1159
- * Delete a collection
1070
+ * Inner send implementation, separated from the recursion guard.
1160
1071
  */
1161
- deleteCollection(slug: string, options?: {
1162
- force?: boolean;
1163
- }): Promise<void>;
1072
+ private sendInner;
1164
1073
  /**
1165
- * List fields for a collection
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.
1166
1079
  */
1167
- listFields(collectionId: string): Promise<Field[]>;
1080
+ isAvailable(): boolean;
1081
+ }
1082
+ //#endregion
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;
1094
+ }
1095
+ interface PluginContextFactoryOptions {
1096
+ db: Kysely<Database>;
1168
1097
  /**
1169
- * Get a field by slug within a collection
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.
1170
1101
  */
1171
- getField(collectionSlug: string, fieldSlug: string): Promise<Field | null>;
1102
+ getDb?: () => Kysely<Database>;
1172
1103
  /**
1173
- * Create a new field
1104
+ * Storage backend for direct media uploads.
1105
+ * If not provided, upload() will throw.
1174
1106
  */
1175
- createField(collectionSlug: string, input: CreateFieldInput): Promise<Field>;
1107
+ storage?: Storage;
1176
1108
  /**
1177
- * Ensure the content table for an existing collection exists.
1178
- *
1179
- * This repairs interrupted schema creation where the metadata row exists but
1180
- * the physical `ec_*` table was not created.
1109
+ * Function to generate upload URLs for media.
1110
+ * If not provided, media write operations will throw.
1181
1111
  */
1182
- ensureCollectionContentTable(collectionSlug: string): Promise<boolean>;
1112
+ getUploadUrl?: (filename: string, contentType: string) => Promise<{
1113
+ uploadUrl: string;
1114
+ mediaId: string;
1115
+ }>;
1183
1116
  /**
1184
- * Ensure the physical column for an existing field exists on its content table.
1185
- *
1186
- * This repairs interrupted field creation where `_dineway_fields` was written
1187
- * but `ALTER TABLE ec_* ADD COLUMN` did not complete.
1117
+ * Site information for ctx.site and ctx.url().
1118
+ * If not provided, site info will have empty defaults.
1188
1119
  */
1189
- ensureFieldColumn(collectionSlug: string, fieldSlug: string): Promise<boolean>;
1120
+ siteInfo?: SiteInfoOptions;
1190
1121
  /**
1191
- * Update a field
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.
1192
1124
  */
1193
- updateField(collectionSlug: string, fieldSlug: string, input: UpdateFieldInput): Promise<Field>;
1125
+ cronReschedule?: () => void;
1194
1126
  /**
1195
- * Synchronize an existing FTS index with the collection's current state.
1196
- *
1197
- * Schema writes must not first-time enable FTS. Initial enablement stays in
1198
- * explicit seed/import/admin flows where FTS failures can be handled deliberately.
1127
+ * Email pipeline instance for ctx.email.
1128
+ * If not provided (or no provider configured), ctx.email will be undefined.
1199
1129
  */
1200
- private syncSearchState;
1130
+ emailPipeline?: EmailPipeline;
1201
1131
  /**
1202
- * Delete a field
1132
+ * Trusted reverse-proxy headers for request metadata IP extraction.
1203
1133
  */
1204
- deleteField(collectionSlug: string, fieldSlug: string): Promise<void>;
1205
- /**
1206
- * Reorder fields
1134
+ trustedProxyHeaders?: string[];
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";
1139
+ /**
1140
+ * Hook execution result
1141
+ */
1142
+ interface HookResult<T> {
1143
+ success: boolean;
1144
+ value?: T;
1145
+ error?: Error;
1146
+ pluginId: string;
1147
+ duration: number;
1148
+ }
1149
+ /**
1150
+ * Hook pipeline for executing hooks in order
1151
+ */
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;
1160
+ /**
1161
+ * Selected provider plugin ID for each exclusive hook.
1162
+ * Set by the PluginManager after resolution.
1207
1163
  */
1208
- reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void>;
1164
+ private exclusiveSelections;
1165
+ constructor(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions);
1209
1166
  /**
1210
- * Create a content table for a collection
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`).
1211
1173
  */
1212
- private createContentTable;
1174
+ setContextFactory(options: Partial<PluginContextFactoryOptions>): void;
1213
1175
  /**
1214
- * Drop a content table
1176
+ * Get context for a plugin
1215
1177
  */
1216
- private dropContentTable;
1178
+ private getContext;
1217
1179
  /**
1218
- * Add a column to a content table
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.
1219
1186
  */
1220
- private addColumn;
1187
+ private getTypedHooks;
1221
1188
  /**
1222
- * Drop a column from a content table
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.
1223
1194
  */
1224
- private dropColumn;
1195
+ private registerPlugins;
1225
1196
  /**
1226
- * Check if a collection has any content
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.
1227
1202
  */
1228
- private collectionHasContent;
1203
+ private static readonly HOOK_REQUIRED_CAPABILITY;
1229
1204
  /**
1230
- * Get table name for a collection
1205
+ * Register a single plugin's hook by name
1231
1206
  */
1232
- private getTableName;
1207
+ private registerPluginHook;
1233
1208
  /**
1234
- * Get column name for a field
1209
+ * Register a single hook
1235
1210
  */
1236
- private getColumnName;
1211
+ private registerHook;
1237
1212
  /**
1238
- * Validate a slug
1213
+ * Sort hooks by priority and dependencies
1239
1214
  */
1240
- private validateSlug;
1215
+ private sortHooks;
1241
1216
  /**
1242
- * Format a default value for SQL.
1217
+ * Execute a hook with timeout
1218
+ */
1219
+ private executeWithTimeout;
1220
+ /**
1221
+ * Run plugin:install hooks
1222
+ */
1223
+ runPluginInstall(pluginId: string): Promise<HookResult<void>[]>;
1224
+ /**
1225
+ * Run plugin:activate hooks
1226
+ */
1227
+ runPluginActivate(pluginId: string): Promise<HookResult<void>[]>;
1228
+ /**
1229
+ * Run plugin:deactivate hooks
1230
+ */
1231
+ runPluginDeactivate(pluginId: string): Promise<HookResult<void>[]>;
1232
+ /**
1233
+ * Run plugin:uninstall hooks
1234
+ */
1235
+ runPluginUninstall(pluginId: string, deleteData: boolean): Promise<HookResult<void>[]>;
1236
+ private runLifecycleHook;
1237
+ /**
1238
+ * Run content:beforeSave hooks
1239
+ * Returns modified content from the pipeline
1240
+ */
1241
+ runContentBeforeSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<{
1242
+ content: Record<string, unknown>;
1243
+ results: HookResult<Record<string, unknown>>[];
1244
+ }>;
1245
+ /**
1246
+ * Run content:afterSave hooks
1247
+ */
1248
+ runContentAfterSave(content: Record<string, unknown>, collection: string, isNew: boolean): Promise<HookResult<void>[]>;
1249
+ /**
1250
+ * Run content:beforeDelete hooks
1251
+ * Returns whether deletion is allowed
1252
+ */
1253
+ runContentBeforeDelete(id: string, collection: string): Promise<{
1254
+ allowed: boolean;
1255
+ results: HookResult<boolean>[];
1256
+ }>;
1257
+ /**
1258
+ * Run content:afterDelete hooks
1259
+ */
1260
+ runContentAfterDelete(id: string, collection: string, permanent: boolean): Promise<HookResult<void>[]>;
1261
+ /**
1262
+ * Run content:afterPublish hooks (fire-and-forget).
1263
+ */
1264
+ runContentAfterPublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1265
+ /**
1266
+ * Run content:afterUnpublish hooks (fire-and-forget).
1267
+ */
1268
+ runContentAfterUnpublish(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1269
+ /**
1270
+ * Run content:afterRestore hooks (fire-and-forget).
1271
+ */
1272
+ runContentAfterRestore(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1273
+ /**
1274
+ * Run content:afterSchedule hooks (fire-and-forget).
1275
+ */
1276
+ runContentAfterSchedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1277
+ /**
1278
+ * Run content:afterUnschedule hooks (fire-and-forget).
1279
+ */
1280
+ runContentAfterUnschedule(content: Record<string, unknown>, collection: string): Promise<HookResult<void>[]>;
1281
+ private runContentStateChangeHook;
1282
+ /**
1283
+ * Run media:beforeUpload hooks
1284
+ */
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
+ }>;
1301
+ /**
1302
+ * Run media:afterUpload hooks
1303
+ */
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>[]>;
1312
+ /**
1313
+ * Invoke the cron hook for a specific plugin.
1243
1314
  *
1244
- * SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant
1245
- * expression — parameterized values cannot be used here. We manually escape
1246
- * single quotes and coerce types to ensure the output is safe.
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.
1317
+ */
1318
+ invokeCronHook(pluginId: string, event: CronEvent): Promise<HookResult<void>>;
1319
+ /**
1320
+ * Run email:beforeSend hooks (middleware pipeline).
1247
1321
  *
1248
- * INTEGER/REAL values are coerced through `Number()` which can only produce
1249
- * digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.
1250
- * TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).
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.
1251
1325
  */
1252
- private formatDefaultValue;
1326
+ runEmailBeforeSend(message: EmailMessage, source: string): Promise<{
1327
+ message: EmailMessage | false;
1328
+ results: HookResult<EmailMessage | false>[];
1329
+ }>;
1253
1330
  /**
1254
- * Get empty default for a field type
1331
+ * Run email:afterSend hooks (fire-and-forget).
1332
+ *
1333
+ * Errors are logged but don't propagate — they don't affect the caller.
1255
1334
  */
1256
- private getEmptyDefault;
1335
+ runEmailAfterSend(message: EmailMessage, source: string): Promise<HookResult<void>[]>;
1257
1336
  /**
1258
- * Map a collection row to a Collection object
1337
+ * Run comment:beforeCreate hooks (middleware pipeline).
1338
+ *
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.
1259
1342
  */
1260
- private mapCollectionRow;
1343
+ runCommentBeforeCreate(event: CommentBeforeCreateEvent): Promise<CommentBeforeCreateEvent | false>;
1261
1344
  /**
1262
- * Map a field row to a Field object
1345
+ * Run comment:afterCreate hooks (fire-and-forget).
1346
+ *
1347
+ * Errors are logged but don't propagate — they don't affect the caller.
1263
1348
  */
1264
- private mapFieldRow;
1349
+ runCommentAfterCreate(event: CommentAfterCreateEvent): Promise<void>;
1265
1350
  /**
1266
- * Discover orphaned content tables
1351
+ * Run comment:afterModerate hooks (fire-and-forget).
1267
1352
  *
1268
- * Finds ec_* tables that exist in the database but don't have a
1269
- * corresponding entry in _dineway_collections.
1353
+ * Errors are logged but don't propagate — they don't affect the caller.
1270
1354
  */
1271
- discoverOrphanedTables(): Promise<Array<{
1272
- slug: string;
1273
- tableName: string;
1274
- rowCount: number;
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[];
1275
1363
  }>>;
1276
1364
  /**
1277
- * Register an orphaned table as a collection
1278
- *
1279
- * Creates a _dineway_collections entry for an existing ec_* table.
1365
+ * Run page:fragments hooks. Only trusted plugins should be registered
1366
+ * for this hook. Errors are logged but don't propagate.
1280
1367
  */
1281
- registerOrphanedTable(slug: string, options?: {
1282
- label?: string;
1283
- labelSingular?: string;
1284
- description?: string;
1285
- }): Promise<Collection>;
1368
+ runPageFragments(event: PageFragmentEvent): Promise<Array<{
1369
+ pluginId: string;
1370
+ contributions: PageFragmentContribution[];
1371
+ }>>;
1286
1372
  /**
1287
- * Convert slug to human-readable label
1373
+ * Check if any hooks are registered for a given name
1288
1374
  */
1289
- private slugToLabel;
1290
- }
1291
- //#endregion
1292
- //#region src/schema/query.d.ts
1293
- /**
1294
- * Get collection metadata by slug.
1295
- *
1296
- * @example
1297
- * ```ts
1298
- * import { getCollectionInfo } from "dineway";
1299
- *
1300
- * const info = await getCollectionInfo("posts");
1301
- * if (info?.commentsEnabled) {
1302
- * // render comment UI
1303
- * }
1304
- * ```
1305
- */
1306
- declare function getCollectionInfo(slug: string): Promise<Collection | null>;
1307
- //#endregion
1308
- //#region src/sections/types.d.ts
1309
- /**
1310
- * Section source types
1311
- */
1312
- type SectionSource = "theme" | "user" | "import";
1313
- /**
1314
- * Section as returned to templates/admin
1315
- */
1316
- interface Section {
1317
- id: string;
1318
- slug: string;
1319
- title: string;
1320
- description?: string;
1321
- keywords: string[];
1322
- content: PortableTextBlock$1[];
1323
- previewUrl?: string;
1324
- source: SectionSource;
1325
- themeId?: string;
1326
- createdAt: string;
1327
- updatedAt: string;
1328
- }
1329
- /**
1330
- * Input for creating a section
1331
- */
1332
- interface CreateSectionInput {
1333
- slug: string;
1334
- title: string;
1335
- description?: string;
1336
- keywords?: string[];
1337
- content: PortableTextBlock$1[];
1338
- previewMediaId?: string;
1339
- source?: SectionSource;
1340
- themeId?: string;
1341
- }
1342
- /**
1343
- * Input for updating a section
1344
- */
1345
- interface UpdateSectionInput {
1346
- slug?: string;
1347
- title?: string;
1348
- description?: string;
1349
- keywords?: string[];
1350
- content?: PortableTextBlock$1[];
1351
- previewMediaId?: string | null;
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>;
1352
1436
  }
1353
1437
  /**
1354
- * Options for querying sections
1438
+ * Create a hook pipeline from plugins
1355
1439
  */
1356
- interface GetSectionsOptions {
1357
- /** Filter by source */
1358
- source?: SectionSource;
1359
- /** Search title, description, keywords */
1360
- search?: string;
1361
- /** Limit results */
1362
- limit?: number;
1363
- /** Cursor for pagination */
1364
- cursor?: string;
1365
- }
1440
+ declare function createHookPipeline(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions): HookPipeline;
1366
1441
  //#endregion
1367
- //#region src/sections/index.d.ts
1368
- /**
1369
- * Get a section by slug
1370
- *
1371
- * @example
1372
- * ```ts
1373
- * import { getSection } from "dineway";
1374
- *
1375
- * const section = await getSection("hero-centered");
1376
- * if (section) {
1377
- * console.log(section.content); // Portable Text array
1378
- * }
1379
- * ```
1380
- */
1381
- declare function getSection(slug: string): Promise<Section | null>;
1382
- /**
1383
- * Get all sections with optional filtering
1384
- *
1385
- * @example
1386
- * ```ts
1387
- * import { getSections } from "dineway";
1388
- *
1389
- * // Get all theme-provided sections
1390
- * const themeSections = await getSections({ source: "theme" });
1391
- *
1392
- * // Search sections
1393
- * const results = await getSections({ search: "pricing" });
1394
- * ```
1395
- */
1396
- declare function getSections(options?: GetSectionsOptions): Promise<FindManyResult<Section>>;
1442
+ //#region src/plugins/mcp.d.ts
1443
+ interface RegisteredPluginMcpTool {
1444
+ pluginId: string;
1445
+ pluginVersion: string;
1446
+ tool: PluginMcpTool;
1447
+ authorizeTarget?: PluginMcpTargetAuthorizer$1;
1448
+ }
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>>;
1397
1476
  //#endregion
1398
1477
  //#region src/plugins/sandbox/types.d.ts
1399
1478
  /**
@@ -1497,6 +1576,8 @@ interface SerializedRequest {
1497
1576
  headers: Record<string, string>;
1498
1577
  /** Normalized request metadata extracted before RPC serialization */
1499
1578
  meta: RequestMeta;
1579
+ /** Safe authenticated actor metadata; null for unauthenticated public routes. */
1580
+ actor?: PluginActor | null;
1500
1581
  }
1501
1582
  /**
1502
1583
  * Sandbox runner interface.
@@ -1543,1316 +1624,1654 @@ interface SandboxRunner {
1543
1624
  */
1544
1625
  type SandboxRunnerFactory = (options: SandboxOptions) => SandboxRunner;
1545
1626
  //#endregion
1546
- //#region src/content/converters/types.d.ts
1547
- /**
1548
- * Portable Text Types
1549
- *
1550
- * Defines the structure of Portable Text blocks used in Dineway.
1551
- */
1627
+ //#region src/plugins/routes.d.ts
1552
1628
  /**
1553
- * Base span (inline text)
1629
+ * Result from a route invocation
1554
1630
  */
1555
- interface PortableTextSpan {
1556
- _type: "span";
1557
- _key: string;
1558
- text: string;
1559
- 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;
1560
1640
  }
1561
1641
  /**
1562
- * Mark definition (bold, italic, link, etc.)
1642
+ * Route invocation options
1563
1643
  */
1564
- interface PortableTextMarkDef {
1565
- _type: string;
1566
- _key: string;
1567
- [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;
1568
1653
  }
1569
1654
  /**
1570
- * Link mark definition
1655
+ * Error class for plugin routes
1656
+ * Allows plugins to return structured errors with specific HTTP status codes
1571
1657
  */
1572
- interface PortableTextLinkMark extends PortableTextMarkDef {
1573
- _type: "link";
1574
- href: string;
1575
- 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;
1576
1687
  }
1577
- /**
1578
- * Text block (paragraph, heading, etc.)
1579
- */
1580
- interface PortableTextTextBlock {
1581
- _type: "block";
1582
- _key: string;
1583
- style?: "normal" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote";
1584
- listItem?: "bullet" | "number";
1585
- level?: number;
1586
- children: PortableTextSpan[];
1587
- markDefs?: PortableTextMarkDef[];
1688
+ //#endregion
1689
+ //#region src/plugins/sandbox/runtime-options.d.ts
1690
+ interface SandboxRunnerRuntimeOptions extends SandboxOptions {
1691
+ mediaStorage?: Storage;
1692
+ cronReschedule?: () => void;
1588
1693
  }
1694
+ //#endregion
1695
+ //#region src/dineway-runtime.d.ts
1589
1696
  /**
1590
- * Image block
1697
+ * Sandboxed plugin entry from virtual module
1591
1698
  */
1592
- interface PortableTextImageBlock {
1593
- _type: "image";
1594
- _key: string;
1595
- asset: {
1596
- _ref: string;
1597
- url?: string; /** Provider ID for external media (e.g., "image-cdn") */
1598
- provider?: string;
1599
- };
1600
- alt?: string;
1601
- caption?: string;
1602
- /** Original image width */
1603
- width?: number;
1604
- /** Original image height */
1605
- height?: number;
1606
- /** Display width for this instance (overrides original) */
1607
- displayWidth?: number;
1608
- /** Display height for this instance (overrides original) */
1609
- displayHeight?: number;
1610
- }
1611
- /**
1612
- * Code block
1613
- */
1614
- interface PortableTextCodeBlock {
1615
- _type: "code";
1616
- _key: string;
1699
+ interface SandboxedPluginEntry {
1700
+ id: string;
1701
+ version: string;
1702
+ options: Record<string, unknown>;
1617
1703
  code: string;
1618
- language?: string;
1619
- filename?: 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[];
1620
1733
  }
1621
- /**
1622
- * HTML block (raw HTML content)
1623
- */
1624
- interface PortableTextHtmlBlock {
1625
- _type: "htmlBlock";
1626
- _key: string;
1627
- html: string;
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[];
1747
+ };
1628
1748
  }
1749
+ type CollectionMap = Record<string, CollectionDefinition>;
1629
1750
  /**
1630
- * Unknown/custom block (preserved for plugin compatibility)
1751
+ * Generate admin manifest from collections
1631
1752
  */
1632
- interface PortableTextUnknownBlock {
1633
- _type: string;
1634
- _key: string;
1635
- [key: string]: unknown;
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;
1765
+ }
1766
+ interface RevisionResponse {
1767
+ item: Revision;
1636
1768
  }
1637
1769
  /**
1638
- * Any Portable Text block
1639
- */
1640
- type PortableTextBlock = PortableTextTextBlock | PortableTextImageBlock | PortableTextCodeBlock | PortableTextHtmlBlock | PortableTextUnknownBlock;
1641
- /**
1642
- * ProseMirror JSON types (simplified for TipTap)
1770
+ * List revisions for a content entry
1643
1771
  */
1644
- interface ProseMirrorMark {
1645
- type: string;
1646
- attrs?: Record<string, unknown>;
1647
- }
1648
- interface ProseMirrorNode {
1649
- type: string;
1650
- attrs?: Record<string, unknown>;
1651
- content?: ProseMirrorNode[];
1652
- marks?: ProseMirrorMark[];
1653
- text?: string;
1654
- }
1655
- interface ProseMirrorDocument {
1656
- type: "doc";
1657
- content: ProseMirrorNode[];
1658
- }
1659
- //#endregion
1660
- //#region src/content/converters/prosemirror-to-portable-text.d.ts
1772
+ declare function handleRevisionList(db: Kysely<Database>, collection: string, entryId: string, params?: {
1773
+ limit?: number;
1774
+ }): Promise<ApiResult<RevisionListResponse>>;
1661
1775
  /**
1662
- * Convert ProseMirror document to Portable Text
1776
+ * Get a specific revision
1663
1777
  */
1664
- declare function prosemirrorToPortableText(doc: ProseMirrorDocument): PortableTextBlock[];
1665
- //#endregion
1666
- //#region src/content/converters/portable-text-to-prosemirror.d.ts
1778
+ declare function handleRevisionGet(db: Kysely<Database>, revisionId: string): Promise<ApiResult<RevisionResponse>>;
1667
1779
  /**
1668
- * Convert Portable Text to ProseMirror document
1780
+ * Restore a revision (updates content to this revision's data and creates new revision)
1669
1781
  */
1670
- declare function portableTextToProsemirror(blocks: PortableTextBlock[]): ProseMirrorDocument;
1782
+ declare function handleRevisionRestore(db: Kysely<Database>, revisionId: string, callerUserId: string): Promise<ApiResult<ContentResponse>>;
1671
1783
  //#endregion
1672
- //#region src/utils/hash.d.ts
1784
+ //#region src/api/handlers/media.d.ts
1785
+ interface MediaListResponse {
1786
+ items: MediaItem[];
1787
+ nextCursor?: string;
1788
+ }
1789
+ interface MediaResponse {
1790
+ item: MediaItem;
1791
+ }
1673
1792
  /**
1674
- * SHA-256 hash of a string, truncated to 16 hex chars (64 bits).
1675
- * For cache invalidation / ETags — not for security.
1793
+ * List media items
1676
1794
  */
1677
- declare function hashString(content: string): Promise<string>;
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>>;
1678
1801
  /**
1679
- * Compute content hash using Web Crypto API
1680
- *
1681
- * Uses SHA-1 which is the fastest option in SubtleCrypto.
1682
- * SHA-1 is cryptographically weak but fine for content deduplication
1683
- * where we only need to detect identical files, not resist attacks.
1684
- *
1685
- * Returns hex string prefixed with "sha1:" for future-proofing
1802
+ * Get single media item
1686
1803
  */
1687
- declare function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string>;
1688
- //#endregion
1689
- //#region src/utils/url.d.ts
1804
+ declare function handleMediaGet(db: Kysely<Database>, id: string): Promise<ApiResult<MediaResponse>>;
1690
1805
  /**
1691
- * URL scheme validation utilities
1692
- *
1693
- * Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
1694
- * by allowlisting known-safe schemes before rendering into href attributes.
1806
+ * Create media item (after file upload)
1695
1807
  */
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>>;
1696
1821
  /**
1697
- * Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
1698
- *
1699
- * Use this at the render layer as the primary defense against XSS via
1700
- * dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
1701
- *
1702
- * @example
1703
- * ```ts
1704
- * sanitizeHref("https://example.com") // "https://example.com"
1705
- * sanitizeHref("/about") // "/about"
1706
- * sanitizeHref("#section") // "#section"
1707
- * sanitizeHref("mailto:a@b.com") // "mailto:a@b.com"
1708
- * sanitizeHref("javascript:alert(1)") // "#"
1709
- * sanitizeHref("data:text/html,<script>") // "#"
1710
- * sanitizeHref("") // "#"
1711
- * ```
1822
+ * Update media metadata
1712
1823
  */
1713
- declare function sanitizeHref(url: string | undefined | null): 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>>;
1714
1830
  /**
1715
- * Returns true if the URL uses a safe scheme for rendering in href attributes.
1831
+ * Delete media item
1716
1832
  */
1717
- declare function isSafeHref(url: string): boolean;
1833
+ declare function handleMediaDelete(db: Kysely<Database>, id: string): Promise<ApiResult<{
1834
+ deleted: true;
1835
+ }>>;
1718
1836
  //#endregion
1719
- //#region src/visual-editing/editable.d.ts
1837
+ //#region src/schema/registry.d.ts
1720
1838
  /**
1721
- * Visual editing annotation system
1722
- *
1723
- * Creates Proxy objects that emit data-dineway-ref attributes when spread onto elements.
1839
+ * Error thrown when a schema operation fails
1724
1840
  */
1725
- interface CMSAnnotation {
1726
- collection: string;
1727
- 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;
1737
- }
1738
- interface EditableOptions {
1739
- /** Entry status: "draft", "published", "scheduled" */
1740
- status?: string;
1741
- /** true when draftRevisionId exists and differs from liveRevisionId */
1742
- hasDraft?: boolean;
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);
1743
1845
  }
1744
1846
  /**
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)
1751
- */
1752
- declare function createEditable(collection: string, id: string, options?: EditableOptions): EditProxy;
1753
- /**
1754
- * Create a noop proxy for production mode.
1755
- * Spreading this produces no attributes.
1756
- */
1757
- declare function createNoop(): EditProxy;
1758
- /**
1759
- * Visual editing proxy type.
1760
- *
1761
- * Spread directly onto elements for entry-level annotations: `{...entry.edit}`
1762
- * Access a field for field-level annotations: `{...entry.edit.title}`
1847
+ * Schema Registry
1763
1848
  *
1764
- * In production, spreading produces no attributes (noop).
1849
+ * Manages collection and field definitions stored in the database.
1850
+ * Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).
1765
1851
  */
1766
- type EditProxy = {
1767
- readonly [field: string]: Partial<FieldAnnotation>;
1768
- };
1769
- //#endregion
1770
- //#region src/query.d.ts
1771
- /**
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.
1776
- *
1777
- * @example
1778
- * ```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
- * }
1786
- *
1787
- * // Then in your code:
1788
- * const { entries } = await getDinewayCollection("posts");
1789
- * // entries[0].data.title is typed as string
1790
- * ```
1791
- */
1792
- interface DinewayCollections {}
1793
- /**
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>.
1796
- */
1797
- type InferCollectionData<T extends string> = T extends keyof DinewayCollections ? DinewayCollections[T] : Record<string, unknown>;
1798
- /**
1799
- * Sort direction
1800
- */
1801
- type SortDirection = "asc" | "desc";
1802
- /**
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
1807
- */
1808
- type OrderBySpec = Record<string, SortDirection>;
1809
- interface CollectionFilter {
1810
- status?: "draft" | "published" | "archived";
1811
- limit?: number;
1852
+ declare class SchemaRegistry {
1853
+ private db;
1854
+ constructor(db: Kysely<Database>);
1812
1855
  /**
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
- * ```
1856
+ * List all collections
1823
1857
  */
1824
- cursor?: string;
1858
+ listCollections(): Promise<Collection[]>;
1825
1859
  /**
1826
- * 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.
1827
1902
  *
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.
1903
+ * This repairs interrupted schema creation where the metadata row exists but
1904
+ * the physical `ec_*` table was not created.
1905
+ */
1906
+ ensureCollectionContentTable(collectionSlug: string): Promise<boolean>;
1907
+ /**
1908
+ * Ensure the physical column for an existing field exists on its content table.
1833
1909
  *
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
1910
+ * This repairs interrupted field creation where `_dineway_fields` was written
1911
+ * but `ALTER TABLE ec_* ADD COLUMN` did not complete.
1840
1912
  */
1841
- where?: Record<string, WhereValue>;
1913
+ ensureFieldColumn(collectionSlug: string, fieldSlug: string): Promise<boolean>;
1842
1914
  /**
1843
- * Case-insensitive substring search across selected content fields.
1915
+ * Update a field
1916
+ */
1917
+ updateField(collectionSlug: string, fieldSlug: string, input: UpdateFieldInput): Promise<Field>;
1918
+ /**
1919
+ * Synchronize an existing FTS index with the collection's current state.
1844
1920
  *
1845
- * `searchColumns` must contain concrete field slugs or system column names.
1846
- * When `q` is present without `searchColumns`, no search condition is applied.
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.
1847
1923
  */
1848
- q?: string;
1849
- searchColumns?: string[];
1924
+ private syncSearchState;
1850
1925
  /**
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
1926
+ * Delete a field
1856
1927
  */
1857
- orderBy?: OrderBySpec;
1928
+ deleteField(collectionSlug: string, fieldSlug: string): Promise<void>;
1858
1929
  /**
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
1930
+ * Reorder fields
1863
1931
  */
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;
1876
- }
1877
- /**
1878
- * Result from getDinewayCollection
1879
- */
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;
1932
+ reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void>;
1887
1933
  /**
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.
1934
+ * Create a content table for a collection
1891
1935
  */
1892
- nextCursor?: string;
1936
+ private createContentTable;
1893
1937
  /**
1894
- * Total number of entries matching the current filter, excluding cursor and limit.
1938
+ * Drop a content table
1895
1939
  */
1896
- total?: number;
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;
1897
2014
  }
2015
+ //#endregion
2016
+ //#region src/schema/query.d.ts
1898
2017
  /**
1899
- * Result from getDinewayEntry
2018
+ * Get collection metadata by slug.
2019
+ *
2020
+ * @example
2021
+ * ```ts
2022
+ * import { getCollectionInfo } from "dineway";
2023
+ *
2024
+ * const info = await getCollectionInfo("posts");
2025
+ * if (info?.commentsEnabled) {
2026
+ * // render comment UI
2027
+ * }
2028
+ * ```
1900
2029
  */
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;
1918
- }
2030
+ declare function getCollectionInfo(slug: string): Promise<Collection | null>;
2031
+ //#endregion
2032
+ //#region src/sections/types.d.ts
1919
2033
  /**
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.
2034
+ * Section source types
1923
2035
  */
1924
- declare function getEditMeta(value: unknown): EditFieldMeta | undefined;
2036
+ type SectionSource = "theme" | "user" | "import";
1925
2037
  /**
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
- * ```
2038
+ * Section as returned to templates/admin
1947
2039
  */
1948
- declare function getDinewayCollection<T extends string, D = InferCollectionData<T>>(type: T, filter?: CollectionFilter): Promise<CollectionResult<D>>;
2040
+ interface Section {
2041
+ id: 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;
2052
+ }
1949
2053
  /**
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
- * ```
2054
+ * Input for creating a section
1968
2055
  */
1969
- declare function getDinewayEntry<T extends string, D = InferCollectionData<T>>(type: T, id: string, options?: {
1970
- locale?: string;
1971
- }): Promise<EntryResult<D>>;
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;
2065
+ }
1972
2066
  /**
1973
- * Translation summary for a single locale variant
2067
+ * Input for updating a section
1974
2068
  */
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;
2069
+ interface UpdateSectionInput {
2070
+ slug?: string;
2071
+ title?: string;
2072
+ description?: string;
2073
+ keywords?: string[];
2074
+ content?: PortableTextBlock$1[];
2075
+ previewMediaId?: string | null;
1984
2076
  }
1985
2077
  /**
1986
- * Result from getTranslations
2078
+ * Options for querying sections
1987
2079
  */
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;
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;
1995
2089
  }
2090
+ //#endregion
2091
+ //#region src/sections/index.d.ts
1996
2092
  /**
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.
2093
+ * Get a section by slug
2001
2094
  *
2002
2095
  * @example
2003
2096
  * ```ts
2004
- * import { getDinewayEntry, getTranslations } from "dineway";
2097
+ * import { getSection } from "dineway";
2005
2098
  *
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" }, ...]
2099
+ * const section = await getSection("hero-centered");
2100
+ * if (section) {
2101
+ * console.log(section.content); // Portable Text array
2102
+ * }
2009
2103
  * ```
2010
2104
  */
2011
- declare function getTranslations(type: string, id: string): Promise<TranslationsResult>;
2012
- /**
2013
- * Result from resolveDinewayPath
2014
- */
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
- }
2105
+ declare function getSection(slug: string): Promise<Section | null>;
2023
2106
  /**
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.
2107
+ * Get all sections with optional filtering
2028
2108
  *
2029
2109
  * @example
2030
2110
  * ```ts
2031
- * import { resolveDinewayPath } from "dineway";
2111
+ * import { getSections } from "dineway";
2032
2112
  *
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
- * }
2113
+ * // Get all theme-provided sections
2114
+ * const themeSections = await getSections({ source: "theme" });
2115
+ *
2116
+ * // Search sections
2117
+ * const results = await getSections({ search: "pricing" });
2040
2118
  * ```
2041
2119
  */
2042
- declare function resolveDinewayPath<T = Record<string, unknown>>(path: string): Promise<ResolvePathResult<T> | null>;
2120
+ declare function getSections(options?: GetSectionsOptions): Promise<FindManyResult<Section>>;
2043
2121
  //#endregion
2044
- //#region src/after.d.ts
2122
+ //#region src/content/converters/types.d.ts
2045
2123
  /**
2046
- * Defer work past the current synchronous path.
2124
+ * Portable Text Types
2047
2125
  *
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.
2126
+ * Defines the structure of Portable Text blocks used in Dineway.
2052
2127
  */
2053
- type AfterCallback = () => void | Promise<void>;
2054
- declare function after(fn: AfterCallback): void;
2055
- //#endregion
2056
- //#region src/i18n/config.d.ts
2057
2128
  /**
2058
- * Dineway i18n Configuration
2059
- *
2060
- * Reads locale configuration from the virtual module (sourced from Astro config).
2061
- * Initialized during runtime startup, then available via getI18nConfig().
2129
+ * Base span (inline text)
2062
2130
  */
2063
- interface I18nConfig {
2064
- defaultLocale: string;
2065
- locales: string[];
2066
- fallback?: Record<string, string>;
2067
- prefixDefaultLocale?: boolean;
2131
+ interface PortableTextSpan {
2132
+ _type: "span";
2133
+ _key: string;
2134
+ text: string;
2135
+ marks?: string[];
2068
2136
  }
2069
2137
  /**
2070
- * Get the current i18n config.
2071
- * Returns null if i18n is not configured.
2138
+ * Mark definition (bold, italic, link, etc.)
2072
2139
  */
2073
- declare function getI18nConfig(): I18nConfig | null;
2140
+ interface PortableTextMarkDef {
2141
+ _type: string;
2142
+ _key: string;
2143
+ [key: string]: unknown;
2144
+ }
2074
2145
  /**
2075
- * Check if i18n is enabled.
2076
- * Returns true when multiple locales are configured.
2146
+ * Link mark definition
2077
2147
  */
2078
- declare function isI18nEnabled(): boolean;
2148
+ interface PortableTextLinkMark extends PortableTextMarkDef {
2149
+ _type: "link";
2150
+ href: string;
2151
+ blank?: boolean;
2152
+ }
2079
2153
  /**
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.
2154
+ * Text block (paragraph, heading, etc.)
2083
2155
  */
2084
- declare function getFallbackChain(locale: string): string[];
2085
- //#endregion
2086
- //#region src/preview/sidecar-client.d.ts
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";
2165
+ }
2087
2166
  /**
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.
2167
+ * Image block
2092
2168
  */
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;
2113
- 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[];
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;
2125
2187
  }
2126
- interface SessionOpenOptions {
2127
- id: string;
2128
- now?: number;
2188
+ /**
2189
+ * Code block
2190
+ */
2191
+ interface PortableTextCodeBlock {
2192
+ _type: "code";
2193
+ _key: string;
2194
+ code: string;
2195
+ language?: string;
2196
+ filename?: string;
2129
2197
  }
2130
- interface SessionOpenOrCreateOptions extends SessionOpenOptions {
2131
- ttlMs: number;
2198
+ /**
2199
+ * HTML block (raw HTML content)
2200
+ */
2201
+ interface PortableTextHtmlBlock {
2202
+ _type: "htmlBlock";
2203
+ _key: string;
2204
+ html: string;
2132
2205
  }
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>;
2206
+ /**
2207
+ * Unknown/custom block (preserved for plugin compatibility)
2208
+ */
2209
+ interface PortableTextUnknownBlock {
2210
+ _type: string;
2211
+ _key: string;
2212
+ [key: string]: unknown;
2139
2213
  }
2140
- interface FileSessionDatabaseFactoryOptions {
2141
- rootDir: string;
2142
- maxDiskBytes?: number;
2143
- registryFileName?: string;
2144
- sessionsDirName?: string;
2214
+ /**
2215
+ * Any Portable Text block
2216
+ */
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>;
2145
2224
  }
2146
- declare class SessionDatabaseLimitError extends Error {
2147
- constructor(message?: string);
2225
+ interface ProseMirrorNode {
2226
+ type: string;
2227
+ attrs?: Record<string, unknown>;
2228
+ content?: ProseMirrorNode[];
2229
+ marks?: ProseMirrorMark[];
2230
+ text?: string;
2148
2231
  }
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;
2232
+ interface ProseMirrorDocument {
2233
+ type: "doc";
2234
+ content: ProseMirrorNode[];
2169
2235
  }
2170
2236
  //#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;
2181
- }
2182
- declare function createFilePreviewMiddleware(config: FilePreviewMiddlewareConfig): MiddlewareHandler;
2237
+ //#region src/content/converters/prosemirror-to-portable-text.d.ts
2238
+ /**
2239
+ * Convert ProseMirror document to Portable Text
2240
+ */
2241
+ declare function prosemirrorToPortableText(doc: ProseMirrorDocument): PortableTextBlock[];
2183
2242
  //#endregion
2184
- //#region src/plugins/define-plugin.d.ts
2243
+ //#region src/content/converters/portable-text-to-prosemirror.d.ts
2185
2244
  /**
2186
- * Define a Dineway plugin.
2245
+ * Convert Portable Text to ProseMirror document
2246
+ */
2247
+ declare function portableTextToProsemirror(blocks: PortableTextBlock[]): ProseMirrorDocument;
2248
+ //#endregion
2249
+ //#region src/utils/hash.d.ts
2250
+ /**
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
2187
2257
  *
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.
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.
2190
2261
  *
2191
- * @example
2192
- * ```typescript
2193
- * import { definePlugin } from "dineway";
2262
+ * Returns hex string prefixed with "sha1:" for future-proofing
2263
+ */
2264
+ declare function computeContentHash(content: Uint8Array | ArrayBuffer): Promise<string>;
2265
+ //#endregion
2266
+ //#region src/utils/url.d.ts
2267
+ /**
2268
+ * URL scheme validation utilities
2194
2269
  *
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
- * ```
2270
+ * Prevents XSS via dangerous URL schemes (javascript:, data:, vbscript:, etc.)
2271
+ * by allowlisting known-safe schemes before rendering into href attributes.
2272
+ */
2273
+ /**
2274
+ * Returns the URL unchanged if it uses a safe scheme, otherwise returns "#".
2210
2275
  *
2211
- * **Native format** -- for plugins that need React admin, direct DB access,
2212
- * or other capabilities not available in the sandbox.
2276
+ * Use this at the render layer as the primary defense against XSS via
2277
+ * dangerous URL schemes like `javascript:`, `data:`, or `vbscript:`.
2213
2278
  *
2214
2279
  * @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
- * }
2234
- * }
2235
- * });
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("") // "#"
2236
2288
  * ```
2237
2289
  */
2238
- declare function definePlugin<TStorage extends PluginStorageConfig>(definition: PluginDefinition<TStorage>): ResolvedPlugin<TStorage>;
2239
- declare function definePlugin(definition: StandardPluginDefinition): StandardPluginDefinition;
2290
+ declare function sanitizeHref(url: string | undefined | null): string;
2291
+ /**
2292
+ * Returns true if the URL uses a safe scheme for rendering in href attributes.
2293
+ */
2294
+ declare function isSafeHref(url: string): boolean;
2240
2295
  //#endregion
2241
- //#region src/plugins/manifest-schema.d.ts
2296
+ //#region src/auth/rate-limit.d.ts
2242
2297
  /**
2243
- * Zod schema matching the PluginManifest interface from types.ts.
2298
+ * Result of a rate limit check.
2299
+ */
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
+ }
2308
+ /**
2309
+ * Check (and increment) the rate limit for a given IP + endpoint.
2244
2310
  *
2245
- * Every JSON.parse of a manifest.json should validate through this.
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.
2246
2321
  */
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
- image: "image";
2393
- datetime: "datetime";
2394
- slug: "slug";
2395
- text: "text";
2396
- integer: "integer";
2397
- select: "select";
2398
- multiSelect: "multiSelect";
2399
- portableText: "portableText";
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>;
2322
+ declare function checkRateLimit(db: Kysely<Database>, ip: string | null, endpoint: string, maxRequests: number, windowSeconds: number): Promise<RateLimitResult>;
2413
2323
  //#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";
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;
2333
+ expiresAt: number;
2334
+ }
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;
2344
+ now?: number;
2345
+ }
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;
2363
+ }
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");
2376
+ }
2416
2377
  /**
2417
- * Hook execution result
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.
2418
2380
  */
2419
- interface HookResult<T> {
2420
- success: boolean;
2421
- value?: T;
2422
- error?: Error;
2423
- pluginId: string;
2424
- duration: number;
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;
2404
+ }
2405
+ /** The shape returned when spreading an edit annotation onto an element */
2406
+ interface FieldAnnotation {
2407
+ "data-dineway-ref": string;
2408
+ }
2409
+ interface EditableOptions {
2410
+ /** Entry status: "draft", "published", "scheduled" */
2411
+ status?: string;
2412
+ /** true when draftRevisionId exists and differs from liveRevisionId */
2413
+ hasDraft?: boolean;
2425
2414
  }
2426
2415
  /**
2427
- * Hook pipeline for executing hooks in order
2416
+ * Create an editable proxy for an entry.
2417
+ *
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)
2428
2422
  */
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;
2456
- /**
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.
2460
- *
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.
2467
- *
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.
2471
- */
2472
- private registerPlugins;
2473
- /**
2474
- * Maps hook names to the capability required to register them.
2475
- *
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
2491
- */
2492
- private sortHooks;
2493
- /**
2494
- * Execute a hook with timeout
2495
- */
2496
- private executeWithTimeout;
2497
- /**
2498
- * Run plugin:install hooks
2499
- */
2500
- runPluginInstall(pluginId: string): Promise<HookResult<void>[]>;
2501
- /**
2502
- * Run plugin:activate hooks
2503
- */
2504
- runPluginActivate(pluginId: string): Promise<HookResult<void>[]>;
2505
- /**
2506
- * Run plugin:deactivate hooks
2507
- */
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>[]>;
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.
2431
+ *
2432
+ * Spread directly onto elements for entry-level annotations: `{...entry.edit}`
2433
+ * Access a field for field-level annotations: `{...entry.edit.title}`
2434
+ *
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.
2444
+ *
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.
2447
+ *
2448
+ * @example
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[]; };
2455
+ * }
2456
+ * }
2457
+ *
2458
+ * // Then in your code:
2459
+ * const { entries } = await getDinewayCollection("posts");
2460
+ * // entries[0].data.title is typed as string
2461
+ * ```
2462
+ */
2463
+ interface DinewayCollections {}
2464
+ /**
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>.
2467
+ */
2468
+ type InferCollectionData<T extends string> = T extends keyof DinewayCollections ? DinewayCollections[T] : Record<string, unknown>;
2469
+ /**
2470
+ * Sort direction
2471
+ */
2472
+ type SortDirection = "asc" | "desc";
2473
+ /**
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
2478
+ */
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;
2600
2486
  /**
2601
- * Run comment:beforeCreate hooks (middleware pipeline).
2487
+ * Filter by field values, taxonomy terms, byline credits, or ranges.
2602
2488
  *
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).
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.
2610
2494
  *
2611
- * Errors are logged but don't propagate — they don't affect the caller.
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
2612
2501
  */
2613
- runCommentAfterCreate(event: CommentAfterCreateEvent): Promise<void>;
2502
+ where?: Record<string, WhereValue>;
2614
2503
  /**
2615
- * Run comment:afterModerate hooks (fire-and-forget).
2504
+ * Case-insensitive substring search across selected content fields.
2616
2505
  *
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
2506
+ * `searchColumns` must contain concrete field slugs or system column names.
2507
+ * When `q` is present without `searchColumns`, no search condition is applied.
2650
2508
  */
2651
- getRegisteredExclusiveHooks(): string[];
2509
+ q?: string;
2510
+ searchColumns?: string[];
2652
2511
  /**
2653
- * Check if a hook is exclusive
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
2654
2517
  */
2655
- isExclusiveHook(name: string): boolean;
2518
+ orderBy?: OrderBySpec;
2656
2519
  /**
2657
- * Set the selected provider for an exclusive hook.
2658
- * Called by PluginManager after resolution.
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
2659
2524
  */
2660
- setExclusiveSelection(hookName: string, pluginId: string): void;
2525
+ locale?: string;
2526
+ }
2527
+ /** Keyset-paginated query filter. Cannot also carry an offset. */
2528
+ interface CursorCollectionFilter extends CollectionFilterBase {
2661
2529
  /**
2662
- * Clear the selected provider for an exclusive hook.
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
+ * ```
2663
2540
  */
2664
- clearExclusiveSelection(hookName: string): void;
2541
+ cursor?: string;
2542
+ offset?: never;
2543
+ }
2544
+ /** Offset-paginated query filter. Cannot also carry a cursor. */
2545
+ interface OffsetCollectionFilter extends CollectionFilterBase {
2665
2546
  /**
2666
- * Get the selected provider for an exclusive hook (if any).
2547
+ * Skip this many entries before returning results. Use with `limit` for
2548
+ * numbered archive routes, for example `offset = (page - 1) * perPage`.
2667
2549
  */
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;
2590
+ }
2591
+ /**
2592
+ * Result from getDinewayEntry
2593
+ */
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
+ }
2612
+ /**
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.
2616
+ */
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;
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;
2700
2847
  }
2701
2848
  /**
2702
- * Create a hook pipeline from plugins
2849
+ * Get the current i18n config.
2850
+ * Returns null if i18n is not configured.
2703
2851
  */
2704
- declare function createHookPipeline(plugins: ResolvedPlugin[], factoryOptions?: PluginContextFactoryOptions): HookPipeline;
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[];
2705
2864
  //#endregion
2706
- //#region src/plugins/email.d.ts
2865
+ //#region src/preview/sidecar-client.d.ts
2707
2866
  /**
2708
- * EmailPipeline orchestrates email delivery through the plugin hook system.
2867
+ * Preview sidecar protocol helpers.
2709
2868
  *
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
2869
+ * These utilities define the signed URL and snapshot-auth contract shared
2870
+ * by preview sidecars and the source site serving snapshot exports.
2714
2871
  */
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;
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;
2748
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
  *
@@ -4615,4 +5078,4 @@ declare global {
4615
5078
  var __dinewayConfig: DinewayConfig | undefined;
4616
5079
  }
4617
5080
  //#endregion
4618
- export { CreateMenuItemInput as $, PortableTextMarkDef as $n, handleContentUnpublish as $r, createFilePreviewMiddleware as $t, UpdateWidgetInput as A, ParseResult as Ai, ResolvePathResult as An, RevisionListResponse as Ar, GeneratePreviewTokenOptions as At, getTerm as B, FieldDescriptor as Bi, FieldAnnotation as Bn, handleContentCreate as Br, SandboxNotAvailableError as Bt, getWidgetArea as C, WhereRange as Ci, CollectionFilter as Cn, MediaListResponse as Cr, renderPreviewLoadingPage as Ct, CreateWidgetInput as D, DatabaseConfig as Di, EditFieldMeta as Dn, handleMediaGet as Dr, GetPreviewUrlOptions as Dt, CreateWidgetAreaInput as E, getDb as Ei, DinewayCollections as En, handleMediaDelete as Er, isPreviewRequest as Et, getEntriesByTerm as F, apiSuccess as Fi, getEditMeta as Fn, generateManifest as Fr, parseContentId as Ft, TaxonomyTermRow as G, computeContentHash as Gn, handleContentGetIncludingTrashed as Gr, EmailPipeline as Gt, CreateTermInput as H, ManifestResponse as Hi, createNoop as Hn, handleContentDiscardDraft as Hr, PluginManager as Ht, getEntryTerms as I, handleError as Ii, getTranslations as In, handleContentAuthors as Ir, verifyPreviewToken as It, getBylineBySlug as J, prosemirrorToPortableText as Jn, handleContentPermanentDelete as Jr, createHookPipeline as Jt, UpdateTermInput as K, hashString as Kn, handleContentList as Kr, HookPipeline as Kt, getTaxonomyDef as L, ApiContext as Li, resolveDinewayPath as Ln, handleContentCompare as Lr, NodeSandboxRunner as Lt, WidgetArea as M, parseBody as Mi, TranslationsResult as Mn, handleRevisionGet as Mr, VerifyPreviewTokenOptions as Mt, WidgetComponentDef as N, parseQuery as Ni, getDinewayCollection as Nn, handleRevisionList as Nr, VerifyPreviewTokenResult as Nt, PropDef as O, DinewayDatabaseError as Oi, EntryResult as On, handleMediaList as Or, buildPreviewUrl as Ot, WidgetType as P, apiError as Pi, getDinewayEntry as Pn, handleRevisionRestore as Pr, generatePreviewToken as Pt, CreateMenuInput as Q, PortableTextLinkMark as Qn, handleContentTranslations as Qr, FilePreviewMiddlewareConfig as Qt, getTaxonomyDefs as R, ContentListResponse as Ri, CMSAnnotation as Rn, handleContentCountScheduled as Rr, createNodeSandboxRunner as Rt, Suggestion as S, EntryFilter as Si, CacheHint as Sn, SchemaRegistry as Sr, Snapshot as St, getWidgetComponents as T, dinewayLoader as Ti, ContentEntry as Tn, handleMediaCreate as Tr, getPreviewToken as Tt, TaxonomyDef as U, isSafeHref as Un, handleContentDuplicate as Ur, createPluginManager as Ut, getTermsForEntries as V, ListResponse as Vi, createEditable as Vn, handleContentDelete as Vr, createNoopSandboxRunner as Vt, TaxonomyTerm as W, sanitizeHref as Wn, handleContentGet as Wr, PluginRouteError as Wt, getMenu as X, PortableTextHtmlBlock as Xn, handleContentRestore as Xr, pluginManifestSchema as Xt, getEntriesByByline as Y, PortableTextCodeBlock as Yn, handleContentPublish as Yr, ValidatedPluginManifest as Yt, getMenus as Z, PortableTextImageBlock as Zn, handleContentSchedule as Zr, definePlugin as Zt, SearchOptions as _, MediaItem as _i, getFallbackChain as _n, Section as _r, AppliedSnapshotMeta as _t, S3StorageConfig as a, FieldDefinition as ai, SessionDatabaseInfo as an, ProseMirrorNode as ar, UpdateMenuItemInput as at, SearchStats as b, CollectionFilter$1 as bi, AfterCallback as bn, getCollectionInfo as br, dropSessionDatabaseTables as bt, extractSearchableFields as c, ImageValue as ci, SessionOpenOrCreateOptions as cn, SandboxOptions as cr, getCommentCount as ct, search as d, CreateRelationInput as di, buildPreviewSignatureHeader as dn, SandboxedPlugin as dr, getPluginSettings as dt, handleContentUnschedule as ei, FileSessionDatabaseFactory as en, PortableTextSpan as er, Menu as et, searchCollection as f, Relation as fi, defaultPreviewSidecarClient as fn, SerializedRequest as fr, getSiteSetting as ft, SearchConfig as g, CreateMediaInput as gi, I18nConfig as gn, GetSectionsOptions as gr, renderPreviewToolbar as gt, CollectionSearchOptions as h, PublicComment as hi, verifyPreviewSignature as hn, CreateSectionInput as hr, PreviewToolbarConfig as ht, LocalStorageConfig as i, image as ii, SessionDatabaseHandle as in, ProseMirrorMark as ir, UpdateMenuInput as it, Widget as j, isParseError as ji, TranslationSummary as jn, RevisionResponse as jr, PreviewTokenPayload as jt, ReorderWidgetsInput as k, OptionsRepository as ki, InferCollectionData as kn, handleMediaUpdate as kr, getPreviewUrl as kt, getSearchStats as l, PortableTextBlock$1 as li, PreviewSidecarClient as ln, SandboxRunner as lr, getComments as lt, FTSManager as m, UpdateRelationInput as mi, signPreviewUrl as mn, getSections as mr, setSiteSettings as mt, PluginDescriptor as n, portableText as ni, SessionCleanupResult as nn, PortableTextUnknownBlock as nr, MenuItemType as nt, StorageDescriptor as o, FieldUIHints as oi, SessionDatabaseLimitError as on, SandboxEmailMessage as or, GetCommentsOptions as ot, searchWithDb as p, RelationRepository as pi, parsePreviewSignatureHeader as pn, getSection as pr, getSiteSettings as pt, getByline as q, portableTextToProsemirror as qn, handleContentListTrashed as qr, HookResult as qt, getStoredConfig as r, reference as ri, SessionDatabaseFactory as rn, ProseMirrorDocument as rr, ReorderMenuItemsInput as rt, extractPlainText as s, FileValue as si, SessionOpenOptions as sn, SandboxEmailSendCallback as sr, GetCommentsResult as st, DinewayConfig as t, handleContentUpdate as ti, FileSessionDatabaseFactoryOptions as tn, PortableTextTextBlock as tr, MenuItem as tt, getSuggestions as u, ContentReference as ui, PreviewSidecarSignature as un, SandboxRunnerFactory as ur, getPluginSetting as ut, SearchResponse as v, MediaRepository as vi, getI18nConfig as vn, SectionSource as vr, ApplySnapshotToDatabaseOptions as vt, getWidgetAreas as w, WhereValue as wi, CollectionResult as wn, MediaResponse as wr, isBlockedInPreview as wt, SuggestOptions as x, EntryData as xi, after as xn, SchemaError as xr, getAppliedSnapshotMeta as xt, SearchResult as y, ContentRepository as yi, isI18nEnabled as yn, UpdateSectionInput as yr, applySnapshotToDatabase as yt, getTaxonomyTerms as z, ContentResponse as zi, EditProxy as zn, handleContentCountTrashed 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 };