@forumone/throughline-publishing 0.3.4 → 0.5.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/CHANGELOG.md +77 -0
- package/README.md +4 -1
- package/dist/admin/PublishButton.d.ts.map +1 -1
- package/dist/admin/PublishButton.js +36 -3
- package/dist/admin/PublishButton.js.map +1 -1
- package/dist/admin/publishing-client.d.ts +46 -1
- package/dist/admin/publishing-client.d.ts.map +1 -1
- package/dist/admin/publishing-client.js +72 -1
- package/dist/admin/publishing-client.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/steps/approval.d.ts.map +1 -1
- package/dist/pipeline/steps/approval.js +13 -1
- package/dist/pipeline/steps/approval.js.map +1 -1
- package/dist/pipeline/steps/execute.d.ts +9 -0
- package/dist/pipeline/steps/execute.d.ts.map +1 -1
- package/dist/pipeline/steps/execute.js +68 -12
- package/dist/pipeline/steps/execute.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,82 @@
|
|
|
1
1
|
# @forumone/throughline-publishing
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 43c0636: Show a blocked publish on the fields that blocked it, and stop announcing the draft save
|
|
8
|
+
|
|
9
|
+
Every publish diagnostic arrived as a toast in the corner, which left an editor reading `layout.7.image` and counting blocks. The pipeline's issues have always named their fields; they are now dispatched into form state, so the field carries the message and the collapsed block row containing it carries an error count. An issue with no field — an embargo, a missing approval — stays in the toast, which still lists everything.
|
|
10
|
+
|
|
11
|
+
Only fields the form actually has are marked, and an issue that names something deeper (a populated relationship's image, a block index) marks the nearest field that owns it. Payload's reducer creates a field state entry for any path it is handed, so an invented path would become invented data on the next save.
|
|
12
|
+
|
|
13
|
+
A field the collection itself refuses is now a failed step rather than a thrown error: `failedAt: 'execute'`, `code: 'field-validation-failed'`, with Payload's field paths as `issues`. The publishing write is the first step that enforces `required` — a draft write deliberately does not — so an empty required field inside a block is caught there and nowhere earlier. `publishDocument` and the `publish` MCP tool now return that as a result instead of throwing.
|
|
14
|
+
|
|
15
|
+
The interim draft save the Publish button performs no longer shows its own success toast. It is a step inside publishing rather than something the editor asked for, and its notice used to land on top of the publish one. Payload's own Save Draft button is untouched.
|
|
16
|
+
|
|
17
|
+
## 0.4.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- d20f909: Bind an approval to the document's content rather than to its `updatedAt`.
|
|
22
|
+
|
|
23
|
+
`request_approval` stored `String(document['updatedAt'] ?? …)` as `targetVersion`,
|
|
24
|
+
and publishing's approval step recomputed the same expression at publish time. So
|
|
25
|
+
an approval was tied to a timestamp that moves on **every** save. An editor fixing
|
|
26
|
+
a typo between an approver opening the request and clicking approve invalidated the
|
|
27
|
+
approval — and the approver spent that time reading a version that no longer
|
|
28
|
+
existed.
|
|
29
|
+
|
|
30
|
+
Requiring re-approval after an edit is a defensible rule. Inheriting it from
|
|
31
|
+
whichever timestamp field happened to be nearby is not, and it is why **autosave
|
|
32
|
+
could not be turned on** anywhere the approvals plugin is installed: autosave moves
|
|
33
|
+
`updatedAt` every couple of seconds of typing, so a pending approval would be
|
|
34
|
+
invalidated continuously.
|
|
35
|
+
|
|
36
|
+
Both sides now call `documentContentHash(document)`, new in
|
|
37
|
+
`@forumone/throughline-core`. It hashes the document with the metadata that moves
|
|
38
|
+
without the content moving stripped at every level — `id`, `createdAt`,
|
|
39
|
+
`updatedAt`, `_status`, `__v`, `_id`, `globalType` — over keys in sorted order,
|
|
40
|
+
since blocks come back out of JSONB in no promised order. Array order is preserved,
|
|
41
|
+
because that is the order of the blocks on the page. `{ exclude }` adds
|
|
42
|
+
app-specific bookkeeping fields to the strip list.
|
|
43
|
+
|
|
44
|
+
The rule is now the one that was wanted all along: a save that changed nothing
|
|
45
|
+
keeps a granted approval, a save that changed something invalidates it, and an edit
|
|
46
|
+
that is reverted brings the approval back. That last one is why this is a content
|
|
47
|
+
hash rather than a version id — a version id moves whether or not the content did.
|
|
48
|
+
|
|
49
|
+
The two sides only agree because they load the document identically, with
|
|
50
|
+
`payload.findByID({ collection, id, draft: true })` at the config's default depth.
|
|
51
|
+
A populated relationship and a bare relationship id are different values and no
|
|
52
|
+
normalising makes them one, so a caller hashing a document fetched at some other
|
|
53
|
+
depth gets a hash that matches nothing. That is stated on the function.
|
|
54
|
+
|
|
55
|
+
**Approvals pending at upgrade must be re-requested.** Their `targetVersion` holds
|
|
56
|
+
an ISO timestamp; the publish step now computes a hash, so nothing matches and
|
|
57
|
+
those documents report `approval-required` until a fresh request is granted. No
|
|
58
|
+
migration is offered, because the old value cannot be converted — the content it
|
|
59
|
+
was granted against is not recoverable from a timestamp. Grant a moment for
|
|
60
|
+
in-flight requests to clear before upgrading, or expect approvers to be asked once
|
|
61
|
+
more.
|
|
62
|
+
|
|
63
|
+
Also exports `isDraftWrite` from `@forumone/throughline-publishing`. It is the
|
|
64
|
+
predicate the plugin's own trust boundary uses to tell a "Save draft" apart from
|
|
65
|
+
an unpublish, and it is unavailable to host code that needs the same answer: an
|
|
66
|
+
`afterChange` hook cannot work it out, because Payload sets `data._status =
|
|
67
|
+
'draft'` on any `draft: true` update before the hooks run and `previousDoc` is the
|
|
68
|
+
latest _version_ rather than the live document. With autosave on, a host hook that
|
|
69
|
+
drops a cache or sends a notification fires every few seconds of typing unless it
|
|
70
|
+
asks this first.
|
|
71
|
+
|
|
72
|
+
Minor rather than patch on all three: `documentContentHash` and `isDraftWrite` are
|
|
73
|
+
new public API, and the stored meaning of `targetVersion` changes.
|
|
74
|
+
|
|
75
|
+
### Patch Changes
|
|
76
|
+
|
|
77
|
+
- Updated dependencies [d20f909]
|
|
78
|
+
- @forumone/throughline-core@0.3.0
|
|
79
|
+
|
|
3
80
|
## 0.3.4
|
|
4
81
|
|
|
5
82
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -52,7 +52,8 @@ What you get:
|
|
|
52
52
|
- **No API key in the editorial publish path.** The endpoint authenticates off the Payload session cookie.
|
|
53
53
|
- **The person is the actor.** The audit event records the logged-in editor, with `mcpTool` set to `admin:publish` so admin publishes are distinguishable from MCP ones.
|
|
54
54
|
- **Access control still applies.** The write runs with `overrideAccess: false` as that user. Bypassing the status hook is not bypassing permissions.
|
|
55
|
-
- **Real feedback.** A blocked publish renders the failing step, its issues, and its suggestion —
|
|
55
|
+
- **Real feedback, on the field that caused it.** A blocked publish renders the failing step, its issues, and its suggestion — and every issue naming a field is marked on that field, with an error count on the collapsed block row containing it. An issue with no field (an embargo, a missing approval) stays in the toast, which is where the full list still appears.
|
|
56
|
+
- **One notice per action.** The interim draft save the button performs does not announce itself; publishing says "published" once.
|
|
56
57
|
|
|
57
58
|
The Publish button is hidden on the create view: the pipeline's first step is `exist`, so there is nothing to evaluate until the draft is saved. Use Payload's Save Draft button, then publish from the edit view.
|
|
58
59
|
|
|
@@ -74,6 +75,8 @@ With `adminComponents: false` the admin has **no** working publish path until yo
|
|
|
74
75
|
|
|
75
76
|
A publish blocked by the pipeline returns **200** with `{ published: false, failedAt, reason, code, issues, suggestion }`. The pipeline ran correctly and the answer was no; that is not a transport error. Non-2xx is reserved for auth (401/403), bad input (400), and genuine failures (500).
|
|
76
77
|
|
|
78
|
+
A field the collection itself refuses is one of those blocks — `failedAt: 'execute'`, `code: 'field-validation-failed'`, with Payload's own field paths as `issues`. The publishing write is the first step that enforces `required`, because a draft write deliberately does not, so an empty required field inside a block is caught there and nowhere earlier.
|
|
79
|
+
|
|
77
80
|
## Publishing from host code
|
|
78
81
|
|
|
79
82
|
`runPublishPipeline` needs plugin options and an audit writer that only exist inside the plugin. Rather than export the raw pipeline, the plugin attaches a service to the Payload instance at `onInit` and exposes these helpers:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PublishButton.d.ts","sourceRoot":"","sources":["../../src/admin/PublishButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAgC,MAAM,OAAO,CAAA;AAYpD,MAAM,WAAW,6BAA6B;IAC5C,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAE,6BAAkC,GAAG,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"PublishButton.d.ts","sourceRoot":"","sources":["../../src/admin/PublishButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAgC,MAAM,OAAO,CAAA;AAYpD,MAAM,WAAW,6BAA6B;IAC5C,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAE,6BAAkC,GAAG,KAAK,CAAC,SAAS,CA2KxF"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useState } from 'react';
|
|
4
4
|
import { FormSubmit, toast, useConfig, useDocumentInfo, useForm, useFormModified, useTranslation, } from '@payloadcms/ui';
|
|
5
|
-
import { callPublishingEndpoint, describeBlock } from './publishing-client.js';
|
|
5
|
+
import { callPublishingEndpoint, describeBlock, fieldErrorsFromBlock } from './publishing-client.js';
|
|
6
6
|
/**
|
|
7
7
|
* Replaces Payload's Publish button on collections the publishing plugin
|
|
8
8
|
* governs.
|
|
@@ -22,7 +22,7 @@ export function PublishButton(props = {}) {
|
|
|
22
22
|
const routePrefix = props.routePrefix ?? '/publishing';
|
|
23
23
|
const { collectionSlug, hasPublishedDoc, hasPublishPermission, id, setHasPublishedDoc, setMostRecentVersionIsAutosaved, setUnpublishedVersionCount, unpublishedVersionCount, uploadStatus, } = useDocumentInfo();
|
|
24
24
|
const { config } = useConfig();
|
|
25
|
-
const { submit } = useForm();
|
|
25
|
+
const { dispatchFields, getFields, setIsValid, setSubmitted, submit } = useForm();
|
|
26
26
|
const modified = useFormModified();
|
|
27
27
|
const { t } = useTranslation();
|
|
28
28
|
const [publishing, setPublishing] = useState(false);
|
|
@@ -47,6 +47,12 @@ export function PublishButton(props = {}) {
|
|
|
47
47
|
method: 'PATCH',
|
|
48
48
|
overrides: { _status: 'draft' },
|
|
49
49
|
skipValidation: true,
|
|
50
|
+
// No toast for this write. It is a step inside publishing, not
|
|
51
|
+
// something the editor asked for, and its success toast used to
|
|
52
|
+
// land on top of the publish one — two overlapping notices for one
|
|
53
|
+
// action, the first of which announced the lesser outcome.
|
|
54
|
+
// Payload's own Save Draft button is untouched and still toasts.
|
|
55
|
+
disableSuccessStatus: true,
|
|
50
56
|
});
|
|
51
57
|
// `submit` returns void and toasts its own error on most failures,
|
|
52
58
|
// but falls through with a non-ok response when the body carries no
|
|
@@ -67,7 +73,30 @@ export function PublishButton(props = {}) {
|
|
|
67
73
|
return;
|
|
68
74
|
}
|
|
69
75
|
if (!result.body.published) {
|
|
70
|
-
|
|
76
|
+
/*
|
|
77
|
+
The pipeline's issues already name their fields; until now they only
|
|
78
|
+
reached a toast, which left the editor reading `layout.7.image` and
|
|
79
|
+
counting blocks. Dispatched into form state they render where the
|
|
80
|
+
problem is — on the field, and as an error count on the collapsed
|
|
81
|
+
block row containing it.
|
|
82
|
+
|
|
83
|
+
`setSubmitted` is what makes them visible: a field shows its error
|
|
84
|
+
only once the form has been submitted, and a publish with no pending
|
|
85
|
+
edits never submits the form at all. `setIsValid(false)` mirrors what
|
|
86
|
+
Payload does with the field errors from an ordinary save.
|
|
87
|
+
|
|
88
|
+
The toast still lists everything, because an issue with no field — an
|
|
89
|
+
embargo, a missing approval — has nowhere else to go.
|
|
90
|
+
*/
|
|
91
|
+
const fieldErrors = fieldErrorsFromBlock(result.body, Object.keys(getFields()));
|
|
92
|
+
if (fieldErrors.length > 0) {
|
|
93
|
+
dispatchFields({ type: 'ADD_SERVER_ERRORS', errors: fieldErrors });
|
|
94
|
+
setIsValid(false);
|
|
95
|
+
setSubmitted(true);
|
|
96
|
+
}
|
|
97
|
+
const { title, description } = describeBlock(result.body, {
|
|
98
|
+
markedFields: fieldErrors.length,
|
|
99
|
+
});
|
|
71
100
|
toast.error(title, {
|
|
72
101
|
...(description ? { description } : {}),
|
|
73
102
|
duration: 10_000,
|
|
@@ -105,13 +134,17 @@ export function PublishButton(props = {}) {
|
|
|
105
134
|
}, [
|
|
106
135
|
api,
|
|
107
136
|
collectionSlug,
|
|
137
|
+
dispatchFields,
|
|
138
|
+
getFields,
|
|
108
139
|
id,
|
|
109
140
|
modified,
|
|
110
141
|
publishing,
|
|
111
142
|
routePrefix,
|
|
112
143
|
serverURL,
|
|
113
144
|
setHasPublishedDoc,
|
|
145
|
+
setIsValid,
|
|
114
146
|
setMostRecentVersionIsAutosaved,
|
|
147
|
+
setSubmitted,
|
|
115
148
|
setUnpublishedVersionCount,
|
|
116
149
|
submit,
|
|
117
150
|
t,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PublishButton.js","sourceRoot":"","sources":["../../src/admin/PublishButton.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAc,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACpD,OAAO,EACL,UAAU,EACV,KAAK,EACL,SAAS,EACT,eAAe,EACf,OAAO,EACP,eAAe,EACf,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"PublishButton.js","sourceRoot":"","sources":["../../src/admin/PublishButton.tsx"],"names":[],"mappings":"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"}
|
|
@@ -42,13 +42,58 @@ export type PublishingCallResult = {
|
|
|
42
42
|
* back as `ok: true` with a `published: false` body.
|
|
43
43
|
*/
|
|
44
44
|
export declare function callPublishingEndpoint(args: CallPublishingEndpointArgs): Promise<PublishingCallResult>;
|
|
45
|
+
/**
|
|
46
|
+
* A field error in the shape Payload's form reducer accepts. `path` is a
|
|
47
|
+
* *form state* path — dotted, with numeric segments for array and block rows —
|
|
48
|
+
* which is not the same dialect the pipeline's issues speak.
|
|
49
|
+
*
|
|
50
|
+
* Structurally `ValidationFieldError` from `payload`, redeclared so this file
|
|
51
|
+
* needs no import of its own and stays unit-testable without a form.
|
|
52
|
+
*/
|
|
53
|
+
export interface PublishingFieldError {
|
|
54
|
+
path: string;
|
|
55
|
+
message: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Rewrites a pipeline issue's field path into a form state path.
|
|
59
|
+
*
|
|
60
|
+
* The checks address array members with brackets — `layout[2].image` — because
|
|
61
|
+
* they walk a document. Payload's form state keys the same field
|
|
62
|
+
* `layout.2.image`. One is not a prefix of the other, so an unrewritten path
|
|
63
|
+
* matches no field and the error would land nowhere.
|
|
64
|
+
*/
|
|
65
|
+
export declare function toFormPath(field: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Turns a pipeline block into errors attached to the fields that caused it.
|
|
68
|
+
*
|
|
69
|
+
* `formPaths` is what the form actually has — `Object.keys(getFields())` at the
|
|
70
|
+
* call site. Only those paths are used, and that restriction is load-bearing
|
|
71
|
+
* rather than defensive: Payload's reducer *creates* a field state entry for
|
|
72
|
+
* any path it is handed, and an invented entry becomes invented data on the
|
|
73
|
+
* next save. `speakers.0.portrait` is a real issue path — the pipeline walks
|
|
74
|
+
* the document at depth, so a related person's portrait is in the tree — and
|
|
75
|
+
* writing it into form state would turn a relationship's list of ids into a
|
|
76
|
+
* list of objects.
|
|
77
|
+
*
|
|
78
|
+
* An issue whose exact path is not a field falls back to the nearest ancestor
|
|
79
|
+
* that is, so a problem inside a populated relationship marks the relationship
|
|
80
|
+
* and a block-level composition failure marks the block field. That is also
|
|
81
|
+
* what puts the error count on a *collapsed* block row: the reducer propagates
|
|
82
|
+
* every error path up to its parents.
|
|
83
|
+
*
|
|
84
|
+
* Anything that resolves to no field at all is left out and stays in the toast,
|
|
85
|
+
* which is the whole reason the toast keeps listing the issues.
|
|
86
|
+
*/
|
|
87
|
+
export declare function fieldErrorsFromBlock(body: PublishingResponse, formPaths: Iterable<string>): PublishingFieldError[];
|
|
45
88
|
/**
|
|
46
89
|
* Turns a pipeline block into something an editor can act on: which step
|
|
47
90
|
* said no, what it objected to, and what to do about it. This is the
|
|
48
91
|
* information the pipeline already returns — it just never had a way to
|
|
49
92
|
* reach the screen.
|
|
50
93
|
*/
|
|
51
|
-
export declare function describeBlock(body: PublishingResponse
|
|
94
|
+
export declare function describeBlock(body: PublishingResponse, options?: {
|
|
95
|
+
markedFields?: number;
|
|
96
|
+
}): {
|
|
52
97
|
title: string;
|
|
53
98
|
description: string;
|
|
54
99
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publishing-client.d.ts","sourceRoot":"","sources":["../../src/admin/publishing-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,eAAe,EAAE,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,SAAS,GAAG,WAAW,CAAA;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAElC;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CA8B/B;
|
|
1
|
+
{"version":3,"file":"publishing-client.d.ts","sourceRoot":"","sources":["../../src/admin/publishing-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,eAAe,EAAE,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,SAAS,GAAG,WAAW,CAAA;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAElC;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CA8B/B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,kBAAkB,EACxB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC1B,oBAAoB,EAAE,CAgBxB;AAeD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,kBAAkB,EACxB,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GACtC;IACD,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;CACpB,CA4BA"}
|
|
@@ -36,6 +36,71 @@ export async function callPublishingEndpoint(args) {
|
|
|
36
36
|
}
|
|
37
37
|
return { ok: true, body };
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Rewrites a pipeline issue's field path into a form state path.
|
|
41
|
+
*
|
|
42
|
+
* The checks address array members with brackets — `layout[2].image` — because
|
|
43
|
+
* they walk a document. Payload's form state keys the same field
|
|
44
|
+
* `layout.2.image`. One is not a prefix of the other, so an unrewritten path
|
|
45
|
+
* matches no field and the error would land nowhere.
|
|
46
|
+
*/
|
|
47
|
+
export function toFormPath(field) {
|
|
48
|
+
return field
|
|
49
|
+
.replace(/\[(\d+)\]/g, '.$1')
|
|
50
|
+
.replace(/\.{2,}/g, '.')
|
|
51
|
+
.replace(/^\.|\.$/g, '');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Turns a pipeline block into errors attached to the fields that caused it.
|
|
55
|
+
*
|
|
56
|
+
* `formPaths` is what the form actually has — `Object.keys(getFields())` at the
|
|
57
|
+
* call site. Only those paths are used, and that restriction is load-bearing
|
|
58
|
+
* rather than defensive: Payload's reducer *creates* a field state entry for
|
|
59
|
+
* any path it is handed, and an invented entry becomes invented data on the
|
|
60
|
+
* next save. `speakers.0.portrait` is a real issue path — the pipeline walks
|
|
61
|
+
* the document at depth, so a related person's portrait is in the tree — and
|
|
62
|
+
* writing it into form state would turn a relationship's list of ids into a
|
|
63
|
+
* list of objects.
|
|
64
|
+
*
|
|
65
|
+
* An issue whose exact path is not a field falls back to the nearest ancestor
|
|
66
|
+
* that is, so a problem inside a populated relationship marks the relationship
|
|
67
|
+
* and a block-level composition failure marks the block field. That is also
|
|
68
|
+
* what puts the error count on a *collapsed* block row: the reducer propagates
|
|
69
|
+
* every error path up to its parents.
|
|
70
|
+
*
|
|
71
|
+
* Anything that resolves to no field at all is left out and stays in the toast,
|
|
72
|
+
* which is the whole reason the toast keeps listing the issues.
|
|
73
|
+
*/
|
|
74
|
+
export function fieldErrorsFromBlock(body, formPaths) {
|
|
75
|
+
const paths = formPaths instanceof Set ? formPaths : new Set(formPaths);
|
|
76
|
+
// Grouped, because several issues can resolve to one field — three bad
|
|
77
|
+
// blocks all land on `layout` — and the reducer keeps one message per path.
|
|
78
|
+
const byPath = new Map();
|
|
79
|
+
for (const issue of body.issues ?? []) {
|
|
80
|
+
if (!issue.field)
|
|
81
|
+
continue;
|
|
82
|
+
const resolved = resolveFieldPath(toFormPath(issue.field), paths);
|
|
83
|
+
if (!resolved)
|
|
84
|
+
continue;
|
|
85
|
+
const messages = byPath.get(resolved) ?? [];
|
|
86
|
+
if (!messages.includes(issue.message))
|
|
87
|
+
messages.push(issue.message);
|
|
88
|
+
byPath.set(resolved, messages);
|
|
89
|
+
}
|
|
90
|
+
return [...byPath].map(([path, messages]) => ({ path, message: messages.join('; ') }));
|
|
91
|
+
}
|
|
92
|
+
/** The path itself if the form has it, else its nearest ancestor that it does. */
|
|
93
|
+
function resolveFieldPath(path, formPaths) {
|
|
94
|
+
if (path === '' || path === '(root)')
|
|
95
|
+
return undefined;
|
|
96
|
+
const segments = path.split('.');
|
|
97
|
+
for (let end = segments.length; end > 0; end--) {
|
|
98
|
+
const candidate = segments.slice(0, end).join('.');
|
|
99
|
+
if (formPaths.has(candidate))
|
|
100
|
+
return candidate;
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
39
104
|
const MAX_LISTED_ISSUES = 5;
|
|
40
105
|
/**
|
|
41
106
|
* Turns a pipeline block into something an editor can act on: which step
|
|
@@ -43,7 +108,7 @@ const MAX_LISTED_ISSUES = 5;
|
|
|
43
108
|
* information the pipeline already returns — it just never had a way to
|
|
44
109
|
* reach the screen.
|
|
45
110
|
*/
|
|
46
|
-
export function describeBlock(body) {
|
|
111
|
+
export function describeBlock(body, options = {}) {
|
|
47
112
|
const title = body.reason ?? `Publish blocked at the ${body.failedAt ?? 'policy'} check.`;
|
|
48
113
|
const lines = [];
|
|
49
114
|
if (body.failedAt && body.reason) {
|
|
@@ -59,6 +124,12 @@ export function describeBlock(body) {
|
|
|
59
124
|
if (body.suggestion) {
|
|
60
125
|
lines.push(`Suggestion: ${body.suggestion}`);
|
|
61
126
|
}
|
|
127
|
+
// Said only when it is true. An editor who has read a toast listing five
|
|
128
|
+
// paths still has to find them, and the answer — they are marked on the
|
|
129
|
+
// fields — is not something the toast otherwise reveals.
|
|
130
|
+
if ((options.markedFields ?? 0) > 0) {
|
|
131
|
+
lines.push('Fields with a problem are highlighted in the form.');
|
|
132
|
+
}
|
|
62
133
|
return { title, description: lines.join('\n') };
|
|
63
134
|
}
|
|
64
135
|
//# sourceMappingURL=publishing-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publishing-client.js","sourceRoot":"","sources":["../../src/admin/publishing-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoCH;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAgC;IAEhC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,EAAE,CAAA;IAEjF,IAAI,QAAkB,CAAA;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC1B,MAAM,EAAE,MAAM;YACd,WAAW,EAAE,SAAS;YACtB,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;SACnE,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,wCAAwC,EAAE,CAAA;IACzE,CAAC;IAED,IAAI,IAAwB,CAAA;IAC5B,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAuB,CAAA;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,8BAA8B,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAA;IACjF,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,IAAI,CAAC,KAAK,IAAI,8BAA8B,QAAQ,CAAC,MAAM,GAAG;SACxE,CAAA;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AAC3B,CAAC;AAED,MAAM,iBAAiB,GAAG,CAAC,CAAA;AAE3B;;;;;GAKG;AACH,MAAM,UAAU,aAAa,
|
|
1
|
+
{"version":3,"file":"publishing-client.js","sourceRoot":"","sources":["../../src/admin/publishing-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,4 +8,21 @@ export type { PipelineContext, PipelineResult, PipelineStep, PipelineStepResult,
|
|
|
8
8
|
*/
|
|
9
9
|
export { getPublishStatus, getPublishingService, publishDocument, unpublishDocument, } from './service.js';
|
|
10
10
|
export type { DocumentActionArgs, PublishOutcome, PublishRequest, PublishStatusOutcome, PublishingActor, PublishingService, UnpublishOutcome, } from './service.js';
|
|
11
|
+
/**
|
|
12
|
+
* Whether the update in flight on this document is a draft write — a "Save
|
|
13
|
+
* draft", or a tick of autosave — rather than one that changes what the
|
|
14
|
+
* public sees.
|
|
15
|
+
*
|
|
16
|
+
* `afterChange` cannot work this out for itself. Payload sets
|
|
17
|
+
* `data._status = 'draft'` on any `draft: true` update before the hooks
|
|
18
|
+
* run, and `previousDoc` is the latest *version* rather than the live
|
|
19
|
+
* document, so a draft save of a published page and an unpublish of it look
|
|
20
|
+
* the same from inside the hook. The publishing plugin already records the
|
|
21
|
+
* operation's real `draft` argument in `beforeOperation` for its own trust
|
|
22
|
+
* boundary; this exposes the same answer to host hooks.
|
|
23
|
+
*
|
|
24
|
+
* With autosave on, a host `afterChange` that drops a cache or sends a
|
|
25
|
+
* notification fires every few seconds of typing unless it asks this first.
|
|
26
|
+
*/
|
|
27
|
+
export { isDraftWrite } from './hooks/draft-writes.js';
|
|
11
28
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAE5B;;;;GAIG;AACH,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,GAClB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,eAAe,EACf,cAAc,EACd,YAAY,EACZ,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAE5B;;;;GAIG;AACH,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,GAClB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,cAAc,CAAA;AAErB;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -5,4 +5,21 @@ export { publishingPlugin } from './plugin.js';
|
|
|
5
5
|
* given user, with no API key and correct audit attribution.
|
|
6
6
|
*/
|
|
7
7
|
export { getPublishStatus, getPublishingService, publishDocument, unpublishDocument, } from './service.js';
|
|
8
|
+
/**
|
|
9
|
+
* Whether the update in flight on this document is a draft write — a "Save
|
|
10
|
+
* draft", or a tick of autosave — rather than one that changes what the
|
|
11
|
+
* public sees.
|
|
12
|
+
*
|
|
13
|
+
* `afterChange` cannot work this out for itself. Payload sets
|
|
14
|
+
* `data._status = 'draft'` on any `draft: true` update before the hooks
|
|
15
|
+
* run, and `previousDoc` is the latest *version* rather than the live
|
|
16
|
+
* document, so a draft save of a published page and an unpublish of it look
|
|
17
|
+
* the same from inside the hook. The publishing plugin already records the
|
|
18
|
+
* operation's real `draft` argument in `beforeOperation` for its own trust
|
|
19
|
+
* boundary; this exposes the same answer to host hooks.
|
|
20
|
+
*
|
|
21
|
+
* With autosave on, a host `afterChange` that drops a cache or sends a
|
|
22
|
+
* notification fires every few seconds of typing unless it asks this first.
|
|
23
|
+
*/
|
|
24
|
+
export { isDraftWrite } from './hooks/draft-writes.js';
|
|
8
25
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAmB9C;;;;GAIG;AACH,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,GAClB,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAmB9C;;;;GAIG;AACH,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,GAClB,MAAM,cAAc,CAAA;AAYrB;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../src/pipeline/steps/approval.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../src/pipeline/steps/approval.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,eAErC,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,EAAE,YA+C1B,CAAA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { documentContentHash } from '@forumone/throughline-core';
|
|
1
2
|
/**
|
|
2
3
|
* Symbol the approvals plugin attaches its resolver under. Publishing's
|
|
3
4
|
* approval step looks here when no resolver is supplied via options, which
|
|
@@ -29,7 +30,18 @@ export const approvalStep = async (ctx) => {
|
|
|
29
30
|
suggestion: 'Register approvalsPlugin in your Payload config (it attaches the resolver automatically) or pass an explicit `approvalResolver` to publishingPlugin.',
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
/*
|
|
34
|
+
The approval binds to the document's content, not to its `updatedAt`. The
|
|
35
|
+
approvals plugin's `request_approval` computes this same hash, with this
|
|
36
|
+
same function, over a document loaded by the same `findByID` call — so an
|
|
37
|
+
approval granted on what an approver read still resolves after a save that
|
|
38
|
+
changed nothing, and does not resolve after one that changed something.
|
|
39
|
+
|
|
40
|
+
Binding to `updatedAt` made that a property of a timestamp rather than a
|
|
41
|
+
rule: any save at all invalidated a pending approval, which is also why
|
|
42
|
+
autosave and approvals could not both be on. See #341.
|
|
43
|
+
*/
|
|
44
|
+
const versionId = await documentContentHash(ctx.document);
|
|
33
45
|
const approval = await resolver.getActiveApproval(ctx.collection.slug, ctx.documentId, versionId);
|
|
34
46
|
if (!approval) {
|
|
35
47
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval.js","sourceRoot":"","sources":["../../../src/pipeline/steps/approval.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"approval.js","sourceRoot":"","sources":["../../../src/pipeline/steps/approval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAIhE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC,GAAG,CACjD,0CAA0C,CAC3C,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,YAAY,GAAiB,KAAK,EAAE,GAAG,EAAE,EAAE;IACtD,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAEzC,CAAA;IACb,IAAI,CAAC,MAAM,EAAE,CAAC,kBAAkB,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IAExD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,IAAI,uBAAuB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACrF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,IAAI,EAAE,KAAK;YACX,IAAI,EAAE,2BAA2B;YACjC,MAAM,EAAE,mEAAmE;YAC3E,UAAU,EACR,sJAAsJ;SACzJ,CAAA;IACH,CAAC;IAED;;;;;;;;;;MAUE;IACF,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACzD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CAC/C,GAAG,CAAC,UAAU,CAAC,IAAI,EACnB,GAAG,CAAC,UAAU,EACd,SAAS,CACV,CAAA;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,IAAI,EAAE,KAAK;YACX,IAAI,EAAE,mBAAmB;YACzB,MAAM,EACJ,wFAAwF;YAC1F,UAAU,EACR,mFAAmF;SACtF,CAAA;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACvB,CAAC,CAAA;AAED,SAAS,uBAAuB,CAAC,OAAe;IAC9C,MAAM,KAAK,GAAI,OAAmC,CAAC,yBAAyB,CAAC,CAAA;IAC7E,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAE,KAA0B,CAAC,CAAC,CAAC,SAAS,CAAA;AAC9F,CAAC"}
|
|
@@ -30,6 +30,15 @@ import type { PipelineStep } from '../types.js';
|
|
|
30
30
|
* The event is emitted after the write and cannot fail the step: once
|
|
31
31
|
* `_status` is `published` the publish has happened, and reporting failure
|
|
32
32
|
* would send an editor back to re-publish live content.
|
|
33
|
+
*
|
|
34
|
+
* A field Payload refuses is a failed *step*, not a thrown error. The write is
|
|
35
|
+
* the first thing in the whole pipeline that enforces `required` — a draft
|
|
36
|
+
* write does not, which is the point of drafts — so an empty required field
|
|
37
|
+
* inside a block reaches here and nowhere earlier. Thrown, it left the
|
|
38
|
+
* transport to explain itself: the admin got a bare message and the MCP tool
|
|
39
|
+
* got an exception, when Payload had already said exactly which paths were
|
|
40
|
+
* wrong. Returned as issues, it travels the same road as every other block —
|
|
41
|
+
* onto the fields in the admin, into the tool's result, into the audit row.
|
|
33
42
|
*/
|
|
34
43
|
export declare const executeStep: PipelineStep;
|
|
35
44
|
//# sourceMappingURL=execute.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/pipeline/steps/execute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/pipeline/steps/execute.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,aAAa,CAAA;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,WAAW,EAAE,YAoDzB,CAAA"}
|
|
@@ -30,6 +30,15 @@ import { sendEventSafely } from '../../events.js';
|
|
|
30
30
|
* The event is emitted after the write and cannot fail the step: once
|
|
31
31
|
* `_status` is `published` the publish has happened, and reporting failure
|
|
32
32
|
* would send an editor back to re-publish live content.
|
|
33
|
+
*
|
|
34
|
+
* A field Payload refuses is a failed *step*, not a thrown error. The write is
|
|
35
|
+
* the first thing in the whole pipeline that enforces `required` — a draft
|
|
36
|
+
* write does not, which is the point of drafts — so an empty required field
|
|
37
|
+
* inside a block reaches here and nowhere earlier. Thrown, it left the
|
|
38
|
+
* transport to explain itself: the admin got a bare message and the MCP tool
|
|
39
|
+
* got an exception, when Payload had already said exactly which paths were
|
|
40
|
+
* wrong. Returned as issues, it travels the same road as every other block —
|
|
41
|
+
* onto the fields in the admin, into the tool's result, into the audit row.
|
|
33
42
|
*/
|
|
34
43
|
export const executeStep = async (ctx) => {
|
|
35
44
|
const now = new Date().toISOString();
|
|
@@ -37,18 +46,35 @@ export const executeStep = async (ctx) => {
|
|
|
37
46
|
? ctx.document[ctx.collection.publishedAtField]
|
|
38
47
|
: null;
|
|
39
48
|
const wasFirstPublish = previousPublishedAt === null;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
try {
|
|
50
|
+
await ctx.payload.update({
|
|
51
|
+
collection: ctx.collection.slug,
|
|
52
|
+
id: ctx.documentId,
|
|
53
|
+
data: {
|
|
54
|
+
_status: 'published',
|
|
55
|
+
...(wasFirstPublish ? { [ctx.collection.publishedAtField]: now } : {}),
|
|
56
|
+
},
|
|
57
|
+
...(ctx.actor.enforceAccessAs
|
|
58
|
+
? { user: ctx.actor.enforceAccessAs, overrideAccess: false }
|
|
59
|
+
: {}),
|
|
60
|
+
context: { bypassPublishingServer: true },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
const issues = fieldIssues(error);
|
|
65
|
+
// Only a field rejection is an answer. A database or access failure is
|
|
66
|
+
// not, and rethrowing keeps it out of the diagnostics an editor reads as
|
|
67
|
+
// "fix these fields".
|
|
68
|
+
if (!issues)
|
|
69
|
+
throw error;
|
|
70
|
+
return {
|
|
71
|
+
pass: false,
|
|
72
|
+
code: 'field-validation-failed',
|
|
73
|
+
reason: `${issues.length} field${issues.length === 1 ? '' : 's'} the collection will not accept`,
|
|
74
|
+
issues,
|
|
75
|
+
suggestion: 'These are required by the collection rather than by a policy check, so they must be filled before this document can be published.',
|
|
76
|
+
};
|
|
77
|
+
}
|
|
52
78
|
// The write has landed. From here the publish has happened, so nothing
|
|
53
79
|
// below may turn it back into a failure.
|
|
54
80
|
const warning = await sendEventSafely(ctx.inngest, {
|
|
@@ -64,4 +90,34 @@ export const executeStep = async (ctx) => {
|
|
|
64
90
|
});
|
|
65
91
|
return { pass: true, ...(warning ? { warnings: [warning] } : {}) };
|
|
66
92
|
};
|
|
93
|
+
/**
|
|
94
|
+
* Payload's `ValidationError` as issues, or `undefined` for anything else.
|
|
95
|
+
*
|
|
96
|
+
* Read structurally rather than with `instanceof`. The class would work in the
|
|
97
|
+
* ordinary install and fail in the one that matters — two copies of `payload`
|
|
98
|
+
* resolved under one tree make `instanceof` false for an error that is one in
|
|
99
|
+
* every other respect, and the failure mode is a silent rethrow of something
|
|
100
|
+
* an editor could have fixed. The shape is stable: `data.errors` is a list of
|
|
101
|
+
* `{ path, message }`, and the paths are already dotted form paths.
|
|
102
|
+
*/
|
|
103
|
+
function fieldIssues(error) {
|
|
104
|
+
if (!error || typeof error !== 'object')
|
|
105
|
+
return undefined;
|
|
106
|
+
const data = error.data;
|
|
107
|
+
if (!data || typeof data !== 'object')
|
|
108
|
+
return undefined;
|
|
109
|
+
const errors = data.errors;
|
|
110
|
+
if (!Array.isArray(errors) || errors.length === 0)
|
|
111
|
+
return undefined;
|
|
112
|
+
const issues = [];
|
|
113
|
+
for (const entry of errors) {
|
|
114
|
+
if (!entry || typeof entry !== 'object')
|
|
115
|
+
return undefined;
|
|
116
|
+
const { path, message } = entry;
|
|
117
|
+
if (typeof path !== 'string' || typeof message !== 'string')
|
|
118
|
+
return undefined;
|
|
119
|
+
issues.push({ field: path, message, severity: 'error' });
|
|
120
|
+
}
|
|
121
|
+
return issues;
|
|
122
|
+
}
|
|
67
123
|
//# sourceMappingURL=execute.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/pipeline/steps/execute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/pipeline/steps/execute.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forumone/throughline-publishing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Policy-gated publishing server for Throughline. Wraps Payload's update operation with composition, accessibility, required-field, embargo, and approval gating.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"zod": "^3.23.0",
|
|
62
|
-
"@forumone/throughline-core": "0.
|
|
62
|
+
"@forumone/throughline-core": "0.3.0",
|
|
63
63
|
"@forumone/throughline-plugin-contract": "0.2.1"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|