@byline/host-tanstack-start 4.19.0 → 5.1.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 (322) hide show
  1. package/dist/admin-shell/chrome/admin-app-bar.d.ts +7 -0
  2. package/dist/admin-shell/chrome/admin-app-bar.js +10 -2
  3. package/dist/admin-shell/chrome/session-change-boundary.d.ts +14 -0
  4. package/dist/admin-shell/chrome/session-change-boundary.js +87 -0
  5. package/dist/admin-shell/chrome/session-change-boundary.test.d.ts +8 -0
  6. package/dist/admin-shell/chrome/sign-in-page.d.ts +2 -1
  7. package/dist/admin-shell/chrome/sign-in-page.js +60 -3
  8. package/dist/admin-shell/collections/edit.d.ts +1 -1
  9. package/dist/admin-shell/collections/edit.js +151 -31
  10. package/dist/admin-shell/collections/history.js +4 -2
  11. package/dist/admin-shell/collections/list.js +30 -6
  12. package/dist/admin-shell/collections/restore-version-modal.d.ts +3 -1
  13. package/dist/admin-shell/collections/restore-version-modal.js +9 -4
  14. package/dist/admin-shell/collections/tree-list.js +16 -6
  15. package/dist/admin-shell/collections/version-history.d.ts +2 -1
  16. package/dist/admin-shell/collections/version-history.js +11 -2
  17. package/dist/admin-shell/document-mutation-notice.d.ts +6 -0
  18. package/dist/admin-shell/document-mutation-notice.js +53 -0
  19. package/dist/admin-shell/document-mutation-state.d.ts +22 -0
  20. package/dist/admin-shell/document-mutation-state.js +71 -0
  21. package/dist/admin-shell/document-mutation-state.test.d.ts +1 -0
  22. package/dist/admin-shell/scheduled-publications/list.js +15 -5
  23. package/dist/admin-shell/singletons/history.js +4 -2
  24. package/dist/admin-shell/singletons/view.d.ts +1 -1
  25. package/dist/admin-shell/singletons/view.js +98 -19
  26. package/dist/integrations/byline-admin-services.js +7 -1
  27. package/dist/integrations/byline-field-services.js +2 -9
  28. package/dist/integrations/client-ip.d.ts +19 -0
  29. package/dist/integrations/client-ip.js +34 -0
  30. package/dist/integrations/session-coordination.d.ts +24 -0
  31. package/dist/integrations/session-coordination.js +85 -0
  32. package/dist/integrations/session-middleware.d.ts +11 -0
  33. package/dist/integrations/session-middleware.js +94 -0
  34. package/dist/integrations/session-request-kind.d.ts +9 -0
  35. package/dist/integrations/session-request-kind.js +10 -0
  36. package/dist/integrations/session-request-middleware.d.ts +9 -0
  37. package/dist/integrations/session-request-middleware.js +7 -0
  38. package/dist/integrations/sign-in-body.d.ts +12 -0
  39. package/dist/integrations/sign-in-body.js +52 -0
  40. package/dist/integrations/sign-in-middleware.d.ts +9 -0
  41. package/dist/integrations/sign-in-middleware.js +10 -0
  42. package/dist/routes/create-admin-layout-route.js +46 -31
  43. package/dist/routes/create-collection-edit-route.js +1 -1
  44. package/dist/routes/create-collection-list-route.d.ts +0 -7
  45. package/dist/routes/create-collection-list-route.js +7 -9
  46. package/dist/routes/create-sign-in-route.js +4 -2
  47. package/dist/routes/create-singleton-route.d.ts +2 -0
  48. package/dist/routes/create-singleton-route.js +4 -3
  49. package/dist/server-fns/admin-account/change-password.d.ts +3 -1
  50. package/dist/server-fns/admin-account/change-password.js +9 -3
  51. package/dist/server-fns/admin-account/get.d.ts +3 -1
  52. package/dist/server-fns/admin-account/get.js +4 -1
  53. package/dist/server-fns/admin-account/index.d.ts +5 -5
  54. package/dist/server-fns/admin-account/update.d.ts +3 -1
  55. package/dist/server-fns/admin-account/update.js +4 -1
  56. package/dist/server-fns/admin-activity/get.d.ts +3 -1
  57. package/dist/server-fns/admin-activity/get.js +4 -1
  58. package/dist/server-fns/admin-permissions/get-role-abilities.d.ts +3 -1
  59. package/dist/server-fns/admin-permissions/get-role-abilities.js +4 -1
  60. package/dist/server-fns/admin-permissions/index.d.ts +4 -4
  61. package/dist/server-fns/admin-permissions/list-registered.d.ts +3 -1
  62. package/dist/server-fns/admin-permissions/list-registered.js +4 -1
  63. package/dist/server-fns/admin-permissions/set-role-abilities.d.ts +3 -1
  64. package/dist/server-fns/admin-permissions/set-role-abilities.js +4 -1
  65. package/dist/server-fns/admin-permissions/who-has.d.ts +3 -1
  66. package/dist/server-fns/admin-permissions/who-has.js +4 -1
  67. package/dist/server-fns/admin-roles/create.d.ts +3 -1
  68. package/dist/server-fns/admin-roles/create.js +4 -1
  69. package/dist/server-fns/admin-roles/delete.d.ts +3 -1
  70. package/dist/server-fns/admin-roles/delete.js +4 -1
  71. package/dist/server-fns/admin-roles/get.d.ts +3 -1
  72. package/dist/server-fns/admin-roles/get.js +4 -1
  73. package/dist/server-fns/admin-roles/index.d.ts +6 -6
  74. package/dist/server-fns/admin-roles/list.d.ts +3 -1
  75. package/dist/server-fns/admin-roles/list.js +4 -1
  76. package/dist/server-fns/admin-roles/reorder.d.ts +3 -1
  77. package/dist/server-fns/admin-roles/reorder.js +4 -1
  78. package/dist/server-fns/admin-roles/update.d.ts +3 -1
  79. package/dist/server-fns/admin-roles/update.js +4 -1
  80. package/dist/server-fns/admin-users/create.d.ts +3 -1
  81. package/dist/server-fns/admin-users/create.js +4 -1
  82. package/dist/server-fns/admin-users/delete.d.ts +3 -1
  83. package/dist/server-fns/admin-users/delete.js +4 -1
  84. package/dist/server-fns/admin-users/disable.d.ts +3 -1
  85. package/dist/server-fns/admin-users/disable.js +4 -1
  86. package/dist/server-fns/admin-users/enable.d.ts +3 -1
  87. package/dist/server-fns/admin-users/enable.js +4 -1
  88. package/dist/server-fns/admin-users/get-user-roles.d.ts +3 -1
  89. package/dist/server-fns/admin-users/get-user-roles.js +4 -1
  90. package/dist/server-fns/admin-users/get.d.ts +3 -1
  91. package/dist/server-fns/admin-users/get.js +4 -1
  92. package/dist/server-fns/admin-users/index.d.ts +10 -10
  93. package/dist/server-fns/admin-users/list.d.ts +3 -1
  94. package/dist/server-fns/admin-users/list.js +4 -1
  95. package/dist/server-fns/admin-users/set-password.d.ts +3 -1
  96. package/dist/server-fns/admin-users/set-password.js +4 -1
  97. package/dist/server-fns/admin-users/set-user-roles.d.ts +3 -1
  98. package/dist/server-fns/admin-users/set-user-roles.js +4 -1
  99. package/dist/server-fns/admin-users/update.d.ts +3 -1
  100. package/dist/server-fns/admin-users/update.js +4 -1
  101. package/dist/server-fns/ai/execute.d.ts +3 -1
  102. package/dist/server-fns/ai/execute.js +4 -1
  103. package/dist/server-fns/ai/index.d.ts +1 -1
  104. package/dist/server-fns/analytics/maintenance.d.ts +6 -2
  105. package/dist/server-fns/analytics/maintenance.js +7 -2
  106. package/dist/server-fns/analytics/queries.d.ts +18 -6
  107. package/dist/server-fns/analytics/queries.js +19 -6
  108. package/dist/server-fns/auth/current-user.d.ts +1 -0
  109. package/dist/server-fns/auth/current-user.js +5 -2
  110. package/dist/server-fns/auth/renew.d.ts +13 -0
  111. package/dist/server-fns/auth/renew.js +45 -0
  112. package/dist/server-fns/auth/sign-in.d.ts +2 -1
  113. package/dist/server-fns/auth/sign-in.js +88 -17
  114. package/dist/server-fns/auth/sign-out.d.ts +3 -1
  115. package/dist/server-fns/auth/sign-out.js +38 -6
  116. package/dist/server-fns/collections/audit.d.ts +3 -1
  117. package/dist/server-fns/collections/audit.js +4 -1
  118. package/dist/server-fns/collections/copy-to-locale.d.ts +5 -1
  119. package/dist/server-fns/collections/copy-to-locale.js +7 -2
  120. package/dist/server-fns/collections/create.d.ts +4 -1
  121. package/dist/server-fns/collections/create.js +8 -3
  122. package/dist/server-fns/collections/delete-locale.d.ts +5 -1
  123. package/dist/server-fns/collections/delete-locale.js +7 -2
  124. package/dist/server-fns/collections/delete-outcome.d.ts +7 -3
  125. package/dist/server-fns/collections/delete-outcome.js +4 -0
  126. package/dist/server-fns/collections/delete.d.ts +5 -1
  127. package/dist/server-fns/collections/delete.js +8 -3
  128. package/dist/server-fns/collections/duplicate.d.ts +5 -1
  129. package/dist/server-fns/collections/duplicate.js +8 -3
  130. package/dist/server-fns/collections/get.d.ts +1 -0
  131. package/dist/server-fns/collections/get.js +12 -6
  132. package/dist/server-fns/collections/history.d.ts +3 -1
  133. package/dist/server-fns/collections/history.js +4 -1
  134. package/dist/server-fns/collections/index.d.ts +21 -21
  135. package/dist/server-fns/collections/list.d.ts +3 -1
  136. package/dist/server-fns/collections/list.js +15 -4
  137. package/dist/server-fns/collections/reindex.d.ts +3 -1
  138. package/dist/server-fns/collections/reindex.js +4 -1
  139. package/dist/server-fns/collections/reorder.d.ts +10 -2
  140. package/dist/server-fns/collections/reorder.js +23 -76
  141. package/dist/server-fns/collections/restore-version.d.ts +6 -1
  142. package/dist/server-fns/collections/restore-version.js +8 -2
  143. package/dist/server-fns/collections/save-outcome.d.ts +1 -0
  144. package/dist/server-fns/collections/save-outcome.js +1 -0
  145. package/dist/server-fns/collections/scheduled-publication.d.ts +64 -7
  146. package/dist/server-fns/collections/scheduled-publication.js +42 -21
  147. package/dist/server-fns/collections/set-list-view-preference.d.ts +3 -1
  148. package/dist/server-fns/collections/set-list-view-preference.js +4 -1
  149. package/dist/server-fns/collections/stats.js +4 -1
  150. package/dist/server-fns/collections/status.d.ts +14 -2
  151. package/dist/server-fns/collections/status.js +18 -5
  152. package/dist/server-fns/collections/tree-mutation.d.ts +7 -6
  153. package/dist/server-fns/collections/tree-mutation.js +17 -5
  154. package/dist/server-fns/collections/tree.d.ts +29 -6
  155. package/dist/server-fns/collections/tree.js +32 -17
  156. package/dist/server-fns/collections/update.d.ts +18 -6
  157. package/dist/server-fns/collections/update.js +39 -20
  158. package/dist/server-fns/collections/upload.d.ts +11 -1
  159. package/dist/server-fns/collections/upload.js +6 -2
  160. package/dist/server-fns/document-mutation-errors.d.ts +5 -0
  161. package/dist/server-fns/document-mutation-errors.js +50 -0
  162. package/dist/server-fns/editable-revision.d.ts +9 -0
  163. package/dist/server-fns/editable-revision.js +11 -0
  164. package/dist/server-fns/i18n/set-locale.d.ts +3 -1
  165. package/dist/server-fns/i18n/set-locale.js +18 -3
  166. package/dist/server-fns/preview/disable.d.ts +3 -1
  167. package/dist/server-fns/preview/disable.js +4 -1
  168. package/dist/server-fns/preview/enable.d.ts +3 -1
  169. package/dist/server-fns/preview/enable.js +4 -1
  170. package/dist/server-fns/singleton-document-read.d.ts +1 -1
  171. package/dist/server-fns/singleton-document-read.js +7 -3
  172. package/dist/server-fns/singletons/cancel-scheduled-publish.d.ts +9 -2
  173. package/dist/server-fns/singletons/cancel-scheduled-publish.js +7 -1
  174. package/dist/server-fns/singletons/change-status.d.ts +5 -1
  175. package/dist/server-fns/singletons/change-status.js +7 -1
  176. package/dist/server-fns/singletons/confirm-scheduled-publish.d.ts +8 -2
  177. package/dist/server-fns/singletons/confirm-scheduled-publish.js +7 -2
  178. package/dist/server-fns/singletons/copy-to-locale.d.ts +5 -1
  179. package/dist/server-fns/singletons/copy-to-locale.js +7 -2
  180. package/dist/server-fns/singletons/find-by-version.d.ts +3 -1
  181. package/dist/server-fns/singletons/find-by-version.js +4 -1
  182. package/dist/server-fns/singletons/get-scheduled-publish.d.ts +3 -1
  183. package/dist/server-fns/singletons/get-scheduled-publish.js +4 -1
  184. package/dist/server-fns/singletons/get.d.ts +6 -4
  185. package/dist/server-fns/singletons/get.js +4 -1
  186. package/dist/server-fns/singletons/history.d.ts +3 -1
  187. package/dist/server-fns/singletons/history.js +4 -1
  188. package/dist/server-fns/singletons/restore-version.d.ts +5 -1
  189. package/dist/server-fns/singletons/restore-version.js +9 -3
  190. package/dist/server-fns/singletons/schedule-publish.d.ts +8 -2
  191. package/dist/server-fns/singletons/schedule-publish.js +7 -2
  192. package/dist/server-fns/singletons/unpublish.d.ts +5 -1
  193. package/dist/server-fns/singletons/unpublish.js +7 -1
  194. package/dist/server-fns/singletons/update.d.ts +6 -4
  195. package/dist/server-fns/singletons/update.js +8 -4
  196. package/dist/server-fns/structural-receipt.d.ts +4 -0
  197. package/dist/server-fns/structural-receipt.js +31 -0
  198. package/package.json +20 -20
  199. package/src/admin-shell/chrome/admin-app-bar.tsx +11 -6
  200. package/src/admin-shell/chrome/session-change-boundary.test.tsx +78 -0
  201. package/src/admin-shell/chrome/session-change-boundary.tsx +94 -0
  202. package/src/admin-shell/chrome/sign-in-page.tsx +68 -3
  203. package/src/admin-shell/collections/edit.tsx +173 -54
  204. package/src/admin-shell/collections/history.tsx +11 -2
  205. package/src/admin-shell/collections/list.tsx +22 -6
  206. package/src/admin-shell/collections/restore-version-modal.tsx +12 -3
  207. package/src/admin-shell/collections/save-navigation.test.tsx +156 -8
  208. package/src/admin-shell/collections/tree-list.tsx +16 -6
  209. package/src/admin-shell/collections/version-history.tsx +13 -3
  210. package/src/admin-shell/document-mutation-notice.tsx +45 -0
  211. package/src/admin-shell/document-mutation-state.test.tsx +146 -0
  212. package/src/admin-shell/document-mutation-state.ts +95 -0
  213. package/src/admin-shell/scheduled-publications/list.tsx +16 -6
  214. package/src/admin-shell/singletons/history.test.tsx +3 -1
  215. package/src/admin-shell/singletons/history.tsx +10 -2
  216. package/src/admin-shell/singletons/view.test.tsx +59 -18
  217. package/src/admin-shell/singletons/view.tsx +110 -29
  218. package/src/integrations/byline-admin-services.ts +7 -1
  219. package/src/integrations/byline-field-services.ts +2 -3
  220. package/src/integrations/client-ip.test.node.ts +45 -0
  221. package/src/integrations/client-ip.ts +54 -0
  222. package/src/integrations/framework-fetch-shape.test.node.ts +56 -0
  223. package/src/integrations/session-client.test.node.ts +121 -0
  224. package/src/integrations/session-coordination.test.node.ts +77 -0
  225. package/src/integrations/session-coordination.ts +96 -0
  226. package/src/integrations/session-middleware.test.node.ts +87 -0
  227. package/src/integrations/session-middleware.ts +107 -0
  228. package/src/integrations/session-request-kind.ts +18 -0
  229. package/src/integrations/session-request-middleware.ts +17 -0
  230. package/src/integrations/sign-in-body.test.node.ts +59 -0
  231. package/src/integrations/sign-in-body.ts +50 -0
  232. package/src/integrations/sign-in-middleware.ts +24 -0
  233. package/src/routes/create-admin-layout-route.tsx +48 -30
  234. package/src/routes/create-collection-edit-route.tsx +1 -0
  235. package/src/routes/create-collection-list-route.tsx +13 -2
  236. package/src/routes/create-sign-in-route.tsx +10 -2
  237. package/src/routes/create-singleton-route.test.node.ts +10 -2
  238. package/src/routes/create-singleton-route.tsx +6 -4
  239. package/src/server-fns/admin-account/change-password.test.node.ts +69 -0
  240. package/src/server-fns/admin-account/change-password.ts +13 -2
  241. package/src/server-fns/admin-account/get.ts +2 -0
  242. package/src/server-fns/admin-account/update.ts +2 -0
  243. package/src/server-fns/admin-activity/get.ts +2 -0
  244. package/src/server-fns/admin-permissions/get-role-abilities.ts +2 -0
  245. package/src/server-fns/admin-permissions/list-registered.ts +5 -4
  246. package/src/server-fns/admin-permissions/set-role-abilities.ts +2 -0
  247. package/src/server-fns/admin-permissions/who-has.ts +2 -0
  248. package/src/server-fns/admin-roles/create.ts +2 -0
  249. package/src/server-fns/admin-roles/delete.ts +2 -0
  250. package/src/server-fns/admin-roles/get.ts +2 -0
  251. package/src/server-fns/admin-roles/list.ts +5 -4
  252. package/src/server-fns/admin-roles/reorder.ts +2 -0
  253. package/src/server-fns/admin-roles/update.ts +2 -0
  254. package/src/server-fns/admin-users/create.ts +2 -0
  255. package/src/server-fns/admin-users/delete.ts +2 -0
  256. package/src/server-fns/admin-users/disable.ts +2 -0
  257. package/src/server-fns/admin-users/enable.ts +2 -0
  258. package/src/server-fns/admin-users/get-user-roles.ts +2 -0
  259. package/src/server-fns/admin-users/get.ts +2 -0
  260. package/src/server-fns/admin-users/list.ts +2 -0
  261. package/src/server-fns/admin-users/set-password.ts +2 -0
  262. package/src/server-fns/admin-users/set-user-roles.ts +2 -0
  263. package/src/server-fns/admin-users/update.ts +2 -0
  264. package/src/server-fns/ai/execute.ts +3 -0
  265. package/src/server-fns/analytics/maintenance.ts +4 -0
  266. package/src/server-fns/analytics/queries.ts +14 -8
  267. package/src/server-fns/auth/current-user.ts +7 -3
  268. package/src/server-fns/auth/renew.test.node.ts +85 -0
  269. package/src/server-fns/auth/renew.ts +54 -0
  270. package/src/server-fns/auth/sign-in.test.node.ts +114 -0
  271. package/src/server-fns/auth/sign-in.ts +80 -27
  272. package/src/server-fns/auth/sign-out.test.node.ts +85 -0
  273. package/src/server-fns/auth/sign-out.ts +44 -19
  274. package/src/server-fns/collections/audit.ts +2 -0
  275. package/src/server-fns/collections/copy-to-locale.ts +43 -36
  276. package/src/server-fns/collections/create.ts +56 -50
  277. package/src/server-fns/collections/delete-locale.ts +43 -32
  278. package/src/server-fns/collections/delete-outcome.test.node.ts +16 -0
  279. package/src/server-fns/collections/delete-outcome.ts +27 -16
  280. package/src/server-fns/collections/delete.ts +46 -38
  281. package/src/server-fns/collections/duplicate.ts +40 -32
  282. package/src/server-fns/collections/get.ts +11 -4
  283. package/src/server-fns/collections/history.ts +2 -0
  284. package/src/server-fns/collections/list.ts +10 -3
  285. package/src/server-fns/collections/reindex.ts +2 -0
  286. package/src/server-fns/collections/reorder.ts +34 -124
  287. package/src/server-fns/collections/restore-version.ts +49 -39
  288. package/src/server-fns/collections/revision-input.test.node.ts +122 -0
  289. package/src/server-fns/collections/save-outcome.test.node.ts +3 -0
  290. package/src/server-fns/collections/save-outcome.ts +2 -0
  291. package/src/server-fns/collections/scheduled-publication.ts +149 -115
  292. package/src/server-fns/collections/set-list-view-preference.ts +2 -0
  293. package/src/server-fns/collections/stats.ts +2 -0
  294. package/src/server-fns/collections/status.ts +89 -64
  295. package/src/server-fns/collections/tree-mutation.test.node.ts +87 -29
  296. package/src/server-fns/collections/tree-mutation.ts +28 -11
  297. package/src/server-fns/collections/tree.ts +156 -122
  298. package/src/server-fns/collections/update.ts +113 -86
  299. package/src/server-fns/collections/upload-singleton.test.node.ts +10 -7
  300. package/src/server-fns/collections/upload.ts +91 -77
  301. package/src/server-fns/document-mutation-errors.ts +67 -0
  302. package/src/server-fns/document-mutation-transport.test.node.ts +211 -0
  303. package/src/server-fns/editable-revision.test.node.ts +23 -0
  304. package/src/server-fns/editable-revision.ts +18 -0
  305. package/src/server-fns/i18n/set-locale.ts +19 -3
  306. package/src/server-fns/preview/disable.ts +8 -4
  307. package/src/server-fns/preview/enable.ts +9 -5
  308. package/src/server-fns/singleton-document-read.ts +7 -3
  309. package/src/server-fns/singletons/cancel-scheduled-publish.ts +12 -3
  310. package/src/server-fns/singletons/change-status.ts +12 -3
  311. package/src/server-fns/singletons/confirm-scheduled-publish.ts +14 -6
  312. package/src/server-fns/singletons/copy-to-locale.ts +22 -15
  313. package/src/server-fns/singletons/find-by-version.ts +2 -0
  314. package/src/server-fns/singletons/get-scheduled-publish.ts +2 -0
  315. package/src/server-fns/singletons/get.ts +5 -3
  316. package/src/server-fns/singletons/history.ts +2 -0
  317. package/src/server-fns/singletons/restore-version.ts +19 -12
  318. package/src/server-fns/singletons/schedule-publish.ts +20 -7
  319. package/src/server-fns/singletons/singletons.test.node.ts +69 -25
  320. package/src/server-fns/singletons/unpublish.ts +12 -3
  321. package/src/server-fns/singletons/update.ts +23 -16
  322. package/src/server-fns/structural-receipt.ts +41 -0
@@ -6,6 +6,7 @@
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
8
  export interface CurrentAdminUser {
9
+ sessionId: string;
9
10
  id: string;
10
11
  email: string;
11
12
  given_name: string | null;
@@ -5,11 +5,12 @@ import { bylineCore } from "../../integrations/byline-core.js";
5
5
  const getCurrentAdminUser = createServerFn({
6
6
  method: 'GET'
7
7
  }).handler(async ()=>{
8
- const { actor } = await getAdminRequestContext();
8
+ const { actor, sessionId } = await getAdminRequestContext();
9
9
  if (!actor) throw new Error('unexpected null actor after getAdminRequestContext');
10
10
  const row = await bylineCore().adminStore?.adminUsers.getById(actor.id);
11
11
  if (!row) throw new Error('admin user not found for current session');
12
12
  return {
13
+ sessionId: sessionId,
13
14
  id: row.id,
14
15
  email: row.email,
15
16
  given_name: row.given_name,
@@ -23,8 +24,9 @@ const getCurrentAdminUserSoft = createServerFn({
23
24
  }).handler(async ()=>{
24
25
  try {
25
26
  let actor;
27
+ let sessionId;
26
28
  try {
27
- ({ actor } = await getAdminRequestContext());
29
+ ({ actor, sessionId } = await getAdminRequestContext());
28
30
  } catch (err) {
29
31
  if (err instanceof AuthError) return null;
30
32
  throw err;
@@ -33,6 +35,7 @@ const getCurrentAdminUserSoft = createServerFn({
33
35
  const row = await bylineCore().adminStore?.adminUsers.getById(actor.id);
34
36
  if (!row) return null;
35
37
  return {
38
+ sessionId: sessionId,
36
39
  id: row.id,
37
40
  email: row.email,
38
41
  given_name: row.given_name,
@@ -0,0 +1,13 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ /** Explicit renewal only. Global CSRF protection applies before this POST handler. */
9
+ export declare const renewAdminSession: import("@tanstack/react-start").OptionalFetcher<undefined, (value: unknown) => {
10
+ expectedSessionId?: string;
11
+ }, Promise<{
12
+ sessionId: string;
13
+ }>>;
@@ -0,0 +1,45 @@
1
+ import { createServerFn } from "@tanstack/react-start";
2
+ import { setResponseHeader } from "@tanstack/react-start/server";
3
+ import { AuthError, ERR_SESSION_CHANGED, ERR_UNAUTHENTICATED } from "@byline/auth";
4
+ import { readAccessTokenCookie, readRefreshTokenCookie, setSessionCookies } from "@byline/client/server";
5
+ import { getServerConfig } from "@byline/core";
6
+ const renewAdminSession = createServerFn({
7
+ method: 'POST'
8
+ }).validator((value)=>{
9
+ if (null == value) return {};
10
+ if ('object' != typeof value) throw new Error('Invalid renewal input');
11
+ const sid = value.expectedSessionId;
12
+ if (void 0 !== sid && ('string' != typeof sid || !sid || sid.length > 256)) throw new Error('Invalid login identity');
13
+ return {
14
+ expectedSessionId: sid
15
+ };
16
+ }).handler(async ({ data })=>{
17
+ setResponseHeader('Cache-Control', 'no-store');
18
+ const provider = getServerConfig().sessionProvider;
19
+ if (!provider) throw new Error('no sessionProvider configured');
20
+ const access = readAccessTokenCookie();
21
+ if (access) try {
22
+ const verified = await provider.verifyAccessToken(access);
23
+ if (data.expectedSessionId && data.expectedSessionId !== verified.sessionId) throw ERR_SESSION_CHANGED({
24
+ message: 'session changed'
25
+ });
26
+ return {
27
+ sessionId: verified.sessionId
28
+ };
29
+ } catch (error) {
30
+ if (!(error instanceof AuthError) || 'ERR_ACCESS_EXPIRED' !== error.code) throw error;
31
+ }
32
+ const refreshToken = readRefreshTokenCookie();
33
+ if (!refreshToken) throw ERR_UNAUTHENTICATED({
34
+ message: 'no session to renew'
35
+ });
36
+ const tokens = await provider.refreshSession({
37
+ refreshToken,
38
+ expectedSessionId: data.expectedSessionId
39
+ });
40
+ setSessionCookies(tokens);
41
+ return {
42
+ sessionId: tokens.sessionId
43
+ };
44
+ });
45
+ export { renewAdminSession };
@@ -11,8 +11,9 @@ export interface SignInInput {
11
11
  }
12
12
  export interface SignInResult {
13
13
  userId: string;
14
+ sessionId: string;
14
15
  }
15
- export declare const adminSignIn: import("@tanstack/react-start").RequiredFetcher<undefined, (input: SignInInput) => {
16
+ export declare const adminSignIn: import("@tanstack/react-start").OptionalFetcher<undefined, (input: unknown) => {
16
17
  email: string;
17
18
  password: string;
18
19
  }, Promise<SignInResult>>;
@@ -1,36 +1,107 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
- import { getRequestHeader } from "@tanstack/react-start/server";
3
- import { setSessionCookies } from "@byline/client/server";
2
+ import { getRequest, getRequestHeader } from "@tanstack/react-start/server";
3
+ import { readAccessTokenCookie, readRefreshTokenCookie, setSessionCookies } from "@byline/client/server";
4
4
  import { getServerConfig } from "@byline/core";
5
+ import { passwordSignInSchema } from "@byline/core/validation";
5
6
  import { readAdminLocaleCookie } from "../../i18n/locale-cookie.js";
6
7
  import { bylineCore } from "../../integrations/byline-core.js";
8
+ import { normalizeClientIp } from "../../integrations/client-ip.js";
9
+ import { wasSignInBodyChecked } from "../../integrations/sign-in-body.js";
7
10
  const adminSignIn = createServerFn({
8
11
  method: 'POST'
9
12
  }).validator((input)=>{
10
- if ('string' != typeof input?.email || 0 === input.email.length) throw new Error('email is required');
11
- if ('string' != typeof input?.password || 0 === input.password.length) throw new Error('password is required');
12
- return {
13
- email: input.email,
14
- password: input.password
15
- };
13
+ const parsed = passwordSignInSchema.safeParse(input);
14
+ if (!parsed.success) throw new Response('Invalid sign-in input', {
15
+ status: 400
16
+ });
17
+ return parsed.data;
16
18
  }).handler(async ({ data })=>{
17
19
  const provider = getServerConfig().sessionProvider;
18
20
  if (!provider) throw new Error('no sessionProvider configured');
19
- const userAgent = getRequestHeader('user-agent') ?? void 0;
20
- const forwardedFor = getRequestHeader('x-forwarded-for') ?? void 0;
21
- const ip = forwardedFor?.split(',')[0]?.trim() || void 0;
22
- const result = await provider.signInWithPassword({
23
- email: data.email,
24
- password: data.password,
25
- userAgent,
26
- ip
21
+ const request = getRequest();
22
+ const protection = getServerConfig().passwordSignIn;
23
+ if (!wasSignInBodyChecked(request)) throw new Response('Password sign-in request middleware is not configured', {
24
+ status: 503
25
+ });
26
+ if (!protection) throw new Response('Password sign-in protection is not configured', {
27
+ status: 503
27
28
  });
29
+ const userAgent = getRequestHeader('user-agent')?.slice(0, 512);
30
+ let ip;
31
+ try {
32
+ ip = normalizeClientIp(await protection.resolveClientIp(request));
33
+ } catch {
34
+ throw new Response('Client address unavailable', {
35
+ status: 503
36
+ });
37
+ }
38
+ if (!ip) throw new Response('Client address unavailable', {
39
+ status: 503
40
+ });
41
+ const tooMany = (seconds)=>new Response('Too many sign-in attempts', {
42
+ status: 429,
43
+ headers: {
44
+ 'Retry-After': String(seconds),
45
+ 'Cache-Control': 'no-store'
46
+ }
47
+ });
48
+ let release;
49
+ try {
50
+ release = await protection.limiter.acquire();
51
+ } catch {
52
+ throw new Response('Sign-in temporarily unavailable', {
53
+ status: 503
54
+ });
55
+ }
56
+ if (!release) throw tooMany(1);
57
+ const recordResult = (outcome)=>{
58
+ try {
59
+ protection.limiter.recordResult?.({
60
+ email: data.email,
61
+ ip
62
+ }, outcome);
63
+ } catch {}
64
+ };
65
+ const result = await (async ()=>{
66
+ try {
67
+ let admission;
68
+ try {
69
+ admission = await protection.limiter.consume({
70
+ email: data.email,
71
+ ip
72
+ });
73
+ } catch {
74
+ throw new Response('Sign-in temporarily unavailable', {
75
+ status: 503
76
+ });
77
+ }
78
+ if (!admission.allowed) throw tooMany(admission.retryAfterSeconds);
79
+ try {
80
+ const result = await provider.signInWithPassword({
81
+ previousAccessToken: readAccessTokenCookie(),
82
+ previousRefreshToken: readRefreshTokenCookie(),
83
+ email: data.email,
84
+ password: data.password,
85
+ userAgent,
86
+ ip
87
+ });
88
+ recordResult('success');
89
+ return result;
90
+ } catch (error) {
91
+ recordResult('failure');
92
+ throw error;
93
+ }
94
+ } finally{
95
+ release();
96
+ }
97
+ })();
28
98
  setSessionCookies(result);
29
99
  try {
30
100
  await reconcileLocaleAfterSignIn(result.actor.id);
31
101
  } catch {}
32
102
  return {
33
- userId: result.actor.id
103
+ userId: result.actor.id,
104
+ sessionId: result.sessionId
34
105
  };
35
106
  });
36
107
  async function reconcileLocaleAfterSignIn(adminUserId) {
@@ -5,6 +5,8 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
- export declare const adminSignOut: import("@tanstack/react-start").OptionalFetcher<undefined, undefined, Promise<{
8
+ export declare const adminSignOut: import("@tanstack/react-start").OptionalFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterClient<{}, unknown, undefined, {
9
+ expectedSessionId: string | null;
10
+ }, undefined>], undefined, Promise<{
9
11
  status: 'ok';
10
12
  }>>;
@@ -1,14 +1,46 @@
1
- import { createServerFn } from "@tanstack/react-start";
2
- import { clearPreviewCookie, clearSessionCookies, readRefreshTokenCookie } from "@byline/client/server";
1
+ import { createMiddleware, createServerFn } from "@tanstack/react-start";
2
+ import { ERR_SESSION_CHANGED } from "@byline/auth";
3
+ import { clearPreviewCookie, clearSessionCookies, readAccessTokenCookie, readRefreshTokenCookie } from "@byline/client/server";
3
4
  import { getServerConfig } from "@byline/core";
5
+ import { coordinateAuthAction, flagSessionChanged, notifySessionAction, sessionSnapshot } from "../../integrations/session-coordination.js";
6
+ const signOutBoundary = createMiddleware({
7
+ type: 'function'
8
+ }).client(async ({ next })=>{
9
+ const snapshot = sessionSnapshot();
10
+ return coordinateAuthAction(async ()=>{
11
+ try {
12
+ const result = await next({
13
+ sendContext: {
14
+ expectedSessionId: snapshot.sessionId
15
+ }
16
+ });
17
+ notifySessionAction();
18
+ return result;
19
+ } catch (error) {
20
+ if (error?.code === 'ERR_SESSION_CHANGED') flagSessionChanged();
21
+ throw error;
22
+ }
23
+ });
24
+ });
4
25
  const adminSignOut = createServerFn({
5
26
  method: 'POST'
6
- }).handler(async ()=>{
27
+ }).middleware([
28
+ signOutBoundary
29
+ ]).handler(async ({ context })=>{
7
30
  const provider = getServerConfig().sessionProvider;
8
31
  const refreshToken = readRefreshTokenCookie();
9
- if (provider && refreshToken) try {
10
- await provider.revokeSession(refreshToken);
11
- } catch {}
32
+ const accessToken = readAccessTokenCookie();
33
+ if (refreshToken || accessToken) {
34
+ if (!provider) throw new Error('no sessionProvider configured');
35
+ if (!context.expectedSessionId) throw ERR_SESSION_CHANGED({
36
+ message: 'logout requires the page login identity'
37
+ });
38
+ await provider.revokeSession({
39
+ refreshToken,
40
+ accessToken,
41
+ expectedSessionId: context.expectedSessionId
42
+ });
43
+ }
12
44
  clearSessionCookies();
13
45
  clearPreviewCookie();
14
46
  return {
@@ -30,7 +30,9 @@ export interface AuditLogEntryDto {
30
30
  after: string | string[] | null;
31
31
  occurredAt: string;
32
32
  }
33
- export declare const getCollectionDocumentAuditLog: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
33
+ export declare const getCollectionDocumentAuditLog: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
34
+ bylineExpectedSessionId: string | null;
35
+ }, undefined, undefined>], (input: {
34
36
  collection: string;
35
37
  id: string;
36
38
  params?: AuditLogSearchParams;
@@ -2,10 +2,13 @@ import { createServerFn } from "@tanstack/react-start";
2
2
  import { getAdminBylineClient } from "@byline/client/server";
3
3
  import { ERR_NOT_FOUND, getLogger } from "@byline/core";
4
4
  import { ensureCollection } from "../../integrations/api-utils.js";
5
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
5
6
  import { resolveActorLabels } from "./actors.js";
6
7
  const getCollectionDocumentAuditLog = createServerFn({
7
8
  method: 'GET'
8
- }).validator((input)=>input).handler(async ({ data })=>{
9
+ }).middleware([
10
+ adminSessionMiddleware
11
+ ]).validator((input)=>input).handler(async ({ data })=>{
9
12
  const { collection: path, id, params } = data;
10
13
  const config = await ensureCollection(path);
11
14
  if (!config) throw ERR_NOT_FOUND({
@@ -16,13 +16,17 @@ import { type CollectionDocumentCommittedHookFailureResponse } from './save-outc
16
16
  * `assertActorCanPerform('update')` runs inside the service; auth
17
17
  * failures propagate to TanStack Start's transport layer.
18
18
  */
19
- export declare const copyDocumentToLocale: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
19
+ export declare const copyDocumentToLocale: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
20
+ bylineExpectedSessionId: string | null;
21
+ }, undefined, undefined>], (input: {
22
+ expectedRevision: number;
20
23
  collection: string;
21
24
  id: string;
22
25
  sourceLocale: string;
23
26
  targetLocale: string;
24
27
  overwrite: boolean;
25
28
  }) => {
29
+ expectedRevision: number;
26
30
  collection: string;
27
31
  id: string;
28
32
  sourceLocale: string;
@@ -3,10 +3,14 @@ import { getAdminRequestContext } from "@byline/client/server";
3
3
  import { ERR_NOT_FOUND, getLogger, getServerConfig } from "@byline/core";
4
4
  import { copyToLocale } from "@byline/core/services";
5
5
  import { ensureCollection } from "../../integrations/api-utils.js";
6
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
7
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
6
8
  import { toCommittedDocumentHookFailureResponse } from "./save-outcome.js";
7
9
  const copyDocumentToLocale = createServerFn({
8
10
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
11
+ }).middleware([
12
+ adminSessionMiddleware
13
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
14
  const { collection: path, id, sourceLocale, targetLocale, overwrite } = input;
11
15
  const logger = getLogger();
12
16
  const config = await ensureCollection(path);
@@ -31,6 +35,7 @@ const copyDocumentToLocale = createServerFn({
31
35
  try {
32
36
  return await copyToLocale(ctx, {
33
37
  documentId: id,
38
+ expectedRevision: input.expectedRevision,
34
39
  sourceLocale,
35
40
  targetLocale,
36
41
  overwrite
@@ -40,5 +45,5 @@ const copyDocumentToLocale = createServerFn({
40
45
  if (null != committedFailure) return committedFailure;
41
46
  throw error;
42
47
  }
43
- });
48
+ }));
44
49
  export { copyDocumentToLocale };
@@ -5,7 +5,9 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
- export declare const createCollectionDocument: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
8
+ export declare const createCollectionDocument: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
9
11
  collection: string;
10
12
  data: any;
11
13
  locale?: string;
@@ -21,4 +23,5 @@ export declare const createCollectionDocument: import("@tanstack/react-start").R
21
23
  status: 'ok';
22
24
  documentId: string;
23
25
  documentVersionId: string;
26
+ revision: number;
24
27
  }>>;
@@ -3,10 +3,14 @@ import { getAdminRequestContext } from "@byline/client/server";
3
3
  import { ERR_NOT_FOUND, getLogger, getServerConfig } from "@byline/core";
4
4
  import { createDocument } from "@byline/core/services";
5
5
  import { ensureCollection } from "../../integrations/api-utils.js";
6
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
7
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
6
8
  import { toCommittedDocumentHookFailureResponse } from "./save-outcome.js";
7
9
  const createCollectionDocument = createServerFn({
8
10
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
11
+ }).middleware([
12
+ adminSessionMiddleware
13
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
14
  const { collection: path, data: documentData, locale, path: explicitPath, availableLocales } = input;
11
15
  const logger = getLogger();
12
16
  const config = await ensureCollection(path);
@@ -45,7 +49,8 @@ const createCollectionDocument = createServerFn({
45
49
  return {
46
50
  status: 'ok',
47
51
  documentId: result.documentId,
48
- documentVersionId: result.documentVersionId
52
+ documentVersionId: result.documentVersionId,
53
+ revision: result.revision
49
54
  };
50
- });
55
+ }));
51
56
  export { createCollectionDocument };
@@ -17,11 +17,15 @@ import { type CollectionDocumentCommittedHookFailureResponse } from './save-outc
17
17
  * the service; auth and validation failures propagate to TanStack Start's
18
18
  * transport layer.
19
19
  */
20
- export declare const deleteDocumentLocale: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
20
+ export declare const deleteDocumentLocale: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
21
+ bylineExpectedSessionId: string | null;
22
+ }, undefined, undefined>], (input: {
23
+ expectedRevision: number;
21
24
  collection: string;
22
25
  id: string;
23
26
  locale: string;
24
27
  }) => {
28
+ expectedRevision: number;
25
29
  collection: string;
26
30
  id: string;
27
31
  locale: string;
@@ -3,10 +3,14 @@ import { getAdminRequestContext } from "@byline/client/server";
3
3
  import { ERR_NOT_FOUND, getLogger, getServerConfig } from "@byline/core";
4
4
  import { deleteLocale } from "@byline/core/services";
5
5
  import { ensureCollection } from "../../integrations/api-utils.js";
6
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
7
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
6
8
  import { toCommittedDocumentHookFailureResponse } from "./save-outcome.js";
7
9
  const deleteDocumentLocale = createServerFn({
8
10
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
11
+ }).middleware([
12
+ adminSessionMiddleware
13
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
14
  const { collection: path, id, locale } = input;
11
15
  const logger = getLogger();
12
16
  const config = await ensureCollection(path);
@@ -31,6 +35,7 @@ const deleteDocumentLocale = createServerFn({
31
35
  try {
32
36
  return await deleteLocale(ctx, {
33
37
  documentId: id,
38
+ expectedRevision: input.expectedRevision,
34
39
  locale
35
40
  });
36
41
  } catch (error) {
@@ -38,5 +43,5 @@ const deleteDocumentLocale = createServerFn({
38
43
  if (null != committedFailure) return committedFailure;
39
44
  throw error;
40
45
  }
41
- });
46
+ }));
42
47
  export { deleteDocumentLocale };
@@ -5,26 +5,30 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
- import type { DeleteDocumentResult, DeleteDocumentSideEffectCode, DeleteDocumentSideEffectPhase } from '@byline/core';
8
+ import type { DeleteDocumentResult, DeleteDocumentSideEffectCode, DeleteDocumentSideEffectPhase, StructuralMutationReceipt } from '@byline/core';
9
9
  export type DeleteDocumentPublicSideEffectPhase = DeleteDocumentSideEffectPhase | 'unknown';
10
10
  export type DeleteDocumentPublicSideEffectCode = DeleteDocumentSideEffectCode;
11
11
  export interface DeleteDocumentPublicSideEffectFailure {
12
12
  phase: DeleteDocumentPublicSideEffectPhase;
13
13
  code: DeleteDocumentPublicSideEffectCode;
14
14
  }
15
- export type DeleteDocumentResponse = {
15
+ export type DeleteDocumentResponse = StructuralMutationReceipt & ({
16
16
  status: 'ok';
17
+ documentId: string;
18
+ revision: number;
17
19
  deletedVersionCount: number;
18
20
  outcome: 'committed';
19
21
  sideEffectFailures: [];
20
22
  } | {
21
23
  status: 'ok';
24
+ documentId: string;
25
+ revision: number;
22
26
  deletedVersionCount: number;
23
27
  outcome: 'committed-with-side-effect-failures';
24
28
  sideEffectFailures: [
25
29
  DeleteDocumentPublicSideEffectFailure,
26
30
  ...DeleteDocumentPublicSideEffectFailure[]
27
31
  ];
28
- };
32
+ });
29
33
  export declare function toDeleteDocumentResponse(result: DeleteDocumentResult): DeleteDocumentResponse;
30
34
  export declare function hasDeleteSideEffectFailures(result: Pick<DeleteDocumentResult, 'outcome'>): boolean;
@@ -20,6 +20,10 @@ function toDeleteDocumentResponse(result) {
20
20
  const [firstFailure, ...remainingFailures] = result.sideEffectFailures;
21
21
  return {
22
22
  status: 'ok',
23
+ documentId: result.documentId,
24
+ revision: result.revision,
25
+ affectedDocuments: result.affectedDocuments,
26
+ scheduledPublicationsNeedReconfirmation: result.scheduledPublicationsNeedReconfirmation,
23
27
  deletedVersionCount: result.deletedVersionCount,
24
28
  outcome: result.outcome,
25
29
  sideEffectFailures: [
@@ -5,10 +5,14 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
- export declare const deleteDocument: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
8
+ export declare const deleteDocument: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
11
+ expectedRevision: number;
9
12
  collection: string;
10
13
  id: string;
11
14
  }) => {
15
+ expectedRevision: number;
12
16
  collection: string;
13
17
  id: string;
14
18
  }, Promise<import("./delete-outcome.js").DeleteDocumentResponse>>;
@@ -3,10 +3,14 @@ import { getAdminRequestContext } from "@byline/client/server";
3
3
  import { ERR_NOT_FOUND, getLogger, getServerConfig, getUploadFields } from "@byline/core";
4
4
  import { deleteDocument } from "@byline/core/services";
5
5
  import { ensureCollection } from "../../integrations/api-utils.js";
6
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
7
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
6
8
  import { toDeleteDocumentResponse } from "./delete-outcome.js";
7
9
  const delete_deleteDocument = createServerFn({
8
10
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
11
+ }).middleware([
12
+ adminSessionMiddleware
13
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
14
  const { collection: path, id } = input;
11
15
  const logger = getLogger();
12
16
  const config = await ensureCollection(path);
@@ -35,8 +39,9 @@ const delete_deleteDocument = createServerFn({
35
39
  requestContext: await getAdminRequestContext()
36
40
  };
37
41
  const result = await deleteDocument(ctx, {
38
- documentId: id
42
+ documentId: id,
43
+ expectedRevision: input.expectedRevision
39
44
  });
40
45
  return toDeleteDocumentResponse(result);
41
- });
46
+ }));
42
47
  export { delete_deleteDocument as deleteDocument };
@@ -18,10 +18,14 @@ import { type CollectionDocumentCommittedHookFailureResponse } from './save-outc
18
18
  * `assertActorCanPerform(..., 'create')`; any auth failure propagates to
19
19
  * TanStack Start's transport layer for the client to branch on.
20
20
  */
21
- export declare const duplicateCollectionDocument: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
21
+ export declare const duplicateCollectionDocument: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
22
+ bylineExpectedSessionId: string | null;
23
+ }, undefined, undefined>], (input: {
24
+ expectedRevision: number;
22
25
  collection: string;
23
26
  id: string;
24
27
  }) => {
28
+ expectedRevision: number;
25
29
  collection: string;
26
30
  id: string;
27
31
  }, Promise<CollectionDocumentCommittedHookFailureResponse | DuplicateDocumentResult>>;
@@ -3,10 +3,14 @@ import { getAdminRequestContext } from "@byline/client/server";
3
3
  import { ERR_NOT_FOUND, getLogger, getServerConfig } from "@byline/core";
4
4
  import { duplicateDocument } from "@byline/core/services";
5
5
  import { ensureCollection } from "../../integrations/api-utils.js";
6
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
7
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
6
8
  import { toCommittedDocumentHookFailureResponse } from "./save-outcome.js";
7
9
  const duplicateCollectionDocument = createServerFn({
8
10
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
11
+ }).middleware([
12
+ adminSessionMiddleware
13
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
14
  const { collection: path, id: sourceDocumentId } = input;
11
15
  const logger = getLogger();
12
16
  const config = await ensureCollection(path);
@@ -30,12 +34,13 @@ const duplicateCollectionDocument = createServerFn({
30
34
  };
31
35
  try {
32
36
  return await duplicateDocument(ctx, {
33
- sourceDocumentId
37
+ sourceDocumentId,
38
+ expectedRevision: input.expectedRevision
34
39
  });
35
40
  } catch (error) {
36
41
  const committedFailure = toCommittedDocumentHookFailureResponse(error);
37
42
  if (null != committedFailure) return committedFailure;
38
43
  throw error;
39
44
  }
40
- });
45
+ }));
41
46
  export { duplicateCollectionDocument };
@@ -16,6 +16,7 @@
16
16
  * `{target_document_id, target_collection_id}` refs.
17
17
  */
18
18
  export declare function getCollectionDocument(collection: string, id: string, locale?: string, depth?: number, populateRelations?: boolean): Promise<{
19
+ revision: number;
19
20
  _publishedVersion: Record<string, any> | null;
20
21
  _restoreWarnings?: string[] | undefined;
21
22
  availableLocales?: string[] | undefined;