@byline/host-tanstack-start 3.21.0 → 4.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 (236) hide show
  1. package/dist/admin-shell/admin-activity/list.js +15 -5
  2. package/dist/admin-shell/admin-roles/delete.js +2 -1
  3. package/dist/admin-shell/admin-roles/list.js +2 -1
  4. package/dist/admin-shell/admin-users/delete.js +2 -1
  5. package/dist/admin-shell/admin-users/list.js +4 -7
  6. package/dist/admin-shell/chrome/admin-app-bar.js +2 -1
  7. package/dist/admin-shell/chrome/admin-menu-drawer.js +9 -8
  8. package/dist/admin-shell/chrome/admin-menu-provider.js +2 -1
  9. package/dist/admin-shell/chrome/dashboard.js +4 -3
  10. package/dist/admin-shell/chrome/sign-in-page.d.ts +2 -2
  11. package/dist/admin-shell/chrome/sign-in-page.js +2 -2
  12. package/dist/admin-shell/collections/create.js +4 -3
  13. package/dist/admin-shell/collections/document-history.js +6 -1
  14. package/dist/admin-shell/collections/edit.js +18 -14
  15. package/dist/admin-shell/collections/history.js +5 -4
  16. package/dist/admin-shell/collections/list.js +8 -7
  17. package/dist/admin-shell/collections/restore-version-modal.js +2 -1
  18. package/dist/admin-shell/collections/tree-list.js +53 -17
  19. package/dist/admin-shell/collections/view-menu.js +9 -8
  20. package/dist/i18n/resolve-locale.js +1 -1
  21. package/dist/index.d.ts +5 -6
  22. package/dist/integrations/abilities.js +8 -7
  23. package/dist/integrations/host-bridge.d.ts +13 -0
  24. package/dist/integrations/host-bridge.js +22 -0
  25. package/dist/integrations/serve-uploads.d.ts +1 -0
  26. package/dist/integrations/serve-uploads.js +1 -0
  27. package/dist/integrations/start-errors.js +2 -1
  28. package/dist/routes/admin-path.d.ts +22 -0
  29. package/dist/routes/admin-path.js +35 -0
  30. package/dist/routes/create-admin-account-route.js +3 -2
  31. package/dist/routes/create-admin-activity-route.js +3 -2
  32. package/dist/routes/create-admin-dashboard-route.js +2 -1
  33. package/dist/routes/create-admin-layout-route.d.ts +1 -1
  34. package/dist/routes/create-admin-layout-route.js +3 -1
  35. package/dist/routes/create-admin-permissions-route.js +3 -2
  36. package/dist/routes/create-admin-role-edit-route.js +4 -3
  37. package/dist/routes/create-admin-roles-list-route.js +3 -2
  38. package/dist/routes/create-admin-user-edit-route.js +4 -3
  39. package/dist/routes/create-admin-users-list-route.js +3 -2
  40. package/dist/routes/create-collection-api-route.js +5 -4
  41. package/dist/routes/create-collection-create-route.js +4 -3
  42. package/dist/routes/create-collection-edit-route.js +4 -3
  43. package/dist/routes/create-collection-history-route.js +5 -4
  44. package/dist/routes/create-collection-list-route.js +3 -2
  45. package/dist/routes/create-sign-in-route.js +3 -2
  46. package/dist/routes/index.d.ts +3 -0
  47. package/dist/routes/index.js +2 -0
  48. package/dist/routes/sign-in-path.d.ts +13 -0
  49. package/dist/routes/sign-in-path.js +19 -0
  50. package/dist/server-fns/admin-account/change-password.js +1 -1
  51. package/dist/server-fns/admin-account/get.js +1 -1
  52. package/dist/server-fns/admin-account/update.js +1 -1
  53. package/dist/server-fns/admin-activity/get.js +1 -1
  54. package/dist/server-fns/admin-permissions/get-role-abilities.js +1 -1
  55. package/dist/server-fns/admin-permissions/list-registered.js +1 -1
  56. package/dist/server-fns/admin-permissions/set-role-abilities.js +1 -1
  57. package/dist/server-fns/admin-permissions/who-has.js +1 -1
  58. package/dist/server-fns/admin-roles/create.js +1 -1
  59. package/dist/server-fns/admin-roles/delete.js +1 -1
  60. package/dist/server-fns/admin-roles/get.js +1 -1
  61. package/dist/server-fns/admin-roles/list.js +1 -1
  62. package/dist/server-fns/admin-roles/reorder.js +1 -1
  63. package/dist/server-fns/admin-roles/update.js +1 -1
  64. package/dist/server-fns/admin-users/create.js +1 -1
  65. package/dist/server-fns/admin-users/delete.js +1 -1
  66. package/dist/server-fns/admin-users/disable.js +1 -1
  67. package/dist/server-fns/admin-users/enable.js +1 -1
  68. package/dist/server-fns/admin-users/get-user-roles.js +1 -1
  69. package/dist/server-fns/admin-users/get.js +1 -1
  70. package/dist/server-fns/admin-users/list.js +1 -1
  71. package/dist/server-fns/admin-users/set-password.js +1 -1
  72. package/dist/server-fns/admin-users/set-user-roles.js +1 -1
  73. package/dist/server-fns/admin-users/update.js +1 -1
  74. package/dist/server-fns/ai/execute.js +1 -1
  75. package/dist/server-fns/auth/current-user.js +1 -1
  76. package/dist/server-fns/auth/sign-in.js +1 -1
  77. package/dist/server-fns/auth/sign-out.js +1 -2
  78. package/dist/server-fns/collections/audit.js +1 -1
  79. package/dist/server-fns/collections/copy-to-locale.js +1 -1
  80. package/dist/server-fns/collections/create.js +1 -1
  81. package/dist/server-fns/collections/delete-locale.js +1 -1
  82. package/dist/server-fns/collections/delete-outcome.d.ts +30 -0
  83. package/dist/server-fns/collections/delete-outcome.js +34 -0
  84. package/dist/server-fns/collections/delete.d.ts +1 -4
  85. package/dist/server-fns/collections/delete.js +3 -5
  86. package/dist/server-fns/collections/duplicate.js +1 -1
  87. package/dist/server-fns/collections/get.js +1 -1
  88. package/dist/server-fns/collections/history.js +1 -1
  89. package/dist/server-fns/collections/index.d.ts +1 -0
  90. package/dist/server-fns/collections/index.js +1 -0
  91. package/dist/server-fns/collections/list.js +1 -1
  92. package/dist/server-fns/collections/reindex.js +1 -1
  93. package/dist/server-fns/collections/reorder.js +1 -1
  94. package/dist/server-fns/collections/restore-version.js +1 -1
  95. package/dist/server-fns/collections/stats.js +1 -1
  96. package/dist/server-fns/collections/status.js +1 -1
  97. package/dist/server-fns/collections/tree-mutation.d.ts +46 -0
  98. package/dist/server-fns/collections/tree-mutation.js +109 -0
  99. package/dist/server-fns/collections/tree-read.d.ts +6 -0
  100. package/dist/server-fns/collections/tree-read.js +15 -0
  101. package/dist/server-fns/collections/tree.d.ts +5 -4
  102. package/dist/server-fns/collections/tree.js +16 -13
  103. package/dist/server-fns/collections/update.js +3 -2
  104. package/dist/server-fns/collections/upload.js +1 -1
  105. package/dist/server-fns/i18n/set-locale.js +1 -1
  106. package/dist/server-fns/preview/disable.js +1 -1
  107. package/dist/server-fns/preview/enable.js +1 -2
  108. package/dist/server-fns/preview/state.js +1 -1
  109. package/dist/vite/client-hook-boundary.d.ts +19 -0
  110. package/dist/vite/client-hook-boundary.js +20 -0
  111. package/dist/{integrations/byline-public-client.d.ts → vite/index.d.ts} +1 -2
  112. package/dist/vite/index.js +1 -0
  113. package/package.json +15 -14
  114. package/src/admin-shell/admin-activity/list.tsx +13 -3
  115. package/src/admin-shell/admin-roles/delete.tsx +2 -1
  116. package/src/admin-shell/admin-roles/list.tsx +2 -1
  117. package/src/admin-shell/admin-users/delete.tsx +3 -2
  118. package/src/admin-shell/admin-users/list.tsx +9 -8
  119. package/src/admin-shell/chrome/admin-app-bar.tsx +2 -1
  120. package/src/admin-shell/chrome/admin-menu-drawer.tsx +13 -8
  121. package/src/admin-shell/chrome/admin-menu-provider.tsx +2 -1
  122. package/src/admin-shell/chrome/dashboard.tsx +4 -3
  123. package/src/admin-shell/chrome/sign-in-page.tsx +3 -3
  124. package/src/admin-shell/collections/create.tsx +4 -3
  125. package/src/admin-shell/collections/document-history.tsx +5 -0
  126. package/src/admin-shell/collections/edit.tsx +20 -13
  127. package/src/admin-shell/collections/history.tsx +6 -5
  128. package/src/admin-shell/collections/list.tsx +8 -7
  129. package/src/admin-shell/collections/restore-version-modal.tsx +2 -1
  130. package/src/admin-shell/collections/tree-list.tsx +78 -22
  131. package/src/admin-shell/collections/view-menu.tsx +9 -8
  132. package/src/i18n/resolve-locale.ts +1 -1
  133. package/src/index.ts +5 -6
  134. package/src/integrations/abilities.tsx +14 -4
  135. package/src/integrations/host-bridge.ts +56 -0
  136. package/src/integrations/serve-uploads.ts +6 -0
  137. package/src/integrations/start-errors.test.node.ts +22 -0
  138. package/src/integrations/start-errors.ts +1 -0
  139. package/src/routes/admin-path.test.node.ts +129 -0
  140. package/src/routes/admin-path.ts +66 -0
  141. package/src/routes/auth-routes.test.node.ts +39 -0
  142. package/src/routes/create-admin-account-route.tsx +3 -2
  143. package/src/routes/create-admin-activity-route.tsx +3 -2
  144. package/src/routes/create-admin-dashboard-route.tsx +2 -1
  145. package/src/routes/create-admin-layout-route.tsx +4 -4
  146. package/src/routes/create-admin-permissions-route.tsx +3 -2
  147. package/src/routes/create-admin-role-edit-route.tsx +7 -3
  148. package/src/routes/create-admin-roles-list-route.tsx +3 -2
  149. package/src/routes/create-admin-user-edit-route.tsx +7 -3
  150. package/src/routes/create-admin-users-list-route.tsx +3 -2
  151. package/src/routes/create-collection-api-route.tsx +8 -4
  152. package/src/routes/create-collection-create-route.tsx +7 -3
  153. package/src/routes/create-collection-edit-route.tsx +7 -3
  154. package/src/routes/create-collection-history-route.tsx +8 -4
  155. package/src/routes/create-collection-list-route.tsx +3 -2
  156. package/src/routes/create-sign-in-route.tsx +9 -3
  157. package/src/routes/index.ts +11 -0
  158. package/src/routes/sign-in-path.test.node.ts +79 -0
  159. package/src/routes/sign-in-path.ts +36 -0
  160. package/src/server-fns/admin-account/change-password.ts +1 -1
  161. package/src/server-fns/admin-account/get.ts +1 -1
  162. package/src/server-fns/admin-account/update.ts +1 -1
  163. package/src/server-fns/admin-activity/get.ts +1 -1
  164. package/src/server-fns/admin-permissions/get-role-abilities.ts +1 -1
  165. package/src/server-fns/admin-permissions/list-registered.ts +1 -1
  166. package/src/server-fns/admin-permissions/set-role-abilities.ts +1 -1
  167. package/src/server-fns/admin-permissions/who-has.ts +1 -1
  168. package/src/server-fns/admin-roles/create.ts +1 -1
  169. package/src/server-fns/admin-roles/delete.ts +1 -1
  170. package/src/server-fns/admin-roles/get.ts +1 -1
  171. package/src/server-fns/admin-roles/list.ts +1 -1
  172. package/src/server-fns/admin-roles/reorder.ts +1 -1
  173. package/src/server-fns/admin-roles/update.ts +1 -1
  174. package/src/server-fns/admin-users/create.ts +1 -1
  175. package/src/server-fns/admin-users/delete.ts +1 -1
  176. package/src/server-fns/admin-users/disable.ts +1 -1
  177. package/src/server-fns/admin-users/enable.ts +1 -1
  178. package/src/server-fns/admin-users/get-user-roles.ts +1 -1
  179. package/src/server-fns/admin-users/get.ts +1 -1
  180. package/src/server-fns/admin-users/list.ts +1 -1
  181. package/src/server-fns/admin-users/set-password.ts +1 -1
  182. package/src/server-fns/admin-users/set-user-roles.ts +1 -1
  183. package/src/server-fns/admin-users/update.ts +1 -1
  184. package/src/server-fns/ai/execute.ts +1 -2
  185. package/src/server-fns/auth/current-user.ts +1 -1
  186. package/src/server-fns/auth/sign-in.ts +1 -1
  187. package/src/server-fns/auth/sign-out.ts +5 -3
  188. package/src/server-fns/collections/audit.ts +1 -1
  189. package/src/server-fns/collections/copy-to-locale.ts +1 -1
  190. package/src/server-fns/collections/create.ts +1 -1
  191. package/src/server-fns/collections/delete-locale.ts +1 -1
  192. package/src/server-fns/collections/delete-outcome.test.node.ts +72 -0
  193. package/src/server-fns/collections/delete-outcome.ts +80 -0
  194. package/src/server-fns/collections/delete.ts +3 -2
  195. package/src/server-fns/collections/duplicate.ts +1 -1
  196. package/src/server-fns/collections/get.ts +3 -1
  197. package/src/server-fns/collections/history.ts +1 -1
  198. package/src/server-fns/collections/index.ts +1 -0
  199. package/src/server-fns/collections/list.ts +1 -1
  200. package/src/server-fns/collections/reindex.ts +1 -1
  201. package/src/server-fns/collections/reorder.ts +1 -1
  202. package/src/server-fns/collections/restore-version.ts +1 -1
  203. package/src/server-fns/collections/stats.ts +2 -1
  204. package/src/server-fns/collections/status.ts +1 -1
  205. package/src/server-fns/collections/tree-mutation.test.node.ts +225 -0
  206. package/src/server-fns/collections/tree-mutation.ts +165 -0
  207. package/src/server-fns/collections/tree-read.test.node.ts +46 -0
  208. package/src/server-fns/collections/tree-read.ts +26 -0
  209. package/src/server-fns/collections/tree.ts +27 -11
  210. package/src/server-fns/collections/update.ts +4 -1
  211. package/src/server-fns/collections/upload.ts +1 -1
  212. package/src/server-fns/i18n/set-locale.ts +1 -1
  213. package/src/server-fns/preview/disable.ts +1 -1
  214. package/src/server-fns/preview/enable.ts +1 -2
  215. package/src/server-fns/preview/state.ts +1 -1
  216. package/src/vite/client-hook-boundary.test.node.ts +50 -0
  217. package/src/vite/client-hook-boundary.ts +45 -0
  218. package/src/vite/index.ts +9 -0
  219. package/dist/auth/auth-context.d.ts +0 -37
  220. package/dist/auth/auth-context.js +0 -57
  221. package/dist/auth/auth-cookies.d.ts +0 -34
  222. package/dist/auth/auth-cookies.js +0 -46
  223. package/dist/auth/preview-cookies.d.ts +0 -19
  224. package/dist/auth/preview-cookies.js +0 -26
  225. package/dist/integrations/byline-client.d.ts +0 -24
  226. package/dist/integrations/byline-client.js +0 -25
  227. package/dist/integrations/byline-public-client.js +0 -15
  228. package/dist/integrations/byline-viewer-client.d.ts +0 -20
  229. package/dist/integrations/byline-viewer-client.js +0 -39
  230. package/src/auth/auth-context.test.node.ts +0 -215
  231. package/src/auth/auth-context.ts +0 -124
  232. package/src/auth/auth-cookies.ts +0 -113
  233. package/src/auth/preview-cookies.ts +0 -73
  234. package/src/integrations/byline-client.ts +0 -66
  235. package/src/integrations/byline-public-client.ts +0 -53
  236. package/src/integrations/byline-viewer-client.ts +0 -99
@@ -7,6 +7,7 @@ import { Container, GripperVerticalIcon, IconButton, LoaderRing, PlusIcon, Searc
7
7
  import { DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
8
8
  import { SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
9
9
  import classnames from "classnames";
10
+ import { getAdminRoutePath } from "../../routes/admin-path.js";
10
11
  import { Link, useNavigate } from "../chrome/loose-router.js";
11
12
  import { RouterPager } from "../chrome/router-pager.js";
12
13
  import { SortAscendingIcon } from "../chrome/sort-icons.js";
@@ -157,7 +158,7 @@ const ListView = ({ data, columns, workflowStatuses, useAsTitle, orderable = fal
157
158
  delete params.page;
158
159
  params.query = query;
159
160
  navigate({
160
- to: '/admin/collections/$collection',
161
+ to: getAdminRoutePath('collections', '$collection'),
161
162
  params: {
162
163
  collection: data.included.collection.path
163
164
  },
@@ -170,7 +171,7 @@ const ListView = ({ data, columns, workflowStatuses, useAsTitle, orderable = fal
170
171
  delete params.page;
171
172
  delete params.query;
172
173
  navigate({
173
- to: '/admin/collections/$collection',
174
+ to: getAdminRoutePath('collections', '$collection'),
174
175
  params: {
175
176
  collection: data.included.collection.path
176
177
  },
@@ -184,7 +185,7 @@ const ListView = ({ data, columns, workflowStatuses, useAsTitle, orderable = fal
184
185
  if ('_all' === value) delete params.status;
185
186
  else params.status = value;
186
187
  navigate({
187
- to: '/admin/collections/$collection',
188
+ to: getAdminRoutePath('collections', '$collection'),
188
189
  params: {
189
190
  collection: data.included.collection.path
190
191
  },
@@ -197,7 +198,7 @@ const ListView = ({ data, columns, workflowStatuses, useAsTitle, orderable = fal
197
198
  delete params.page;
198
199
  params.page_size = Number.parseInt(value, 10);
199
200
  navigate({
200
- to: '/admin/collections/$collection',
201
+ to: getAdminRoutePath('collections', '$collection'),
201
202
  params: {
202
203
  collection: data.included.collection.path
203
204
  },
@@ -223,7 +224,7 @@ const ListView = ({ data, columns, workflowStatuses, useAsTitle, orderable = fal
223
224
  /*#__PURE__*/ jsx(IconButton, {
224
225
  "aria-label": t('collections.list.createAriaLabel'),
225
226
  render: /*#__PURE__*/ jsx(Link, {
226
- to: '/admin/collections/$collection/create',
227
+ to: getAdminRoutePath('collections', '$collection', 'create'),
227
228
  params: {
228
229
  collection: data.included.collection.path
229
230
  }
@@ -328,7 +329,7 @@ const ListView = ({ data, columns, workflowStatuses, useAsTitle, orderable = fal
328
329
  [list_module.cellCenter]: 'center' === column.align
329
330
  }),
330
331
  children: useAsTitle && column.fieldName === useAsTitle ? /*#__PURE__*/ jsx(Link, {
331
- to: '/admin/collections/$collection/$id',
332
+ to: getAdminRoutePath('collections', '$collection', '$id'),
332
333
  params: {
333
334
  collection: data.included.collection.path,
334
335
  id: document.id
@@ -371,7 +372,7 @@ const ListView = ({ data, columns, workflowStatuses, useAsTitle, orderable = fal
371
372
  [list_module.cellCenter]: 'center' === column.align
372
373
  }),
373
374
  children: useAsTitle && column.fieldName === useAsTitle ? /*#__PURE__*/ jsx(Link, {
374
- to: '/admin/collections/$collection/$id',
375
+ to: getAdminRoutePath('collections', '$collection', '$id'),
375
376
  params: {
376
377
  collection: data.included.collection.path,
377
378
  id: document.id
@@ -5,6 +5,7 @@ import { useRouter } from "@tanstack/react-router";
5
5
  import { useTranslation } from "@byline/i18n/react";
6
6
  import { Alert, Button, LoaderEllipsis, Modal } from "@byline/ui/react";
7
7
  import classnames from "classnames";
8
+ import { getAdminRoutePath } from "../../routes/admin-path.js";
8
9
  import { restoreDocumentVersion } from "../../server-fns/collections/index.js";
9
10
  import { useNavigate } from "../chrome/loose-router.js";
10
11
  import restore_version_modal_module from "./restore-version-modal.module.js";
@@ -29,7 +30,7 @@ function RestoreVersionModal({ collection, documentId, versionId, versionLabel,
29
30
  onClose();
30
31
  await router.invalidate();
31
32
  navigate({
32
- to: '/admin/collections/$collection/$id',
33
+ to: getAdminRoutePath('collections', '$collection', '$id'),
33
34
  params: {
34
35
  collection,
35
36
  id: documentId
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useEffect, useMemo, useState } from "react";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
3
  import { useRouter } from "@tanstack/react-router";
4
4
  import { StatusBadge, renderFormatted } from "@byline/admin/react";
5
5
  import { useTranslation } from "@byline/i18n/react";
@@ -7,6 +7,8 @@ import { Container, GripperVerticalIcon, IconButton, PlusIcon, Section, Table, u
7
7
  import { DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
8
8
  import { SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
9
9
  import classnames from "classnames";
10
+ import { getAdminRoutePath } from "../../routes/admin-path.js";
11
+ import { createAdminTreeMoveController, getAdminTreeMoveUiEffects, shouldSyncAdminTreeRows } from "../../server-fns/collections/tree-mutation.js";
10
12
  import { Link } from "../chrome/loose-router.js";
11
13
  import { TableHeadingCellSortable } from "../chrome/th-sortable.js";
12
14
  import { formatNumber } from "../chrome/utils.js";
@@ -17,9 +19,10 @@ function getColumnValue(row, fieldName) {
17
19
  if (row.fields && fieldName in row.fields) return row.fields[fieldName];
18
20
  return row[fieldName];
19
21
  }
20
- function SortableTreeRow({ id, depth, dragging, dragHandleLabel, children }) {
22
+ function SortableTreeRow({ id, dragging, disabled, dragHandleLabel, children }) {
21
23
  const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({
22
- id
24
+ id,
25
+ disabled
23
26
  });
24
27
  const style = {
25
28
  transform: transform ? `translate3d(0, ${transform.y}px, 0)` : void 0,
@@ -39,6 +42,7 @@ function SortableTreeRow({ id, depth, dragging, dragHandleLabel, children }) {
39
42
  className: classnames('byline-tree-list-drag-cell', tree_list_module.dragCell),
40
43
  children: /*#__PURE__*/ jsx("button", {
41
44
  type: "button",
45
+ disabled: disabled,
42
46
  className: classnames('byline-tree-list-drag-handle', tree_list_module.dragHandle),
43
47
  "aria-label": dragHandleLabel,
44
48
  ...attributes,
@@ -59,8 +63,12 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
59
63
  ]);
60
64
  const [localPlaced, setLocalPlaced] = useState(()=>rows.filter((r)=>!r.unplaced));
61
65
  const [isMoving, setIsMoving] = useState(false);
66
+ const [moveController] = useState(()=>createAdminTreeMoveController());
67
+ const preserveOptimisticForRows = useRef(null);
62
68
  useEffect(()=>{
63
- if (!isMoving) setLocalPlaced(rows.filter((r)=>!r.unplaced));
69
+ if (!shouldSyncAdminTreeRows(rows, preserveOptimisticForRows.current, isMoving)) return;
70
+ preserveOptimisticForRows.current = null;
71
+ setLocalPlaced(rows.filter((r)=>!r.unplaced));
64
72
  }, [
65
73
  rows,
66
74
  isMoving
@@ -89,10 +97,13 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
89
97
  setOverId(null);
90
98
  setOffsetLeft(0);
91
99
  };
92
- const handleDragStart = ({ active })=>setActiveId(String(active.id));
100
+ const handleDragStart = ({ active })=>{
101
+ if (!moveController.isMoving()) setActiveId(String(active.id));
102
+ };
93
103
  const handleDragMove = ({ delta })=>setOffsetLeft(delta.x);
94
104
  const handleDragOver = ({ over })=>setOverId(over ? String(over.id) : null);
95
105
  const handleDragEnd = async ({ active, over })=>{
106
+ if (moveController.isMoving()) return void resetDnd();
96
107
  const proj = null != over ? getTreeProjection(localPlaced, String(active.id), String(over.id), offsetLeft, INDENT) : null;
97
108
  resetDnd();
98
109
  if (!onMove || null == proj) return;
@@ -103,19 +114,24 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
103
114
  if (unchanged) return;
104
115
  setLocalPlaced(next);
105
116
  setIsMoving(true);
106
- try {
107
- await onMove({
117
+ const outcome = await moveController.execute(()=>onMove({
108
118
  documentId,
109
119
  parentDocumentId: proj.parentId,
110
120
  beforeDocumentId: proj.beforeId,
111
121
  afterDocumentId: proj.afterId
112
- });
113
- await router.invalidate();
114
- } catch {
122
+ }), ()=>router.invalidate());
123
+ if ('suppressed' === outcome.status) {
115
124
  setLocalPlaced(current);
125
+ setIsMoving(moveController.isMoving());
126
+ return;
127
+ }
128
+ const effects = getAdminTreeMoveUiEffects(outcome);
129
+ if (effects.rollback) setLocalPlaced(current);
130
+ if (null != effects.structuralFailure) {
131
+ const conflict = 'conflict' === effects.structuralFailure;
116
132
  toastManager.add({
117
- title: t('collections.list.reorderFailedToast'),
118
- description: t("collections.list.reorderFailedDescription"),
133
+ title: t(conflict ? 'collections.list.treeConflictToast' : 'collections.list.reorderFailedToast'),
134
+ description: t(conflict ? "collections.list.treeConflictDescription" : "collections.list.reorderFailedDescription"),
119
135
  data: {
120
136
  intent: 'danger',
121
137
  iconType: 'danger',
@@ -123,9 +139,29 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
123
139
  close: true
124
140
  }
125
141
  });
126
- } finally{
127
- setIsMoving(false);
128
142
  }
143
+ if (effects.committedHookWarning) toastManager.add({
144
+ title: t('collections.list.treeHookFailedToast'),
145
+ description: t("collections.list.treeHookFailedDescription"),
146
+ data: {
147
+ intent: 'warning',
148
+ iconType: 'warning',
149
+ icon: true,
150
+ close: true
151
+ }
152
+ });
153
+ if (effects.refreshWarning) toastManager.add({
154
+ title: t('collections.list.treeRefreshFailedToast'),
155
+ description: t("collections.list.treeRefreshFailedDescription"),
156
+ data: {
157
+ intent: 'warning',
158
+ iconType: 'warning',
159
+ icon: true,
160
+ close: true
161
+ }
162
+ });
163
+ if (effects.preserveOptimistic) preserveOptimisticForRows.current = rows;
164
+ setIsMoving(false);
129
165
  };
130
166
  const renderCells = (row, depth)=>columns.map((column)=>{
131
167
  const fieldName = column.fieldName;
@@ -147,7 +183,7 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
147
183
  children: "└─"
148
184
  }),
149
185
  /*#__PURE__*/ jsx(Link, {
150
- to: '/admin/collections/$collection/$id',
186
+ to: getAdminRoutePath('collections', '$collection', '$id'),
151
187
  params: {
152
188
  collection,
153
189
  id: row.id
@@ -183,7 +219,7 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
183
219
  /*#__PURE__*/ jsx(IconButton, {
184
220
  "aria-label": t('collections.list.createAriaLabel'),
185
221
  render: /*#__PURE__*/ jsx(Link, {
186
- to: '/admin/collections/$collection/create',
222
+ to: getAdminRoutePath('collections', '$collection', 'create'),
187
223
  params: {
188
224
  collection
189
225
  }
@@ -234,8 +270,8 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
234
270
  const depth = row.id === activeId && projection ? projection.depth : row.depth;
235
271
  return dndEnabled ? /*#__PURE__*/ jsx(SortableTreeRow, {
236
272
  id: row.id,
237
- depth: depth,
238
273
  dragging: row.id === activeId,
274
+ disabled: isMoving,
239
275
  dragHandleLabel: t('collections.list.dragHandleAriaLabel'),
240
276
  children: renderCells(row, depth)
241
277
  }, row.id) : /*#__PURE__*/ jsx(Table.Row, {
@@ -3,6 +3,7 @@ import { useEffect } from "react";
3
3
  import { useTranslation } from "@byline/i18n/react";
4
4
  import { Button, HistoryIcon, IconButton, Label, Select } from "@byline/ui/react";
5
5
  import classnames from "classnames";
6
+ import { getAdminRoutePath } from "../../routes/admin-path.js";
6
7
  import { useNavigate } from "../chrome/loose-router.js";
7
8
  import { PreviewLink } from "./preview-link.js";
8
9
  import view_menu_module from "./view-menu.module.js";
@@ -11,7 +12,7 @@ const ViewMenu = ({ collection, documentId, activeView, locale, depth, contentLo
11
12
  const { t } = useTranslation('byline-admin');
12
13
  useEffect(()=>{
13
14
  if ('edit' === activeView && 'all' === locale) navigate({
14
- to: '/admin/collections/$collection/$id',
15
+ to: getAdminRoutePath('collections', '$collection', '$id'),
15
16
  params: {
16
17
  collection,
17
18
  id: documentId
@@ -36,7 +37,7 @@ const ViewMenu = ({ collection, documentId, activeView, locale, depth, contentLo
36
37
  locale: value
37
38
  });
38
39
  if ('api' === activeView) navigate({
39
- to: '/admin/collections/$collection/$id/api',
40
+ to: getAdminRoutePath('collections', '$collection', '$id', 'api'),
40
41
  params: {
41
42
  collection,
42
43
  id: documentId
@@ -44,14 +45,14 @@ const ViewMenu = ({ collection, documentId, activeView, locale, depth, contentLo
44
45
  search: search
45
46
  });
46
47
  else 'history' === activeView ? navigate({
47
- to: '/admin/collections/$collection/$id/history',
48
+ to: getAdminRoutePath('collections', '$collection', '$id', 'history'),
48
49
  params: {
49
50
  collection,
50
51
  id: documentId
51
52
  },
52
53
  search: search
53
54
  }) : navigate({
54
- to: '/admin/collections/$collection/$id',
55
+ to: getAdminRoutePath('collections', '$collection', '$id'),
55
56
  params: {
56
57
  collection,
57
58
  id: documentId
@@ -64,7 +65,7 @@ const ViewMenu = ({ collection, documentId, activeView, locale, depth, contentLo
64
65
  const n = Number.parseInt(value, 10);
65
66
  const nextDepth = Number.isFinite(n) ? Math.max(0, Math.min(3, n)) : 0;
66
67
  navigate({
67
- to: '/admin/collections/$collection/$id/api',
68
+ to: getAdminRoutePath('collections', '$collection', '$id', 'api'),
68
69
  params: {
69
70
  collection,
70
71
  id: documentId
@@ -154,7 +155,7 @@ const ViewMenu = ({ collection, documentId, activeView, locale, depth, contentLo
154
155
  size: "xs",
155
156
  variant: 'history' === activeView ? 'filled' : 'text',
156
157
  onClick: ()=>navigate({
157
- to: '/admin/collections/$collection/$id/history',
158
+ to: getAdminRoutePath('collections', '$collection', '$id', 'history'),
158
159
  params: {
159
160
  collection,
160
161
  id: documentId
@@ -172,7 +173,7 @@ const ViewMenu = ({ collection, documentId, activeView, locale, depth, contentLo
172
173
  variant: 'edit' === activeView ? 'filled' : 'outlined',
173
174
  className: classnames('byline-view-menu-button', view_menu_module.button),
174
175
  onClick: ()=>navigate({
175
- to: '/admin/collections/$collection/$id',
176
+ to: getAdminRoutePath('collections', '$collection', '$id'),
176
177
  params: {
177
178
  collection,
178
179
  id: documentId
@@ -188,7 +189,7 @@ const ViewMenu = ({ collection, documentId, activeView, locale, depth, contentLo
188
189
  variant: 'api' === activeView ? 'filled' : 'outlined',
189
190
  className: classnames('byline-view-menu-button', view_menu_module.button),
190
191
  onClick: ()=>navigate({
191
- to: '/admin/collections/$collection/$id/api',
192
+ to: getAdminRoutePath('collections', '$collection', '$id', 'api'),
192
193
  params: {
193
194
  collection,
194
195
  id: documentId
@@ -1,7 +1,7 @@
1
1
  import { getRequestHeader } from "@tanstack/react-start/server";
2
2
  import { AuthError, AuthErrorCodes } from "@byline/auth";
3
+ import { getAdminRequestContext } from "@byline/client/server";
3
4
  import { resolveInterfaceLocale } from "@byline/i18n";
4
- import { getAdminRequestContext } from "../auth/auth-context.js";
5
5
  import { bylineCore } from "../integrations/byline-core.js";
6
6
  import { readAdminLocaleCookie } from "./locale-cookie.js";
7
7
  async function resolveRequestLocale(options) {
package/dist/index.d.ts CHANGED
@@ -18,14 +18,13 @@
18
18
  * - `@byline/host-tanstack-start/server-fns/<module>` — TanStack Start
19
19
  * server functions for each admin module (admin-account, admin-roles,
20
20
  * admin-users, admin-permissions, auth, collections).
21
- * - `@byline/host-tanstack-start/auth/auth-context` — request-scoped
22
- * `RequestContext` resolution that reads session cookies, refreshes
23
- * transparently, and surfaces `ERR_UNAUTHENTICATED` to callers.
24
21
  * - `@byline/host-tanstack-start/integrations/*` — host-side adapters
25
22
  * binding TanStack Start primitives to the framework-neutral
26
- * contracts in `@byline/ui` and `@byline/client`
27
- * (`bylineFieldServices`, `bylineAdminServices`, the admin
28
- * `BylineClient` singleton).
23
+ * contracts in `@byline/ui`, `@byline/core`, and `@byline/client`
24
+ * (`bylineFieldServices`, `bylineAdminServices`, and `host-bridge` —
25
+ * the `HostRequestBridge` implementation behind the
26
+ * `@byline/client/server` getters; request-context resolution and the
27
+ * client singletons themselves live in `@byline/client/server`).
29
28
  * - `@byline/host-tanstack-start/admin-shell/{chrome,collections,...}` —
30
29
  * router-coupled admin UI: shared shell chrome (menu drawer, app bar,
31
30
  * route-error, breadcrumbs, etc.) plus per-area page containers.
@@ -1,16 +1,17 @@
1
1
  import { useRouteContext } from "@tanstack/react-router";
2
- const ADMIN_ROUTE_ID = '/_byline/admin';
3
- function useAbility(ability) {
4
- const { user } = useRouteContext({
5
- from: ADMIN_ROUTE_ID
2
+ import { getAdminRouteId } from "../routes/admin-path.js";
3
+ function useAbilityRouteContext() {
4
+ return useRouteContext({
5
+ from: getAdminRouteId()
6
6
  });
7
+ }
8
+ function useAbility(ability) {
9
+ const { user } = useAbilityRouteContext();
7
10
  if (user.is_super_admin) return true;
8
11
  return user.abilities.includes(ability);
9
12
  }
10
13
  function useAbilities() {
11
- const { user } = useRouteContext({
12
- from: ADMIN_ROUTE_ID
13
- });
14
+ const { user } = useAbilityRouteContext();
14
15
  const has = (ability)=>user.is_super_admin || user.abilities.includes(ability);
15
16
  const hasAny = (abilities)=>user.is_super_admin || abilities.some((key)=>user.abilities.includes(key));
16
17
  return {
@@ -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
+ /**
9
+ * Register the TanStack Start bridge. Safe to call any number of times;
10
+ * exported for hosts that want registration to be explicit in their
11
+ * server config rather than relying on a side-effect import.
12
+ */
13
+ export declare function registerTanstackStartHostBridge(): void;
@@ -0,0 +1,22 @@
1
+ import { getCookie, getRequest, setCookie } from "@tanstack/react-start/server";
2
+ import { registerHostRequestBridge } from "@byline/core";
3
+ const tanstackStartRequestBridge = {
4
+ getRequest () {
5
+ try {
6
+ return getRequest();
7
+ } catch {
8
+ return;
9
+ }
10
+ },
11
+ getCookie (name) {
12
+ return getCookie(name);
13
+ },
14
+ setCookie (name, value, options) {
15
+ setCookie(name, value, options);
16
+ }
17
+ };
18
+ function registerTanstackStartHostBridge() {
19
+ registerHostRequestBridge(tanstackStartRequestBridge);
20
+ }
21
+ registerTanstackStartHostBridge();
22
+ export { registerTanstackStartHostBridge };
@@ -5,6 +5,7 @@
5
5
  *
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
+ import './host-bridge.js';
8
9
  export interface UploadsHandlerOptions {
9
10
  /**
10
11
  * URL prefix to match. Trailing slash required. Default `'/uploads/'`.
@@ -1,5 +1,6 @@
1
1
  import { readFile, stat } from "node:fs/promises";
2
2
  import { resolve } from "node:path";
3
+ import "./host-bridge.js";
3
4
  const DEFAULT_MIME = {
4
5
  '.avif': 'image/avif',
5
6
  '.webp': 'image/webp',
@@ -4,7 +4,8 @@ const CODED_ERROR_NAMES = new Set([
4
4
  'AdminPermissionsError',
5
5
  'AdminRolesError',
6
6
  'AdminUsersError',
7
- 'AuthError'
7
+ 'AuthError',
8
+ 'BylineError'
8
9
  ]);
9
10
  class BylineCodedError extends Error {
10
11
  constructor(payload){
@@ -0,0 +1,22 @@
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
+ /** Build an admin URL or parameterized TanStack route from client-safe config. */
9
+ export declare function getAdminRoutePath(...segments: ReadonlyArray<string | number>): string;
10
+ /** Build the matching pathless-group route ID used by generated host route trees. */
11
+ export declare function getAdminRouteId(...segments: ReadonlyArray<string | number>): string;
12
+ /** True when a pathname is the target route or one of its segment-delimited descendants. */
13
+ export declare function isRoutePathWithin(pathname: string, target: string): boolean;
14
+ /**
15
+ * Accept an untrusted callback only when it is an unencoded, same-origin path
16
+ * inside the configured admin mount.
17
+ */
18
+ export declare function resolveAdminCallbackPath(value: unknown): string | undefined;
19
+ /** Resolve an untrusted callback or fall back to the configured admin dashboard. */
20
+ export declare function resolveAdminSignInRedirect(value: unknown): string;
21
+ /** Match the admin root exactly and admin child entries by pathname prefix. */
22
+ export declare function isAdminRoutePathActive(pathname: string, ...segments: ReadonlyArray<string>): boolean;
@@ -0,0 +1,35 @@
1
+ import { getClientConfig, normalizeRootRelativeRedirect } from "@byline/core";
2
+ function getAdminRoutePath(...segments) {
3
+ const configuredBase = getClientConfig().routes.admin;
4
+ const normalizedBase = configuredBase.replace(/^\/+|\/+$/g, '');
5
+ const base = normalizedBase ? `/${normalizedBase}` : '/';
6
+ const suffix = segments.map((segment)=>String(segment).replace(/^\/+|\/+$/g, '')).filter(Boolean).join('/');
7
+ if (!suffix) return base;
8
+ return '/' === base ? `/${suffix}` : `${base}/${suffix}`;
9
+ }
10
+ function getAdminRouteId(...segments) {
11
+ return `/_byline${getAdminRoutePath(...segments)}`;
12
+ }
13
+ function isRoutePathWithin(pathname, target) {
14
+ const current = pathname.length > 1 ? pathname.replace(/\/+$/, '') : pathname;
15
+ const base = target.length > 1 ? target.replace(/\/+$/, '') : target;
16
+ return current === base || ('/' === base ? current.startsWith('/') : current.startsWith(`${base}/`));
17
+ }
18
+ function resolveAdminCallbackPath(value) {
19
+ if ('string' != typeof value) return;
20
+ const normalized = normalizeRootRelativeRedirect(value);
21
+ if (!normalized) return;
22
+ const url = new URL(normalized, 'https://byline.invalid');
23
+ if (!isRoutePathWithin(url.pathname, getAdminRoutePath())) return;
24
+ return `${url.pathname}${url.search}${url.hash}`;
25
+ }
26
+ function resolveAdminSignInRedirect(value) {
27
+ return resolveAdminCallbackPath(value) ?? getAdminRoutePath();
28
+ }
29
+ function isAdminRoutePathActive(pathname, ...segments) {
30
+ const target = getAdminRoutePath(...segments);
31
+ const current = pathname.length > 1 ? pathname.replace(/\/+$/, '') : pathname;
32
+ if (0 === segments.length) return current === target;
33
+ return isRoutePathWithin(current, target);
34
+ }
35
+ export { getAdminRouteId, getAdminRoutePath, isAdminRoutePathActive, isRoutePathWithin, resolveAdminCallbackPath, resolveAdminSignInRedirect };
@@ -5,6 +5,7 @@ import { useTranslation } from "@byline/i18n/react";
5
5
  import { Container, Section } from "@byline/ui/react";
6
6
  import { BreadcrumbsClient } from "../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js";
7
7
  import { getAccount } from "../server-fns/admin-account/index.js";
8
+ import { getAdminRoutePath } from "./admin-path.js";
8
9
  function displayNameFor(account) {
9
10
  const parts = [
10
11
  account.given_name,
@@ -31,11 +32,11 @@ function createAdminAccountRoute(path) {
31
32
  breadcrumbs: [
32
33
  {
33
34
  label: t('chrome.menu.dashboard'),
34
- href: '/admin'
35
+ href: getAdminRoutePath()
35
36
  },
36
37
  {
37
38
  label: t('chrome.account'),
38
- href: '/admin/account'
39
+ href: getAdminRoutePath('account')
39
40
  }
40
41
  ]
41
42
  }),
@@ -5,6 +5,7 @@ import { z } from "zod";
5
5
  import { ActivitySystemView } from "../admin-shell/admin-activity/list.js";
6
6
  import { BreadcrumbsClient } from "../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js";
7
7
  import { getSystemActivityLog } from "../server-fns/admin-activity/index.js";
8
+ import { getAdminRoutePath } from "./admin-path.js";
8
9
  const searchSchema = z.object({
9
10
  page: z.coerce.number().int().min(1).optional(),
10
11
  page_size: z.coerce.number().int().min(1).max(100).optional(),
@@ -51,11 +52,11 @@ function createAdminActivityRoute(path) {
51
52
  breadcrumbs: [
52
53
  {
53
54
  label: t('chrome.menu.dashboard'),
54
- href: '/admin'
55
+ href: getAdminRoutePath()
55
56
  },
56
57
  {
57
58
  label: t('activity.title'),
58
- href: '/admin/activity'
59
+ href: getAdminRoutePath('activity')
59
60
  }
60
61
  ]
61
62
  }),
@@ -5,6 +5,7 @@ import { useTranslation } from "@byline/i18n/react";
5
5
  import { BreadcrumbsClient } from "../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js";
6
6
  import { AdminDashboard } from "../admin-shell/chrome/dashboard.js";
7
7
  import { getCollectionStats } from "../server-fns/collections/index.js";
8
+ import { getAdminRoutePath } from "./admin-path.js";
8
9
  function createAdminDashboardRoute(path) {
9
10
  const Route = createFileRoute(path)({
10
11
  loader: async ()=>{
@@ -30,7 +31,7 @@ function createAdminDashboardRoute(path) {
30
31
  breadcrumbs: [
31
32
  {
32
33
  label: t('chrome.menu.dashboard'),
33
- href: '/admin'
34
+ href: getAdminRoutePath()
34
35
  }
35
36
  ]
36
37
  }),
@@ -6,7 +6,7 @@
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
8
  interface AdminLayoutOpts {
9
- /** Path users are redirected to when unauthenticated. Defaults to `/sign-in`. */
9
+ /** @deprecated Configure `routes.signIn`; an override must resolve to the same path. */
10
10
  signInPath?: string;
11
11
  }
12
12
  export declare function createAdminLayoutRoute(path: string, opts?: AdminLayoutOpts): any;
@@ -20,10 +20,12 @@ import { BylineAiAdminProvider } from "../integrations/byline-ai.js";
20
20
  import { bylineFieldServices } from "../integrations/byline-field-services.js";
21
21
  import { getCurrentAdminUser } from "../server-fns/auth/index.js";
22
22
  import { getActiveLocaleFn, setInterfaceLocaleFn } from "../server-fns/i18n/index.js";
23
+ import { createSignInRoutePathResolver } from "./sign-in-path.js";
23
24
  function createAdminLayoutRoute(path, opts = {}) {
24
- const signInPath = opts.signInPath ?? '/sign-in';
25
+ const resolveSignInPath = createSignInRoutePathResolver(opts.signInPath);
25
26
  const Route = createFileRoute(path)({
26
27
  beforeLoad: async ({ location })=>{
28
+ const signInPath = resolveSignInPath();
27
29
  try {
28
30
  const user = await getCurrentAdminUser();
29
31
  const activeLocale = await getActiveLocaleFn();
@@ -4,6 +4,7 @@ import { AbilitiesInspector } from "@byline/admin/admin-permissions/components/i
4
4
  import { useTranslation } from "@byline/i18n/react";
5
5
  import { BreadcrumbsClient } from "../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js";
6
6
  import { listRegisteredAbilities } from "../server-fns/admin-permissions/index.js";
7
+ import { getAdminRoutePath } from "./admin-path.js";
7
8
  function createAdminPermissionsRoute(path) {
8
9
  const Route = createFileRoute(path)({
9
10
  loader: async ()=>{
@@ -21,11 +22,11 @@ function createAdminPermissionsRoute(path) {
21
22
  breadcrumbs: [
22
23
  {
23
24
  label: t('chrome.menu.dashboard'),
24
- href: '/admin'
25
+ href: getAdminRoutePath()
25
26
  },
26
27
  {
27
28
  label: t('chrome.menu.permissions'),
28
- href: '/admin/permissions'
29
+ href: getAdminRoutePath('permissions')
29
30
  }
30
31
  ]
31
32
  }),