@byline/host-tanstack-start 4.19.0 → 5.0.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 (142) hide show
  1. package/dist/admin-shell/collections/edit.d.ts +1 -1
  2. package/dist/admin-shell/collections/edit.js +151 -31
  3. package/dist/admin-shell/collections/history.js +4 -2
  4. package/dist/admin-shell/collections/list.js +30 -6
  5. package/dist/admin-shell/collections/restore-version-modal.d.ts +3 -1
  6. package/dist/admin-shell/collections/restore-version-modal.js +9 -4
  7. package/dist/admin-shell/collections/tree-list.js +16 -6
  8. package/dist/admin-shell/collections/version-history.d.ts +2 -1
  9. package/dist/admin-shell/collections/version-history.js +11 -2
  10. package/dist/admin-shell/document-mutation-notice.d.ts +6 -0
  11. package/dist/admin-shell/document-mutation-notice.js +53 -0
  12. package/dist/admin-shell/document-mutation-state.d.ts +22 -0
  13. package/dist/admin-shell/document-mutation-state.js +71 -0
  14. package/dist/admin-shell/document-mutation-state.test.d.ts +1 -0
  15. package/dist/admin-shell/scheduled-publications/list.js +15 -5
  16. package/dist/admin-shell/singletons/history.js +4 -2
  17. package/dist/admin-shell/singletons/view.d.ts +1 -1
  18. package/dist/admin-shell/singletons/view.js +98 -19
  19. package/dist/integrations/byline-field-services.js +2 -9
  20. package/dist/routes/create-collection-edit-route.js +1 -1
  21. package/dist/routes/create-collection-list-route.d.ts +0 -7
  22. package/dist/routes/create-collection-list-route.js +7 -9
  23. package/dist/routes/create-singleton-route.d.ts +2 -0
  24. package/dist/routes/create-singleton-route.js +4 -3
  25. package/dist/server-fns/collections/copy-to-locale.d.ts +2 -7
  26. package/dist/server-fns/collections/copy-to-locale.js +4 -2
  27. package/dist/server-fns/collections/create.d.ts +1 -7
  28. package/dist/server-fns/collections/create.js +5 -3
  29. package/dist/server-fns/collections/delete-locale.d.ts +2 -7
  30. package/dist/server-fns/collections/delete-locale.js +4 -2
  31. package/dist/server-fns/collections/delete-outcome.d.ts +7 -3
  32. package/dist/server-fns/collections/delete-outcome.js +4 -0
  33. package/dist/server-fns/collections/delete.d.ts +2 -7
  34. package/dist/server-fns/collections/delete.js +5 -3
  35. package/dist/server-fns/collections/duplicate.d.ts +2 -7
  36. package/dist/server-fns/collections/duplicate.js +5 -3
  37. package/dist/server-fns/collections/get.d.ts +1 -7
  38. package/dist/server-fns/collections/get.js +5 -4
  39. package/dist/server-fns/collections/list.d.ts +0 -7
  40. package/dist/server-fns/collections/list.js +11 -3
  41. package/dist/server-fns/collections/reorder.d.ts +7 -8
  42. package/dist/server-fns/collections/reorder.js +20 -76
  43. package/dist/server-fns/collections/restore-version.d.ts +3 -7
  44. package/dist/server-fns/collections/restore-version.js +5 -2
  45. package/dist/server-fns/collections/save-outcome.d.ts +1 -0
  46. package/dist/server-fns/collections/save-outcome.js +1 -0
  47. package/dist/server-fns/collections/scheduled-publication.d.ts +49 -9
  48. package/dist/server-fns/collections/scheduled-publication.js +31 -21
  49. package/dist/server-fns/collections/status.d.ts +8 -7
  50. package/dist/server-fns/collections/status.js +13 -5
  51. package/dist/server-fns/collections/tree-mutation.d.ts +7 -6
  52. package/dist/server-fns/collections/tree-mutation.js +17 -5
  53. package/dist/server-fns/collections/tree.d.ts +14 -8
  54. package/dist/server-fns/collections/tree.js +21 -17
  55. package/dist/server-fns/collections/update.d.ts +12 -11
  56. package/dist/server-fns/collections/update.js +34 -20
  57. package/dist/server-fns/collections/upload.d.ts +1 -0
  58. package/dist/server-fns/collections/upload.js +3 -2
  59. package/dist/server-fns/document-mutation-errors.d.ts +5 -0
  60. package/dist/server-fns/document-mutation-errors.js +50 -0
  61. package/dist/server-fns/editable-revision.d.ts +9 -0
  62. package/dist/server-fns/editable-revision.js +11 -0
  63. package/dist/server-fns/singleton-document-read.d.ts +1 -1
  64. package/dist/server-fns/singleton-document-read.js +7 -3
  65. package/dist/server-fns/singletons/cancel-scheduled-publish.d.ts +6 -8
  66. package/dist/server-fns/singletons/cancel-scheduled-publish.js +4 -1
  67. package/dist/server-fns/singletons/change-status.d.ts +2 -7
  68. package/dist/server-fns/singletons/change-status.js +4 -1
  69. package/dist/server-fns/singletons/confirm-scheduled-publish.d.ts +5 -8
  70. package/dist/server-fns/singletons/confirm-scheduled-publish.js +4 -2
  71. package/dist/server-fns/singletons/copy-to-locale.d.ts +2 -7
  72. package/dist/server-fns/singletons/copy-to-locale.js +4 -2
  73. package/dist/server-fns/singletons/get.d.ts +4 -4
  74. package/dist/server-fns/singletons/restore-version.d.ts +2 -7
  75. package/dist/server-fns/singletons/restore-version.js +6 -3
  76. package/dist/server-fns/singletons/schedule-publish.d.ts +5 -8
  77. package/dist/server-fns/singletons/schedule-publish.js +4 -2
  78. package/dist/server-fns/singletons/unpublish.d.ts +2 -7
  79. package/dist/server-fns/singletons/unpublish.js +4 -1
  80. package/dist/server-fns/singletons/update.d.ts +4 -11
  81. package/dist/server-fns/singletons/update.js +5 -4
  82. package/dist/server-fns/structural-receipt.d.ts +4 -0
  83. package/dist/server-fns/structural-receipt.js +31 -0
  84. package/package.json +11 -11
  85. package/src/admin-shell/collections/edit.tsx +173 -54
  86. package/src/admin-shell/collections/history.tsx +11 -2
  87. package/src/admin-shell/collections/list.tsx +22 -6
  88. package/src/admin-shell/collections/restore-version-modal.tsx +12 -3
  89. package/src/admin-shell/collections/save-navigation.test.tsx +156 -8
  90. package/src/admin-shell/collections/tree-list.tsx +16 -6
  91. package/src/admin-shell/collections/version-history.tsx +13 -3
  92. package/src/admin-shell/document-mutation-notice.tsx +45 -0
  93. package/src/admin-shell/document-mutation-state.test.tsx +146 -0
  94. package/src/admin-shell/document-mutation-state.ts +95 -0
  95. package/src/admin-shell/scheduled-publications/list.tsx +16 -6
  96. package/src/admin-shell/singletons/history.test.tsx +3 -1
  97. package/src/admin-shell/singletons/history.tsx +10 -2
  98. package/src/admin-shell/singletons/view.test.tsx +59 -18
  99. package/src/admin-shell/singletons/view.tsx +110 -29
  100. package/src/integrations/byline-field-services.ts +2 -3
  101. package/src/routes/create-collection-edit-route.tsx +1 -0
  102. package/src/routes/create-collection-list-route.tsx +13 -2
  103. package/src/routes/create-singleton-route.test.node.ts +10 -2
  104. package/src/routes/create-singleton-route.tsx +6 -4
  105. package/src/server-fns/collections/copy-to-locale.ts +41 -36
  106. package/src/server-fns/collections/create.ts +54 -50
  107. package/src/server-fns/collections/delete-locale.ts +41 -32
  108. package/src/server-fns/collections/delete-outcome.test.node.ts +16 -0
  109. package/src/server-fns/collections/delete-outcome.ts +27 -16
  110. package/src/server-fns/collections/delete.ts +44 -38
  111. package/src/server-fns/collections/duplicate.ts +38 -32
  112. package/src/server-fns/collections/get.ts +8 -4
  113. package/src/server-fns/collections/list.ts +8 -3
  114. package/src/server-fns/collections/reorder.ts +32 -124
  115. package/src/server-fns/collections/restore-version.ts +47 -39
  116. package/src/server-fns/collections/revision-input.test.node.ts +108 -0
  117. package/src/server-fns/collections/save-outcome.test.node.ts +3 -0
  118. package/src/server-fns/collections/save-outcome.ts +2 -0
  119. package/src/server-fns/collections/scheduled-publication.ts +138 -111
  120. package/src/server-fns/collections/status.ts +86 -64
  121. package/src/server-fns/collections/tree-mutation.test.node.ts +87 -29
  122. package/src/server-fns/collections/tree-mutation.ts +28 -11
  123. package/src/server-fns/collections/tree.ts +150 -122
  124. package/src/server-fns/collections/update.ts +110 -86
  125. package/src/server-fns/collections/upload-singleton.test.node.ts +3 -7
  126. package/src/server-fns/collections/upload.ts +81 -77
  127. package/src/server-fns/document-mutation-errors.ts +67 -0
  128. package/src/server-fns/document-mutation-transport.test.node.ts +211 -0
  129. package/src/server-fns/editable-revision.test.node.ts +23 -0
  130. package/src/server-fns/editable-revision.ts +18 -0
  131. package/src/server-fns/singleton-document-read.ts +7 -3
  132. package/src/server-fns/singletons/cancel-scheduled-publish.ts +10 -3
  133. package/src/server-fns/singletons/change-status.ts +10 -3
  134. package/src/server-fns/singletons/confirm-scheduled-publish.ts +12 -6
  135. package/src/server-fns/singletons/copy-to-locale.ts +20 -15
  136. package/src/server-fns/singletons/get.ts +3 -3
  137. package/src/server-fns/singletons/restore-version.ts +17 -12
  138. package/src/server-fns/singletons/schedule-publish.ts +18 -7
  139. package/src/server-fns/singletons/singletons.test.node.ts +63 -25
  140. package/src/server-fns/singletons/unpublish.ts +10 -3
  141. package/src/server-fns/singletons/update.ts +21 -16
  142. package/src/server-fns/structural-receipt.ts +41 -0
@@ -2,7 +2,7 @@
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { useRouter } from "@tanstack/react-router";
4
4
  import { FormRenderer } from "@byline/admin/react";
5
- import { ErrorCodes, getDefaultStatus, getWorkflow, getWorkflowStatuses, validateStatusTransition } from "@byline/core";
5
+ import { getDefaultStatus, getWorkflow, getWorkflowStatuses, validateStatusTransition } from "@byline/core";
6
6
  import { useTranslation } from "@byline/i18n/react";
7
7
  import { Container, Section, useToastManager } from "@byline/ui/react";
8
8
  import { getAdminRoutePath } from "../../routes/admin-path.js";
@@ -10,11 +10,11 @@ import { hasCommittedDocumentHookFailure } from "../../server-fns/collections/in
10
10
  import { cancelSingletonScheduledPublish, changeSingletonStatus, confirmSingletonScheduledPublish, copySingletonToLocale, scheduleSingletonPublish, unpublishSingleton, updateSingleton } from "../../server-fns/singletons/index.js";
11
11
  import { useNavigate } from "../chrome/loose-router.js";
12
12
  import { useTanStackNavigationGuard } from "../collections/tanstack-navigation-guard.js";
13
+ import { useDocumentMutationState } from "../document-mutation-state.js";
13
14
  import { SingletonViewMenu } from "./view-menu.js";
14
- function errorCode(error) {
15
- return 'string' == typeof error?.code ? error.code : null;
16
- }
17
- function SingletonView({ singletonDefinition, adminConfig, document, initialData, locale, contentLocales, defaultContentLocale }) {
15
+ function SingletonView({ singletonDefinition, adminConfig, document: loadedDocument, initialData, locale, contentLocales, defaultContentLocale }) {
16
+ const mutation = useDocumentMutationState(loadedDocument);
17
+ const document = mutation.document ?? null;
18
18
  const router = useRouter();
19
19
  const navigate = useNavigate();
20
20
  const toastManager = useToastManager();
@@ -55,14 +55,20 @@ function SingletonView({ singletonDefinition, adminConfig, document, initialData
55
55
  };
56
56
  const handleSubmit = async ({ data })=>{
57
57
  try {
58
+ mutation.assertWritable();
58
59
  const result = await updateSingleton({
59
60
  data: {
60
61
  singleton: path,
61
62
  data,
62
63
  locale: locale ?? defaultContentLocale,
63
- expectedVersionId: document?.versionId
64
+ ...null == document ? {
65
+ expectedState: 'empty'
66
+ } : {
67
+ expectedRevision: mutation.expectedRevision()
68
+ }
64
69
  }
65
70
  });
71
+ mutation.adopt(result);
66
72
  if (null != document) notifyScheduleSuspended();
67
73
  if (hasCommittedDocumentHookFailure(result)) notifyCommittedHookFailure();
68
74
  else toast(t('singletons.edit.updateTitle', {
@@ -72,8 +78,14 @@ function SingletonView({ singletonDefinition, adminConfig, document, initialData
72
78
  }), 'success');
73
79
  await reload();
74
80
  } catch (err) {
75
- const code = errorCode(err);
76
- const description = code === ErrorCodes.CONFLICT ? t("singletons.edit.conflictDescription") : code === ErrorCodes.NOT_FOUND ? t("singletons.edit.notConfiguredDescription") : t("singletons.edit.updateFailedDescription", {
81
+ const handled = mutation.report(err);
82
+ if ('blocked' === handled) throw err;
83
+ if ('committed' === handled) {
84
+ notifyCommittedHookFailure();
85
+ await reload();
86
+ return;
87
+ }
88
+ const description = t("singletons.edit.updateFailedDescription", {
77
89
  label: label.toLowerCase()
78
90
  });
79
91
  toast(t('singletons.edit.updateTitle', {
@@ -84,12 +96,15 @@ function SingletonView({ singletonDefinition, adminConfig, document, initialData
84
96
  };
85
97
  const handleStatusChange = async (status)=>{
86
98
  try {
87
- await changeSingletonStatus({
99
+ mutation.assertWritable();
100
+ const result = await changeSingletonStatus({
88
101
  data: {
102
+ expectedRevision: mutation.expectedRevision(),
89
103
  singleton: path,
90
104
  status
91
105
  }
92
106
  });
107
+ mutation.adopt(result);
93
108
  toast(t('collections.edit.statusUpdateTitle', {
94
109
  label
95
110
  }), t("collections.edit.statusChangedDescription", {
@@ -97,44 +112,64 @@ function SingletonView({ singletonDefinition, adminConfig, document, initialData
97
112
  }), 'success');
98
113
  await reload();
99
114
  } catch (err) {
115
+ const handled = mutation.report(err);
116
+ if ('blocked' === handled) throw err;
117
+ if ('committed' === handled) {
118
+ notifyCommittedHookFailure();
119
+ await reload();
120
+ return;
121
+ }
100
122
  toast(t('collections.edit.statusUpdateTitle', {
101
123
  label
102
124
  }), t("collections.edit.statusChangeFailedDescription", {
103
- message: err.message
125
+ message: t('documentConcurrency.failed')
104
126
  }), 'danger');
105
127
  throw err;
106
128
  }
107
129
  };
108
130
  const handleUnpublish = async ()=>{
109
131
  try {
110
- await unpublishSingleton({
132
+ mutation.assertWritable();
133
+ const result = await unpublishSingleton({
111
134
  data: {
135
+ expectedRevision: mutation.expectedRevision(),
112
136
  singleton: path
113
137
  }
114
138
  });
139
+ mutation.adopt(result);
115
140
  toast(t('collections.edit.unpublishTitle', {
116
141
  label
117
142
  }), t("collections.edit.unpublishedDescription"), 'success');
118
143
  await reload();
119
144
  } catch (err) {
145
+ const handled = mutation.report(err);
146
+ if ('blocked' === handled) throw err;
147
+ if ('committed' === handled) {
148
+ notifyCommittedHookFailure();
149
+ await reload();
150
+ return;
151
+ }
120
152
  toast(t('collections.edit.unpublishTitle', {
121
153
  label
122
154
  }), t("collections.edit.unpublishFailedDescription", {
123
- message: err.message
155
+ message: t('documentConcurrency.failed')
124
156
  }), 'danger');
125
157
  throw err;
126
158
  }
127
159
  };
128
160
  const handleCopyToLocale = async ({ targetLocale, overwrite })=>{
129
161
  try {
162
+ mutation.assertWritable();
130
163
  const result = await copySingletonToLocale({
131
164
  data: {
165
+ expectedRevision: mutation.expectedRevision(),
132
166
  singleton: path,
133
167
  sourceLocale: locale ?? defaultContentLocale,
134
168
  targetLocale,
135
169
  overwrite
136
170
  }
137
171
  });
172
+ mutation.adopt(result);
138
173
  const sourceLocale = locale ?? defaultContentLocale;
139
174
  const sourceLabel = contentLocales.find((entry)=>entry.code === sourceLocale)?.label ?? sourceLocale;
140
175
  const targetLabel = contentLocales.find((entry)=>entry.code === targetLocale)?.label ?? targetLocale;
@@ -156,62 +191,106 @@ function SingletonView({ singletonDefinition, adminConfig, document, initialData
156
191
  }
157
192
  });
158
193
  } catch (err) {
194
+ const handled = mutation.report(err);
195
+ if ('blocked' === handled) throw err;
196
+ if ('committed' === handled) {
197
+ notifyCommittedHookFailure();
198
+ await reload();
199
+ return;
200
+ }
159
201
  toast(t('collections.edit.copyToLocaleTitle', {
160
202
  label
161
203
  }), t("collections.edit.copyFailedDescription", {
162
- message: err.message
204
+ message: t('documentConcurrency.failed')
163
205
  }), 'danger');
164
206
  throw err;
165
207
  }
166
208
  };
167
209
  const handleSchedulePublication = async ({ publishAt })=>{
168
210
  try {
169
- await scheduleSingletonPublish({
211
+ mutation.assertWritable();
212
+ const result = await scheduleSingletonPublish({
170
213
  data: {
214
+ expectedRevision: mutation.expectedRevision(),
171
215
  singleton: path,
172
216
  publishAt,
173
217
  expectedVersionId: String(document?.versionId)
174
218
  }
175
219
  });
220
+ mutation.adopt(result);
176
221
  toast(t('scheduledPublication.toast.scheduledTitle'), t("scheduledPublication.toast.scheduledDescription"), 'success');
177
222
  await reload();
178
223
  } catch (err) {
179
- toast(t('scheduledPublication.toast.failedTitle'), err.message, 'danger');
224
+ const handled = mutation.report(err);
225
+ if ('blocked' === handled) throw err;
226
+ if ('committed' === handled) {
227
+ notifyCommittedHookFailure();
228
+ await reload();
229
+ return;
230
+ }
231
+ toast(t('scheduledPublication.toast.failedTitle'), t('documentConcurrency.failed'), 'danger');
180
232
  throw err;
181
233
  }
182
234
  };
183
235
  const handleConfirmScheduledPublication = async ()=>{
184
236
  try {
185
- await confirmSingletonScheduledPublish({
237
+ mutation.assertWritable();
238
+ const result = await confirmSingletonScheduledPublish({
186
239
  data: {
240
+ expectedRevision: mutation.expectedRevision(),
187
241
  singleton: path,
188
242
  expectedVersionId: String(document?.versionId)
189
243
  }
190
244
  });
245
+ mutation.adopt(result);
191
246
  toast(t('scheduledPublication.toast.confirmedTitle'), t("scheduledPublication.toast.confirmedDescription"), 'success');
192
247
  await reload();
193
248
  } catch (err) {
194
- toast(t('scheduledPublication.toast.failedTitle'), err.message, 'danger');
249
+ const handled = mutation.report(err);
250
+ if ('blocked' === handled) throw err;
251
+ if ('committed' === handled) {
252
+ notifyCommittedHookFailure();
253
+ await reload();
254
+ return;
255
+ }
256
+ toast(t('scheduledPublication.toast.failedTitle'), t('documentConcurrency.failed'), 'danger');
195
257
  throw err;
196
258
  }
197
259
  };
198
260
  const handleCancelScheduledPublication = async ()=>{
199
261
  try {
200
- await cancelSingletonScheduledPublish({
262
+ mutation.assertWritable();
263
+ const result = await cancelSingletonScheduledPublish({
201
264
  data: {
265
+ expectedRevision: mutation.expectedRevision(),
202
266
  singleton: path
203
267
  }
204
268
  });
269
+ mutation.adopt({
270
+ ...result,
271
+ documentId: String(document?.id)
272
+ });
205
273
  toast(t('scheduledPublication.toast.cancelledTitle'), t("scheduledPublication.toast.cancelledDescription"), 'success');
206
274
  await reload();
207
275
  } catch (err) {
208
- toast(t('scheduledPublication.toast.failedTitle'), err.message, 'danger');
276
+ const handled = mutation.report(err);
277
+ if ('blocked' === handled) throw err;
278
+ if ('committed' === handled) {
279
+ notifyCommittedHookFailure();
280
+ await reload();
281
+ return;
282
+ }
283
+ toast(t('scheduledPublication.toast.failedTitle'), t('documentConcurrency.failed'), 'danger');
209
284
  throw err;
210
285
  }
211
286
  };
212
287
  return /*#__PURE__*/ jsx(Section, {
213
288
  children: /*#__PURE__*/ jsx(Container, {
214
289
  children: /*#__PURE__*/ jsx(FormRenderer, {
290
+ mutationIssue: mutation.issue,
291
+ mutationsBlocked: mutation.blocked,
292
+ observedRevision: mutation.revision,
293
+ onMutationError: mutation.report,
215
294
  mode: null == document ? 'create' : 'edit',
216
295
  fields: fields,
217
296
  onSubmit: handleSubmit,
@@ -8,19 +8,12 @@ const byline_field_services_getCollectionDocuments = ({ collection, params })=>g
8
8
  }
9
9
  });
10
10
  const byline_field_services_uploadField = (collection, formData, createDocument)=>uploadField(collection, formData, createDocument);
11
- const byline_field_services_placeTreeNode = async (input)=>{
12
- const { orderKey } = await placeTreeNode({
11
+ const byline_field_services_placeTreeNode = async (input)=>placeTreeNode({
13
12
  data: input
14
13
  });
15
- return {
16
- orderKey
17
- };
18
- };
19
- const byline_field_services_removeFromTree = async (input)=>{
20
- await removeFromTree({
14
+ const byline_field_services_removeFromTree = async (input)=>removeFromTree({
21
15
  data: input
22
16
  });
23
- };
24
17
  const byline_field_services_getTreeAncestors = (input)=>getTreeAncestors({
25
18
  data: input
26
19
  });
@@ -122,7 +122,7 @@ function createCollectionEditRoute(path) {
122
122
  contentLocales: contentLocales,
123
123
  defaultContentLocale: defaultContentLocale,
124
124
  returnSearch: returnSearch
125
- })
125
+ }, `${collection}/${id}/${locale}`)
126
126
  ]
127
127
  });
128
128
  }
@@ -1,8 +1 @@
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
1
  export declare function createCollectionListRoute(path: string): any;
@@ -1,8 +1,8 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { getCollectionAdminConfig, getWorkflowStatuses, parseDocumentRevision } from "@byline/core";
2
3
  import { useEffect, useRef } from "react";
3
4
  import { createFileRoute, notFound } from "@tanstack/react-router";
4
5
  import { applyRelationColumnFormatters } from "@byline/admin/react";
5
- import { getCollectionAdminConfig, getWorkflowStatuses } from "@byline/core";
6
6
  import { useTranslation } from "@byline/i18n/react";
7
7
  import { useToastManager } from "@byline/ui/react";
8
8
  import { BreadcrumbsClient } from "../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js";
@@ -124,17 +124,16 @@ function createCollectionListRoute(path) {
124
124
  collection: collection,
125
125
  collectionLabels: data.included.collection.labels,
126
126
  listActions: adminConfig?.listActions,
127
- onMove: async ({ documentId, parentDocumentId, beforeDocumentId, afterDocumentId })=>{
128
- await placeTreeNode({
127
+ onMove: async ({ documentId, parentDocumentId, beforeDocumentId, afterDocumentId })=>await placeTreeNode({
129
128
  data: {
129
+ expectedRevision: parseDocumentRevision(data.rows.find((row)=>row.id === documentId)?.revision),
130
130
  collection,
131
131
  documentId,
132
132
  parentDocumentId,
133
133
  beforeDocumentId,
134
134
  afterDocumentId
135
135
  }
136
- });
137
- }
136
+ })
138
137
  }) : CustomListView ? /*#__PURE__*/ jsx(CustomListView, {
139
138
  data: data,
140
139
  workflowStatuses: workflowStatuses
@@ -145,16 +144,15 @@ function createCollectionListRoute(path) {
145
144
  useAsTitle: collectionDef.useAsTitle,
146
145
  orderable: true === collectionDef.orderable,
147
146
  listActions: adminConfig?.listActions,
148
- onReorder: async ({ documentId, beforeDocumentId, afterDocumentId })=>{
149
- await reorderCollectionDocument({
147
+ onReorder: async ({ documentId, beforeDocumentId, afterDocumentId })=>await reorderCollectionDocument({
150
148
  data: {
149
+ expectedRevision: parseDocumentRevision(data.docs.find((row)=>row.id === documentId)?.revision),
151
150
  collection,
152
151
  documentId,
153
152
  beforeDocumentId,
154
153
  afterDocumentId
155
154
  }
156
- });
157
- }
155
+ })
158
156
  })
159
157
  ]
160
158
  });
@@ -20,8 +20,10 @@ export declare const getSingletonRouteDocument: import("@tanstack/react-start").
20
20
  locale?: string;
21
21
  }, Promise<{
22
22
  document: null;
23
+ expectedEmpty: true;
23
24
  initialData: Record<string, any>;
24
25
  } | {
26
+ expectedEmpty?: undefined;
25
27
  document: {
26
28
  _publishedVersion: Record<string, any> | null;
27
29
  _scheduledPublicationEnabled: boolean;
@@ -1,7 +1,7 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { createFileRoute, notFound } from "@tanstack/react-router";
3
3
  import { createServerFn } from "@tanstack/react-start";
4
- import { getAdminBylineClient, getAdminRequestContext } from "@byline/client/server";
4
+ import { getAdminRequestContext } from "@byline/client/server";
5
5
  import { buildInitialDataFromFields, documentAbilityKey, getServerConfig, getSingletonAdminConfig } from "@byline/core";
6
6
  import { useTranslation } from "@byline/i18n/react";
7
7
  import { z } from "zod";
@@ -28,6 +28,7 @@ const getSingletonRouteDocument = createServerFn({
28
28
  });
29
29
  if (null == document) return {
30
30
  document: null,
31
+ expectedEmpty: true,
31
32
  initialData: serialise(await buildInitialDataFromFields(definition.fields, {
32
33
  locale: data.locale ?? getServerConfig().i18n.content.defaultLocale
33
34
  }))
@@ -54,7 +55,7 @@ const getSingletonRouteDocument = createServerFn({
54
55
  if (scheduledPublicationEnabled) {
55
56
  const actor = (await getAdminRequestContext()).actor;
56
57
  canSchedulePublication = actor?.hasAbility(documentAbilityKey(definition, 'changeStatus')) === true && actor.hasAbility(documentAbilityKey(definition, 'publish'));
57
- if (canSchedulePublication) scheduledPublish = await getAdminBylineClient().singleton(data.singleton).getScheduledPublish();
58
+ if (canSchedulePublication) scheduledPublish = document.scheduledPublication;
58
59
  }
59
60
  const serializedSchedule = null == scheduledPublish ? null : serialise(scheduledPublish);
60
61
  return {
@@ -120,7 +121,7 @@ function createSingletonRoute(path) {
120
121
  locale: locale,
121
122
  contentLocales: contentLocales,
122
123
  defaultContentLocale: defaultContentLocale
123
- })
124
+ }, `${singleton}/${locale}`)
124
125
  ]
125
126
  });
126
127
  }
@@ -1,10 +1,3 @@
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
1
  import type { CopyToLocaleResult } from '@byline/core/services';
9
2
  import { type CollectionDocumentCommittedHookFailureResponse } from './save-outcome.js';
10
3
  /**
@@ -17,12 +10,14 @@ import { type CollectionDocumentCommittedHookFailureResponse } from './save-outc
17
10
  * failures propagate to TanStack Start's transport layer.
18
11
  */
19
12
  export declare const copyDocumentToLocale: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
13
+ expectedRevision: number;
20
14
  collection: string;
21
15
  id: string;
22
16
  sourceLocale: string;
23
17
  targetLocale: string;
24
18
  overwrite: boolean;
25
19
  }) => {
20
+ expectedRevision: number;
26
21
  collection: string;
27
22
  id: string;
28
23
  sourceLocale: string;
@@ -1,3 +1,4 @@
1
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
1
2
  import { createServerFn } from "@tanstack/react-start";
2
3
  import { getAdminRequestContext } from "@byline/client/server";
3
4
  import { ERR_NOT_FOUND, getLogger, getServerConfig } from "@byline/core";
@@ -6,7 +7,7 @@ import { ensureCollection } from "../../integrations/api-utils.js";
6
7
  import { toCommittedDocumentHookFailureResponse } from "./save-outcome.js";
7
8
  const copyDocumentToLocale = createServerFn({
8
9
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
10
+ }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
11
  const { collection: path, id, sourceLocale, targetLocale, overwrite } = input;
11
12
  const logger = getLogger();
12
13
  const config = await ensureCollection(path);
@@ -31,6 +32,7 @@ const copyDocumentToLocale = createServerFn({
31
32
  try {
32
33
  return await copyToLocale(ctx, {
33
34
  documentId: id,
35
+ expectedRevision: input.expectedRevision,
34
36
  sourceLocale,
35
37
  targetLocale,
36
38
  overwrite
@@ -40,5 +42,5 @@ const copyDocumentToLocale = createServerFn({
40
42
  if (null != committedFailure) return committedFailure;
41
43
  throw error;
42
44
  }
43
- });
45
+ }));
44
46
  export { copyDocumentToLocale };
@@ -1,10 +1,3 @@
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
1
  export declare const createCollectionDocument: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
9
2
  collection: string;
10
3
  data: any;
@@ -21,4 +14,5 @@ export declare const createCollectionDocument: import("@tanstack/react-start").R
21
14
  status: 'ok';
22
15
  documentId: string;
23
16
  documentVersionId: string;
17
+ revision: number;
24
18
  }>>;
@@ -1,3 +1,4 @@
1
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
1
2
  import { createServerFn } from "@tanstack/react-start";
2
3
  import { getAdminRequestContext } from "@byline/client/server";
3
4
  import { ERR_NOT_FOUND, getLogger, getServerConfig } from "@byline/core";
@@ -6,7 +7,7 @@ import { ensureCollection } from "../../integrations/api-utils.js";
6
7
  import { toCommittedDocumentHookFailureResponse } from "./save-outcome.js";
7
8
  const createCollectionDocument = createServerFn({
8
9
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
10
+ }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
11
  const { collection: path, data: documentData, locale, path: explicitPath, availableLocales } = input;
11
12
  const logger = getLogger();
12
13
  const config = await ensureCollection(path);
@@ -45,7 +46,8 @@ const createCollectionDocument = createServerFn({
45
46
  return {
46
47
  status: 'ok',
47
48
  documentId: result.documentId,
48
- documentVersionId: result.documentVersionId
49
+ documentVersionId: result.documentVersionId,
50
+ revision: result.revision
49
51
  };
50
- });
52
+ }));
51
53
  export { createCollectionDocument };
@@ -1,10 +1,3 @@
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
1
  import type { DeleteLocaleResult } from '@byline/core/services';
9
2
  import { type CollectionDocumentCommittedHookFailureResponse } from './save-outcome.js';
10
3
  /**
@@ -18,10 +11,12 @@ import { type CollectionDocumentCommittedHookFailureResponse } from './save-outc
18
11
  * transport layer.
19
12
  */
20
13
  export declare const deleteDocumentLocale: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
14
+ expectedRevision: number;
21
15
  collection: string;
22
16
  id: string;
23
17
  locale: string;
24
18
  }) => {
19
+ expectedRevision: number;
25
20
  collection: string;
26
21
  id: string;
27
22
  locale: string;
@@ -1,3 +1,4 @@
1
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
1
2
  import { createServerFn } from "@tanstack/react-start";
2
3
  import { getAdminRequestContext } from "@byline/client/server";
3
4
  import { ERR_NOT_FOUND, getLogger, getServerConfig } from "@byline/core";
@@ -6,7 +7,7 @@ import { ensureCollection } from "../../integrations/api-utils.js";
6
7
  import { toCommittedDocumentHookFailureResponse } from "./save-outcome.js";
7
8
  const deleteDocumentLocale = createServerFn({
8
9
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
10
+ }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
11
  const { collection: path, id, locale } = input;
11
12
  const logger = getLogger();
12
13
  const config = await ensureCollection(path);
@@ -31,6 +32,7 @@ const deleteDocumentLocale = createServerFn({
31
32
  try {
32
33
  return await deleteLocale(ctx, {
33
34
  documentId: id,
35
+ expectedRevision: input.expectedRevision,
34
36
  locale
35
37
  });
36
38
  } catch (error) {
@@ -38,5 +40,5 @@ const deleteDocumentLocale = createServerFn({
38
40
  if (null != committedFailure) return committedFailure;
39
41
  throw error;
40
42
  }
41
- });
43
+ }));
42
44
  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: [
@@ -1,14 +1,9 @@
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
1
  export declare const deleteDocument: import("@tanstack/react-start").RequiredFetcher<undefined, (input: {
2
+ expectedRevision: number;
9
3
  collection: string;
10
4
  id: string;
11
5
  }) => {
6
+ expectedRevision: number;
12
7
  collection: string;
13
8
  id: string;
14
9
  }, Promise<import("./delete-outcome.js").DeleteDocumentResponse>>;
@@ -1,3 +1,4 @@
1
+ import { withDocumentMutationErrors } from "../document-mutation-errors.js";
1
2
  import { createServerFn } from "@tanstack/react-start";
2
3
  import { getAdminRequestContext } from "@byline/client/server";
3
4
  import { ERR_NOT_FOUND, getLogger, getServerConfig, getUploadFields } from "@byline/core";
@@ -6,7 +7,7 @@ import { ensureCollection } from "../../integrations/api-utils.js";
6
7
  import { toDeleteDocumentResponse } from "./delete-outcome.js";
7
8
  const delete_deleteDocument = createServerFn({
8
9
  method: 'POST'
9
- }).validator((input)=>input).handler(async ({ data: input })=>{
10
+ }).validator((input)=>input).handler(withDocumentMutationErrors(async ({ data: input })=>{
10
11
  const { collection: path, id } = input;
11
12
  const logger = getLogger();
12
13
  const config = await ensureCollection(path);
@@ -35,8 +36,9 @@ const delete_deleteDocument = createServerFn({
35
36
  requestContext: await getAdminRequestContext()
36
37
  };
37
38
  const result = await deleteDocument(ctx, {
38
- documentId: id
39
+ documentId: id,
40
+ expectedRevision: input.expectedRevision
39
41
  });
40
42
  return toDeleteDocumentResponse(result);
41
- });
43
+ }));
42
44
  export { delete_deleteDocument as deleteDocument };