@byline/host-tanstack-start 5.0.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 (252) 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/integrations/byline-admin-services.js +7 -1
  9. package/dist/integrations/client-ip.d.ts +19 -0
  10. package/dist/integrations/client-ip.js +34 -0
  11. package/dist/integrations/session-coordination.d.ts +24 -0
  12. package/dist/integrations/session-coordination.js +85 -0
  13. package/dist/integrations/session-middleware.d.ts +11 -0
  14. package/dist/integrations/session-middleware.js +94 -0
  15. package/dist/integrations/session-request-kind.d.ts +9 -0
  16. package/dist/integrations/session-request-kind.js +10 -0
  17. package/dist/integrations/session-request-middleware.d.ts +9 -0
  18. package/dist/integrations/session-request-middleware.js +7 -0
  19. package/dist/integrations/sign-in-body.d.ts +12 -0
  20. package/dist/integrations/sign-in-body.js +52 -0
  21. package/dist/integrations/sign-in-middleware.d.ts +9 -0
  22. package/dist/integrations/sign-in-middleware.js +10 -0
  23. package/dist/routes/create-admin-layout-route.js +46 -31
  24. package/dist/routes/create-sign-in-route.js +4 -2
  25. package/dist/server-fns/admin-account/change-password.d.ts +3 -1
  26. package/dist/server-fns/admin-account/change-password.js +9 -3
  27. package/dist/server-fns/admin-account/get.d.ts +3 -1
  28. package/dist/server-fns/admin-account/get.js +4 -1
  29. package/dist/server-fns/admin-account/index.d.ts +5 -5
  30. package/dist/server-fns/admin-account/update.d.ts +3 -1
  31. package/dist/server-fns/admin-account/update.js +4 -1
  32. package/dist/server-fns/admin-activity/get.d.ts +3 -1
  33. package/dist/server-fns/admin-activity/get.js +4 -1
  34. package/dist/server-fns/admin-permissions/get-role-abilities.d.ts +3 -1
  35. package/dist/server-fns/admin-permissions/get-role-abilities.js +4 -1
  36. package/dist/server-fns/admin-permissions/index.d.ts +4 -4
  37. package/dist/server-fns/admin-permissions/list-registered.d.ts +3 -1
  38. package/dist/server-fns/admin-permissions/list-registered.js +4 -1
  39. package/dist/server-fns/admin-permissions/set-role-abilities.d.ts +3 -1
  40. package/dist/server-fns/admin-permissions/set-role-abilities.js +4 -1
  41. package/dist/server-fns/admin-permissions/who-has.d.ts +3 -1
  42. package/dist/server-fns/admin-permissions/who-has.js +4 -1
  43. package/dist/server-fns/admin-roles/create.d.ts +3 -1
  44. package/dist/server-fns/admin-roles/create.js +4 -1
  45. package/dist/server-fns/admin-roles/delete.d.ts +3 -1
  46. package/dist/server-fns/admin-roles/delete.js +4 -1
  47. package/dist/server-fns/admin-roles/get.d.ts +3 -1
  48. package/dist/server-fns/admin-roles/get.js +4 -1
  49. package/dist/server-fns/admin-roles/index.d.ts +6 -6
  50. package/dist/server-fns/admin-roles/list.d.ts +3 -1
  51. package/dist/server-fns/admin-roles/list.js +4 -1
  52. package/dist/server-fns/admin-roles/reorder.d.ts +3 -1
  53. package/dist/server-fns/admin-roles/reorder.js +4 -1
  54. package/dist/server-fns/admin-roles/update.d.ts +3 -1
  55. package/dist/server-fns/admin-roles/update.js +4 -1
  56. package/dist/server-fns/admin-users/create.d.ts +3 -1
  57. package/dist/server-fns/admin-users/create.js +4 -1
  58. package/dist/server-fns/admin-users/delete.d.ts +3 -1
  59. package/dist/server-fns/admin-users/delete.js +4 -1
  60. package/dist/server-fns/admin-users/disable.d.ts +3 -1
  61. package/dist/server-fns/admin-users/disable.js +4 -1
  62. package/dist/server-fns/admin-users/enable.d.ts +3 -1
  63. package/dist/server-fns/admin-users/enable.js +4 -1
  64. package/dist/server-fns/admin-users/get-user-roles.d.ts +3 -1
  65. package/dist/server-fns/admin-users/get-user-roles.js +4 -1
  66. package/dist/server-fns/admin-users/get.d.ts +3 -1
  67. package/dist/server-fns/admin-users/get.js +4 -1
  68. package/dist/server-fns/admin-users/index.d.ts +10 -10
  69. package/dist/server-fns/admin-users/list.d.ts +3 -1
  70. package/dist/server-fns/admin-users/list.js +4 -1
  71. package/dist/server-fns/admin-users/set-password.d.ts +3 -1
  72. package/dist/server-fns/admin-users/set-password.js +4 -1
  73. package/dist/server-fns/admin-users/set-user-roles.d.ts +3 -1
  74. package/dist/server-fns/admin-users/set-user-roles.js +4 -1
  75. package/dist/server-fns/admin-users/update.d.ts +3 -1
  76. package/dist/server-fns/admin-users/update.js +4 -1
  77. package/dist/server-fns/ai/execute.d.ts +3 -1
  78. package/dist/server-fns/ai/execute.js +4 -1
  79. package/dist/server-fns/ai/index.d.ts +1 -1
  80. package/dist/server-fns/analytics/maintenance.d.ts +6 -2
  81. package/dist/server-fns/analytics/maintenance.js +7 -2
  82. package/dist/server-fns/analytics/queries.d.ts +18 -6
  83. package/dist/server-fns/analytics/queries.js +19 -6
  84. package/dist/server-fns/auth/current-user.d.ts +1 -0
  85. package/dist/server-fns/auth/current-user.js +5 -2
  86. package/dist/server-fns/auth/renew.d.ts +13 -0
  87. package/dist/server-fns/auth/renew.js +45 -0
  88. package/dist/server-fns/auth/sign-in.d.ts +2 -1
  89. package/dist/server-fns/auth/sign-in.js +88 -17
  90. package/dist/server-fns/auth/sign-out.d.ts +3 -1
  91. package/dist/server-fns/auth/sign-out.js +38 -6
  92. package/dist/server-fns/collections/audit.d.ts +3 -1
  93. package/dist/server-fns/collections/audit.js +4 -1
  94. package/dist/server-fns/collections/copy-to-locale.d.ts +10 -1
  95. package/dist/server-fns/collections/copy-to-locale.js +5 -2
  96. package/dist/server-fns/collections/create.d.ts +10 -1
  97. package/dist/server-fns/collections/create.js +5 -2
  98. package/dist/server-fns/collections/delete-locale.d.ts +10 -1
  99. package/dist/server-fns/collections/delete-locale.js +5 -2
  100. package/dist/server-fns/collections/delete.d.ts +10 -1
  101. package/dist/server-fns/collections/delete.js +5 -2
  102. package/dist/server-fns/collections/duplicate.d.ts +10 -1
  103. package/dist/server-fns/collections/duplicate.js +5 -2
  104. package/dist/server-fns/collections/get.d.ts +7 -0
  105. package/dist/server-fns/collections/get.js +8 -3
  106. package/dist/server-fns/collections/history.d.ts +3 -1
  107. package/dist/server-fns/collections/history.js +4 -1
  108. package/dist/server-fns/collections/index.d.ts +21 -21
  109. package/dist/server-fns/collections/list.d.ts +10 -1
  110. package/dist/server-fns/collections/list.js +5 -2
  111. package/dist/server-fns/collections/reindex.d.ts +3 -1
  112. package/dist/server-fns/collections/reindex.js +4 -1
  113. package/dist/server-fns/collections/reorder.d.ts +10 -1
  114. package/dist/server-fns/collections/reorder.js +5 -2
  115. package/dist/server-fns/collections/restore-version.d.ts +10 -1
  116. package/dist/server-fns/collections/restore-version.js +5 -2
  117. package/dist/server-fns/collections/scheduled-publication.d.ts +22 -5
  118. package/dist/server-fns/collections/scheduled-publication.js +17 -6
  119. package/dist/server-fns/collections/set-list-view-preference.d.ts +3 -1
  120. package/dist/server-fns/collections/set-list-view-preference.js +4 -1
  121. package/dist/server-fns/collections/stats.js +4 -1
  122. package/dist/server-fns/collections/status.d.ts +13 -2
  123. package/dist/server-fns/collections/status.js +8 -3
  124. package/dist/server-fns/collections/tree.d.ts +22 -5
  125. package/dist/server-fns/collections/tree.js +17 -6
  126. package/dist/server-fns/collections/update.d.ts +13 -2
  127. package/dist/server-fns/collections/update.js +8 -3
  128. package/dist/server-fns/collections/upload.d.ts +10 -1
  129. package/dist/server-fns/collections/upload.js +4 -1
  130. package/dist/server-fns/i18n/set-locale.d.ts +3 -1
  131. package/dist/server-fns/i18n/set-locale.js +18 -3
  132. package/dist/server-fns/preview/disable.d.ts +3 -1
  133. package/dist/server-fns/preview/disable.js +4 -1
  134. package/dist/server-fns/preview/enable.d.ts +3 -1
  135. package/dist/server-fns/preview/enable.js +4 -1
  136. package/dist/server-fns/singletons/cancel-scheduled-publish.d.ts +10 -1
  137. package/dist/server-fns/singletons/cancel-scheduled-publish.js +5 -2
  138. package/dist/server-fns/singletons/change-status.d.ts +10 -1
  139. package/dist/server-fns/singletons/change-status.js +5 -2
  140. package/dist/server-fns/singletons/confirm-scheduled-publish.d.ts +10 -1
  141. package/dist/server-fns/singletons/confirm-scheduled-publish.js +5 -2
  142. package/dist/server-fns/singletons/copy-to-locale.d.ts +10 -1
  143. package/dist/server-fns/singletons/copy-to-locale.js +5 -2
  144. package/dist/server-fns/singletons/find-by-version.d.ts +3 -1
  145. package/dist/server-fns/singletons/find-by-version.js +4 -1
  146. package/dist/server-fns/singletons/get-scheduled-publish.d.ts +3 -1
  147. package/dist/server-fns/singletons/get-scheduled-publish.js +4 -1
  148. package/dist/server-fns/singletons/get.d.ts +3 -1
  149. package/dist/server-fns/singletons/get.js +4 -1
  150. package/dist/server-fns/singletons/history.d.ts +3 -1
  151. package/dist/server-fns/singletons/history.js +4 -1
  152. package/dist/server-fns/singletons/restore-version.d.ts +10 -1
  153. package/dist/server-fns/singletons/restore-version.js +5 -2
  154. package/dist/server-fns/singletons/schedule-publish.d.ts +10 -1
  155. package/dist/server-fns/singletons/schedule-publish.js +5 -2
  156. package/dist/server-fns/singletons/unpublish.d.ts +10 -1
  157. package/dist/server-fns/singletons/unpublish.js +5 -2
  158. package/dist/server-fns/singletons/update.d.ts +10 -1
  159. package/dist/server-fns/singletons/update.js +5 -2
  160. package/package.json +19 -19
  161. package/src/admin-shell/chrome/admin-app-bar.tsx +11 -6
  162. package/src/admin-shell/chrome/session-change-boundary.test.tsx +78 -0
  163. package/src/admin-shell/chrome/session-change-boundary.tsx +94 -0
  164. package/src/admin-shell/chrome/sign-in-page.tsx +68 -3
  165. package/src/integrations/byline-admin-services.ts +7 -1
  166. package/src/integrations/client-ip.test.node.ts +45 -0
  167. package/src/integrations/client-ip.ts +54 -0
  168. package/src/integrations/framework-fetch-shape.test.node.ts +56 -0
  169. package/src/integrations/session-client.test.node.ts +121 -0
  170. package/src/integrations/session-coordination.test.node.ts +77 -0
  171. package/src/integrations/session-coordination.ts +96 -0
  172. package/src/integrations/session-middleware.test.node.ts +87 -0
  173. package/src/integrations/session-middleware.ts +107 -0
  174. package/src/integrations/session-request-kind.ts +18 -0
  175. package/src/integrations/session-request-middleware.ts +17 -0
  176. package/src/integrations/sign-in-body.test.node.ts +59 -0
  177. package/src/integrations/sign-in-body.ts +50 -0
  178. package/src/integrations/sign-in-middleware.ts +24 -0
  179. package/src/routes/create-admin-layout-route.tsx +48 -30
  180. package/src/routes/create-sign-in-route.tsx +10 -2
  181. package/src/server-fns/admin-account/change-password.test.node.ts +69 -0
  182. package/src/server-fns/admin-account/change-password.ts +13 -2
  183. package/src/server-fns/admin-account/get.ts +2 -0
  184. package/src/server-fns/admin-account/update.ts +2 -0
  185. package/src/server-fns/admin-activity/get.ts +2 -0
  186. package/src/server-fns/admin-permissions/get-role-abilities.ts +2 -0
  187. package/src/server-fns/admin-permissions/list-registered.ts +5 -4
  188. package/src/server-fns/admin-permissions/set-role-abilities.ts +2 -0
  189. package/src/server-fns/admin-permissions/who-has.ts +2 -0
  190. package/src/server-fns/admin-roles/create.ts +2 -0
  191. package/src/server-fns/admin-roles/delete.ts +2 -0
  192. package/src/server-fns/admin-roles/get.ts +2 -0
  193. package/src/server-fns/admin-roles/list.ts +5 -4
  194. package/src/server-fns/admin-roles/reorder.ts +2 -0
  195. package/src/server-fns/admin-roles/update.ts +2 -0
  196. package/src/server-fns/admin-users/create.ts +2 -0
  197. package/src/server-fns/admin-users/delete.ts +2 -0
  198. package/src/server-fns/admin-users/disable.ts +2 -0
  199. package/src/server-fns/admin-users/enable.ts +2 -0
  200. package/src/server-fns/admin-users/get-user-roles.ts +2 -0
  201. package/src/server-fns/admin-users/get.ts +2 -0
  202. package/src/server-fns/admin-users/list.ts +2 -0
  203. package/src/server-fns/admin-users/set-password.ts +2 -0
  204. package/src/server-fns/admin-users/set-user-roles.ts +2 -0
  205. package/src/server-fns/admin-users/update.ts +2 -0
  206. package/src/server-fns/ai/execute.ts +3 -0
  207. package/src/server-fns/analytics/maintenance.ts +4 -0
  208. package/src/server-fns/analytics/queries.ts +14 -8
  209. package/src/server-fns/auth/current-user.ts +7 -3
  210. package/src/server-fns/auth/renew.test.node.ts +85 -0
  211. package/src/server-fns/auth/renew.ts +54 -0
  212. package/src/server-fns/auth/sign-in.test.node.ts +114 -0
  213. package/src/server-fns/auth/sign-in.ts +80 -27
  214. package/src/server-fns/auth/sign-out.test.node.ts +85 -0
  215. package/src/server-fns/auth/sign-out.ts +44 -19
  216. package/src/server-fns/collections/audit.ts +2 -0
  217. package/src/server-fns/collections/copy-to-locale.ts +3 -1
  218. package/src/server-fns/collections/create.ts +3 -1
  219. package/src/server-fns/collections/delete-locale.ts +3 -1
  220. package/src/server-fns/collections/delete.ts +3 -1
  221. package/src/server-fns/collections/duplicate.ts +3 -1
  222. package/src/server-fns/collections/get.ts +4 -1
  223. package/src/server-fns/collections/history.ts +2 -0
  224. package/src/server-fns/collections/list.ts +3 -1
  225. package/src/server-fns/collections/reindex.ts +2 -0
  226. package/src/server-fns/collections/reorder.ts +3 -1
  227. package/src/server-fns/collections/restore-version.ts +3 -1
  228. package/src/server-fns/collections/revision-input.test.node.ts +14 -0
  229. package/src/server-fns/collections/scheduled-publication.ts +14 -7
  230. package/src/server-fns/collections/set-list-view-preference.ts +2 -0
  231. package/src/server-fns/collections/stats.ts +2 -0
  232. package/src/server-fns/collections/status.ts +4 -1
  233. package/src/server-fns/collections/tree.ts +7 -1
  234. package/src/server-fns/collections/update.ts +4 -1
  235. package/src/server-fns/collections/upload-singleton.test.node.ts +8 -1
  236. package/src/server-fns/collections/upload.ts +10 -0
  237. package/src/server-fns/i18n/set-locale.ts +19 -3
  238. package/src/server-fns/preview/disable.ts +8 -4
  239. package/src/server-fns/preview/enable.ts +9 -5
  240. package/src/server-fns/singletons/cancel-scheduled-publish.ts +3 -1
  241. package/src/server-fns/singletons/change-status.ts +3 -1
  242. package/src/server-fns/singletons/confirm-scheduled-publish.ts +3 -1
  243. package/src/server-fns/singletons/copy-to-locale.ts +3 -1
  244. package/src/server-fns/singletons/find-by-version.ts +2 -0
  245. package/src/server-fns/singletons/get-scheduled-publish.ts +2 -0
  246. package/src/server-fns/singletons/get.ts +2 -0
  247. package/src/server-fns/singletons/history.ts +2 -0
  248. package/src/server-fns/singletons/restore-version.ts +3 -1
  249. package/src/server-fns/singletons/schedule-publish.ts +3 -1
  250. package/src/server-fns/singletons/singletons.test.node.ts +6 -0
  251. package/src/server-fns/singletons/unpublish.ts +3 -1
  252. package/src/server-fns/singletons/update.ts +3 -1
@@ -1,4 +1,13 @@
1
- export declare const changeSingletonStatus: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
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
+ export declare const changeSingletonStatus: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
2
11
  expectedRevision: number;
3
12
  singleton: string;
4
13
  status: string;
@@ -1,10 +1,13 @@
1
- import { withDocumentMutationErrors } from "../document-mutation-errors.js";
2
1
  import { createServerFn } from "@tanstack/react-start";
3
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
4
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
4
5
  import { serialise } from "../serialise.js";
5
6
  const changeSingletonStatus = createServerFn({
6
7
  method: 'POST'
7
- }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).changeStatus(data.status, {
8
+ }).middleware([
9
+ adminSessionMiddleware
10
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).changeStatus(data.status, {
8
11
  expectedRevision: data.expectedRevision
9
12
  }))));
10
13
  export { changeSingletonStatus };
@@ -1,4 +1,13 @@
1
- export declare const confirmSingletonScheduledPublish: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
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
+ export declare const confirmSingletonScheduledPublish: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
2
11
  expectedRevision: number;
3
12
  singleton: string;
4
13
  expectedVersionId: string;
@@ -1,10 +1,13 @@
1
- import { withDocumentMutationErrors } from "../document-mutation-errors.js";
2
1
  import { createServerFn } from "@tanstack/react-start";
3
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
4
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
4
5
  import { serialise } from "../serialise.js";
5
6
  const confirmSingletonScheduledPublish = createServerFn({
6
7
  method: 'POST'
7
- }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).confirmScheduledPublish({
8
+ }).middleware([
9
+ adminSessionMiddleware
10
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).confirmScheduledPublish({
8
11
  expectedRevision: data.expectedRevision,
9
12
  expectedVersionId: data.expectedVersionId
10
13
  }))));
@@ -1,4 +1,13 @@
1
- export declare const copySingletonToLocale: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
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
+ export declare const copySingletonToLocale: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
2
11
  expectedRevision: number;
3
12
  singleton: string;
4
13
  sourceLocale: string;
@@ -1,11 +1,14 @@
1
- import { withDocumentMutationErrors } from "../document-mutation-errors.js";
2
1
  import { createServerFn } from "@tanstack/react-start";
3
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
4
4
  import { toCommittedDocumentHookFailureResponse } from "../collections/save-outcome.js";
5
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
5
6
  import { serialise } from "../serialise.js";
6
7
  const copySingletonToLocale = createServerFn({
7
8
  method: 'POST'
8
- }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>{
9
+ }).middleware([
10
+ adminSessionMiddleware
11
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>{
9
12
  try {
10
13
  return serialise(await getAdminBylineClient().singleton(data.singleton).copyToLocale({
11
14
  expectedRevision: data.expectedRevision,
@@ -5,7 +5,9 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
- export declare const findSingletonByVersion: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
8
+ export declare const findSingletonByVersion: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
9
11
  singleton: string;
10
12
  versionId: string;
11
13
  locale?: string;
@@ -1,9 +1,12 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
3
4
  import { serialise } from "../serialise.js";
4
5
  const findSingletonByVersion = createServerFn({
5
6
  method: 'GET'
6
- }).validator((input)=>input).handler(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).findByVersion(data.versionId, {
7
+ }).middleware([
8
+ adminSessionMiddleware
9
+ ]).validator((input)=>input).handler(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).findByVersion(data.versionId, {
7
10
  locale: data.locale ?? 'all'
8
11
  })));
9
12
  export { findSingletonByVersion };
@@ -5,7 +5,9 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
- export declare const getSingletonScheduledPublish: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
8
+ export declare const getSingletonScheduledPublish: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
9
11
  singleton: string;
10
12
  }) => {
11
13
  singleton: string;
@@ -1,7 +1,10 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
3
4
  import { serialise } from "../serialise.js";
4
5
  const getSingletonScheduledPublish = createServerFn({
5
6
  method: 'GET'
6
- }).validator((input)=>input).handler(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).getScheduledPublish()));
7
+ }).middleware([
8
+ adminSessionMiddleware
9
+ ]).validator((input)=>input).handler(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).getScheduledPublish()));
7
10
  export { getSingletonScheduledPublish };
@@ -21,4 +21,6 @@ export interface GetSingletonInput {
21
21
  * enablement, capability, and schedule aliases. Schedule state itself comes
22
22
  * from the same editable snapshot as the source document.
23
23
  */
24
- export declare const getSingleton: import("@tanstack/react-start").RequiredFetcher<undefined, (input: GetSingletonInput) => GetSingletonInput, Promise<Omit<import("@byline/client").EditableDocument<Record<string, any>>, "path"> | null>>;
24
+ export declare const getSingleton: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
25
+ bylineExpectedSessionId: string | null;
26
+ }, undefined, undefined>], (input: GetSingletonInput) => GetSingletonInput, Promise<Omit<import("@byline/client").EditableDocument<Record<string, any>>, "path"> | null>>;
@@ -1,6 +1,9 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
2
3
  import { readSingletonDocument } from "../singleton-document-read.js";
3
4
  const getSingleton = createServerFn({
4
5
  method: 'GET'
5
- }).validator((input)=>input).handler(async ({ data })=>readSingletonDocument(data));
6
+ }).middleware([
7
+ adminSessionMiddleware
8
+ ]).validator((input)=>input).handler(async ({ data })=>readSingletonDocument(data));
6
9
  export { getSingleton };
@@ -13,7 +13,9 @@ export interface SingletonHistorySearchParams {
13
13
  desc?: boolean;
14
14
  locale?: string;
15
15
  }
16
- export declare const getSingletonHistory: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
16
+ export declare const getSingletonHistory: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
17
+ bylineExpectedSessionId: string | null;
18
+ }, undefined, undefined>], (input: {
17
19
  singleton: string;
18
20
  params?: SingletonHistorySearchParams;
19
21
  }) => {
@@ -1,10 +1,13 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
3
4
  import { resolveActorLabels } from "../actors.js";
4
5
  import { serialise } from "../serialise.js";
5
6
  const getSingletonHistory = createServerFn({
6
7
  method: 'GET'
7
- }).validator((input)=>input).handler(async ({ data })=>{
8
+ }).middleware([
9
+ adminSessionMiddleware
10
+ ]).validator((input)=>input).handler(async ({ data })=>{
8
11
  const params = data.params ?? {};
9
12
  const result = await getAdminBylineClient().singleton(data.singleton).history({
10
13
  locale: params.locale ?? 'en',
@@ -1,4 +1,13 @@
1
- export declare const restoreSingletonVersion: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
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
+ export declare const restoreSingletonVersion: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
2
11
  expectedRevision: number;
3
12
  singleton: string;
4
13
  versionId: string;
@@ -1,11 +1,14 @@
1
- import { withDocumentMutationErrors } from "../document-mutation-errors.js";
2
1
  import { createServerFn } from "@tanstack/react-start";
3
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
4
4
  import { toCommittedDocumentHookFailureResponse } from "../collections/save-outcome.js";
5
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
5
6
  import { serialise } from "../serialise.js";
6
7
  const restoreSingletonVersion = createServerFn({
7
8
  method: 'POST'
8
- }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>{
9
+ }).middleware([
10
+ adminSessionMiddleware
11
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>{
9
12
  try {
10
13
  return serialise(await getAdminBylineClient().singleton(data.singleton).restoreVersion(data.versionId, {
11
14
  expectedRevision: data.expectedRevision
@@ -1,4 +1,13 @@
1
- export declare const scheduleSingletonPublish: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
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
+ export declare const scheduleSingletonPublish: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
2
11
  expectedRevision: number;
3
12
  singleton: string;
4
13
  publishAt: string;
@@ -1,10 +1,13 @@
1
- import { withDocumentMutationErrors } from "../document-mutation-errors.js";
2
1
  import { createServerFn } from "@tanstack/react-start";
3
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
4
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
4
5
  import { serialise } from "../serialise.js";
5
6
  const scheduleSingletonPublish = createServerFn({
6
7
  method: 'POST'
7
- }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).schedulePublish({
8
+ }).middleware([
9
+ adminSessionMiddleware
10
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).schedulePublish({
8
11
  publishAt: data.publishAt,
9
12
  expectedRevision: data.expectedRevision,
10
13
  expectedVersionId: data.expectedVersionId
@@ -1,4 +1,13 @@
1
- export declare const unpublishSingleton: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
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
+ export declare const unpublishSingleton: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
9
+ bylineExpectedSessionId: string | null;
10
+ }, undefined, undefined>], (input: {
2
11
  expectedRevision: number;
3
12
  singleton: string;
4
13
  }) => {
@@ -1,10 +1,13 @@
1
- import { withDocumentMutationErrors } from "../document-mutation-errors.js";
2
1
  import { createServerFn } from "@tanstack/react-start";
3
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
4
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
4
5
  import { serialise } from "../serialise.js";
5
6
  const unpublishSingleton = createServerFn({
6
7
  method: 'POST'
7
- }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).unpublish({
8
+ }).middleware([
9
+ adminSessionMiddleware
10
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>serialise(await getAdminBylineClient().singleton(data.singleton).unpublish({
8
11
  expectedRevision: data.expectedRevision
9
12
  }))));
10
13
  export { unpublishSingleton };
@@ -1,7 +1,16 @@
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
+ */
1
8
  import type { SingletonSavePrecondition } from '@byline/core';
2
9
  export type UpdateSingletonInput = SingletonSavePrecondition & {
3
10
  singleton: string;
4
11
  data: Record<string, any>;
5
12
  locale?: string;
6
13
  };
7
- export declare const updateSingleton: import("@tanstack/react-start").RequiredFetcher<undefined, (input: UpdateSingletonInput) => UpdateSingletonInput, Promise<import("@byline/core").UpdateSingletonResult>>;
14
+ export declare const updateSingleton: import("@tanstack/react-start").RequiredFetcher<readonly [import("@tanstack/react-start").FunctionMiddlewareAfterServer<{}, unknown, undefined, undefined, {
15
+ bylineExpectedSessionId: string | null;
16
+ }, undefined, undefined>], (input: UpdateSingletonInput) => UpdateSingletonInput, Promise<import("@byline/core").UpdateSingletonResult>>;
@@ -1,11 +1,14 @@
1
- import { withDocumentMutationErrors } from "../document-mutation-errors.js";
2
1
  import { createServerFn } from "@tanstack/react-start";
3
2
  import { getAdminBylineClient } from "@byline/client/server";
3
+ import { adminSessionMiddleware } from "../../integrations/session-middleware.js";
4
4
  import { toCommittedDocumentHookFailureResponse } from "../collections/save-outcome.js";
5
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
5
6
  import { serialise } from "../serialise.js";
6
7
  const updateSingleton = createServerFn({
7
8
  method: 'POST'
8
- }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>{
9
+ }).middleware([
10
+ adminSessionMiddleware
11
+ ]).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data })=>{
9
12
  const { singleton, data: fields, locale, ...precondition } = data;
10
13
  try {
11
14
  const result = await getAdminBylineClient().singleton(singleton).update(fields, {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "private": false,
4
4
  "type": "module",
5
5
  "license": "MPL-2.0",
6
- "version": "5.0.0",
6
+ "version": "5.1.0",
7
7
  "engines": {
8
8
  "node": ">=20.9.0"
9
9
  },
@@ -124,16 +124,16 @@
124
124
  "clsx": "^2.1.1",
125
125
  "react-json-view-lite": "^2.5.0",
126
126
  "react-swipeable": "^7.0.2",
127
- "zod": "^4.4.3",
128
- "@byline/admin": "5.0.0",
129
- "@byline/analytics": "5.0.0",
130
- "@byline/ai": "5.0.0",
131
- "@byline/analytics-agent": "5.0.0",
132
- "@byline/core": "5.0.0",
133
- "@byline/i18n": "5.0.0",
134
- "@byline/ui": "5.0.0",
135
- "@byline/client": "5.0.0",
136
- "@byline/auth": "5.0.0"
127
+ "zod": "^4.5.4",
128
+ "@byline/admin": "5.1.0",
129
+ "@byline/analytics-agent": "5.1.0",
130
+ "@byline/analytics": "5.1.0",
131
+ "@byline/client": "5.1.0",
132
+ "@byline/ai": "5.1.0",
133
+ "@byline/auth": "5.1.0",
134
+ "@byline/core": "5.1.0",
135
+ "@byline/i18n": "5.1.0",
136
+ "@byline/ui": "5.1.0"
137
137
  },
138
138
  "peerDependencies": {
139
139
  "@tanstack/react-router": "^1.167.0",
@@ -143,15 +143,15 @@
143
143
  "vite": "^8.0.0"
144
144
  },
145
145
  "devDependencies": {
146
- "@biomejs/biome": "2.5.10",
146
+ "@biomejs/biome": "2.5.12",
147
147
  "@rsbuild/plugin-react": "^2.1.0",
148
- "@rslib/core": "^0.23.2",
149
- "@tanstack/react-router": "^1.170.32",
150
- "@tanstack/react-start": "^1.168.49",
151
- "@types/node": "^26.4.0",
148
+ "@rslib/core": "^1.0.0",
149
+ "@tanstack/react-router": "^1.170.33",
150
+ "@tanstack/react-start": "^1.168.50",
151
+ "@types/node": "^26.5.0",
152
152
  "@types/react": "19.2.18",
153
- "@types/react-dom": "19.2.5",
154
- "@vitejs/plugin-react": "^6.1.0",
153
+ "@types/react-dom": "19.2.7",
154
+ "@vitejs/plugin-react": "^6.1.1",
155
155
  "jsdom": "^30.0.1",
156
156
  "npm-run-all": "^4.1.5",
157
157
  "react": "^19.2.8",
@@ -159,7 +159,7 @@
159
159
  "typescript": "^7.0.2",
160
160
  "typescript-plugin-css-modules": "^5.2.0",
161
161
  "vite": "^8.2.2",
162
- "vitest": "^4.1.11"
162
+ "vitest": "^5.0.0"
163
163
  },
164
164
  "publishConfig": {
165
165
  "access": "public",
@@ -1,5 +1,3 @@
1
- 'use client'
2
-
3
1
  /**
4
2
  * This Source Code is subject to the terms of the Mozilla Public
5
3
  * License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -22,6 +20,8 @@ import { Branding } from './branding.js'
22
20
  import { Breadcrumbs } from './breadcrumbs/breadcrumbs.js'
23
21
  import { useBreadcrumbs } from './breadcrumbs/breadcrumbs-provider.js'
24
22
 
23
+ ;('use client')
24
+
25
25
  interface AdminAppBarProps {
26
26
  user: CurrentAdminUser
27
27
  }
@@ -37,16 +37,18 @@ export function AdminAppBar({ user }: AdminAppBarProps) {
37
37
  const { breadCrumbSettings } = useBreadcrumbs()
38
38
  const { t } = useTranslation('byline-admin')
39
39
  const [signingOut, setSigningOut] = useState(false)
40
+ const [signOutError, setSignOutError] = useState(false)
40
41
 
41
42
  async function handleSignOut() {
42
43
  if (signingOut) return
43
44
  setSigningOut(true)
45
+ setSignOutError(false)
44
46
  try {
45
47
  await adminSignOut()
46
- } catch (err) {
47
- // Even on transport failure, the server-side handler clears the
48
- // cookies best-effort. Navigate to sign-in regardless.
49
- console.warn('sign-out request failed', err)
48
+ } catch {
49
+ setSignOutError(true)
50
+ setSigningOut(false)
51
+ return
50
52
  }
51
53
  // Full-page navigation so the admin guard re-runs with cleared cookies.
52
54
  window.location.assign(getSignInRoutePath())
@@ -71,6 +73,9 @@ export function AdminAppBar({ user }: AdminAppBarProps) {
71
73
  {displayNameFor(user)}
72
74
  </span>
73
75
  </span>
76
+ {signOutError && (
77
+ <span role="alert">Sign-out could not be confirmed. Please try again.</span>
78
+ )}
74
79
  <Button size="xs" intent="secondary" onClick={handleSignOut} disabled={signingOut}>
75
80
  {signingOut ? t('common.actions.signingOut') : t('common.actions.signOut')}
76
81
  </Button>
@@ -0,0 +1,78 @@
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
+
9
+ import { act } from 'react'
10
+
11
+ import { createRoot, type Root } from 'react-dom/client'
12
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
13
+
14
+ const mocks = vi.hoisted(() => ({ current: vi.fn() }))
15
+ vi.mock('../../server-fns/auth/current-user.js', () => ({ getCurrentAdminUser: mocks.current }))
16
+ vi.mock('../../routes/sign-in-path.js', () => ({ getSignInRoutePath: () => '/sign-in' }))
17
+
18
+ import { acceptSession, expectedSession } from '../../integrations/session-coordination.js'
19
+ import { SessionChangeBoundary } from './session-change-boundary.js'
20
+
21
+ const user = (sessionId: string, email: string) => ({
22
+ sessionId,
23
+ email,
24
+ id: email,
25
+ given_name: null,
26
+ family_name: null,
27
+ is_super_admin: false,
28
+ abilities: [],
29
+ })
30
+ let root: Root
31
+ let container: HTMLDivElement
32
+ beforeEach(() => {
33
+ vi.clearAllMocks()
34
+ vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true)
35
+ vi.stubGlobal('BroadcastChannel', undefined)
36
+ window.sessionStorage.clear()
37
+ acceptSession('expected-B')
38
+ container = document.createElement('div')
39
+ document.body.appendChild(container)
40
+ root = createRoot(container)
41
+ })
42
+ afterEach(() => {
43
+ act(() => root.unmount())
44
+ container.remove()
45
+ vi.unstubAllGlobals()
46
+ })
47
+ async function render() {
48
+ await act(async () => {
49
+ root.render(
50
+ <SessionChangeBoundary user={user('late-A', 'x@example.test')}>
51
+ <button type="button">Publish</button>
52
+ </SessionChangeBoundary>
53
+ )
54
+ })
55
+ }
56
+ describe('session-change acknowledgement', () => {
57
+ it('blocks business UI on the first post-sign-in render when cookies select a different login', async () => {
58
+ mocks.current.mockResolvedValue(user('late-A', 'x@example.test'))
59
+ await render()
60
+ expect(container.textContent).not.toContain('Publish')
61
+ expect(container.querySelector('[role="alertdialog"]')).not.toBeNull()
62
+ expect(container.textContent).toContain('Active account: x@example.test')
63
+ expect(expectedSession()).toBe('expected-B')
64
+ })
65
+ it('requires renewed acknowledgement when the server account changes again', async () => {
66
+ mocks.current.mockResolvedValue(user('late-A', 'x@example.test'))
67
+ await render()
68
+ mocks.current.mockResolvedValue(user('new-C', 'z@example.test'))
69
+ await act(async () => {
70
+ container.querySelector('button')?.click()
71
+ })
72
+ expect(container.textContent).toContain(
73
+ 'The active session changed again. Review the account before continuing.'
74
+ )
75
+ expect(expectedSession()).toBe('expected-B')
76
+ expect(container.textContent).not.toContain('Publish')
77
+ })
78
+ })
@@ -0,0 +1,94 @@
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
+
9
+ import { type ReactNode, useEffect, useState, useSyncExternalStore } from 'react'
10
+
11
+ import {
12
+ acceptSession,
13
+ expectedSession,
14
+ flagSessionChanged,
15
+ observeSession,
16
+ sessionEpoch,
17
+ sessionIsChanged,
18
+ startSessionNotifications,
19
+ subscribeSessionChange,
20
+ } from '../../integrations/session-coordination.js'
21
+ import { getSignInRoutePath } from '../../routes/sign-in-path.js'
22
+ import { type CurrentAdminUser, getCurrentAdminUser } from '../../server-fns/auth/current-user.js'
23
+
24
+ /** Blocks the page until the user explicitly acknowledges freshly verified login identity. */
25
+ export function SessionChangeBoundary({
26
+ user,
27
+ children,
28
+ }: {
29
+ user?: CurrentAdminUser
30
+ children: ReactNode
31
+ }) {
32
+ const epoch = useSyncExternalStore(subscribeSessionChange, sessionEpoch, () => 0)
33
+ const changed = sessionIsChanged()
34
+ const [current, setCurrent] = useState(user)
35
+ const [error, setError] = useState<string>()
36
+ const [busy, setBusy] = useState(false)
37
+ const mismatch =
38
+ typeof window !== 'undefined' &&
39
+ !!user &&
40
+ !!expectedSession() &&
41
+ expectedSession() !== user.sessionId
42
+ useEffect(() => {
43
+ startSessionNotifications()
44
+ if (user) {
45
+ try {
46
+ observeSession(user.sessionId)
47
+ } catch {
48
+ /* Interstitial owns this mismatch. */
49
+ }
50
+ }
51
+ }, [user])
52
+ useEffect(() => {
53
+ if (!changed && !mismatch) return
54
+ void getCurrentAdminUser()
55
+ .then((verified) => {
56
+ if (sessionEpoch() !== epoch) return
57
+ setCurrent(verified)
58
+ setError(undefined)
59
+ })
60
+ .catch(() => setError('The session is no longer available. Please sign in again.'))
61
+ }, [changed, mismatch, epoch])
62
+ if (!changed && !mismatch) return children
63
+ async function acknowledge() {
64
+ setBusy(true)
65
+ try {
66
+ const verified = await getCurrentAdminUser()
67
+ // Require a second acknowledgement if the identity changed while this interstitial was open.
68
+ if (!current || current.sessionId !== verified.sessionId) {
69
+ setCurrent(verified)
70
+ setError('The active session changed again. Review the account before continuing.')
71
+ return
72
+ }
73
+ acceptSession(verified.sessionId)
74
+ window.location.reload() // Discard queued edits and old page state; never replay them.
75
+ } catch {
76
+ flagSessionChanged()
77
+ setError('Unable to verify the active session. Please sign in again.')
78
+ } finally {
79
+ setBusy(false)
80
+ }
81
+ }
82
+ return (
83
+ <main role="alertdialog" aria-modal="true" aria-labelledby="session-change-title">
84
+ <h1 id="session-change-title">Your session has changed</h1>
85
+ <p>Your previous work has not been retried. Check the active account before continuing.</p>
86
+ {current && <p>Active account: {current.email}</p>}
87
+ {error && <p role="alert">{error}</p>}
88
+ <button type="button" disabled={busy || !current} onClick={acknowledge}>
89
+ Continue as this account
90
+ </button>
91
+ <a href={`${getSignInRoutePath()}?reauthenticate=1`}>Sign in again</a>
92
+ </main>
93
+ )
94
+ }