@forumone/throughline-publishing 0.3.1 → 0.3.2
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 +22 -0
- package/README.md +19 -0
- package/dist/admin/PublishButton.d.ts.map +1 -1
- package/dist/admin/PublishButton.js +8 -3
- package/dist/admin/PublishButton.js.map +1 -1
- package/dist/hooks/block-status-writes.d.ts +11 -2
- package/dist/hooks/block-status-writes.d.ts.map +1 -1
- package/dist/hooks/block-status-writes.js +24 -3
- package/dist/hooks/block-status-writes.js.map +1 -1
- package/dist/hooks/draft-writes.d.ts +32 -0
- package/dist/hooks/draft-writes.d.ts.map +1 -0
- package/dist/hooks/draft-writes.js +76 -0
- package/dist/hooks/draft-writes.js.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +9 -1
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @forumone/throughline-publishing
|
|
2
2
|
|
|
3
|
+
## 0.3.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4eeb721: Fix published documents being uneditable: allow draft writes through the trust boundary.
|
|
8
|
+
|
|
9
|
+
Editing an already-published document failed with `Direct writes to _status are not allowed` — from both the plugin's own Publish button and Payload's native Save Draft, which discarded the editor's work. Only first publishes worked, because an unmodified document skips the draft save.
|
|
10
|
+
|
|
11
|
+
Payload sets `data._status = 'draft'` on every `draft: true` update _before_ `beforeChange` runs, whether or not the caller supplied it. By the time the hook saw the write, saving a draft of a published document was indistinguishable from unpublishing it: `data._status` was `'draft'` and `originalDoc._status` was `'published'` in both cases. A draft save writes a version and leaves the live document alone, so it should never have been blocked.
|
|
12
|
+
|
|
13
|
+
The plugin now installs a `beforeOperation` hook that records the operation's own `draft` argument, which `beforeChange` reads to tell the two apart. That argument is visible identically on the Local API, REST and GraphQL, unlike `req.query.draft`, which is only populated on the REST path.
|
|
14
|
+
|
|
15
|
+
A `draft: true` request that sets `_status: 'published'` is still blocked — Payload's own `isSavingDraft` excludes it, so it is a real publish and belongs in the pipeline. Genuine unpublishes and direct publishes are unchanged. Installing the status-write hook without the recorder fails closed.
|
|
16
|
+
|
|
17
|
+
- 4eeb721: Fix two defects reported against 0.3.0.
|
|
18
|
+
|
|
19
|
+
**The `alt-text` check false-positived on Payload upload derivatives.** `walkForImages` descended into a populated upload's `sizes` map, and every generated size carries `filename` and `mimeType` but never `alt` — that lives on the parent document. Each configured `imageSize` therefore produced one false failure, and any page carrying a sized image could not be published. The walk now skips `sizes` on an object that is itself an image; alt text is checked once, on the parent. A parent with missing or empty alt still fails, at the parent's path, and a host with no `imageSizes` is unaffected.
|
|
20
|
+
|
|
21
|
+
**A failed Inngest emission failed a publish that had already succeeded.** The event is sent after the document is written, so a transport failure (an invalid `INNGEST_EVENT_KEY`, say) returned 500 for a document that was published — and lost the audit record for it. Publish, unpublish, rollback and `schedule_publish` now report success and carry the emission failure as a `warnings` array on the result. The admin renders it as a warning toast on an otherwise successful publish.
|
|
22
|
+
|
|
23
|
+
Also adds `disableAccessibilityChecks`, naming built-in checks to skip. `accessibilityChecks` only appends, so previously a built-in that misfired on a host's content shape blocked every publish until the plugin shipped a fix.
|
|
24
|
+
|
|
3
25
|
## 0.3.1
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -96,6 +96,25 @@ if (!result.published) {
|
|
|
96
96
|
|
|
97
97
|
All three run the same pipeline the admin and MCP paths use, so host code cannot drift from the plugin's policy. `getPublishStatus` runs every check except the write and mutates nothing.
|
|
98
98
|
|
|
99
|
+
## What the trust boundary blocks
|
|
100
|
+
|
|
101
|
+
The plugin installs two hooks on every configured collection, and they work as a pair:
|
|
102
|
+
|
|
103
|
+
- `beforeOperation` records whether the update in flight is a draft write.
|
|
104
|
+
- `beforeChange` rejects writes that change the **live** document's `_status`.
|
|
105
|
+
|
|
106
|
+
| Write | Result |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `draft: true` on a draft or published document | **allowed** — writes a version, live status unchanged |
|
|
109
|
+
| `draft: false`, `_status: 'published'` | **blocked** — publish through the pipeline |
|
|
110
|
+
| `draft: false`, `_status: 'draft'` on a published document | **blocked** — unpublish through the pipeline |
|
|
111
|
+
| `draft: true` with `_status: 'published'` | **blocked** — Payload treats this as a publish, not a draft save |
|
|
112
|
+
| Any write carrying `bypassPublishingServer` | **allowed** |
|
|
113
|
+
|
|
114
|
+
Draft saves have to be allowed explicitly because Payload sets `data._status = 'draft'` on every `draft: true` update before `beforeChange` runs, whether or not the caller supplied it — so at that point a draft save of a published document and an unpublish look identical. The `draft` flag is read from the operation's own arguments in `beforeOperation`, which sees it the same way on the Local API, REST and GraphQL. (`req.query.draft` is only populated on the REST path, so keying on the request would cover the admin and silently miss scripts.)
|
|
115
|
+
|
|
116
|
+
If you install `createBlockStatusWritesHook` yourself without the recorder, it fails closed: every status change is blocked.
|
|
117
|
+
|
|
99
118
|
## Bypassing the pipeline
|
|
100
119
|
|
|
101
120
|
`bypassPublishingServer: true` in the Payload request context is the only way to write `_status` without the pipeline. It is intended for seed scripts and migrations:
|
|
@@ -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;IACpB,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;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;IACpB,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAE,6BAAkC,GAAG,KAAK,CAAC,SAAS,CA4IxF"}
|
|
@@ -33,9 +33,14 @@ export function PublishButton(props = {}) {
|
|
|
33
33
|
return;
|
|
34
34
|
setPublishing(true);
|
|
35
35
|
try {
|
|
36
|
-
// Persist pending edits first.
|
|
37
|
-
//
|
|
38
|
-
//
|
|
36
|
+
// Persist pending edits first, as a draft. Payload writes those to the
|
|
37
|
+
// versions table and leaves the published document alone, so the trust
|
|
38
|
+
// boundary lets them through; the pipeline then evaluates what was
|
|
39
|
+
// actually saved rather than what is on screen.
|
|
40
|
+
//
|
|
41
|
+
// `?draft=true` is what makes this a draft write. The `_status`
|
|
42
|
+
// override only pins the intent when form state carries a `_status` of
|
|
43
|
+
// its own, and mirrors what Payload's native Save Draft sends.
|
|
39
44
|
if (modified) {
|
|
40
45
|
const saved = await submit({
|
|
41
46
|
action: `${serverURL}${api}/${collectionSlug}/${id}?draft=true&depth=0`,
|
|
@@ -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;AAS9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAAC,QAAuC,EAAE;IACrE,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,aAAa,CAAA;IAEtD,MAAM,EACJ,cAAc,EACd,IAAI,EACJ,eAAe,EACf,oBAAoB,EACpB,EAAE,EACF,kBAAkB,EAClB,+BAA+B,EAC/B,0BAA0B,EAC1B,uBAAuB,EACvB,YAAY,GACb,GAAG,eAAe,EAAE,CAAA;IAErB,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAA;IAC9B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAAA;IACnC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAA;IAClC,MAAM,EAAE,CAAC,EAAE,GAAG,cAAc,EAAE,CAAA;IAC9B,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEnD,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,CAAA;IAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAA;IAExC,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACrC,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,cAAc,IAAI,UAAU;YAAE,OAAM;QAC5E,aAAa,CAAC,IAAI,CAAC,CAAA;QAEnB,IAAI,CAAC;YACH,
|
|
1
|
+
{"version":3,"file":"PublishButton.js","sourceRoot":"","sources":["../../src/admin/PublishButton.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import type { CollectionBeforeChangeHook } from 'payload';
|
|
2
2
|
/**
|
|
3
3
|
* The trust boundary. This `beforeChange` hook rejects every update that
|
|
4
|
-
*
|
|
5
|
-
* `bypassPublishingServer` context flag (set by the pipeline's
|
|
4
|
+
* changes the live document's `_status` unless the request explicitly
|
|
5
|
+
* carries the `bypassPublishingServer` context flag (set by the pipeline's
|
|
6
|
+
* `executeStep`).
|
|
6
7
|
*
|
|
7
8
|
* Without this hook, the Payload MCP could let Claude flip a document to
|
|
8
9
|
* `published` directly, sidestepping every check the publishing server
|
|
9
10
|
* exists to enforce. With it, the only sanctioned path is the pipeline.
|
|
10
11
|
*
|
|
12
|
+
* Draft writes pass through. A `draft: true` update writes a new row in the
|
|
13
|
+
* versions table and leaves the published document alone, so it changes no
|
|
14
|
+
* live status — but Payload injects `data._status = 'draft'` into every such
|
|
15
|
+
* update before this hook runs, which made saving a draft of a published
|
|
16
|
+
* document indistinguishable from unpublishing it. `createRecordDraftWritesHook`
|
|
17
|
+
* captures the operation's real `draft` flag so the two can be told apart;
|
|
18
|
+
* both hooks must be installed together.
|
|
19
|
+
*
|
|
11
20
|
* Throws `APIError` rather than `Error` so Payload returns 400 with the
|
|
12
21
|
* message intact instead of swallowing it into a 500 and a generic
|
|
13
22
|
* "Something went wrong" toast.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-status-writes.d.ts","sourceRoot":"","sources":["../../src/hooks/block-status-writes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"block-status-writes.d.ts","sourceRoot":"","sources":["../../src/hooks/block-status-writes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAGzD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,2BAA2B,IAAI,0BAA0B,CAoCxE"}
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import { APIError } from 'payload';
|
|
2
|
+
import { isDraftWrite } from './draft-writes.js';
|
|
2
3
|
/**
|
|
3
4
|
* The trust boundary. This `beforeChange` hook rejects every update that
|
|
4
|
-
*
|
|
5
|
-
* `bypassPublishingServer` context flag (set by the pipeline's
|
|
5
|
+
* changes the live document's `_status` unless the request explicitly
|
|
6
|
+
* carries the `bypassPublishingServer` context flag (set by the pipeline's
|
|
7
|
+
* `executeStep`).
|
|
6
8
|
*
|
|
7
9
|
* Without this hook, the Payload MCP could let Claude flip a document to
|
|
8
10
|
* `published` directly, sidestepping every check the publishing server
|
|
9
11
|
* exists to enforce. With it, the only sanctioned path is the pipeline.
|
|
10
12
|
*
|
|
13
|
+
* Draft writes pass through. A `draft: true` update writes a new row in the
|
|
14
|
+
* versions table and leaves the published document alone, so it changes no
|
|
15
|
+
* live status — but Payload injects `data._status = 'draft'` into every such
|
|
16
|
+
* update before this hook runs, which made saving a draft of a published
|
|
17
|
+
* document indistinguishable from unpublishing it. `createRecordDraftWritesHook`
|
|
18
|
+
* captures the operation's real `draft` flag so the two can be told apart;
|
|
19
|
+
* both hooks must be installed together.
|
|
20
|
+
*
|
|
11
21
|
* Throws `APIError` rather than `Error` so Payload returns 400 with the
|
|
12
22
|
* message intact instead of swallowing it into a 500 and a generic
|
|
13
23
|
* "Something went wrong" toast.
|
|
14
24
|
*/
|
|
15
25
|
export function createBlockStatusWritesHook() {
|
|
16
|
-
return ({ data, originalDoc, operation, context, req }) => {
|
|
26
|
+
return ({ collection, data, originalDoc, operation, context, req }) => {
|
|
17
27
|
if (operation !== 'update')
|
|
18
28
|
return data;
|
|
19
29
|
if (!hasStatusChange(data))
|
|
@@ -27,6 +37,17 @@ export function createBlockStatusWritesHook() {
|
|
|
27
37
|
}
|
|
28
38
|
if (isBypassed(context) || isBypassed(req?.context))
|
|
29
39
|
return data;
|
|
40
|
+
// A draft save touches a version, not the live document.
|
|
41
|
+
//
|
|
42
|
+
// Mirror Payload's own `isSavingDraft`, which requires the incoming
|
|
43
|
+
// status to be something other than `published`. A request that asks for
|
|
44
|
+
// `draft: true` while setting `_status: 'published'` is a real publish —
|
|
45
|
+
// Payload treats it as one — so it stays blocked. Without this, `draft`
|
|
46
|
+
// would be a way to publish around the pipeline.
|
|
47
|
+
if (data['_status'] !== 'published' &&
|
|
48
|
+
isDraftWrite(req, collection?.slug, originalDoc?.id)) {
|
|
49
|
+
return data;
|
|
50
|
+
}
|
|
30
51
|
throw new APIError('Direct writes to `_status` are not allowed. Use the publishing server (publish / unpublish / rollback) so the policy pipeline runs.', 400);
|
|
31
52
|
};
|
|
32
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-status-writes.js","sourceRoot":"","sources":["../../src/hooks/block-status-writes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"block-status-writes.js","sourceRoot":"","sources":["../../src/hooks/block-status-writes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAElC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE;QACpE,IAAI,SAAS,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAA;QACvC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QAEvC,+DAA+D;QAC/D,IACE,WAAW;YACX,OAAO,WAAW,KAAK,QAAQ;YAC9B,IAAgC,CAAC,SAAS,CAAC;gBACzC,WAAuC,CAAC,SAAS,CAAC,EACrD,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;YAAE,OAAO,IAAI,CAAA;QAEhE,yDAAyD;QACzD,EAAE;QACF,oEAAoE;QACpE,yEAAyE;QACzE,yEAAyE;QACzE,wEAAwE;QACxE,iDAAiD;QACjD,IACG,IAAgC,CAAC,SAAS,CAAC,KAAK,WAAW;YAC5D,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAG,WAA4C,EAAE,EAAE,CAAC,EACtF,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QAED,MAAM,IAAI,QAAQ,CAChB,qIAAqI,EACrI,GAAG,CACJ,CAAA;IACH,CAAC,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAC,IAAa;IACpC,OAAO,CACL,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,SAAS,IAAI,IAAI,CAC/D,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,OAAgB;IAClC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IACzD,OAAQ,OAAmC,CAAC,wBAAwB,CAAC,KAAK,IAAI,CAAA;AAChF,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CollectionBeforeOperationHook, PayloadRequest } from 'payload';
|
|
2
|
+
/**
|
|
3
|
+
* Records whether the update in flight is a draft write, so the
|
|
4
|
+
* status-write hook can tell a draft save apart from an unpublish.
|
|
5
|
+
*
|
|
6
|
+
* It has to be recorded here because `beforeChange` cannot work it out:
|
|
7
|
+
* Payload sets `data._status = 'draft'` for any `draft: true` update
|
|
8
|
+
* *before* calling the hook, whether or not the caller supplied it —
|
|
9
|
+
*
|
|
10
|
+
* const isSavingDraft = Boolean(draftArg && hasDraftsEnabled(config))
|
|
11
|
+
* && data._status !== 'published' && !publishAllLocales
|
|
12
|
+
* if (isSavingDraft) { data._status = 'draft' }
|
|
13
|
+
*
|
|
14
|
+
* so by the time `beforeChange` runs, saving a draft of a published
|
|
15
|
+
* document and unpublishing it look identical: `data._status` is `'draft'`
|
|
16
|
+
* and `originalDoc._status` is `'published'` in both cases.
|
|
17
|
+
*
|
|
18
|
+
* `beforeOperation` is the one place that sees the operation's own `draft`
|
|
19
|
+
* argument, and it sees it identically on the Local API, REST and GraphQL —
|
|
20
|
+
* unlike `req.query.draft`, which is only populated on the REST path.
|
|
21
|
+
* `beforeOperation` shares `req.context` with `beforeChange`, which is how
|
|
22
|
+
* the flag gets across.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createRecordDraftWritesHook(): CollectionBeforeOperationHook;
|
|
25
|
+
/**
|
|
26
|
+
* Whether the update in flight on this document is a draft write.
|
|
27
|
+
*
|
|
28
|
+
* Defaults to `false` when nothing was recorded, so a caller that installs
|
|
29
|
+
* the status-write hook without this one keeps the stricter behaviour.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isDraftWrite(req: Pick<PayloadRequest, 'context'> | undefined, collectionSlug: string | undefined, id: unknown): boolean;
|
|
32
|
+
//# sourceMappingURL=draft-writes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft-writes.d.ts","sourceRoot":"","sources":["../../src/hooks/draft-writes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAM5E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,2BAA2B,IAAI,6BAA6B,CAW3E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,GAAG,SAAS,EAChD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,EAAE,EAAE,OAAO,GACV,OAAO,CAcT"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const DRAFT_WRITES_KEY = '__throughlinePublishingDraftWrites';
|
|
2
|
+
/**
|
|
3
|
+
* Records whether the update in flight is a draft write, so the
|
|
4
|
+
* status-write hook can tell a draft save apart from an unpublish.
|
|
5
|
+
*
|
|
6
|
+
* It has to be recorded here because `beforeChange` cannot work it out:
|
|
7
|
+
* Payload sets `data._status = 'draft'` for any `draft: true` update
|
|
8
|
+
* *before* calling the hook, whether or not the caller supplied it —
|
|
9
|
+
*
|
|
10
|
+
* const isSavingDraft = Boolean(draftArg && hasDraftsEnabled(config))
|
|
11
|
+
* && data._status !== 'published' && !publishAllLocales
|
|
12
|
+
* if (isSavingDraft) { data._status = 'draft' }
|
|
13
|
+
*
|
|
14
|
+
* so by the time `beforeChange` runs, saving a draft of a published
|
|
15
|
+
* document and unpublishing it look identical: `data._status` is `'draft'`
|
|
16
|
+
* and `originalDoc._status` is `'published'` in both cases.
|
|
17
|
+
*
|
|
18
|
+
* `beforeOperation` is the one place that sees the operation's own `draft`
|
|
19
|
+
* argument, and it sees it identically on the Local API, REST and GraphQL —
|
|
20
|
+
* unlike `req.query.draft`, which is only populated on the REST path.
|
|
21
|
+
* `beforeOperation` shares `req.context` with `beforeChange`, which is how
|
|
22
|
+
* the flag gets across.
|
|
23
|
+
*/
|
|
24
|
+
export function createRecordDraftWritesHook() {
|
|
25
|
+
return ({ args, operation, req }) => {
|
|
26
|
+
// `update` and `updateByID` both arrive as the `update` hook operation.
|
|
27
|
+
if (operation !== 'update')
|
|
28
|
+
return;
|
|
29
|
+
const updateArgs = args;
|
|
30
|
+
const slug = collectionSlug(args);
|
|
31
|
+
if (!slug)
|
|
32
|
+
return;
|
|
33
|
+
registry(req)[draftWriteKey(slug, updateArgs.id)] = updateArgs.draft === true;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Whether the update in flight on this document is a draft write.
|
|
38
|
+
*
|
|
39
|
+
* Defaults to `false` when nothing was recorded, so a caller that installs
|
|
40
|
+
* the status-write hook without this one keeps the stricter behaviour.
|
|
41
|
+
*/
|
|
42
|
+
export function isDraftWrite(req, collectionSlug, id) {
|
|
43
|
+
if (!req || !collectionSlug)
|
|
44
|
+
return false;
|
|
45
|
+
const entries = req.context?.[DRAFT_WRITES_KEY];
|
|
46
|
+
if (!entries)
|
|
47
|
+
return false;
|
|
48
|
+
// Keyed per document so a nested write to a different document during the
|
|
49
|
+
// same request cannot be mistaken for this one.
|
|
50
|
+
const scoped = entries[draftWriteKey(collectionSlug, id)];
|
|
51
|
+
if (scoped !== undefined)
|
|
52
|
+
return scoped;
|
|
53
|
+
// Bulk updates match by `where` and carry no id.
|
|
54
|
+
return entries[draftWriteKey(collectionSlug, undefined)] === true;
|
|
55
|
+
}
|
|
56
|
+
function draftWriteKey(collectionSlug, id) {
|
|
57
|
+
return `${collectionSlug}:${id === undefined || id === null ? '*' : String(id)}`;
|
|
58
|
+
}
|
|
59
|
+
function collectionSlug(args) {
|
|
60
|
+
const slug = args?.collection?.config
|
|
61
|
+
?.slug;
|
|
62
|
+
return typeof slug === 'string' ? slug : undefined;
|
|
63
|
+
}
|
|
64
|
+
function registry(req) {
|
|
65
|
+
// Payload always assigns `req.context`, but attach it if absent rather
|
|
66
|
+
// than writing the flag to an object nothing else can see.
|
|
67
|
+
if (!req.context) {
|
|
68
|
+
req.context = {};
|
|
69
|
+
}
|
|
70
|
+
const context = req.context;
|
|
71
|
+
if (!context[DRAFT_WRITES_KEY]) {
|
|
72
|
+
context[DRAFT_WRITES_KEY] = {};
|
|
73
|
+
}
|
|
74
|
+
return context[DRAFT_WRITES_KEY];
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=draft-writes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft-writes.js","sourceRoot":"","sources":["../../src/hooks/draft-writes.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAG,oCAAoC,CAAA;AAI7D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,EAAE;QAClC,wEAAwE;QACxE,IAAI,SAAS,KAAK,QAAQ;YAAE,OAAM;QAElC,MAAM,UAAU,GAAG,IAAiD,CAAA;QACpE,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;QACjC,IAAI,CAAC,IAAI;YAAE,OAAM;QAEjB,QAAQ,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,KAAK,IAAI,CAAA;IAC/E,CAAC,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,GAAgD,EAChD,cAAkC,EAClC,EAAW;IAEX,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc;QAAE,OAAO,KAAK,CAAA;IACzC,MAAM,OAAO,GAAI,GAAG,CAAC,OAA+C,EAAE,CACpE,gBAAgB,CACiB,CAAA;IACnC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IAE1B,0EAA0E;IAC1E,gDAAgD;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAA;IACzD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IAEvC,iDAAiD;IACjD,OAAO,OAAO,CAAC,aAAa,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,KAAK,IAAI,CAAA;AACnE,CAAC;AAED,SAAS,aAAa,CAAC,cAAsB,EAAE,EAAW;IACxD,OAAO,GAAG,cAAc,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;AAClF,CAAC;AAED,SAAS,cAAc,CAAC,IAAa;IACnC,MAAM,IAAI,GAAI,IAAyD,EAAE,UAAU,EAAE,MAAM;QACzF,EAAE,IAAI,CAAA;IACR,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;AACpD,CAAC;AAED,SAAS,QAAQ,CAAC,GAAmB;IACnC,uEAAuE;IACvE,2DAA2D;IAC3D,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,GAAG,CAAC,OAAO,GAAG,EAA+B,CAAA;IAC/C,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAA6C,CAAA;IACjE,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,gBAAgB,CAAC,GAAG,EAA+B,CAAA;IAC7D,CAAC;IACD,OAAO,OAAO,CAAC,gBAAgB,CAAuB,CAAA;AACxD,CAAC"}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAA;AAQvE,OAAO,EACL,KAAK,uBAAuB,EAG7B,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAA;AAQvE,OAAO,EACL,KAAK,uBAAuB,EAG7B,MAAM,cAAc,CAAA;AAqBrB,eAAO,MAAM,gBAAgB,EAAE,UAAU,CAAC,uBAAuB,CA8G9D,CAAA"}
|
package/dist/plugin.js
CHANGED
|
@@ -2,6 +2,7 @@ import { getPluginRegistry } from '@forumone/throughline-plugin-contract';
|
|
|
2
2
|
import { createMcpHandler, createNamedLogger, defaultLogger, getAuditWriter, } from '@forumone/throughline-core';
|
|
3
3
|
import { resolveCollection, validateOptions, } from './options.js';
|
|
4
4
|
import { createBlockStatusWritesHook } from './hooks/block-status-writes.js';
|
|
5
|
+
import { createRecordDraftWritesHook } from './hooks/draft-writes.js';
|
|
5
6
|
import { createAdminEndpoints } from './endpoints/admin.js';
|
|
6
7
|
import { attachPublishingService, createPublishingService } from './service.js';
|
|
7
8
|
import { createGetPublishStatusTool, createPublishTool, createRollbackTool, createSchedulePublishTool, createUnpublishTool, } from './tools/index.js';
|
|
@@ -24,9 +25,16 @@ export const publishingPlugin = (rawOptions) => (incomingConfig) => {
|
|
|
24
25
|
return collection;
|
|
25
26
|
return {
|
|
26
27
|
...collection,
|
|
27
|
-
// The trust boundary: nothing may
|
|
28
|
+
// The trust boundary: nothing may change the live document's
|
|
29
|
+
// `_status` outside the pipeline. `beforeOperation` records whether
|
|
30
|
+
// the update is a draft write, which is the only place Payload
|
|
31
|
+
// exposes that; `beforeChange` enforces. They must ship together.
|
|
28
32
|
hooks: {
|
|
29
33
|
...(collection.hooks ?? {}),
|
|
34
|
+
beforeOperation: [
|
|
35
|
+
...(collection.hooks?.beforeOperation ?? []),
|
|
36
|
+
createRecordDraftWritesHook(),
|
|
37
|
+
],
|
|
30
38
|
beforeChange: [
|
|
31
39
|
...(collection.hooks?.beforeChange ?? []),
|
|
32
40
|
createBlockStatusWritesHook(),
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AACzE,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,cAAc,GACf,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAEL,iBAAiB,EACjB,eAAe,GAChB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAC/E,OAAO,EACL,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,kBAAkB,CAAA;AAEzB,MAAM,SAAS,GAAG,kCAAkC,CAAA;AACpD,MAAM,cAAc,GAAG,OAAO,CAAA;AAC9B,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAA;AAErF,MAAM,YAAY,GAAG,yCAAyC,CAAA;AAI9D,MAAM,CAAC,MAAM,gBAAgB,GAC3B,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,cAAc,EAAE,EAAE;IACjC,IAAI,UAAU,CAAC,OAAO,KAAK,KAAK;QAAE,OAAO,cAAc,CAAA;IAEvD,MAAM,OAAO,GAAG,eAAe,CAAC,UAAU,CAAC,CAAA;IAC3C,yEAAyE;IACzE,6CAA6C;IAC7C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,aAAa,CAAA;IACxD,MAAM,MAAM,GAAG,iBAAiB,CAAC,YAAY,EAAE,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC,CAAA;IAC/E,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IACxE,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,KAAK,KAAK,CAAA;IAEzD,MAAM,mBAAmB,GAAG,CAAC,cAAc,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;QAChF,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,UAAU,CAAA;QAE7D,OAAO;YACL,GAAG,UAAU;YACb,
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.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.
|
|
3
|
+
"version": "0.3.2",
|
|
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",
|