@forumone/throughline-publishing 0.2.3 → 0.3.1
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 +27 -0
- package/README.md +154 -1
- package/dist/admin/PublishButton.d.ts +24 -0
- package/dist/admin/PublishButton.d.ts.map +1 -0
- package/dist/admin/PublishButton.js +128 -0
- package/dist/admin/PublishButton.js.map +1 -0
- package/dist/admin/UnpublishButton.d.ts +15 -0
- package/dist/admin/UnpublishButton.d.ts.map +1 -0
- package/dist/admin/UnpublishButton.js +90 -0
- package/dist/admin/UnpublishButton.js.map +1 -0
- package/dist/admin/publishing-client.d.ts +55 -0
- package/dist/admin/publishing-client.d.ts.map +1 -0
- package/dist/admin/publishing-client.js +64 -0
- package/dist/admin/publishing-client.js.map +1 -0
- package/dist/checks/alt-text.d.ts +8 -2
- package/dist/checks/alt-text.d.ts.map +1 -1
- package/dist/checks/alt-text.js +13 -3
- package/dist/checks/alt-text.js.map +1 -1
- package/dist/endpoints/admin.d.ts +19 -0
- package/dist/endpoints/admin.d.ts.map +1 -0
- package/dist/endpoints/admin.js +93 -0
- package/dist/endpoints/admin.js.map +1 -0
- package/dist/events.d.ts +16 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +30 -0
- package/dist/events.js.map +1 -0
- package/dist/exports/client.d.ts +14 -0
- package/dist/exports/client.d.ts.map +1 -0
- package/dist/exports/client.js +11 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/hooks/block-status-writes.d.ts +4 -0
- package/dist/hooks/block-status-writes.d.ts.map +1 -1
- package/dist/hooks/block-status-writes.js +6 -1
- package/dist/hooks/block-status-writes.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +19 -0
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js.map +1 -1
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +9 -1
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/steps/accessibility.d.ts +4 -0
- package/dist/pipeline/steps/accessibility.d.ts.map +1 -1
- package/dist/pipeline/steps/accessibility.js +6 -1
- package/dist/pipeline/steps/accessibility.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 +17 -2
- package/dist/pipeline/steps/execute.js.map +1 -1
- package/dist/pipeline/types.d.ts +15 -1
- package/dist/pipeline/types.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +62 -5
- package/dist/plugin.js.map +1 -1
- package/dist/service.d.ts +116 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +245 -0
- package/dist/service.js.map +1 -0
- package/dist/tools/get-publish-status.d.ts +4 -1
- package/dist/tools/get-publish-status.d.ts.map +1 -1
- package/dist/tools/get-publish-status.js +16 -30
- package/dist/tools/get-publish-status.js.map +1 -1
- package/dist/tools/publish.d.ts +4 -1
- package/dist/tools/publish.d.ts.map +1 -1
- package/dist/tools/publish.js +8 -57
- package/dist/tools/publish.js.map +1 -1
- package/dist/tools/rollback.d.ts.map +1 -1
- package/dist/tools/rollback.js +5 -1
- package/dist/tools/rollback.js.map +1 -1
- package/dist/tools/schedule-publish.d.ts.map +1 -1
- package/dist/tools/schedule-publish.js +9 -2
- package/dist/tools/schedule-publish.js.map +1 -1
- package/dist/tools/unpublish.d.ts +4 -1
- package/dist/tools/unpublish.d.ts.map +1 -1
- package/dist/tools/unpublish.js +8 -47
- package/dist/tools/unpublish.js.map +1 -1
- package/package.json +19 -2
|
@@ -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;
|
|
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;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,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;IACpB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB"}
|
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,
|
|
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
|
-
|
|
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, logger });
|
|
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
|
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,
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Payload, TypedUser } from 'payload';
|
|
2
|
+
import type { AuditWriter } from '@forumone/throughline-core';
|
|
3
|
+
import type { AuthenticatedUser, Logger } 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
|
+
* Non-fatal problems. The publish happened; something downstream of it
|
|
43
|
+
* did not. Present on a successful result.
|
|
44
|
+
*/
|
|
45
|
+
warnings?: string[];
|
|
46
|
+
}
|
|
47
|
+
export interface UnpublishOutcome {
|
|
48
|
+
unpublished: boolean;
|
|
49
|
+
reason?: string;
|
|
50
|
+
warnings?: string[];
|
|
51
|
+
}
|
|
52
|
+
export interface PublishStatusOutcome {
|
|
53
|
+
/** The document's current `_status`. */
|
|
54
|
+
status: string;
|
|
55
|
+
/** Whether every preflight check passes right now. */
|
|
56
|
+
publishable: boolean;
|
|
57
|
+
failedAt?: string;
|
|
58
|
+
reason?: string;
|
|
59
|
+
code?: string;
|
|
60
|
+
issues?: PipelineIssue[];
|
|
61
|
+
suggestion?: string;
|
|
62
|
+
/** Last successful publish, or `null` if never published. */
|
|
63
|
+
publishedAt: string | null;
|
|
64
|
+
hasUnpublishedChanges: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface PublishingService {
|
|
67
|
+
publish: (request: PublishRequest) => Promise<PublishOutcome>;
|
|
68
|
+
unpublish: (request: PublishRequest) => Promise<UnpublishOutcome>;
|
|
69
|
+
getStatus: (request: PublishRequest) => Promise<PublishStatusOutcome>;
|
|
70
|
+
}
|
|
71
|
+
export interface CreatePublishingServiceDeps {
|
|
72
|
+
payload: Payload;
|
|
73
|
+
options: PublishingPluginOptions;
|
|
74
|
+
auditWriter: AuditWriter;
|
|
75
|
+
logger?: Logger | undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The single implementation of publish / unpublish / status. Both the MCP
|
|
79
|
+
* tools and the admin endpoints call through here, so the two channels
|
|
80
|
+
* cannot drift: same pipeline, same audit shape, same trust boundary.
|
|
81
|
+
*/
|
|
82
|
+
export declare function createPublishingService(deps: CreatePublishingServiceDeps): PublishingService;
|
|
83
|
+
/** Attaches the service to the Payload instance so host code can find it. */
|
|
84
|
+
export declare function attachPublishingService(payload: object, service: PublishingService): void;
|
|
85
|
+
/**
|
|
86
|
+
* Returns the publishing service attached to this Payload instance.
|
|
87
|
+
*
|
|
88
|
+
* Use this (or the `publishDocument` / `unpublishDocument` /
|
|
89
|
+
* `getPublishStatus` helpers below) from host code — a custom endpoint, a
|
|
90
|
+
* job, a Server Action — to publish through the full policy pipeline as a
|
|
91
|
+
* given user. No API key, and the audit event records that user.
|
|
92
|
+
*/
|
|
93
|
+
export declare function getPublishingService(payload: object): PublishingService;
|
|
94
|
+
export interface DocumentActionArgs {
|
|
95
|
+
payload: Payload;
|
|
96
|
+
collection: string;
|
|
97
|
+
id: string;
|
|
98
|
+
/** The person the action is attributed to and whose permissions apply. */
|
|
99
|
+
user: TypedUser;
|
|
100
|
+
meta?: PipelineMeta | undefined;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Publishes a document through the full pipeline as `user`. Rejects if that
|
|
104
|
+
* user lacks update access on the collection.
|
|
105
|
+
*/
|
|
106
|
+
export declare function publishDocument(args: DocumentActionArgs): Promise<PublishOutcome>;
|
|
107
|
+
/** Reverts a published document to draft as `user`. */
|
|
108
|
+
export declare function unpublishDocument(args: DocumentActionArgs): Promise<UnpublishOutcome>;
|
|
109
|
+
/**
|
|
110
|
+
* Runs every check except the write and reports whether the document would
|
|
111
|
+
* publish. Mutates nothing.
|
|
112
|
+
*/
|
|
113
|
+
export declare function getPublishStatus(args: DocumentActionArgs): Promise<PublishStatusOutcome>;
|
|
114
|
+
/** Narrows a Payload user document to the audit-log actor shape. */
|
|
115
|
+
export declare function toAuthenticatedUser(user: TypedUser | null): AuthenticatedUser | null;
|
|
116
|
+
//# 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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"}
|
package/dist/service.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { sendEventSafely } from './events.js';
|
|
2
|
+
import { resolveCollection } from './options.js';
|
|
3
|
+
import { runPreflightPipeline, runPublishPipeline } from './pipeline/index.js';
|
|
4
|
+
const SERVICE_SYMBOL = Symbol.for('@forumone/throughline/publishing-service');
|
|
5
|
+
/**
|
|
6
|
+
* The single implementation of publish / unpublish / status. Both the MCP
|
|
7
|
+
* tools and the admin endpoints call through here, so the two channels
|
|
8
|
+
* cannot drift: same pipeline, same audit shape, same trust boundary.
|
|
9
|
+
*/
|
|
10
|
+
export function createPublishingService(deps) {
|
|
11
|
+
const { payload, options, auditWriter, logger } = deps;
|
|
12
|
+
async function loadDocument(slug, id, actor) {
|
|
13
|
+
return (await payload.findByID({
|
|
14
|
+
collection: slug,
|
|
15
|
+
id,
|
|
16
|
+
draft: true,
|
|
17
|
+
...(actor.enforceAccessAs
|
|
18
|
+
? { user: actor.enforceAccessAs, overrideAccess: false }
|
|
19
|
+
: {}),
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
async publish(request) {
|
|
24
|
+
const collection = resolveCollection(options, request.collection);
|
|
25
|
+
const document = await loadDocument(collection.slug, request.id, request.actor);
|
|
26
|
+
const result = await runPublishPipeline({
|
|
27
|
+
payload,
|
|
28
|
+
inngest: options.inngest,
|
|
29
|
+
options,
|
|
30
|
+
collection,
|
|
31
|
+
document,
|
|
32
|
+
documentId: request.id,
|
|
33
|
+
actor: toPipelineActor(request.actor),
|
|
34
|
+
...(request.meta ? { meta: request.meta } : {}),
|
|
35
|
+
});
|
|
36
|
+
await auditWriter({
|
|
37
|
+
actor: toAuditActor(request.actor),
|
|
38
|
+
action: 'publishing.publish',
|
|
39
|
+
mcpServer: 'publishing',
|
|
40
|
+
mcpTool: toolName('publish', request.actor),
|
|
41
|
+
targetCollection: request.collection,
|
|
42
|
+
targetId: request.id,
|
|
43
|
+
targetTitle: stringField(document, 'title') ?? request.id,
|
|
44
|
+
prompt: request.meta?.userPrompt,
|
|
45
|
+
reasoning: request.meta?.reasoning,
|
|
46
|
+
changesSummary: request.meta?.changesSummary,
|
|
47
|
+
success: result.success,
|
|
48
|
+
errorMessage: result.success ? undefined : result.reason,
|
|
49
|
+
});
|
|
50
|
+
if (result.warnings?.length) {
|
|
51
|
+
logger?.warn('Publish completed with warnings', {
|
|
52
|
+
collection: request.collection,
|
|
53
|
+
id: request.id,
|
|
54
|
+
warnings: result.warnings,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const warnings = result.warnings?.length ? { warnings: result.warnings } : {};
|
|
58
|
+
if (result.success) {
|
|
59
|
+
return {
|
|
60
|
+
published: true,
|
|
61
|
+
...(result.publishedAt ? { publishedAt: result.publishedAt } : {}),
|
|
62
|
+
...warnings,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
published: false,
|
|
67
|
+
...(result.failedAt ? { failedAt: result.failedAt } : {}),
|
|
68
|
+
...(result.reason ? { reason: result.reason } : {}),
|
|
69
|
+
...(result.code ? { code: result.code } : {}),
|
|
70
|
+
...(result.issues ? { issues: result.issues } : {}),
|
|
71
|
+
...(result.suggestion ? { suggestion: result.suggestion } : {}),
|
|
72
|
+
...warnings,
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
async unpublish(request) {
|
|
76
|
+
const collection = resolveCollection(options, request.collection);
|
|
77
|
+
const document = await loadDocument(collection.slug, request.id, request.actor);
|
|
78
|
+
if (document['_status'] !== 'published') {
|
|
79
|
+
return { unpublished: false, reason: 'Document is not currently published' };
|
|
80
|
+
}
|
|
81
|
+
await payload.update({
|
|
82
|
+
collection: collection.slug,
|
|
83
|
+
id: request.id,
|
|
84
|
+
data: { _status: 'draft' },
|
|
85
|
+
...(request.actor.enforceAccessAs
|
|
86
|
+
? { user: request.actor.enforceAccessAs, overrideAccess: false }
|
|
87
|
+
: {}),
|
|
88
|
+
context: { bypassPublishingServer: true },
|
|
89
|
+
});
|
|
90
|
+
// Same rule as publish: the write has landed, so a failed emission is
|
|
91
|
+
// a warning, not a failure.
|
|
92
|
+
const slug = document[collection.slugField];
|
|
93
|
+
const warning = await sendEventSafely(options.inngest, {
|
|
94
|
+
name: 'content/page.unpublished',
|
|
95
|
+
data: {
|
|
96
|
+
collection: collection.slug,
|
|
97
|
+
id: request.id,
|
|
98
|
+
slug: typeof slug === 'string' ? slug : request.id,
|
|
99
|
+
unpublishedBy: request.actor.user?.id ?? 'system',
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
if (warning) {
|
|
103
|
+
logger?.warn('Unpublish completed with warnings', {
|
|
104
|
+
collection: request.collection,
|
|
105
|
+
id: request.id,
|
|
106
|
+
warnings: [warning],
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
await auditWriter({
|
|
110
|
+
actor: toAuditActor(request.actor),
|
|
111
|
+
action: 'publishing.unpublish',
|
|
112
|
+
mcpServer: 'publishing',
|
|
113
|
+
mcpTool: toolName('unpublish', request.actor),
|
|
114
|
+
targetCollection: request.collection,
|
|
115
|
+
targetId: request.id,
|
|
116
|
+
targetTitle: stringField(document, 'title') ?? request.id,
|
|
117
|
+
prompt: request.meta?.userPrompt,
|
|
118
|
+
reasoning: request.meta?.reasoning,
|
|
119
|
+
changesSummary: request.meta?.changesSummary,
|
|
120
|
+
success: true,
|
|
121
|
+
});
|
|
122
|
+
return { unpublished: true, ...(warning ? { warnings: [warning] } : {}) };
|
|
123
|
+
},
|
|
124
|
+
async getStatus(request) {
|
|
125
|
+
const collection = resolveCollection(options, request.collection);
|
|
126
|
+
const document = await loadDocument(collection.slug, request.id, request.actor);
|
|
127
|
+
const result = await runPreflightPipeline({
|
|
128
|
+
payload,
|
|
129
|
+
inngest: options.inngest,
|
|
130
|
+
options,
|
|
131
|
+
collection,
|
|
132
|
+
document,
|
|
133
|
+
documentId: request.id,
|
|
134
|
+
actor: toPipelineActor(request.actor),
|
|
135
|
+
});
|
|
136
|
+
const updatedAt = stringField(document, 'updatedAt');
|
|
137
|
+
const publishedAt = stringField(document, collection.publishedAtField);
|
|
138
|
+
return {
|
|
139
|
+
status: stringField(document, '_status') ?? 'draft',
|
|
140
|
+
publishable: result.success,
|
|
141
|
+
...(result.failedAt ? { failedAt: result.failedAt } : {}),
|
|
142
|
+
...(result.reason ? { reason: result.reason } : {}),
|
|
143
|
+
...(result.code ? { code: result.code } : {}),
|
|
144
|
+
...(result.issues ? { issues: result.issues } : {}),
|
|
145
|
+
...(result.suggestion ? { suggestion: result.suggestion } : {}),
|
|
146
|
+
publishedAt: publishedAt ?? null,
|
|
147
|
+
hasUnpublishedChanges: Boolean(updatedAt && publishedAt && Date.parse(updatedAt) > Date.parse(publishedAt)),
|
|
148
|
+
};
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function toPipelineActor(actor) {
|
|
153
|
+
return {
|
|
154
|
+
user: actor.user ?? null,
|
|
155
|
+
apiKeyName: actor.apiKeyName ?? '',
|
|
156
|
+
...(actor.enforceAccessAs ? { enforceAccessAs: actor.enforceAccessAs } : {}),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Attribution: a call carrying a real user is a user action, whoever
|
|
161
|
+
* transported it. An admin publish records the editor, not a service key.
|
|
162
|
+
*/
|
|
163
|
+
function toAuditActor(actor) {
|
|
164
|
+
return {
|
|
165
|
+
type: actor.user ? 'user' : 'system',
|
|
166
|
+
userId: actor.user?.id,
|
|
167
|
+
userName: actor.user?.name,
|
|
168
|
+
apiKeyName: actor.apiKeyName,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function toolName(tool, actor) {
|
|
172
|
+
return actor.channel === 'admin' ? `admin:${tool}` : tool;
|
|
173
|
+
}
|
|
174
|
+
function stringField(doc, name) {
|
|
175
|
+
const value = doc[name];
|
|
176
|
+
return typeof value === 'string' ? value : undefined;
|
|
177
|
+
}
|
|
178
|
+
/** Attaches the service to the Payload instance so host code can find it. */
|
|
179
|
+
export function attachPublishingService(payload, service) {
|
|
180
|
+
Object.defineProperty(payload, SERVICE_SYMBOL, {
|
|
181
|
+
value: service,
|
|
182
|
+
enumerable: false,
|
|
183
|
+
writable: false,
|
|
184
|
+
configurable: true,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Returns the publishing service attached to this Payload instance.
|
|
189
|
+
*
|
|
190
|
+
* Use this (or the `publishDocument` / `unpublishDocument` /
|
|
191
|
+
* `getPublishStatus` helpers below) from host code — a custom endpoint, a
|
|
192
|
+
* job, a Server Action — to publish through the full policy pipeline as a
|
|
193
|
+
* given user. No API key, and the audit event records that user.
|
|
194
|
+
*/
|
|
195
|
+
export function getPublishingService(payload) {
|
|
196
|
+
const service = payload[SERVICE_SYMBOL];
|
|
197
|
+
if (!service) {
|
|
198
|
+
throw new Error('Publishing service not found on this Payload instance. Add publishingPlugin() to your Payload config — the service is attached during onInit.');
|
|
199
|
+
}
|
|
200
|
+
return service;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Publishes a document through the full pipeline as `user`. Rejects if that
|
|
204
|
+
* user lacks update access on the collection.
|
|
205
|
+
*/
|
|
206
|
+
export function publishDocument(args) {
|
|
207
|
+
return getPublishingService(args.payload).publish(toRequest(args));
|
|
208
|
+
}
|
|
209
|
+
/** Reverts a published document to draft as `user`. */
|
|
210
|
+
export function unpublishDocument(args) {
|
|
211
|
+
return getPublishingService(args.payload).unpublish(toRequest(args));
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Runs every check except the write and reports whether the document would
|
|
215
|
+
* publish. Mutates nothing.
|
|
216
|
+
*/
|
|
217
|
+
export function getPublishStatus(args) {
|
|
218
|
+
return getPublishingService(args.payload).getStatus(toRequest(args));
|
|
219
|
+
}
|
|
220
|
+
function toRequest(args) {
|
|
221
|
+
return {
|
|
222
|
+
collection: args.collection,
|
|
223
|
+
id: args.id,
|
|
224
|
+
actor: {
|
|
225
|
+
user: toAuthenticatedUser(args.user),
|
|
226
|
+
enforceAccessAs: args.user,
|
|
227
|
+
channel: 'admin',
|
|
228
|
+
},
|
|
229
|
+
...(args.meta ? { meta: args.meta } : {}),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/** Narrows a Payload user document to the audit-log actor shape. */
|
|
233
|
+
export function toAuthenticatedUser(user) {
|
|
234
|
+
if (!user)
|
|
235
|
+
return null;
|
|
236
|
+
const raw = user;
|
|
237
|
+
return {
|
|
238
|
+
id: String(raw['id']),
|
|
239
|
+
email: String(raw['email'] ?? ''),
|
|
240
|
+
name: String(raw['name'] ?? raw['email'] ?? raw['id']),
|
|
241
|
+
roles: Array.isArray(raw['roles']) ? raw['roles'] : [],
|
|
242
|
+
groups: Array.isArray(raw['groups']) ? raw['groups'] : [],
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { Payload } from 'payload';
|
|
2
2
|
import type { McpToolDefinition } from '@forumone/throughline-plugin-contract';
|
|
3
|
-
import {
|
|
3
|
+
import type { PublishingPluginOptions } from '../options.js';
|
|
4
|
+
import { type PublishingService } from '../service.js';
|
|
4
5
|
export interface GetPublishStatusToolDeps {
|
|
5
6
|
payload: Payload;
|
|
6
7
|
options: PublishingPluginOptions;
|
|
8
|
+
/** Injected by the plugin so every channel shares one service instance. */
|
|
9
|
+
service?: PublishingService;
|
|
7
10
|
}
|
|
8
11
|
export declare function createGetPublishStatusTool(deps: GetPublishStatusToolDeps): McpToolDefinition;
|
|
9
12
|
//# sourceMappingURL=get-publish-status.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-publish-status.d.ts","sourceRoot":"","sources":["../../src/tools/get-publish-status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"get-publish-status.d.ts","sourceRoot":"","sources":["../../src/tools/get-publish-status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAC5D,OAAO,EAA2B,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAE/E,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,uBAAuB,CAAA;IAChC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAC5B;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,wBAAwB,GAAG,iBAAiB,CAyC5F"}
|
|
@@ -1,51 +1,37 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { withMeta } from '@forumone/throughline-core';
|
|
3
|
-
import {
|
|
4
|
-
import { runPreflightPipeline } from '../pipeline/index.js';
|
|
3
|
+
import { createPublishingService } from '../service.js';
|
|
5
4
|
export function createGetPublishStatusTool(deps) {
|
|
6
5
|
const inputSchema = withMeta({
|
|
7
6
|
collection: z.string(),
|
|
8
7
|
id: z.string(),
|
|
9
8
|
});
|
|
9
|
+
const service = deps.service ??
|
|
10
|
+
createPublishingService({ ...deps, auditWriter: async () => { } });
|
|
10
11
|
return {
|
|
11
12
|
name: 'get_publish_status',
|
|
12
13
|
description: "Returns the current publishability of a document without actually publishing. Reports current status, whether unpublished changes exist, the last publish timestamp, and a preflight result indicating whether `publish` would currently succeed. Read-only; no audit record is written.",
|
|
13
14
|
inputSchema,
|
|
14
15
|
handler: async (input, ctx) => {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
collection: collection.slug,
|
|
16
|
+
const status = await service.getStatus({
|
|
17
|
+
collection: input.collection,
|
|
18
18
|
id: input.id,
|
|
19
|
-
|
|
20
|
-
}));
|
|
21
|
-
const preflight = await runPreflightPipeline({
|
|
22
|
-
payload: deps.payload,
|
|
23
|
-
inngest: deps.options.inngest,
|
|
24
|
-
options: deps.options,
|
|
25
|
-
collection,
|
|
26
|
-
document,
|
|
27
|
-
documentId: input.id,
|
|
28
|
-
actor: { user: ctx.user, apiKeyName: ctx.apiKeyName },
|
|
19
|
+
actor: { user: ctx.user, apiKeyName: ctx.apiKeyName, channel: 'mcp' },
|
|
29
20
|
});
|
|
30
|
-
const updatedAt = document['updatedAt'];
|
|
31
|
-
const publishedAt = document[collection.publishedAtField];
|
|
32
|
-
const hasUnpublishedChanges = typeof updatedAt === 'string' &&
|
|
33
|
-
typeof publishedAt === 'string' &&
|
|
34
|
-
Date.parse(updatedAt) > Date.parse(publishedAt);
|
|
35
21
|
return {
|
|
36
|
-
currentStatus:
|
|
37
|
-
hasUnpublishedChanges,
|
|
38
|
-
lastPublished:
|
|
22
|
+
currentStatus: status.status,
|
|
23
|
+
hasUnpublishedChanges: status.hasUnpublishedChanges,
|
|
24
|
+
lastPublished: status.publishedAt,
|
|
39
25
|
wouldPublish: {
|
|
40
|
-
canPublish:
|
|
41
|
-
...(
|
|
26
|
+
canPublish: status.publishable,
|
|
27
|
+
...(status.publishable
|
|
42
28
|
? {}
|
|
43
29
|
: {
|
|
44
|
-
blockedAt:
|
|
45
|
-
code:
|
|
46
|
-
reason:
|
|
47
|
-
suggestion:
|
|
48
|
-
issues:
|
|
30
|
+
blockedAt: status.failedAt,
|
|
31
|
+
code: status.code,
|
|
32
|
+
reason: status.reason,
|
|
33
|
+
suggestion: status.suggestion,
|
|
34
|
+
issues: status.issues ?? [],
|
|
49
35
|
}),
|
|
50
36
|
},
|
|
51
37
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-publish-status.js","sourceRoot":"","sources":["../../src/tools/get-publish-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"get-publish-status.js","sourceRoot":"","sources":["../../src/tools/get-publish-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAGrD,OAAO,EAAE,uBAAuB,EAA0B,MAAM,eAAe,CAAA;AAS/E,MAAM,UAAU,0BAA0B,CAAC,IAA8B;IACvE,MAAM,WAAW,GAAG,QAAQ,CAAC;QAC3B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;QACtB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;KACf,CAAC,CAAA;IAEF,MAAM,OAAO,GACX,IAAI,CAAC,OAAO;QACZ,uBAAuB,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAC,CAAA;IAEnE,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,0RAA0R;QAC5R,WAAW;QACX,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC5B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC;gBACrC,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE;aACtE,CAAC,CAAA;YAEF,OAAO;gBACL,aAAa,EAAE,MAAM,CAAC,MAAM;gBAC5B,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;gBACnD,aAAa,EAAE,MAAM,CAAC,WAAW;gBACjC,YAAY,EAAE;oBACZ,UAAU,EAAE,MAAM,CAAC,WAAW;oBAC9B,GAAG,CAAC,MAAM,CAAC,WAAW;wBACpB,CAAC,CAAC,EAAE;wBACJ,CAAC,CAAC;4BACE,SAAS,EAAE,MAAM,CAAC,QAAQ;4BAC1B,IAAI,EAAE,MAAM,CAAC,IAAI;4BACjB,MAAM,EAAE,MAAM,CAAC,MAAM;4BACrB,UAAU,EAAE,MAAM,CAAC,UAAU;4BAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;yBAC5B,CAAC;iBACP;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|