@forumone/throughline-publishing 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +127 -1
  3. package/dist/admin/PublishButton.d.ts +24 -0
  4. package/dist/admin/PublishButton.d.ts.map +1 -0
  5. package/dist/admin/PublishButton.js +116 -0
  6. package/dist/admin/PublishButton.js.map +1 -0
  7. package/dist/admin/UnpublishButton.d.ts +15 -0
  8. package/dist/admin/UnpublishButton.d.ts.map +1 -0
  9. package/dist/admin/UnpublishButton.js +81 -0
  10. package/dist/admin/UnpublishButton.js.map +1 -0
  11. package/dist/admin/publishing-client.d.ts +53 -0
  12. package/dist/admin/publishing-client.d.ts.map +1 -0
  13. package/dist/admin/publishing-client.js +64 -0
  14. package/dist/admin/publishing-client.js.map +1 -0
  15. package/dist/endpoints/admin.d.ts +19 -0
  16. package/dist/endpoints/admin.d.ts.map +1 -0
  17. package/dist/endpoints/admin.js +93 -0
  18. package/dist/endpoints/admin.js.map +1 -0
  19. package/dist/exports/client.d.ts +14 -0
  20. package/dist/exports/client.d.ts.map +1 -0
  21. package/dist/exports/client.js +11 -0
  22. package/dist/exports/client.js.map +1 -0
  23. package/dist/hooks/block-status-writes.d.ts +4 -0
  24. package/dist/hooks/block-status-writes.d.ts.map +1 -1
  25. package/dist/hooks/block-status-writes.js +6 -1
  26. package/dist/hooks/block-status-writes.js.map +1 -1
  27. package/dist/index.d.ts +7 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +6 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/options.d.ts +10 -0
  32. package/dist/options.d.ts.map +1 -1
  33. package/dist/options.js.map +1 -1
  34. package/dist/pipeline/steps/execute.d.ts +5 -0
  35. package/dist/pipeline/steps/execute.d.ts.map +1 -1
  36. package/dist/pipeline/steps/execute.js +8 -0
  37. package/dist/pipeline/steps/execute.js.map +1 -1
  38. package/dist/pipeline/types.d.ts +8 -1
  39. package/dist/pipeline/types.d.ts.map +1 -1
  40. package/dist/plugin.d.ts.map +1 -1
  41. package/dist/plugin.js +62 -5
  42. package/dist/plugin.js.map +1 -1
  43. package/dist/service.d.ts +109 -0
  44. package/dist/service.d.ts.map +1 -0
  45. package/dist/service.js +225 -0
  46. package/dist/service.js.map +1 -0
  47. package/dist/tools/get-publish-status.d.ts +4 -1
  48. package/dist/tools/get-publish-status.d.ts.map +1 -1
  49. package/dist/tools/get-publish-status.js +16 -30
  50. package/dist/tools/get-publish-status.js.map +1 -1
  51. package/dist/tools/publish.d.ts +4 -1
  52. package/dist/tools/publish.d.ts.map +1 -1
  53. package/dist/tools/publish.js +8 -57
  54. package/dist/tools/publish.js.map +1 -1
  55. package/dist/tools/unpublish.d.ts +4 -1
  56. package/dist/tools/unpublish.d.ts.map +1 -1
  57. package/dist/tools/unpublish.js +8 -47
  58. package/dist/tools/unpublish.js.map +1 -1
  59. package/package.json +21 -4
@@ -0,0 +1,93 @@
1
+ import { APIError } from 'payload';
2
+ import { z } from 'zod';
3
+ import { getPublishingService, toAuthenticatedUser } from '../service.js';
4
+ const BodySchema = z.object({
5
+ collection: z.string().min(1),
6
+ id: z.union([z.string().min(1), z.number()]),
7
+ });
8
+ /**
9
+ * The admin's path into the pipeline.
10
+ *
11
+ * These endpoints authenticate off the Payload session cookie, so `req.user`
12
+ * is the logged-in editor — no API key in the editorial publish path, and
13
+ * the audit event records the person rather than a service principal. The
14
+ * write still goes through the pipeline, and still runs with
15
+ * `overrideAccess: false`, so neither the policy checks nor the collection's
16
+ * access control are skipped.
17
+ */
18
+ export function createAdminEndpoints(deps) {
19
+ return [
20
+ {
21
+ path: `${deps.routePrefix}/publish`,
22
+ method: 'post',
23
+ handler: (req) => handle(req, deps, 'publish'),
24
+ },
25
+ {
26
+ path: `${deps.routePrefix}/unpublish`,
27
+ method: 'post',
28
+ handler: (req) => handle(req, deps, 'unpublish'),
29
+ },
30
+ ];
31
+ }
32
+ async function handle(req, deps, action) {
33
+ if (!req.user) {
34
+ return json({ error: 'You must be logged in to publish.' }, 401);
35
+ }
36
+ let raw;
37
+ try {
38
+ raw = await req.json?.();
39
+ }
40
+ catch {
41
+ return json({ error: 'Invalid JSON body.' }, 400);
42
+ }
43
+ const parsed = BodySchema.safeParse(raw);
44
+ if (!parsed.success) {
45
+ return json({ error: 'Expected a JSON body with `collection` and `id`.' }, 400);
46
+ }
47
+ const { collection } = parsed.data;
48
+ const id = String(parsed.data.id);
49
+ if (!deps.publishableSlugs.has(collection)) {
50
+ return json({
51
+ error: `Collection "${collection}" is not registered as publishable. Add it to publishingPlugin's collections option.`,
52
+ }, 400);
53
+ }
54
+ let service;
55
+ try {
56
+ service = getPublishingService(req.payload);
57
+ }
58
+ catch {
59
+ return json({ error: 'Publishing server not initialized.' }, 503);
60
+ }
61
+ const request = {
62
+ collection,
63
+ id,
64
+ actor: {
65
+ user: toAuthenticatedUser(req.user),
66
+ enforceAccessAs: req.user,
67
+ channel: 'admin',
68
+ },
69
+ };
70
+ try {
71
+ const result = action === 'publish'
72
+ ? await service.publish(request)
73
+ : await service.unpublish(request);
74
+ // A pipeline block is a real answer, not a transport failure: 200 with
75
+ // the diagnostic so the admin can render `failedAt` / `reason` /
76
+ // `issues` / `suggestion` rather than a generic error.
77
+ return json(result, 200);
78
+ }
79
+ catch (error) {
80
+ if (error instanceof APIError) {
81
+ return json({ error: error.message }, error.status || 500);
82
+ }
83
+ req.payload.logger.error({ err: error }, `[publishing] admin ${action} failed for ${collection}/${id}`);
84
+ return json({ error: `Could not ${action} this document.` }, 500);
85
+ }
86
+ }
87
+ function json(body, status) {
88
+ return new Response(JSON.stringify(body), {
89
+ status,
90
+ headers: { 'content-type': 'application/json' },
91
+ });
92
+ }
93
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/endpoints/admin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Client entry point for the admin controls, referenced from Payload's
3
+ * import map as `@forumone/throughline-publishing/client#PublishButton`.
4
+ *
5
+ * Kept separate from the package root so server-only consumers never pull
6
+ * React or `@payloadcms/ui` into their bundle.
7
+ */
8
+ export { PublishButton } from '../admin/PublishButton.js';
9
+ export type { ThroughlinePublishButtonProps } from '../admin/PublishButton.js';
10
+ export { UnpublishButton } from '../admin/UnpublishButton.js';
11
+ export type { ThroughlineUnpublishButtonProps } from '../admin/UnpublishButton.js';
12
+ export { callPublishingEndpoint, describeBlock } from '../admin/publishing-client.js';
13
+ export type { CallPublishingEndpointArgs, PublishingCallResult, PublishingIssue, PublishingResponse, } from '../admin/publishing-client.js';
14
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,YAAY,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAA;AAE9E,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAC7D,YAAY,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAElF,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AACrF,YAAY,EACV,0BAA0B,EAC1B,oBAAoB,EACpB,eAAe,EACf,kBAAkB,GACnB,MAAM,+BAA+B,CAAA"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Client entry point for the admin controls, referenced from Payload's
3
+ * import map as `@forumone/throughline-publishing/client#PublishButton`.
4
+ *
5
+ * Kept separate from the package root so server-only consumers never pull
6
+ * React or `@payloadcms/ui` into their bundle.
7
+ */
8
+ export { PublishButton } from '../admin/PublishButton.js';
9
+ export { UnpublishButton } from '../admin/UnpublishButton.js';
10
+ export { callPublishingEndpoint, describeBlock } from '../admin/publishing-client.js';
11
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAGzD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAG7D,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA"}
@@ -7,6 +7,10 @@ import type { CollectionBeforeChangeHook } from 'payload';
7
7
  * Without this hook, the Payload MCP could let Claude flip a document to
8
8
  * `published` directly, sidestepping every check the publishing server
9
9
  * exists to enforce. With it, the only sanctioned path is the pipeline.
10
+ *
11
+ * Throws `APIError` rather than `Error` so Payload returns 400 with the
12
+ * message intact instead of swallowing it into a 500 and a generic
13
+ * "Something went wrong" toast.
10
14
  */
11
15
  export declare function createBlockStatusWritesHook(): CollectionBeforeChangeHook;
12
16
  //# sourceMappingURL=block-status-writes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-status-writes.d.ts","sourceRoot":"","sources":["../../src/hooks/block-status-writes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,IAAI,0BAA0B,CAqBxE"}
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;AAEzD;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,IAAI,0BAA0B,CAsBxE"}
@@ -1,3 +1,4 @@
1
+ import { APIError } from 'payload';
1
2
  /**
2
3
  * The trust boundary. This `beforeChange` hook rejects every update that
3
4
  * touches `_status` unless the request explicitly carries the
@@ -6,6 +7,10 @@
6
7
  * Without this hook, the Payload MCP could let Claude flip a document to
7
8
  * `published` directly, sidestepping every check the publishing server
8
9
  * exists to enforce. With it, the only sanctioned path is the pipeline.
10
+ *
11
+ * Throws `APIError` rather than `Error` so Payload returns 400 with the
12
+ * message intact instead of swallowing it into a 500 and a generic
13
+ * "Something went wrong" toast.
9
14
  */
10
15
  export function createBlockStatusWritesHook() {
11
16
  return ({ data, originalDoc, operation, context, req }) => {
@@ -22,7 +27,7 @@ export function createBlockStatusWritesHook() {
22
27
  }
23
28
  if (isBypassed(context) || isBypassed(req?.context))
24
29
  return data;
25
- throw new Error('Direct writes to `_status` are not allowed. Use the publishing server (publish / unpublish / rollback) so the policy pipeline runs.');
30
+ throw new APIError('Direct writes to `_status` are not allowed. Use the publishing server (publish / unpublish / rollback) so the policy pipeline runs.', 400);
26
31
  };
27
32
  }
28
33
  function hasStatusChange(data) {
@@ -1 +1 @@
1
- {"version":3,"file":"block-status-writes.js","sourceRoot":"","sources":["../../src/hooks/block-status-writes.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE;QACxD,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,MAAM,IAAI,KAAK,CACb,qIAAqI,CACtI,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"}
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;AAGlC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE;QACxD,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,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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,11 @@
1
1
  export { publishingPlugin } from './plugin.js';
2
2
  export type { AccessibilityCheck, AccessibilityIssue, ActiveApproval, ApprovalResolver, PublishableCollection, PublishingPluginOptions, ResolvedCollection, } from './options.js';
3
3
  export type { PipelineContext, PipelineResult, PipelineStep, PipelineStepResult, } from './pipeline/index.js';
4
+ /**
5
+ * Server-side publishing API. Use these from host code — a custom endpoint,
6
+ * a scheduled job, a Server Action — to run the full policy pipeline as a
7
+ * given user, with no API key and correct audit attribution.
8
+ */
9
+ export { getPublishStatus, getPublishingService, publishDocument, unpublishDocument, } from './service.js';
10
+ export type { DocumentActionArgs, PublishOutcome, PublishRequest, PublishStatusOutcome, PublishingActor, PublishingService, UnpublishOutcome, } from './service.js';
4
11
  //# sourceMappingURL=index.d.ts.map
@@ -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"}
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"}
package/dist/index.js CHANGED
@@ -1,2 +1,8 @@
1
1
  export { publishingPlugin } from './plugin.js';
2
+ /**
3
+ * Server-side publishing API. Use these from host code — a custom endpoint,
4
+ * a scheduled job, a Server Action — to run the full policy pipeline as a
5
+ * given user, with no API key and correct audit attribution.
6
+ */
7
+ export { getPublishStatus, getPublishingService, publishDocument, unpublishDocument, } from './service.js';
2
8
  //# 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"}
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"}
package/dist/options.d.ts CHANGED
@@ -49,6 +49,16 @@ export interface PublishingPluginOptions extends BaseCorePluginOptions {
49
49
  approvalResolver?: ApprovalResolver;
50
50
  /** Required: Inngest client used to fire publishing events. */
51
51
  inngest: Inngest;
52
+ /**
53
+ * Whether to install the plugin's Publish / Unpublish controls on each
54
+ * configured collection. Default: `true`.
55
+ *
56
+ * Payload's native buttons write `_status` directly, which the plugin's
57
+ * trust boundary rejects — so with this off, the admin has no working
58
+ * publish path until the host supplies its own control (see
59
+ * `publishDocument`).
60
+ */
61
+ adminComponents?: boolean;
52
62
  }
53
63
  export type ResolvedCollection = Required<Omit<PublishableCollection, 'requiredFields'>> & Pick<PublishableCollection, 'requiredFields'>;
54
64
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAElF,MAAM,WAAW,qBAAqB;IACpC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mGAAmG;IACnG,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uFAAuF;IACvF,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,0EAA0E;IAC1E,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC1D;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,CACH,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,UAAU,EAAE,kBAAkB,KAC3B,OAAO,CAAC,kBAAkB,EAAE,CAAC,GAAG,kBAAkB,EAAE,CAAA;CAC1D;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,iBAAiB,EAAE,CACjB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,KACZ,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAA;CACpC;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,uEAAuE;IACvE,WAAW,EAAE,qBAAqB,EAAE,CAAA;IACpC,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC1C,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,IAAI,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,CAAC,GACtF,IAAI,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,CAAA;AAe/C;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,uBAAuB,GAAG,uBAAuB,CAiBzF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,uBAAuB,EAChC,IAAI,EAAE,MAAM,GACX,kBAAkB,CAiBpB"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAElF,MAAM,WAAW,qBAAqB;IACpC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mGAAmG;IACnG,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uFAAuF;IACvF,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,0EAA0E;IAC1E,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC1D;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,CACH,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,UAAU,EAAE,kBAAkB,KAC3B,OAAO,CAAC,kBAAkB,EAAE,CAAC,GAAG,kBAAkB,EAAE,CAAA;CAC1D;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,iBAAiB,EAAE,CACjB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,KACZ,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAA;CACpC;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,uEAAuE;IACvE,WAAW,EAAE,qBAAqB,EAAE,CAAA;IACpC,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC1C,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,IAAI,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,CAAC,GACtF,IAAI,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,CAAA;AAe/C;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,uBAAuB,GAAG,uBAAuB,CAiBzF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,uBAAuB,EAChC,IAAI,EAAE,MAAM,GACX,kBAAkB,CAiBpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,11 @@ import type { PipelineStep } from '../types.js';
7
7
  * Sets `context.bypassPublishingServer = true` on the Payload update so the
8
8
  * status-write blocking hook recognizes this as a sanctioned write. Any
9
9
  * other path that tries to flip `_status` will be rejected by the hook.
10
+ *
11
+ * When `actor.enforceAccessAs` is set the write runs as that user with
12
+ * `overrideAccess: false`, so Payload rejects an editor who lacks update
13
+ * access on the collection. Bypassing the hook is not bypassing access
14
+ * control.
10
15
  */
11
16
  export declare const executeStep: PipelineStep;
12
17
  //# sourceMappingURL=execute.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/pipeline/steps/execute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,YA+BzB,CAAA"}
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/pipeline/steps/execute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,EAAE,YAkCzB,CAAA"}
@@ -6,6 +6,11 @@
6
6
  * Sets `context.bypassPublishingServer = true` on the Payload update so the
7
7
  * status-write blocking hook recognizes this as a sanctioned write. Any
8
8
  * other path that tries to flip `_status` will be rejected by the hook.
9
+ *
10
+ * When `actor.enforceAccessAs` is set the write runs as that user with
11
+ * `overrideAccess: false`, so Payload rejects an editor who lacks update
12
+ * access on the collection. Bypassing the hook is not bypassing access
13
+ * control.
9
14
  */
10
15
  export const executeStep = async (ctx) => {
11
16
  const now = new Date().toISOString();
@@ -20,6 +25,9 @@ export const executeStep = async (ctx) => {
20
25
  _status: 'published',
21
26
  [ctx.collection.publishedAtField]: now,
22
27
  },
28
+ ...(ctx.actor.enforceAccessAs
29
+ ? { user: ctx.actor.enforceAccessAs, overrideAccess: false }
30
+ : {}),
23
31
  context: { bypassPublishingServer: true },
24
32
  });
25
33
  await ctx.inngest.send({
@@ -1 +1 @@
1
- {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/pipeline/steps/execute.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,WAAW,GAAiB,KAAK,EAAE,GAAG,EAAE,EAAE;IACrD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACpC,MAAM,mBAAmB,GACvB,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC,KAAK,QAAQ;QAC/D,CAAC,CAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAY;QAC3D,CAAC,CAAC,IAAI,CAAA;IACV,MAAM,eAAe,GAAG,mBAAmB,KAAK,IAAI,CAAA;IAEpD,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QACvB,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI;QAC/B,EAAE,EAAE,GAAG,CAAC,UAAU;QAClB,IAAI,EAAE;YACJ,OAAO,EAAE,WAAW;YACpB,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,GAAG;SACvC;QACD,OAAO,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE;KAC1C,CAAC,CAAA;IAEF,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;QACrB,IAAI,EAAE,wBAAwB;QAC9B,IAAI,EAAE;YACJ,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI;YAC/B,EAAE,EAAE,GAAG,CAAC,UAAU;YAClB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC;YACtE,WAAW,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,QAAQ;YAC3C,mBAAmB;YACnB,cAAc,EAAE,eAAe;SAChC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACvB,CAAC,CAAA"}
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/pipeline/steps/execute.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,WAAW,GAAiB,KAAK,EAAE,GAAG,EAAE,EAAE;IACrD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACpC,MAAM,mBAAmB,GACvB,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC,KAAK,QAAQ;QAC/D,CAAC,CAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAY;QAC3D,CAAC,CAAC,IAAI,CAAA;IACV,MAAM,eAAe,GAAG,mBAAmB,KAAK,IAAI,CAAA;IAEpD,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QACvB,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI;QAC/B,EAAE,EAAE,GAAG,CAAC,UAAU;QAClB,IAAI,EAAE;YACJ,OAAO,EAAE,WAAW;YACpB,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,GAAG;SACvC;QACD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe;YAC3B,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,cAAc,EAAE,KAAK,EAAE;YAC5D,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE;KAC1C,CAAC,CAAA;IAEF,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;QACrB,IAAI,EAAE,wBAAwB;QAC9B,IAAI,EAAE;YACJ,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI;YAC/B,EAAE,EAAE,GAAG,CAAC,UAAU;YAClB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC;YACtE,WAAW,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,QAAQ;YAC3C,mBAAmB;YACnB,cAAc,EAAE,eAAe;SAChC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACvB,CAAC,CAAA"}
@@ -1,11 +1,18 @@
1
1
  import type { Inngest } from 'inngest';
2
- import type { Payload } from 'payload';
2
+ import type { Payload, TypedUser } from 'payload';
3
3
  import type { AuthenticatedUser } from '@forumone/throughline-plugin-contract';
4
4
  import type { AccessibilityIssue, PublishingPluginOptions, ResolvedCollection } from '../options.js';
5
5
  export interface PipelineActor {
6
6
  user: AuthenticatedUser | null;
7
7
  apiKeyName: string;
8
8
  sessionId?: string | undefined;
9
+ /**
10
+ * When set, Payload reads and writes inside the pipeline run as this user
11
+ * with `overrideAccess: false`, so the collection's own access control
12
+ * applies. The admin path sets it to the logged-in editor; the MCP path
13
+ * leaves it unset because the API key is its own trust boundary.
14
+ */
15
+ enforceAccessAs?: TypedUser | undefined;
9
16
  }
10
17
  export interface PipelineMeta {
11
18
  userPrompt?: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pipeline/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,eAAe,CAAA;AAEtB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,uBAAuB,CAAA;IAChC,UAAU,EAAE,kBAAkB,CAAA;IAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,aAAa,CAAA;IACpB,IAAI,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;CAChC;AAED,MAAM,MAAM,aAAa,GAAG,kBAAkB,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAElE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAA;AAEpF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pipeline/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,eAAe,CAAA;AAEtB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CACxC;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,uBAAuB,CAAA;IAChC,UAAU,EAAE,kBAAkB,CAAA;IAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,aAAa,CAAA;IACpB,IAAI,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;CAChC;AAED,MAAM,MAAM,aAAa,GAAG,kBAAkB,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAElE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAA;AAEpF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB"}
@@ -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,EAAE,KAAK,uBAAuB,EAAmB,MAAM,cAAc,CAAA;AAgB5E,eAAO,MAAM,gBAAgB,EAAE,UAAU,CAAC,uBAAuB,CA2F9D,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;AAoBrB,eAAO,MAAM,gBAAgB,EAAE,UAAU,CAAC,uBAAuB,CAuG9D,CAAA"}
package/dist/plugin.js CHANGED
@@ -1,11 +1,14 @@
1
1
  import { getPluginRegistry } from '@forumone/throughline-plugin-contract';
2
2
  import { createMcpHandler, createNamedLogger, defaultLogger, getAuditWriter, } from '@forumone/throughline-core';
3
- import { validateOptions } from './options.js';
3
+ import { resolveCollection, validateOptions, } from './options.js';
4
4
  import { createBlockStatusWritesHook } from './hooks/block-status-writes.js';
5
+ import { createAdminEndpoints } from './endpoints/admin.js';
6
+ import { attachPublishingService, createPublishingService } from './service.js';
5
7
  import { createGetPublishStatusTool, createPublishTool, createRollbackTool, createSchedulePublishTool, createUnpublishTool, } from './tools/index.js';
6
8
  const PLUGIN_ID = '@forumone/throughline-publishing';
7
9
  const PLUGIN_VERSION = '0.1.0';
8
10
  const MCP_HANDLER_SYMBOL = Symbol.for('@forumone/throughline/publishing-mcp-handler');
11
+ const CLIENT_ENTRY = '@forumone/throughline-publishing/client';
9
12
  export const publishingPlugin = (rawOptions) => (incomingConfig) => {
10
13
  if (rawOptions.enabled === false)
11
14
  return incomingConfig;
@@ -15,12 +18,13 @@ export const publishingPlugin = (rawOptions) => (incomingConfig) => {
15
18
  const routePrefix = options.routePrefix ?? '/publishing';
16
19
  const logger = createNamedLogger('publishing', options.logger ?? defaultLogger);
17
20
  const publishableSlugs = new Set(options.collections.map((c) => c.slug));
18
- // Inject the block-status-writes hook into every publishable collection.
21
+ const adminComponents = options.adminComponents !== false;
19
22
  const modifiedCollections = (incomingConfig.collections ?? []).map((collection) => {
20
23
  if (!publishableSlugs.has(collection.slug))
21
24
  return collection;
22
25
  return {
23
26
  ...collection,
27
+ // The trust boundary: nothing may write `_status` outside the pipeline.
24
28
  hooks: {
25
29
  ...(collection.hooks ?? {}),
26
30
  beforeChange: [
@@ -28,6 +32,9 @@ export const publishingPlugin = (rawOptions) => (incomingConfig) => {
28
32
  createBlockStatusWritesHook(),
29
33
  ],
30
34
  },
35
+ ...(adminComponents
36
+ ? { admin: withAdminControls(collection, routePrefix, options) }
37
+ : {}),
31
38
  };
32
39
  });
33
40
  return {
@@ -35,6 +42,7 @@ export const publishingPlugin = (rawOptions) => (incomingConfig) => {
35
42
  collections: modifiedCollections,
36
43
  endpoints: [
37
44
  ...(incomingConfig.endpoints ?? []),
45
+ ...createAdminEndpoints({ routePrefix, publishableSlugs }),
38
46
  {
39
47
  path: `${routePrefix}/mcp`,
40
48
  method: 'post',
@@ -54,11 +62,15 @@ export const publishingPlugin = (rawOptions) => (incomingConfig) => {
54
62
  const registry = getPluginRegistry(payload);
55
63
  registry.requireCapability('audit-log', PLUGIN_ID);
56
64
  const auditWriter = getAuditWriter(payload);
65
+ // One service instance behind every channel — MCP tools, the admin
66
+ // endpoints, and host code reaching in through `publishDocument`.
67
+ const service = createPublishingService({ payload, options, auditWriter });
68
+ attachPublishingService(payload, service);
57
69
  const tools = [
58
- createPublishTool({ payload, options, auditWriter }),
59
- createUnpublishTool({ payload, options, auditWriter }),
70
+ createPublishTool({ payload, options, auditWriter, service }),
71
+ createUnpublishTool({ payload, options, auditWriter, service }),
60
72
  createSchedulePublishTool({ payload, options, auditWriter }),
61
- createGetPublishStatusTool({ payload, options }),
73
+ createGetPublishStatusTool({ payload, options, service }),
62
74
  createRollbackTool({ payload, options, auditWriter }),
63
75
  ];
64
76
  const handler = createMcpHandler({
@@ -80,8 +92,53 @@ export const publishingPlugin = (rawOptions) => (incomingConfig) => {
80
92
  });
81
93
  logger.info('Publishing server ready', {
82
94
  collections: options.collections.map((c) => c.slug),
95
+ adminComponents,
83
96
  });
84
97
  },
85
98
  };
86
99
  };
100
+ /**
101
+ * Points the collection's Publish / Unpublish slots at the plugin's own
102
+ * controls, so a stock admin can publish without any host-side code.
103
+ *
104
+ * A slot the host already set is left alone — an explicit override in the
105
+ * host config wins over the plugin's default.
106
+ *
107
+ * Hosts must run `payload generate:importmap` after adding the plugin (the
108
+ * dev server does it automatically) so Payload can resolve these paths.
109
+ */
110
+ function withAdminControls(collection, routePrefix, options) {
111
+ const resolved = resolveCollection(options, collection.slug);
112
+ const edit = collection.admin?.components?.edit ?? {};
113
+ return {
114
+ ...(collection.admin ?? {}),
115
+ components: {
116
+ ...(collection.admin?.components ?? {}),
117
+ edit: {
118
+ ...edit,
119
+ ...(edit.PublishButton === undefined
120
+ ? {
121
+ PublishButton: {
122
+ path: CLIENT_ENTRY,
123
+ exportName: 'PublishButton',
124
+ clientProps: {
125
+ routePrefix,
126
+ publishedAtField: resolved.publishedAtField,
127
+ },
128
+ },
129
+ }
130
+ : {}),
131
+ ...(edit.UnpublishButton === undefined
132
+ ? {
133
+ UnpublishButton: {
134
+ path: CLIENT_ENTRY,
135
+ exportName: 'UnpublishButton',
136
+ clientProps: { routePrefix },
137
+ },
138
+ }
139
+ : {}),
140
+ },
141
+ },
142
+ };
143
+ }
87
144
  //# sourceMappingURL=plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ import type { Payload, TypedUser } from 'payload';
2
+ import type { AuditWriter } from '@forumone/throughline-core';
3
+ import type { AuthenticatedUser } from '@forumone/throughline-plugin-contract';
4
+ import { type PublishingPluginOptions } from './options.js';
5
+ import type { PipelineIssue, PipelineMeta } from './pipeline/types.js';
6
+ /**
7
+ * Who an action is attributed to, and whose permissions it runs under.
8
+ *
9
+ * `user` is what lands in the audit log. `enforceAccessAs` is separate
10
+ * because the MCP path authenticates an API key linked to a user (the key's
11
+ * own permissions govern) while the admin path runs as a real session (the
12
+ * editor's permissions govern).
13
+ */
14
+ export interface PublishingActor {
15
+ /** The principal recorded as the audit actor. */
16
+ user?: AuthenticatedUser | null | undefined;
17
+ /** Name of the API key, when the call arrived over MCP. */
18
+ apiKeyName?: string | undefined;
19
+ /**
20
+ * When set, Payload reads and writes run as this user with
21
+ * `overrideAccess: false` so collection access control applies.
22
+ */
23
+ enforceAccessAs?: TypedUser | undefined;
24
+ /** Recorded on the audit event's `mcpTool` so channels are distinguishable. */
25
+ channel?: 'mcp' | 'admin' | undefined;
26
+ }
27
+ export interface PublishRequest {
28
+ collection: string;
29
+ id: string;
30
+ actor: PublishingActor;
31
+ meta?: PipelineMeta | undefined;
32
+ }
33
+ export interface PublishOutcome {
34
+ published: boolean;
35
+ publishedAt?: string;
36
+ failedAt?: string;
37
+ reason?: string;
38
+ code?: string;
39
+ issues?: PipelineIssue[];
40
+ suggestion?: string;
41
+ }
42
+ export interface UnpublishOutcome {
43
+ unpublished: boolean;
44
+ reason?: string;
45
+ }
46
+ export interface PublishStatusOutcome {
47
+ /** The document's current `_status`. */
48
+ status: string;
49
+ /** Whether every preflight check passes right now. */
50
+ publishable: boolean;
51
+ failedAt?: string;
52
+ reason?: string;
53
+ code?: string;
54
+ issues?: PipelineIssue[];
55
+ suggestion?: string;
56
+ /** Last successful publish, or `null` if never published. */
57
+ publishedAt: string | null;
58
+ hasUnpublishedChanges: boolean;
59
+ }
60
+ export interface PublishingService {
61
+ publish: (request: PublishRequest) => Promise<PublishOutcome>;
62
+ unpublish: (request: PublishRequest) => Promise<UnpublishOutcome>;
63
+ getStatus: (request: PublishRequest) => Promise<PublishStatusOutcome>;
64
+ }
65
+ export interface CreatePublishingServiceDeps {
66
+ payload: Payload;
67
+ options: PublishingPluginOptions;
68
+ auditWriter: AuditWriter;
69
+ }
70
+ /**
71
+ * The single implementation of publish / unpublish / status. Both the MCP
72
+ * tools and the admin endpoints call through here, so the two channels
73
+ * cannot drift: same pipeline, same audit shape, same trust boundary.
74
+ */
75
+ export declare function createPublishingService(deps: CreatePublishingServiceDeps): PublishingService;
76
+ /** Attaches the service to the Payload instance so host code can find it. */
77
+ export declare function attachPublishingService(payload: object, service: PublishingService): void;
78
+ /**
79
+ * Returns the publishing service attached to this Payload instance.
80
+ *
81
+ * Use this (or the `publishDocument` / `unpublishDocument` /
82
+ * `getPublishStatus` helpers below) from host code — a custom endpoint, a
83
+ * job, a Server Action — to publish through the full policy pipeline as a
84
+ * given user. No API key, and the audit event records that user.
85
+ */
86
+ export declare function getPublishingService(payload: object): PublishingService;
87
+ export interface DocumentActionArgs {
88
+ payload: Payload;
89
+ collection: string;
90
+ id: string;
91
+ /** The person the action is attributed to and whose permissions apply. */
92
+ user: TypedUser;
93
+ meta?: PipelineMeta | undefined;
94
+ }
95
+ /**
96
+ * Publishes a document through the full pipeline as `user`. Rejects if that
97
+ * user lacks update access on the collection.
98
+ */
99
+ export declare function publishDocument(args: DocumentActionArgs): Promise<PublishOutcome>;
100
+ /** Reverts a published document to draft as `user`. */
101
+ export declare function unpublishDocument(args: DocumentActionArgs): Promise<UnpublishOutcome>;
102
+ /**
103
+ * Runs every check except the write and reports whether the document would
104
+ * publish. Mutates nothing.
105
+ */
106
+ export declare function getPublishStatus(args: DocumentActionArgs): Promise<PublishStatusOutcome>;
107
+ /** Narrows a Payload user document to the audit-log actor shape. */
108
+ export declare function toAuthenticatedUser(user: TypedUser | null): AuthenticatedUser | null;
109
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}