@byline/host-tanstack-start 4.18.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.
- package/dist/admin-shell/collections/create.js +22 -5
- package/dist/admin-shell/collections/edit.d.ts +1 -1
- package/dist/admin-shell/collections/edit.js +222 -34
- package/dist/admin-shell/collections/history.js +4 -2
- package/dist/admin-shell/collections/list.js +30 -6
- package/dist/admin-shell/collections/restore-version-modal.d.ts +3 -1
- package/dist/admin-shell/collections/restore-version-modal.js +23 -6
- package/dist/admin-shell/collections/save-navigation.test.d.ts +8 -0
- package/dist/admin-shell/collections/tree-list.js +16 -6
- package/dist/admin-shell/collections/version-history.d.ts +2 -1
- package/dist/admin-shell/collections/version-history.js +11 -2
- package/dist/admin-shell/document-mutation-notice.d.ts +6 -0
- package/dist/admin-shell/document-mutation-notice.js +53 -0
- package/dist/admin-shell/document-mutation-state.d.ts +22 -0
- package/dist/admin-shell/document-mutation-state.js +71 -0
- package/dist/admin-shell/document-mutation-state.test.d.ts +1 -0
- package/dist/admin-shell/scheduled-publications/list.js +15 -5
- package/dist/admin-shell/singletons/history.js +4 -2
- package/dist/admin-shell/singletons/view.d.ts +1 -1
- package/dist/admin-shell/singletons/view.js +108 -23
- package/dist/integrations/byline-field-services.js +2 -9
- package/dist/routes/create-collection-edit-route.js +1 -1
- package/dist/routes/create-collection-list-route.d.ts +0 -7
- package/dist/routes/create-collection-list-route.js +7 -9
- package/dist/routes/create-singleton-route.d.ts +2 -0
- package/dist/routes/create-singleton-route.js +4 -3
- package/dist/server-fns/collections/copy-to-locale.d.ts +4 -8
- package/dist/server-fns/collections/copy-to-locale.js +17 -8
- package/dist/server-fns/collections/create.d.ts +2 -8
- package/dist/server-fns/collections/create.js +20 -10
- package/dist/server-fns/collections/delete-locale.d.ts +4 -8
- package/dist/server-fns/collections/delete-locale.js +15 -6
- package/dist/server-fns/collections/delete-outcome.d.ts +7 -3
- package/dist/server-fns/collections/delete-outcome.js +4 -0
- package/dist/server-fns/collections/delete.d.ts +2 -7
- package/dist/server-fns/collections/delete.js +5 -3
- package/dist/server-fns/collections/duplicate.d.ts +4 -8
- package/dist/server-fns/collections/duplicate.js +14 -5
- package/dist/server-fns/collections/get.d.ts +1 -7
- package/dist/server-fns/collections/get.js +5 -4
- package/dist/server-fns/collections/index.d.ts +1 -0
- package/dist/server-fns/collections/index.js +1 -0
- package/dist/server-fns/collections/list.d.ts +0 -7
- package/dist/server-fns/collections/list.js +11 -3
- package/dist/server-fns/collections/reorder.d.ts +7 -8
- package/dist/server-fns/collections/reorder.js +20 -76
- package/dist/server-fns/collections/restore-version.d.ts +4 -8
- package/dist/server-fns/collections/restore-version.js +22 -12
- package/dist/server-fns/collections/save-outcome.d.ts +24 -0
- package/dist/server-fns/collections/save-outcome.js +19 -0
- package/dist/server-fns/collections/scheduled-publication.d.ts +49 -9
- package/dist/server-fns/collections/scheduled-publication.js +31 -21
- package/dist/server-fns/collections/status.d.ts +8 -7
- package/dist/server-fns/collections/status.js +13 -5
- package/dist/server-fns/collections/tree-mutation.d.ts +7 -6
- package/dist/server-fns/collections/tree-mutation.js +17 -5
- package/dist/server-fns/collections/tree.d.ts +14 -8
- package/dist/server-fns/collections/tree.js +21 -17
- package/dist/server-fns/collections/update.d.ts +14 -11
- package/dist/server-fns/collections/update.js +48 -24
- package/dist/server-fns/collections/upload.d.ts +1 -0
- package/dist/server-fns/collections/upload.js +3 -2
- package/dist/server-fns/document-mutation-errors.d.ts +5 -0
- package/dist/server-fns/document-mutation-errors.js +50 -0
- package/dist/server-fns/editable-revision.d.ts +9 -0
- package/dist/server-fns/editable-revision.js +11 -0
- package/dist/server-fns/singleton-document-read.d.ts +1 -1
- package/dist/server-fns/singleton-document-read.js +7 -3
- package/dist/server-fns/singletons/cancel-scheduled-publish.d.ts +6 -8
- package/dist/server-fns/singletons/cancel-scheduled-publish.js +4 -1
- package/dist/server-fns/singletons/change-status.d.ts +2 -7
- package/dist/server-fns/singletons/change-status.js +4 -1
- package/dist/server-fns/singletons/confirm-scheduled-publish.d.ts +5 -8
- package/dist/server-fns/singletons/confirm-scheduled-publish.js +4 -2
- package/dist/server-fns/singletons/copy-to-locale.d.ts +2 -7
- package/dist/server-fns/singletons/copy-to-locale.js +16 -5
- package/dist/server-fns/singletons/get.d.ts +4 -4
- package/dist/server-fns/singletons/restore-version.d.ts +2 -7
- package/dist/server-fns/singletons/restore-version.js +13 -1
- package/dist/server-fns/singletons/schedule-publish.d.ts +5 -8
- package/dist/server-fns/singletons/schedule-publish.js +4 -2
- package/dist/server-fns/singletons/unpublish.d.ts +2 -7
- package/dist/server-fns/singletons/unpublish.js +4 -1
- package/dist/server-fns/singletons/update.d.ts +4 -11
- package/dist/server-fns/singletons/update.js +16 -8
- package/dist/server-fns/structural-receipt.d.ts +4 -0
- package/dist/server-fns/structural-receipt.js +31 -0
- package/package.json +11 -11
- package/src/admin-shell/collections/create.tsx +22 -3
- package/src/admin-shell/collections/edit.tsx +233 -61
- package/src/admin-shell/collections/history.tsx +11 -2
- package/src/admin-shell/collections/list.tsx +22 -6
- package/src/admin-shell/collections/restore-version-modal.tsx +23 -5
- package/src/admin-shell/collections/save-navigation.test.tsx +532 -0
- package/src/admin-shell/collections/tree-list.tsx +16 -6
- package/src/admin-shell/collections/version-history.tsx +13 -3
- package/src/admin-shell/document-mutation-notice.tsx +45 -0
- package/src/admin-shell/document-mutation-state.test.tsx +146 -0
- package/src/admin-shell/document-mutation-state.ts +95 -0
- package/src/admin-shell/scheduled-publications/list.tsx +16 -6
- package/src/admin-shell/singletons/history.test.tsx +46 -1
- package/src/admin-shell/singletons/history.tsx +10 -2
- package/src/admin-shell/singletons/view.test.tsx +86 -18
- package/src/admin-shell/singletons/view.tsx +145 -45
- package/src/integrations/byline-field-services.ts +2 -3
- package/src/routes/create-collection-edit-route.tsx +1 -0
- package/src/routes/create-collection-list-route.tsx +13 -2
- package/src/routes/create-singleton-route.test.node.ts +10 -2
- package/src/routes/create-singleton-route.tsx +6 -4
- package/src/server-fns/collections/copy-to-locale.ts +48 -29
- package/src/server-fns/collections/create.ts +56 -44
- package/src/server-fns/collections/delete-locale.ts +48 -25
- package/src/server-fns/collections/delete-outcome.test.node.ts +16 -0
- package/src/server-fns/collections/delete-outcome.ts +27 -16
- package/src/server-fns/collections/delete.ts +44 -38
- package/src/server-fns/collections/duplicate.ts +45 -25
- package/src/server-fns/collections/get.ts +8 -4
- package/src/server-fns/collections/index.ts +1 -0
- package/src/server-fns/collections/list.ts +8 -3
- package/src/server-fns/collections/reorder.ts +32 -124
- package/src/server-fns/collections/restore-version.ts +51 -36
- package/src/server-fns/collections/revision-input.test.node.ts +108 -0
- package/src/server-fns/collections/save-outcome.test.node.ts +80 -0
- package/src/server-fns/collections/save-outcome.ts +57 -0
- package/src/server-fns/collections/scheduled-publication.ts +138 -111
- package/src/server-fns/collections/status.ts +86 -64
- package/src/server-fns/collections/tree-mutation.test.node.ts +87 -29
- package/src/server-fns/collections/tree-mutation.ts +28 -11
- package/src/server-fns/collections/tree.ts +150 -122
- package/src/server-fns/collections/update.ts +110 -71
- package/src/server-fns/collections/upload-singleton.test.node.ts +3 -7
- package/src/server-fns/collections/upload.ts +81 -77
- package/src/server-fns/document-mutation-errors.ts +67 -0
- package/src/server-fns/document-mutation-transport.test.node.ts +211 -0
- package/src/server-fns/editable-revision.test.node.ts +23 -0
- package/src/server-fns/editable-revision.ts +18 -0
- package/src/server-fns/singleton-document-read.ts +7 -3
- package/src/server-fns/singletons/cancel-scheduled-publish.ts +10 -3
- package/src/server-fns/singletons/change-status.ts +10 -3
- package/src/server-fns/singletons/confirm-scheduled-publish.ts +12 -6
- package/src/server-fns/singletons/copy-to-locale.ts +20 -8
- package/src/server-fns/singletons/get.ts +3 -3
- package/src/server-fns/singletons/restore-version.ts +17 -3
- package/src/server-fns/singletons/schedule-publish.ts +18 -7
- package/src/server-fns/singletons/singletons.test.node.ts +96 -24
- package/src/server-fns/singletons/unpublish.ts +10 -3
- package/src/server-fns/singletons/update.ts +21 -9
- package/src/server-fns/structural-receipt.ts +41 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withDocumentMutationErrors } from '../document-mutation-errors.js'
|
|
1
2
|
/**
|
|
2
3
|
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
4
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -14,6 +15,10 @@ import type { CopyToLocaleResult, DocumentLifecycleContext } from '@byline/core/
|
|
|
14
15
|
import { copyToLocale } from '@byline/core/services'
|
|
15
16
|
|
|
16
17
|
import { ensureCollection } from '../../integrations/api-utils.js'
|
|
18
|
+
import {
|
|
19
|
+
type CollectionDocumentCommittedHookFailureResponse,
|
|
20
|
+
toCommittedDocumentHookFailureResponse,
|
|
21
|
+
} from './save-outcome.js'
|
|
17
22
|
|
|
18
23
|
// ---------------------------------------------------------------------------
|
|
19
24
|
// Copy document content from one locale into another
|
|
@@ -31,6 +36,7 @@ import { ensureCollection } from '../../integrations/api-utils.js'
|
|
|
31
36
|
export const copyDocumentToLocale = createServerFn({ method: 'POST' })
|
|
32
37
|
.validator(
|
|
33
38
|
(input: {
|
|
39
|
+
expectedRevision: number
|
|
34
40
|
collection: string
|
|
35
41
|
id: string
|
|
36
42
|
sourceLocale: string
|
|
@@ -38,34 +44,47 @@ export const copyDocumentToLocale = createServerFn({ method: 'POST' })
|
|
|
38
44
|
overwrite: boolean
|
|
39
45
|
}) => input
|
|
40
46
|
)
|
|
41
|
-
.handler(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
.handler(
|
|
48
|
+
withDocumentMutationErrors(
|
|
49
|
+
async ({
|
|
50
|
+
data: input,
|
|
51
|
+
}): Promise<CopyToLocaleResult | CollectionDocumentCommittedHookFailureResponse> => {
|
|
52
|
+
const { collection: path, id, sourceLocale, targetLocale, overwrite } = input
|
|
53
|
+
const logger = getLogger()
|
|
54
|
+
const config = await ensureCollection(path)
|
|
55
|
+
if (!config) {
|
|
56
|
+
throw ERR_NOT_FOUND({
|
|
57
|
+
message: 'Collection not found',
|
|
58
|
+
details: { collectionPath: path },
|
|
59
|
+
}).log(logger)
|
|
60
|
+
}
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const serverConfig = getServerConfig()
|
|
63
|
+
const ctx: DocumentLifecycleContext = {
|
|
64
|
+
db: serverConfig.db,
|
|
65
|
+
definition: config.definition,
|
|
66
|
+
collectionId: config.collection.id,
|
|
67
|
+
collectionVersion: config.collection.version,
|
|
68
|
+
collectionPath: path,
|
|
69
|
+
logger,
|
|
70
|
+
defaultLocale: serverConfig.i18n.content.defaultLocale,
|
|
71
|
+
slugifier: serverConfig.slugifier,
|
|
72
|
+
requestContext: await getAdminRequestContext(),
|
|
73
|
+
}
|
|
64
74
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
try {
|
|
76
|
+
return await copyToLocale(ctx, {
|
|
77
|
+
documentId: id,
|
|
78
|
+
expectedRevision: input.expectedRevision,
|
|
79
|
+
sourceLocale,
|
|
80
|
+
targetLocale,
|
|
81
|
+
overwrite,
|
|
82
|
+
})
|
|
83
|
+
} catch (error) {
|
|
84
|
+
const committedFailure = toCommittedDocumentHookFailureResponse(error)
|
|
85
|
+
if (committedFailure != null) return committedFailure
|
|
86
|
+
throw error
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withDocumentMutationErrors } from '../document-mutation-errors.js'
|
|
1
2
|
/**
|
|
2
3
|
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
4
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -10,10 +11,11 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
10
11
|
|
|
11
12
|
import { getAdminRequestContext } from '@byline/client/server'
|
|
12
13
|
import { ERR_NOT_FOUND, getLogger, getServerConfig } from '@byline/core'
|
|
13
|
-
import type { DocumentLifecycleContext } from '@byline/core/services'
|
|
14
|
+
import type { CreateDocumentResult, DocumentLifecycleContext } from '@byline/core/services'
|
|
14
15
|
import { createDocument } from '@byline/core/services'
|
|
15
16
|
|
|
16
17
|
import { ensureCollection } from '../../integrations/api-utils.js'
|
|
18
|
+
import { toCommittedDocumentHookFailureResponse } from './save-outcome.js'
|
|
17
19
|
|
|
18
20
|
// ---------------------------------------------------------------------------
|
|
19
21
|
// Create document
|
|
@@ -29,49 +31,59 @@ export const createCollectionDocument = createServerFn({ method: 'POST' })
|
|
|
29
31
|
availableLocales?: string[]
|
|
30
32
|
}) => input
|
|
31
33
|
)
|
|
32
|
-
.handler(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
.handler(
|
|
35
|
+
withDocumentMutationErrors(async ({ data: input }) => {
|
|
36
|
+
const {
|
|
37
|
+
collection: path,
|
|
38
|
+
data: documentData,
|
|
39
|
+
locale,
|
|
40
|
+
path: explicitPath,
|
|
41
|
+
availableLocales,
|
|
42
|
+
} = input
|
|
43
|
+
const logger = getLogger()
|
|
44
|
+
const config = await ensureCollection(path)
|
|
45
|
+
if (!config) {
|
|
46
|
+
throw ERR_NOT_FOUND({
|
|
47
|
+
message: 'Collection not found',
|
|
48
|
+
details: { collectionPath: path },
|
|
49
|
+
}).log(logger)
|
|
50
|
+
}
|
|
48
51
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
const serverConfig = getServerConfig()
|
|
53
|
+
const ctx: DocumentLifecycleContext = {
|
|
54
|
+
db: serverConfig.db,
|
|
55
|
+
definition: config.definition,
|
|
56
|
+
collectionId: config.collection.id,
|
|
57
|
+
collectionVersion: config.collection.version,
|
|
58
|
+
collectionPath: path,
|
|
59
|
+
logger,
|
|
60
|
+
defaultLocale: serverConfig.i18n.content.defaultLocale,
|
|
61
|
+
slugifier: serverConfig.slugifier,
|
|
62
|
+
requestContext: await getAdminRequestContext(),
|
|
63
|
+
}
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
let result: CreateDocumentResult
|
|
66
|
+
try {
|
|
67
|
+
result = await createDocument(ctx, {
|
|
68
|
+
data: structuredClone(documentData),
|
|
69
|
+
status: documentData.status,
|
|
70
|
+
locale: locale ?? serverConfig.i18n.content.defaultLocale,
|
|
71
|
+
path: explicitPath,
|
|
72
|
+
availableLocales,
|
|
73
|
+
})
|
|
74
|
+
} catch (error) {
|
|
75
|
+
const committedFailure = toCommittedDocumentHookFailureResponse(error)
|
|
76
|
+
if (committedFailure != null) return committedFailure
|
|
77
|
+
throw error
|
|
78
|
+
}
|
|
69
79
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
// The new document's id is returned so the create view can navigate
|
|
81
|
+
// straight to the edit view (create → edit).
|
|
82
|
+
return {
|
|
83
|
+
status: 'ok' as const,
|
|
84
|
+
documentId: result.documentId,
|
|
85
|
+
documentVersionId: result.documentVersionId,
|
|
86
|
+
revision: result.revision,
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withDocumentMutationErrors } from '../document-mutation-errors.js'
|
|
1
2
|
/**
|
|
2
3
|
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
4
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -14,6 +15,10 @@ import type { DeleteLocaleResult, DocumentLifecycleContext } from '@byline/core/
|
|
|
14
15
|
import { deleteLocale } from '@byline/core/services'
|
|
15
16
|
|
|
16
17
|
import { ensureCollection } from '../../integrations/api-utils.js'
|
|
18
|
+
import {
|
|
19
|
+
type CollectionDocumentCommittedHookFailureResponse,
|
|
20
|
+
toCommittedDocumentHookFailureResponse,
|
|
21
|
+
} from './save-outcome.js'
|
|
17
22
|
|
|
18
23
|
// ---------------------------------------------------------------------------
|
|
19
24
|
// Delete one content locale's data from a document
|
|
@@ -30,30 +35,48 @@ import { ensureCollection } from '../../integrations/api-utils.js'
|
|
|
30
35
|
* transport layer.
|
|
31
36
|
*/
|
|
32
37
|
export const deleteDocumentLocale = createServerFn({ method: 'POST' })
|
|
33
|
-
.validator(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
.validator(
|
|
39
|
+
(input: { expectedRevision: number; collection: string; id: string; locale: string }) => input
|
|
40
|
+
)
|
|
41
|
+
.handler(
|
|
42
|
+
withDocumentMutationErrors(
|
|
43
|
+
async ({
|
|
44
|
+
data: input,
|
|
45
|
+
}): Promise<DeleteLocaleResult | CollectionDocumentCommittedHookFailureResponse> => {
|
|
46
|
+
const { collection: path, id, locale } = input
|
|
47
|
+
const logger = getLogger()
|
|
48
|
+
const config = await ensureCollection(path)
|
|
49
|
+
if (!config) {
|
|
50
|
+
throw ERR_NOT_FOUND({
|
|
51
|
+
message: 'Collection not found',
|
|
52
|
+
details: { collectionPath: path },
|
|
53
|
+
}).log(logger)
|
|
54
|
+
}
|
|
44
55
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
const serverConfig = getServerConfig()
|
|
57
|
+
const ctx: DocumentLifecycleContext = {
|
|
58
|
+
db: serverConfig.db,
|
|
59
|
+
definition: config.definition,
|
|
60
|
+
collectionId: config.collection.id,
|
|
61
|
+
collectionVersion: config.collection.version,
|
|
62
|
+
collectionPath: path,
|
|
63
|
+
logger,
|
|
64
|
+
defaultLocale: serverConfig.i18n.content.defaultLocale,
|
|
65
|
+
slugifier: serverConfig.slugifier,
|
|
66
|
+
requestContext: await getAdminRequestContext(),
|
|
67
|
+
}
|
|
57
68
|
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
try {
|
|
70
|
+
return await deleteLocale(ctx, {
|
|
71
|
+
documentId: id,
|
|
72
|
+
expectedRevision: input.expectedRevision,
|
|
73
|
+
locale,
|
|
74
|
+
})
|
|
75
|
+
} catch (error) {
|
|
76
|
+
const committedFailure = toCommittedDocumentHookFailureResponse(error)
|
|
77
|
+
if (committedFailure != null) return committedFailure
|
|
78
|
+
throw error
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
)
|
|
@@ -16,6 +16,10 @@ describe('delete outcome transport and admin interpretation', () => {
|
|
|
16
16
|
// Simulate malformed runtime data from an older or compromised source. The
|
|
17
17
|
// core type rejects this shape, but the transport still sanitizes it.
|
|
18
18
|
const unsafeResult = {
|
|
19
|
+
documentId: 'doc-1',
|
|
20
|
+
revision: 2,
|
|
21
|
+
affectedDocuments: [{ documentId: 'child', revision: 3 }],
|
|
22
|
+
scheduledPublicationsNeedReconfirmation: true,
|
|
19
23
|
deletedVersionCount: 2,
|
|
20
24
|
outcome: 'committed-with-side-effect-failures',
|
|
21
25
|
sideEffectFailures: [
|
|
@@ -36,6 +40,10 @@ describe('delete outcome transport and admin interpretation', () => {
|
|
|
36
40
|
|
|
37
41
|
expect(response).toEqual({
|
|
38
42
|
status: 'ok',
|
|
43
|
+
documentId: 'doc-1',
|
|
44
|
+
revision: 2,
|
|
45
|
+
affectedDocuments: [{ documentId: 'child', revision: 3 }],
|
|
46
|
+
scheduledPublicationsNeedReconfirmation: true,
|
|
39
47
|
deletedVersionCount: 2,
|
|
40
48
|
outcome: 'committed-with-side-effect-failures',
|
|
41
49
|
sideEffectFailures: [
|
|
@@ -53,6 +61,10 @@ describe('delete outcome transport and admin interpretation', () => {
|
|
|
53
61
|
|
|
54
62
|
it('preserves the committed success discriminant and empty failures', () => {
|
|
55
63
|
const response = toDeleteDocumentResponse({
|
|
64
|
+
documentId: 'doc-1',
|
|
65
|
+
revision: 2,
|
|
66
|
+
affectedDocuments: [{ documentId: 'child', revision: 3 }],
|
|
67
|
+
scheduledPublicationsNeedReconfirmation: true,
|
|
56
68
|
deletedVersionCount: 2,
|
|
57
69
|
outcome: 'committed',
|
|
58
70
|
sideEffectFailures: [],
|
|
@@ -60,6 +72,10 @@ describe('delete outcome transport and admin interpretation', () => {
|
|
|
60
72
|
|
|
61
73
|
expect(response).toEqual({
|
|
62
74
|
status: 'ok',
|
|
75
|
+
documentId: 'doc-1',
|
|
76
|
+
revision: 2,
|
|
77
|
+
affectedDocuments: [{ documentId: 'child', revision: 3 }],
|
|
78
|
+
scheduledPublicationsNeedReconfirmation: true,
|
|
63
79
|
deletedVersionCount: 2,
|
|
64
80
|
outcome: 'committed',
|
|
65
81
|
sideEffectFailures: [],
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
DeleteDocumentResult,
|
|
11
11
|
DeleteDocumentSideEffectCode,
|
|
12
12
|
DeleteDocumentSideEffectPhase,
|
|
13
|
+
StructuralMutationReceipt,
|
|
13
14
|
} from '@byline/core'
|
|
14
15
|
import { ErrorCodes } from '@byline/core'
|
|
15
16
|
|
|
@@ -21,22 +22,28 @@ export interface DeleteDocumentPublicSideEffectFailure {
|
|
|
21
22
|
code: DeleteDocumentPublicSideEffectCode
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
export type DeleteDocumentResponse =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
export type DeleteDocumentResponse = StructuralMutationReceipt &
|
|
26
|
+
(
|
|
27
|
+
| {
|
|
28
|
+
status: 'ok'
|
|
29
|
+
documentId: string
|
|
30
|
+
revision: number
|
|
31
|
+
deletedVersionCount: number
|
|
32
|
+
outcome: 'committed'
|
|
33
|
+
sideEffectFailures: []
|
|
34
|
+
}
|
|
35
|
+
| {
|
|
36
|
+
status: 'ok'
|
|
37
|
+
documentId: string
|
|
38
|
+
revision: number
|
|
39
|
+
deletedVersionCount: number
|
|
40
|
+
outcome: 'committed-with-side-effect-failures'
|
|
41
|
+
sideEffectFailures: [
|
|
42
|
+
DeleteDocumentPublicSideEffectFailure,
|
|
43
|
+
...DeleteDocumentPublicSideEffectFailure[],
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
)
|
|
40
47
|
|
|
41
48
|
function sanitizePhase(phase: DeleteDocumentSideEffectPhase): DeleteDocumentPublicSideEffectPhase {
|
|
42
49
|
if (phase === 'afterTreeChange' || phase === 'afterDelete') {
|
|
@@ -67,6 +74,10 @@ export function toDeleteDocumentResponse(result: DeleteDocumentResult): DeleteDo
|
|
|
67
74
|
const [firstFailure, ...remainingFailures] = result.sideEffectFailures
|
|
68
75
|
return {
|
|
69
76
|
status: 'ok',
|
|
77
|
+
documentId: result.documentId,
|
|
78
|
+
revision: result.revision,
|
|
79
|
+
affectedDocuments: result.affectedDocuments,
|
|
80
|
+
scheduledPublicationsNeedReconfirmation: result.scheduledPublicationsNeedReconfirmation,
|
|
70
81
|
deletedVersionCount: result.deletedVersionCount,
|
|
71
82
|
outcome: result.outcome,
|
|
72
83
|
sideEffectFailures: [sanitizeFailure(firstFailure), ...remainingFailures.map(sanitizeFailure)],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withDocumentMutationErrors } from '../document-mutation-errors.js'
|
|
1
2
|
/**
|
|
2
3
|
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
4
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -21,43 +22,48 @@ import { toDeleteDocumentResponse } from './delete-outcome.js'
|
|
|
21
22
|
// ---------------------------------------------------------------------------
|
|
22
23
|
|
|
23
24
|
export const deleteDocument = createServerFn({ method: 'POST' })
|
|
24
|
-
.validator((input: { collection: string; id: string }) => input)
|
|
25
|
-
.handler(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
.validator((input: { expectedRevision: number; collection: string; id: string }) => input)
|
|
26
|
+
.handler(
|
|
27
|
+
withDocumentMutationErrors(async ({ data: input }) => {
|
|
28
|
+
const { collection: path, id } = input
|
|
29
|
+
const logger = getLogger()
|
|
30
|
+
const config = await ensureCollection(path)
|
|
31
|
+
if (!config) {
|
|
32
|
+
throw ERR_NOT_FOUND({
|
|
33
|
+
message: 'Collection not found',
|
|
34
|
+
details: { collectionPath: path },
|
|
35
|
+
}).log(logger)
|
|
36
|
+
}
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
38
|
+
const serverConfig = getServerConfig()
|
|
39
|
+
// Resolve the storage provider so the lifecycle service can clean up
|
|
40
|
+
// uploaded files and variants on deletion. With per-field upload
|
|
41
|
+
// config, a collection may have one (or more) image/file fields with
|
|
42
|
+
// their own storage. The delete path needs *a* provider; we pick the
|
|
43
|
+
// first upload-capable field's, falling back to the site-wide
|
|
44
|
+
// default. Multi-storage collections are out of scope today —
|
|
45
|
+
// deletion routes everything through one provider, which is fine
|
|
46
|
+
// when all upload fields target the same backend (the common case).
|
|
47
|
+
const firstUploadField = getUploadFields(config.definition)[0]
|
|
48
|
+
const storage = firstUploadField?.upload?.storage ?? serverConfig.storage
|
|
49
|
+
const db = serverConfig.db
|
|
50
|
+
const ctx: DocumentLifecycleContext = {
|
|
51
|
+
db,
|
|
52
|
+
definition: config.definition,
|
|
53
|
+
collectionId: config.collection.id,
|
|
54
|
+
collectionVersion: config.collection.version,
|
|
55
|
+
collectionPath: path,
|
|
56
|
+
...(storage ? { storage } : {}),
|
|
57
|
+
logger,
|
|
58
|
+
defaultLocale: serverConfig.i18n.content.defaultLocale,
|
|
59
|
+
slugifier: serverConfig.slugifier,
|
|
60
|
+
requestContext: await getAdminRequestContext(),
|
|
61
|
+
}
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
const result = await deleteDocumentService(ctx, {
|
|
64
|
+
documentId: id,
|
|
65
|
+
expectedRevision: input.expectedRevision,
|
|
66
|
+
})
|
|
67
|
+
return toDeleteDocumentResponse(result)
|
|
68
|
+
})
|
|
69
|
+
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withDocumentMutationErrors } from '../document-mutation-errors.js'
|
|
1
2
|
/**
|
|
2
3
|
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
4
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -14,6 +15,10 @@ import type { DocumentLifecycleContext, DuplicateDocumentResult } from '@byline/
|
|
|
14
15
|
import { duplicateDocument } from '@byline/core/services'
|
|
15
16
|
|
|
16
17
|
import { ensureCollection } from '../../integrations/api-utils.js'
|
|
18
|
+
import {
|
|
19
|
+
type CollectionDocumentCommittedHookFailureResponse,
|
|
20
|
+
toCommittedDocumentHookFailureResponse,
|
|
21
|
+
} from './save-outcome.js'
|
|
17
22
|
|
|
18
23
|
// ---------------------------------------------------------------------------
|
|
19
24
|
// Duplicate document
|
|
@@ -31,30 +36,45 @@ import { ensureCollection } from '../../integrations/api-utils.js'
|
|
|
31
36
|
* TanStack Start's transport layer for the client to branch on.
|
|
32
37
|
*/
|
|
33
38
|
export const duplicateCollectionDocument = createServerFn({ method: 'POST' })
|
|
34
|
-
.validator((input: { collection: string; id: string }) => input)
|
|
35
|
-
.handler(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
.validator((input: { expectedRevision: number; collection: string; id: string }) => input)
|
|
40
|
+
.handler(
|
|
41
|
+
withDocumentMutationErrors(
|
|
42
|
+
async ({
|
|
43
|
+
data: input,
|
|
44
|
+
}): Promise<DuplicateDocumentResult | CollectionDocumentCommittedHookFailureResponse> => {
|
|
45
|
+
const { collection: path, id: sourceDocumentId } = input
|
|
46
|
+
const logger = getLogger()
|
|
47
|
+
const config = await ensureCollection(path)
|
|
48
|
+
if (!config) {
|
|
49
|
+
throw ERR_NOT_FOUND({
|
|
50
|
+
message: 'Collection not found',
|
|
51
|
+
details: { collectionPath: path },
|
|
52
|
+
}).log(logger)
|
|
53
|
+
}
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const serverConfig = getServerConfig()
|
|
56
|
+
const ctx: DocumentLifecycleContext = {
|
|
57
|
+
db: serverConfig.db,
|
|
58
|
+
definition: config.definition,
|
|
59
|
+
collectionId: config.collection.id,
|
|
60
|
+
collectionVersion: config.collection.version,
|
|
61
|
+
collectionPath: path,
|
|
62
|
+
logger,
|
|
63
|
+
defaultLocale: serverConfig.i18n.content.defaultLocale,
|
|
64
|
+
slugifier: serverConfig.slugifier,
|
|
65
|
+
requestContext: await getAdminRequestContext(),
|
|
66
|
+
}
|
|
58
67
|
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
try {
|
|
69
|
+
return await duplicateDocument(ctx, {
|
|
70
|
+
sourceDocumentId,
|
|
71
|
+
expectedRevision: input.expectedRevision,
|
|
72
|
+
})
|
|
73
|
+
} catch (error) {
|
|
74
|
+
const committedFailure = toCommittedDocumentHookFailureResponse(error)
|
|
75
|
+
if (committedFailure != null) return committedFailure
|
|
76
|
+
throw error
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withEditableRevision } from '../editable-revision.js'
|
|
1
2
|
/**
|
|
2
3
|
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
4
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -51,13 +52,16 @@ const getDocumentFn = createServerFn({ method: 'GET' })
|
|
|
51
52
|
const client = getAdminBylineClient()
|
|
52
53
|
const handle = client.collection(path)
|
|
53
54
|
|
|
54
|
-
const {
|
|
55
|
+
const {
|
|
56
|
+
options: { status: _status, ...readOptions },
|
|
57
|
+
populatedTree,
|
|
58
|
+
} = resolveAdminDocumentRead(config.definition, {
|
|
55
59
|
locale,
|
|
56
60
|
depth,
|
|
57
61
|
populateRelations,
|
|
58
62
|
})
|
|
59
63
|
|
|
60
|
-
const document = await handle.
|
|
64
|
+
const document = await handle.findByIdForEdit(id, {
|
|
61
65
|
...readOptions,
|
|
62
66
|
})
|
|
63
67
|
|
|
@@ -141,13 +145,13 @@ const getDocumentFn = createServerFn({ method: 'GET' })
|
|
|
141
145
|
actor?.hasAbility(documentAbilityKey(config.definition, 'changeStatus')) === true &&
|
|
142
146
|
actor.hasAbility(documentAbilityKey(config.definition, 'publish'))
|
|
143
147
|
if (canSchedulePublication) {
|
|
144
|
-
scheduledPublish =
|
|
148
|
+
scheduledPublish = document.scheduledPublication
|
|
145
149
|
}
|
|
146
150
|
}
|
|
147
151
|
const serializedSchedule = scheduledPublish == null ? null : serialise(scheduledPublish)
|
|
148
152
|
|
|
149
153
|
return {
|
|
150
|
-
...(parsed
|
|
154
|
+
...withEditableRevision(parsed, document),
|
|
151
155
|
_publishedVersion: publishedVersion,
|
|
152
156
|
...(restoreWarnings && restoreWarnings.length > 0
|
|
153
157
|
? { _restoreWarnings: restoreWarnings }
|
|
@@ -18,6 +18,7 @@ export * from './list'
|
|
|
18
18
|
export * from './reindex'
|
|
19
19
|
export * from './reorder'
|
|
20
20
|
export * from './restore-version'
|
|
21
|
+
export * from './save-outcome'
|
|
21
22
|
export * from './scheduled-publication'
|
|
22
23
|
export * from './set-list-view-preference'
|
|
23
24
|
export * from './stats'
|