@forumone/throughline-core 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +112 -0
- package/README.md +192 -33
- package/bin/payload-cli.mjs +443 -0
- package/bin/throughline-payload.mjs +6 -0
- package/dist/audit/collection.d.ts +3 -0
- package/dist/audit/collection.d.ts.map +1 -1
- package/dist/audit/collection.js +2 -0
- package/dist/audit/collection.js.map +1 -1
- package/dist/env/index.d.ts +54 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/env/index.js +113 -0
- package/dist/env/index.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/api-key-access.d.ts +50 -0
- package/dist/mcp/api-key-access.d.ts.map +1 -0
- package/dist/mcp/api-key-access.js +94 -0
- package/dist/mcp/api-key-access.js.map +1 -0
- package/dist/mcp/envelope.d.ts +6 -0
- package/dist/mcp/envelope.d.ts.map +1 -1
- package/dist/mcp/envelope.js +6 -0
- package/dist/mcp/envelope.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/payload-mcp.d.ts +1 -15
- package/dist/mcp/payload-mcp.d.ts.map +1 -1
- package/dist/mcp/payload-mcp.js +40 -1
- package/dist/mcp/payload-mcp.js.map +1 -1
- package/dist/observability/collection.d.ts +13 -0
- package/dist/observability/collection.d.ts.map +1 -0
- package/dist/observability/collection.js +76 -0
- package/dist/observability/collection.js.map +1 -0
- package/dist/observability/index.d.ts +9 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +5 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/plugin.d.ts +21 -0
- package/dist/observability/plugin.d.ts.map +1 -0
- package/dist/observability/plugin.js +51 -0
- package/dist/observability/plugin.js.map +1 -0
- package/dist/observability/report.d.ts +175 -0
- package/dist/observability/report.d.ts.map +1 -0
- package/dist/observability/report.js +274 -0
- package/dist/observability/report.js.map +1 -0
- package/dist/observability/writer.d.ts +24 -0
- package/dist/observability/writer.d.ts.map +1 -0
- package/dist/observability/writer.js +72 -0
- package/dist/observability/writer.js.map +1 -0
- package/dist/testing/anonymousAccess.d.ts +111 -0
- package/dist/testing/anonymousAccess.d.ts.map +1 -0
- package/dist/testing/anonymousAccess.js +185 -0
- package/dist/testing/anonymousAccess.js.map +1 -0
- package/dist/testing/describeAnonymousAccess.d.ts +26 -0
- package/dist/testing/describeAnonymousAccess.d.ts.map +1 -0
- package/dist/testing/describeAnonymousAccess.js +76 -0
- package/dist/testing/describeAnonymousAccess.js.map +1 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +9 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +30 -7
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
export { AUDIT_ACTIONS, AUDIT_MCP_SERVERS, DEFAULT_AUDIT_SLUG, auditPlugin, createAuditCollection, createAuditWriter, getAuditWriter, } from './audit/index.js';
|
|
2
2
|
export type { AuditAction, AuditActor, AuditCollectionOptions, AuditEventInput, AuditMcpServer, AuditPluginOptions, AuditWriter, AuditWriterOptions, } from './audit/index.js';
|
|
3
|
+
export { EnvironmentError, assertEnvironment, checkEnvValue } from './env/index.js';
|
|
4
|
+
export type { EnvValueProblem, EnvironmentCheck } from './env/index.js';
|
|
3
5
|
export { createInngestClient } from './events/index.js';
|
|
4
6
|
export type { CoreEvents, FrameworkEvents, InngestClientOptions } from './events/index.js';
|
|
5
|
-
export { McpMetaSchema, auditContext, deniedEnvelope, createMcpToolCollector, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
|
|
7
|
+
export { MCP_API_KEYS_SLUG, McpMetaSchema, auditContext, deniedEnvelope, createMcpToolCollector, isMcpApiKeyPrincipal, isSignedIn, mcpApiKeyAccess, signedIn, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
|
|
6
8
|
export type { AddToolsOptions, AuditContextFields, CreateMcpToolCollectorOptions, DeclareToolsOptions, McpMeta, McpToolCollector, McpToolDescriptor, PayloadMcpRequest, PayloadMcpTool, ToPayloadMcpToolOptions, } from './mcp/index.js';
|
|
7
9
|
export { defaultLogger, createNamedLogger } from './logger/index.js';
|
|
10
|
+
export { DEFAULT_JOB_FAILURES_SLUG, DEFAULT_REPORTED_HEADERS, ERROR_WEBHOOK_URL_ENV, JOB_FAILURE_KINDS, NEVER_REPORTED_HEADERS, buildHealthcheckFailureReport, buildJobFailureReport, buildRequestErrorReport, clientPrefix, createErrorReporter, createJobFailureWriter, createJobFailuresCollection, currentDeployment, describeErrorReporting, getJobFailureWriter, jobFailuresPlugin, reportError, summariseReport, } from './observability/index.js';
|
|
11
|
+
export type { BuildJobFailureReportInput, BuildRequestErrorReportOptions, ErrorReport, ErrorReporter, ErrorReporterOptions, HealthcheckFailureReport, JobFailureKind, JobFailureReport, JobFailureWriter, JobFailureWriterOptions, JobFailuresCollectionOptions, JobFailuresPluginOptions, ReportDeployment, ReportableHeaders, RequestErrorReport, } from './observability/index.js';
|
|
8
12
|
export { documentContentHash, formatZodIssues, sha256Hex, unwrapRelationshipId, } from './utils/index.js';
|
|
9
13
|
export type { DocumentContentHashOptions } from './utils/index.js';
|
|
10
|
-
export type { AuthenticatedUser, BaseCorePluginOptions, CorePlugin, Logger, McpToolContext, McpToolDefinition, PluginRegistry, PluginRegistryEntry, } from '@forumone/throughline-plugin-contract';
|
|
14
|
+
export type { AuthenticatedUser, BaseCorePluginOptions, CollectionPluginOptions, CorePlugin, EnvRequirement, Logger, McpToolContext, McpToolDefinition, PluginAdminGroup, PluginAdminOptions, PluginRegistry, PluginRegistryEntry, } from '@forumone/throughline-plugin-contract';
|
|
11
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,kBAAkB,GACnB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAE1F,OAAO,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,6BAA6B,EAC7B,mBAAmB,EACnB,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,oBAAoB,GACrB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAA;AAIlE,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,MAAM,EACN,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,uCAAuC,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACV,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,kBAAkB,GACnB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnF,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAE1F,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,UAAU,EACV,eAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,6BAA6B,EAC7B,mBAAmB,EACnB,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,6BAA6B,EAC7B,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,WAAW,EACX,eAAe,GAChB,MAAM,0BAA0B,CAAA;AACjC,YAAY,EACV,0BAA0B,EAC1B,8BAA8B,EAC9B,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,wBAAwB,EACxB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,4BAA4B,EAC5B,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,oBAAoB,GACrB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAA;AAIlE,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,MAAM,EACN,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,GACpB,MAAM,uCAAuC,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// Subsystems are re-exported as they are added during C4. The aggregated
|
|
2
2
|
// surface here mirrors the package's `./<subpath>` exports.
|
|
3
3
|
export { AUDIT_ACTIONS, AUDIT_MCP_SERVERS, DEFAULT_AUDIT_SLUG, auditPlugin, createAuditCollection, createAuditWriter, getAuditWriter, } from './audit/index.js';
|
|
4
|
+
export { EnvironmentError, assertEnvironment, checkEnvValue } from './env/index.js';
|
|
4
5
|
export { createInngestClient } from './events/index.js';
|
|
5
|
-
export { McpMetaSchema, auditContext, deniedEnvelope, createMcpToolCollector, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
|
|
6
|
+
export { MCP_API_KEYS_SLUG, McpMetaSchema, auditContext, deniedEnvelope, createMcpToolCollector, isMcpApiKeyPrincipal, isSignedIn, mcpApiKeyAccess, signedIn, toPayloadMcpTool, toPayloadMcpTools, withMeta, } from './mcp/index.js';
|
|
6
7
|
export { defaultLogger, createNamedLogger } from './logger/index.js';
|
|
8
|
+
export { DEFAULT_JOB_FAILURES_SLUG, DEFAULT_REPORTED_HEADERS, ERROR_WEBHOOK_URL_ENV, JOB_FAILURE_KINDS, NEVER_REPORTED_HEADERS, buildHealthcheckFailureReport, buildJobFailureReport, buildRequestErrorReport, clientPrefix, createErrorReporter, createJobFailureWriter, createJobFailuresCollection, currentDeployment, describeErrorReporting, getJobFailureWriter, jobFailuresPlugin, reportError, summariseReport, } from './observability/index.js';
|
|
7
9
|
export { documentContentHash, formatZodIssues, sha256Hex, unwrapRelationshipId, } from './utils/index.js';
|
|
8
10
|
//# 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,yEAAyE;AACzE,4DAA4D;AAE5D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AAYzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGvD,OAAO,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AAcvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,oBAAoB,GACrB,MAAM,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4DAA4D;AAE5D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAA;AAYzB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGvD,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,UAAU,EACV,eAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,QAAQ,GACT,MAAM,gBAAgB,CAAA;AAcvB,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,6BAA6B,EAC7B,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,WAAW,EACX,eAAe,GAChB,MAAM,0BAA0B,CAAA;AAmBjC,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,oBAAoB,GACrB,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Access, CollectionConfig } from 'payload';
|
|
2
|
+
/** The slug `@payloadcms/plugin-mcp` gives its key collection. */
|
|
3
|
+
export declare const MCP_API_KEYS_SLUG = "payload-mcp-api-keys";
|
|
4
|
+
/** What Payload puts on `req.user`. */
|
|
5
|
+
export type AccessUser = Parameters<Access>[0]['req']['user'];
|
|
6
|
+
/**
|
|
7
|
+
* True when `req.user` is an MCP key document rather than a person.
|
|
8
|
+
*
|
|
9
|
+
* Only a request authenticated by Payload's REST API-key strategy against the
|
|
10
|
+
* key collection carries this principal — which Payload 3.89.0 and later no
|
|
11
|
+
* longer register. A tool call through `/api/mcp` arrives as the key's user.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isMcpApiKeyPrincipal(user: AccessUser | undefined): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* A principal a site should treat as a signed-in person.
|
|
16
|
+
*
|
|
17
|
+
* Use this wherever an access rule would otherwise say `Boolean(req.user)` —
|
|
18
|
+
* which is the rule Payload's own `defaultAccess` uses. A bearer credential
|
|
19
|
+
* presented over REST is a `req.user` and is not somebody signed in.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isSignedIn(user: AccessUser | undefined): user is NonNullable<AccessUser>;
|
|
22
|
+
/** `isSignedIn` as a Payload `Access` function. */
|
|
23
|
+
export declare const signedIn: Access;
|
|
24
|
+
/**
|
|
25
|
+
* An `overrideApiKeyCollection` for `mcpPlugin` that makes the key collection
|
|
26
|
+
* admin-only: read, create, update, delete and unlock all answer to `isAdmin`.
|
|
27
|
+
*
|
|
28
|
+
* `isAdmin` is the site's own rule, since only the site knows what an
|
|
29
|
+
* administrator is. Whatever it says, an MCP key principal is refused first, so
|
|
30
|
+
* a key can never manage keys.
|
|
31
|
+
*
|
|
32
|
+
* It touches `access` and nothing else, so it composes with other overrides:
|
|
33
|
+
*
|
|
34
|
+
* ```ts
|
|
35
|
+
* const keysAdminOnly = mcpApiKeyAccess(isAdmin)
|
|
36
|
+
*
|
|
37
|
+
* mcpPlugin({
|
|
38
|
+
* mcp: { tools: mcpTools.tools },
|
|
39
|
+
* overrideApiKeyCollection: collection => {
|
|
40
|
+
* const hardened = keysAdminOnly(collection)
|
|
41
|
+
* return { ...hardened, admin: { ...hardened.admin, group: 'Throughline' } }
|
|
42
|
+
* },
|
|
43
|
+
* })
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* The plugin's field-level rules on the key's `user` relationship are left as
|
|
47
|
+
* shipped: a new key is bound to whoever creates it.
|
|
48
|
+
*/
|
|
49
|
+
export declare function mcpApiKeyAccess(isAdmin: Access): (collection: CollectionConfig) => CollectionConfig;
|
|
50
|
+
//# sourceMappingURL=api-key-access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-access.d.ts","sourceRoot":"","sources":["../../src/mcp/api-key-access.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAiCvD,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,yBAAyB,CAAA;AAEvD,uCAAuC;AACvC,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAA;AAE7D;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAE1E;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,IAAI,WAAW,CAAC,UAAU,CAAC,CAExF;AAED,mDAAmD;AACnD,eAAO,MAAM,QAAQ,EAAE,MAA0C,CAAA;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,GACd,CAAC,UAAU,EAAE,gBAAgB,KAAK,gBAAgB,CAcpD"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Who may manage MCP keys, and who counts as signed in. Issue #157.
|
|
3
|
+
|
|
4
|
+
**The key collection.** `@payloadcms/plugin-mcp` brings `payload-mcp-api-keys`.
|
|
5
|
+
Older releases declared it with no `access` block, so every operation fell
|
|
6
|
+
through to Payload's `defaultAccess` — anybody signed in. Current ones scope each
|
|
7
|
+
person to their own keys. Neither is the right rule for a collection of
|
|
8
|
+
credentials: a key runs every tool as the person it is bound to, so who may mint,
|
|
9
|
+
read, rotate and revoke one is an administrator's decision. `mcpApiKeyAccess`
|
|
10
|
+
makes it one, through the plugin's `overrideApiKeyCollection`.
|
|
11
|
+
|
|
12
|
+
**The principal.** The collection sets `auth.useAPIKey: true`. Before Payload
|
|
13
|
+
3.89.0 that registered Payload's API-key strategy globally, so
|
|
14
|
+
`Authorization: payload-mcp-api-keys API-Key <key>` was accepted on every REST
|
|
15
|
+
route and put the *key document* on `req.user`, tagged
|
|
16
|
+
`collection: 'payload-mcp-api-keys'`. It has no roles, so role checks denied it;
|
|
17
|
+
`Boolean(req.user)` did not. On a site whose draft rule was "published, or
|
|
18
|
+
anybody signed in", that served every draft to anyone holding a key, with no MCP
|
|
19
|
+
involved.
|
|
20
|
+
|
|
21
|
+
3.89.0 excludes that slug from the strategy loop, and the suite's peer floor is
|
|
22
|
+
`^3.89.0` because of it. But one conditional in a dependency is not a control
|
|
23
|
+
anybody here would notice losing, so `isSignedIn` refuses the key principal
|
|
24
|
+
itself. Two things then have to fail for the hole to reopen.
|
|
25
|
+
|
|
26
|
+
**This cannot affect `/api/mcp`.** That endpoint resolves a presented key on its
|
|
27
|
+
own and runs the tool as the *user* the key points at, on the users collection,
|
|
28
|
+
with that person's roles. Only the REST strategy's principal carries the key
|
|
29
|
+
collection's slug, and that is the only principal refused here.
|
|
30
|
+
*/
|
|
31
|
+
/** The slug `@payloadcms/plugin-mcp` gives its key collection. */
|
|
32
|
+
export const MCP_API_KEYS_SLUG = 'payload-mcp-api-keys';
|
|
33
|
+
/**
|
|
34
|
+
* True when `req.user` is an MCP key document rather than a person.
|
|
35
|
+
*
|
|
36
|
+
* Only a request authenticated by Payload's REST API-key strategy against the
|
|
37
|
+
* key collection carries this principal — which Payload 3.89.0 and later no
|
|
38
|
+
* longer register. A tool call through `/api/mcp` arrives as the key's user.
|
|
39
|
+
*/
|
|
40
|
+
export function isMcpApiKeyPrincipal(user) {
|
|
41
|
+
return user?.collection === MCP_API_KEYS_SLUG;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A principal a site should treat as a signed-in person.
|
|
45
|
+
*
|
|
46
|
+
* Use this wherever an access rule would otherwise say `Boolean(req.user)` —
|
|
47
|
+
* which is the rule Payload's own `defaultAccess` uses. A bearer credential
|
|
48
|
+
* presented over REST is a `req.user` and is not somebody signed in.
|
|
49
|
+
*/
|
|
50
|
+
export function isSignedIn(user) {
|
|
51
|
+
return Boolean(user) && !isMcpApiKeyPrincipal(user);
|
|
52
|
+
}
|
|
53
|
+
/** `isSignedIn` as a Payload `Access` function. */
|
|
54
|
+
export const signedIn = ({ req }) => isSignedIn(req.user);
|
|
55
|
+
/**
|
|
56
|
+
* An `overrideApiKeyCollection` for `mcpPlugin` that makes the key collection
|
|
57
|
+
* admin-only: read, create, update, delete and unlock all answer to `isAdmin`.
|
|
58
|
+
*
|
|
59
|
+
* `isAdmin` is the site's own rule, since only the site knows what an
|
|
60
|
+
* administrator is. Whatever it says, an MCP key principal is refused first, so
|
|
61
|
+
* a key can never manage keys.
|
|
62
|
+
*
|
|
63
|
+
* It touches `access` and nothing else, so it composes with other overrides:
|
|
64
|
+
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* const keysAdminOnly = mcpApiKeyAccess(isAdmin)
|
|
67
|
+
*
|
|
68
|
+
* mcpPlugin({
|
|
69
|
+
* mcp: { tools: mcpTools.tools },
|
|
70
|
+
* overrideApiKeyCollection: collection => {
|
|
71
|
+
* const hardened = keysAdminOnly(collection)
|
|
72
|
+
* return { ...hardened, admin: { ...hardened.admin, group: 'Throughline' } }
|
|
73
|
+
* },
|
|
74
|
+
* })
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* The plugin's field-level rules on the key's `user` relationship are left as
|
|
78
|
+
* shipped: a new key is bound to whoever creates it.
|
|
79
|
+
*/
|
|
80
|
+
export function mcpApiKeyAccess(isAdmin) {
|
|
81
|
+
const adminOnly = args => (isMcpApiKeyPrincipal(args.req.user) ? false : isAdmin(args));
|
|
82
|
+
return collection => ({
|
|
83
|
+
...collection,
|
|
84
|
+
access: {
|
|
85
|
+
...collection.access,
|
|
86
|
+
read: adminOnly,
|
|
87
|
+
create: adminOnly,
|
|
88
|
+
update: adminOnly,
|
|
89
|
+
delete: adminOnly,
|
|
90
|
+
unlock: adminOnly,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=api-key-access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-access.js","sourceRoot":"","sources":["../../src/mcp/api-key-access.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BE;AAEF,kEAAkE;AAClE,MAAM,CAAC,MAAM,iBAAiB,GAAG,sBAAsB,CAAA;AAKvD;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAA4B;IAC/D,OAAQ,IAAoD,EAAE,UAAU,KAAK,iBAAiB,CAAA;AAChG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,IAA4B;IACrD,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAA;AACrD,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,MAAM,QAAQ,GAAW,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe;IAEf,MAAM,SAAS,GAAW,IAAI,CAAC,EAAE,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAE/F,OAAO,UAAU,CAAC,EAAE,CAAC,CAAC;QACpB,GAAG,UAAU;QACb,MAAM,EAAE;YACN,GAAG,UAAU,CAAC,MAAM;YACpB,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,SAAS;SAClB;KACF,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/mcp/envelope.d.ts
CHANGED
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
* The role predicates stay with their servers. What counts as an audit reader is
|
|
10
10
|
* not what counts as a forms author, and collapsing them would put one package's
|
|
11
11
|
* policy in another's file.
|
|
12
|
+
*
|
|
13
|
+
* **`error` is reserved for a refusal.** `toPayloadMcpTool` reads it to set
|
|
14
|
+
* MCP's `isError` flag, so a *success* result must report failure some other
|
|
15
|
+
* way — the healthy shapes in this suite use `ok`, `healthy`, `message` and
|
|
16
|
+
* `details`. A success payload carrying an `error` string would reach the
|
|
17
|
+
* caller flagged as an error.
|
|
12
18
|
*/
|
|
13
19
|
export declare function deniedEnvelope(reason: string): {
|
|
14
20
|
error: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/mcp/envelope.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/mcp/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAEhE"}
|
package/dist/mcp/envelope.js
CHANGED
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
* The role predicates stay with their servers. What counts as an audit reader is
|
|
10
10
|
* not what counts as a forms author, and collapsing them would put one package's
|
|
11
11
|
* policy in another's file.
|
|
12
|
+
*
|
|
13
|
+
* **`error` is reserved for a refusal.** `toPayloadMcpTool` reads it to set
|
|
14
|
+
* MCP's `isError` flag, so a *success* result must report failure some other
|
|
15
|
+
* way — the healthy shapes in this suite use `ok`, `healthy`, `message` and
|
|
16
|
+
* `details`. A success payload carrying an `error` string would reach the
|
|
17
|
+
* caller flagged as an error.
|
|
12
18
|
*/
|
|
13
19
|
export function deniedEnvelope(reason) {
|
|
14
20
|
return { error: reason };
|
package/dist/mcp/envelope.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/mcp/envelope.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/mcp/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AAC1B,CAAC"}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export { createMcpToolCollector } from './collector.js';
|
|
|
8
8
|
export type { AddToolsOptions, CreateMcpToolCollectorOptions, DeclareToolsOptions, McpToolCollector, McpToolDescriptor, } from './collector.js';
|
|
9
9
|
export { deniedEnvelope } from './envelope.js';
|
|
10
10
|
export { auditServerFor, mcpServerRefusal } from './audit-server.js';
|
|
11
|
+
export { MCP_API_KEYS_SLUG, isMcpApiKeyPrincipal, isSignedIn, mcpApiKeyAccess, signedIn, } from './api-key-access.js';
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACnD,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE5D,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACtE,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EACV,eAAe,EACf,6BAA6B,EAC7B,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACnD,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAExC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE5D,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACtE,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EACV,eAAe,EACf,6BAA6B,EAC7B,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,eAAe,EACf,QAAQ,GACT,MAAM,qBAAqB,CAAA"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -4,4 +4,5 @@ export { toPayloadMcpTool, toPayloadMcpTools } from './payload-mcp.js';
|
|
|
4
4
|
export { createMcpToolCollector } from './collector.js';
|
|
5
5
|
export { deniedEnvelope } from './envelope.js';
|
|
6
6
|
export { auditServerFor, mcpServerRefusal } from './audit-server.js';
|
|
7
|
+
export { MCP_API_KEYS_SLUG, isMcpApiKeyPrincipal, isSignedIn, mcpApiKeyAccess, signedIn, } from './api-key-access.js';
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGjD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAOtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AASvD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGjD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAOtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AASvD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEpE,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,eAAe,EACf,QAAQ,GACT,MAAM,qBAAqB,CAAA"}
|
|
@@ -12,6 +12,7 @@ export interface PayloadMcpTool {
|
|
|
12
12
|
type: 'text';
|
|
13
13
|
text: string;
|
|
14
14
|
}>;
|
|
15
|
+
isError?: boolean;
|
|
15
16
|
}>;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
@@ -61,21 +62,6 @@ export interface ToPayloadMcpToolOptions {
|
|
|
61
62
|
*/
|
|
62
63
|
auditServer?: AuditMcpServer;
|
|
63
64
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Wraps one Throughline tool so Payload's MCP plugin can serve it.
|
|
66
|
-
*
|
|
67
|
-
* Three things are being translated, and none of them is the tool's logic:
|
|
68
|
-
*
|
|
69
|
-
* - **The schema.** `plugin-mcp` wants the raw shape; `withMeta` produces a
|
|
70
|
-
* `z.object` around it. `.shape` is the whole conversion, which is why tools
|
|
71
|
-
* must build their input with `withMeta` or `z.object` rather than an
|
|
72
|
-
* arbitrary `ZodType`.
|
|
73
|
-
* - **The context.** Payload hands the handler a request. Throughline's tools
|
|
74
|
-
* take a `McpToolContext`, so one is built from it.
|
|
75
|
-
* - **The result.** Payload wants MCP content blocks; Throughline's tools
|
|
76
|
-
* return their own objects, exactly as they do through this package's own
|
|
77
|
-
* handler, which does the same wrapping a layer up.
|
|
78
|
-
*/
|
|
79
65
|
export declare function toPayloadMcpTool(tool: McpToolDefinition, options?: ToPayloadMcpToolOptions): PayloadMcpTool;
|
|
80
66
|
/** Every tool in a server, in one call. */
|
|
81
67
|
export declare function toPayloadMcpTools(tools: McpToolDefinition[], options?: ToPayloadMcpToolOptions): PayloadMcpTool[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload-mcp.d.ts","sourceRoot":"","sources":["../../src/mcp/payload-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,MAAM,EAAkB,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AACtG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AA0BrD,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,CAAC,CAAC,WAAW,CAAA;IACzB,OAAO,EAAE,CACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,OAAO,KACX,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"payload-mcp.d.ts","sourceRoot":"","sources":["../../src/mcp/payload-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,MAAM,EAAkB,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AACtG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AA0BrD,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,CAAC,CAAC,WAAW,CAAA;IACzB,OAAO,EAAE,CACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,OAAO,KACX,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CACpF;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;IAClG,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,cAAc,CAAA;CAC7B;AAqDD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,iBAAiB,EACvB,OAAO,GAAE,uBAA4B,GACpC,cAAc,CAqBhB;AA0ED,2CAA2C;AAC3C,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,iBAAiB,EAAE,EAC1B,OAAO,GAAE,uBAA4B,GACpC,cAAc,EAAE,CAElB"}
|
package/dist/mcp/payload-mcp.js
CHANGED
|
@@ -17,6 +17,42 @@ import { McpMetaSchema } from './meta.js';
|
|
|
17
17
|
* return their own objects, exactly as they do through this package's own
|
|
18
18
|
* handler, which does the same wrapping a layer up.
|
|
19
19
|
*/
|
|
20
|
+
/*
|
|
21
|
+
Whether a tool answered with a refusal, and so whether MCP's `isError` belongs
|
|
22
|
+
on the result.
|
|
23
|
+
|
|
24
|
+
Every server in the suite refuses the same way — `deniedEnvelope`, or a bare
|
|
25
|
+
`{ error }` built in the tool — and returns it as an ordinary value rather than
|
|
26
|
+
throwing, so a denial reads to the model as a denial rather than as a server
|
|
27
|
+
fault. What none of them did was set `isError`, so a refusal arrived as a
|
|
28
|
+
**successful** tool result carrying `{"error": …}`. An agent that checks the
|
|
29
|
+
protocol's flag instead of parsing the body read every refusal as a success —
|
|
30
|
+
including "Must be authenticated to use the publishing tools", which is the one
|
|
31
|
+
every `Bearer` call gets, because `plugin-mcp` assigns no `req.user`.
|
|
32
|
+
|
|
33
|
+
Found exercising `04` F-02 with a real MCP key, and recorded in the consuming
|
|
34
|
+
repository's #614. It is a reporting defect rather than an access one: nothing
|
|
35
|
+
was permitted that should not have been, and everything that was refused stayed
|
|
36
|
+
refused.
|
|
37
|
+
|
|
38
|
+
Here rather than in each tool for the reason the audit wrap below is here. This
|
|
39
|
+
is the one place every tool in the suite passes through, so a tool written
|
|
40
|
+
tomorrow is covered without its author knowing this file exists.
|
|
41
|
+
|
|
42
|
+
**The test is a non-empty string `error`, not a sole `error` key.** A refusal
|
|
43
|
+
that later grows a second field — a code, a retry hint — keeps its flag, which
|
|
44
|
+
is the likelier shape to drift. It costs the inverse risk: a *success* payload
|
|
45
|
+
carrying an `error` string would be flagged wrongly. Nothing in the suite does
|
|
46
|
+
that today — the healthy shapes report through `ok`, `healthy`, `message` and
|
|
47
|
+
`details` — and `payload-mcp.test.ts` pins it so a new one has to argue with a
|
|
48
|
+
test rather than slip past.
|
|
49
|
+
*/
|
|
50
|
+
function isRefusal(result) {
|
|
51
|
+
if (typeof result !== 'object' || result === null)
|
|
52
|
+
return false;
|
|
53
|
+
const error = result['error'];
|
|
54
|
+
return typeof error === 'string' && error.trim() !== '';
|
|
55
|
+
}
|
|
20
56
|
export function toPayloadMcpTool(tool, options = {}) {
|
|
21
57
|
const shape = shapeOf(tool);
|
|
22
58
|
return {
|
|
@@ -27,7 +63,10 @@ export function toPayloadMcpTool(tool, options = {}) {
|
|
|
27
63
|
const context = contextFrom(req, options);
|
|
28
64
|
try {
|
|
29
65
|
const result = await tool.handler(args, context);
|
|
30
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
68
|
+
...(isRefusal(result) ? { isError: true } : {}),
|
|
69
|
+
};
|
|
31
70
|
}
|
|
32
71
|
catch (error) {
|
|
33
72
|
await recordToolFailure(tool.name, error, args, context, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload-mcp.js","sourceRoot":"","sources":["../../src/mcp/payload-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AA4EzC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAuB,EACvB,UAAmC,EAAE;IAErC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3B,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,KAAK;QACjB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;YACzC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;gBAChD,OAAO,
|
|
1
|
+
{"version":3,"file":"payload-mcp.js","sourceRoot":"","sources":["../../src/mcp/payload-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AA4EzC;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BE;AACF,SAAS,SAAS,CAAC,MAAe;IAChC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAC/D,MAAM,KAAK,GAAI,MAAkC,CAAC,OAAO,CAAC,CAAA;IAC1D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAuB,EACvB,UAAmC,EAAE;IAErC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3B,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,KAAK;QACjB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;YACzC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;gBAChD,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;oBAClE,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAChD,CAAA;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;gBACjE,MAAM,KAAK,CAAA;YACb,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCE;AACF,KAAK,UAAU,iBAAiB,CAC9B,QAAgB,EAChB,KAAc,EACd,IAA6B,EAC7B,OAAuB,EACvB,OAAgC;IAEhC,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAA;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAA;IAC9C,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAEtE,MAAM,CAAC,KAAK,CAAC,aAAa,QAAQ,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;IAEhF,IAAI,CAAC,KAAK,IAAI,CAAC,WAAW;QAAE,OAAM;IAElC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;QACnD,MAAM,KAAK,CAAC;YACV,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YAC9D,MAAM,EAAE,cAAc;YACtB,SAAS,EAAE,WAAW;YACtB,OAAO,EAAE,QAAQ;YACjB,OAAO,EAAE,GAAG,QAAQ,WAAW,OAAO,EAAE;YACxC,OAAO,EAAE,KAAK;YACd,YAAY,EAAE,OAAO;SACtB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,WAAW,EAAE,CAAC;QACrB,MAAM,CAAC,KAAK,CAAC,sCAAsC,EAAE;YACnD,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC;SAC3B,CAAC,CAAA;IACJ,CAAC;AACH,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,iBAAiB,CAC/B,KAA0B,EAC1B,UAAmC,EAAE;IAErC,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED,SAAS,OAAO,CAAC,IAAuB;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAA;IAC/B,IAAI,MAAM,YAAY,CAAC,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC,KAAsB,CAAA;IACvE,MAAM,IAAI,KAAK,CACb,SAAS,IAAI,CAAC,IAAI,2EAA2E;QAC3F,0FAA0F,CAC7F,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,GAAsB,EAAE,OAAgC;IAC3E,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI;QACnB,CAAC,CAAC;YACE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;YAC7B,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACnC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACnD,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,IAAI,CAAC,KAAkB,CAAC,CAAC,CAAC,EAAE;YACxE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,IAAI,CAAC,MAAmB,CAAC,CAAC,CAAC,EAAE;SAC5E;QACH,CAAC,CAAC,IAAI,CAAA;IAER,OAAO;QACL,IAAI;QACJ;;;;;UAKE;QACF,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,IAAI,aAAa;KAC/D,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Access, CollectionConfig } from 'payload';
|
|
2
|
+
export declare const DEFAULT_JOB_FAILURES_SLUG = "job-failures";
|
|
3
|
+
/** What kind of thing failed. Adding a value is a schema change and needs a migration. */
|
|
4
|
+
export declare const JOB_FAILURE_KINDS: readonly ["job", "healthcheck"];
|
|
5
|
+
export type JobFailureKind = (typeof JOB_FAILURE_KINDS)[number];
|
|
6
|
+
export interface JobFailuresCollectionOptions {
|
|
7
|
+
/** Override the collection slug. Default: `'job-failures'`. */
|
|
8
|
+
slug?: string;
|
|
9
|
+
/** Read access. Default: users with the `admin` role. */
|
|
10
|
+
readAccess?: Access;
|
|
11
|
+
}
|
|
12
|
+
export declare function createJobFailuresCollection(options?: JobFailuresCollectionOptions): CollectionConfig;
|
|
13
|
+
//# sourceMappingURL=collection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../../src/observability/collection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAgBvD,eAAO,MAAM,yBAAyB,iBAAiB,CAAA;AAEvD,0FAA0F;AAC1F,eAAO,MAAM,iBAAiB,iCAAkC,CAAA;AAChE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE/D,MAAM,WAAW,4BAA4B;IAC3C,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAOD,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,4BAAiC,GACzC,gBAAgB,CAuDlB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Where a background job's failure is recorded.
|
|
3
|
+
|
|
4
|
+
Deliberately not the audit log. `audit-events` records who did what through
|
|
5
|
+
an MCP tool — `mcpServer` and `mcpTool` are `NOT NULL`, and every row answers
|
|
6
|
+
"which tool did this". A cron that ran out of retries is not an action anybody
|
|
7
|
+
took; it is an operational fact, with its own fields (a run id, a triggering
|
|
8
|
+
event) and its own lifetime (worth keeping for weeks, not forever). Giving it
|
|
9
|
+
a fake MCP server name would make that column mean nothing.
|
|
10
|
+
|
|
11
|
+
Read-only from outside the writer, like the audit log: the writer uses the
|
|
12
|
+
Local API, which bypasses these access rules.
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_JOB_FAILURES_SLUG = 'job-failures';
|
|
15
|
+
/** What kind of thing failed. Adding a value is a schema change and needs a migration. */
|
|
16
|
+
export const JOB_FAILURE_KINDS = ['job', 'healthcheck'];
|
|
17
|
+
const adminOnly = ({ req }) => {
|
|
18
|
+
const roles = req.user?.['roles'] ?? [];
|
|
19
|
+
return roles.includes('admin');
|
|
20
|
+
};
|
|
21
|
+
export function createJobFailuresCollection(options = {}) {
|
|
22
|
+
return {
|
|
23
|
+
slug: options.slug ?? DEFAULT_JOB_FAILURES_SLUG,
|
|
24
|
+
admin: {
|
|
25
|
+
useAsTitle: 'summary',
|
|
26
|
+
defaultColumns: ['createdAt', 'kind', 'source', 'message'],
|
|
27
|
+
description: 'Background jobs that ran out of retries, and healthchecks that failed. Read-only; written by the failure handlers.',
|
|
28
|
+
},
|
|
29
|
+
access: {
|
|
30
|
+
read: options.readAccess ?? adminOnly,
|
|
31
|
+
create: () => false,
|
|
32
|
+
update: () => false,
|
|
33
|
+
delete: () => false,
|
|
34
|
+
},
|
|
35
|
+
fields: [
|
|
36
|
+
{
|
|
37
|
+
name: 'createdAt',
|
|
38
|
+
type: 'date',
|
|
39
|
+
required: true,
|
|
40
|
+
defaultValue: () => new Date().toISOString(),
|
|
41
|
+
admin: { position: 'sidebar', readOnly: true },
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'kind',
|
|
45
|
+
type: 'select',
|
|
46
|
+
required: true,
|
|
47
|
+
options: JOB_FAILURE_KINDS.map((value) => ({ label: value, value })),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'source',
|
|
51
|
+
type: 'text',
|
|
52
|
+
required: true,
|
|
53
|
+
admin: { description: 'The function or check that failed, e.g. an Inngest function id.' },
|
|
54
|
+
},
|
|
55
|
+
{ name: 'summary', type: 'text', required: true },
|
|
56
|
+
{ name: 'message', type: 'textarea', required: true },
|
|
57
|
+
{ name: 'errorName', type: 'text' },
|
|
58
|
+
{
|
|
59
|
+
name: 'runId',
|
|
60
|
+
type: 'text',
|
|
61
|
+
admin: { description: "The run's id in the job runner, for finding it in its dashboard." },
|
|
62
|
+
},
|
|
63
|
+
{ name: 'triggerEvent', type: 'text' },
|
|
64
|
+
{
|
|
65
|
+
name: 'details',
|
|
66
|
+
type: 'json',
|
|
67
|
+
admin: { description: 'For a healthcheck: every failed check and what it said.' },
|
|
68
|
+
},
|
|
69
|
+
{ name: 'environment', type: 'text' },
|
|
70
|
+
{ name: 'commit', type: 'text' },
|
|
71
|
+
],
|
|
72
|
+
indexes: [{ fields: ['createdAt'] }, { fields: ['source', 'createdAt'] }],
|
|
73
|
+
timestamps: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collection.js","sourceRoot":"","sources":["../../src/observability/collection.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;EAYE;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,cAAc,CAAA;AAEvD,0FAA0F;AAC1F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,aAAa,CAAU,CAAA;AAUhE,MAAM,SAAS,GAAW,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE;IACpC,MAAM,KAAK,GAAI,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAA0B,IAAI,EAAE,CAAA;IACjE,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;AAChC,CAAC,CAAA;AAED,MAAM,UAAU,2BAA2B,CACzC,UAAwC,EAAE;IAE1C,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,yBAAyB;QAC/C,KAAK,EAAE;YACL,UAAU,EAAE,SAAS;YACrB,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC;YAC1D,WAAW,EACT,oHAAoH;SACvH;QACD,MAAM,EAAE;YACN,IAAI,EAAE,OAAO,CAAC,UAAU,IAAI,SAAS;YACrC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK;YACnB,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK;YACnB,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK;SACpB;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,IAAI;gBACd,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAC5C,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;aAC/C;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;aACrE;YACD;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,EAAE,WAAW,EAAE,iEAAiE,EAAE;aAC1F;YACD,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;YACjD,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE;YACrD,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;YACnC;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,EAAE,WAAW,EAAE,kEAAkE,EAAE;aAC3F;YACD,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE;YACtC;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,EAAE,WAAW,EAAE,yDAAyD,EAAE;aAClF;YACD,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE;YACrC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;SACjC;QACD,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC;QACzE,UAAU,EAAE,KAAK;KAClB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { DEFAULT_REPORTED_HEADERS, ERROR_WEBHOOK_URL_ENV, NEVER_REPORTED_HEADERS, buildHealthcheckFailureReport, buildJobFailureReport, buildRequestErrorReport, clientPrefix, createErrorReporter, currentDeployment, describeErrorReporting, reportError, summariseReport, } from './report.js';
|
|
2
|
+
export type { BuildJobFailureReportInput, BuildRequestErrorReportOptions, ErrorReport, ErrorReporter, ErrorReporterOptions, HealthcheckFailureReport, JobFailureReport, ReportDeployment, ReportableHeaders, RequestErrorReport, } from './report.js';
|
|
3
|
+
export { DEFAULT_JOB_FAILURES_SLUG, JOB_FAILURE_KINDS, createJobFailuresCollection, } from './collection.js';
|
|
4
|
+
export type { JobFailureKind, JobFailuresCollectionOptions } from './collection.js';
|
|
5
|
+
export { createJobFailureWriter } from './writer.js';
|
|
6
|
+
export type { JobFailureWriter, JobFailureWriterOptions } from './writer.js';
|
|
7
|
+
export { getJobFailureWriter, jobFailuresPlugin } from './plugin.js';
|
|
8
|
+
export type { JobFailuresPluginOptions } from './plugin.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,6BAA6B,EAC7B,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,EACX,eAAe,GAChB,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,0BAA0B,EAC1B,8BAA8B,EAC9B,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,wBAAwB,EACxB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,cAAc,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAA;AAEnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACpD,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAE5E,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpE,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DEFAULT_REPORTED_HEADERS, ERROR_WEBHOOK_URL_ENV, NEVER_REPORTED_HEADERS, buildHealthcheckFailureReport, buildJobFailureReport, buildRequestErrorReport, clientPrefix, createErrorReporter, currentDeployment, describeErrorReporting, reportError, summariseReport, } from './report.js';
|
|
2
|
+
export { DEFAULT_JOB_FAILURES_SLUG, JOB_FAILURE_KINDS, createJobFailuresCollection, } from './collection.js';
|
|
3
|
+
export { createJobFailureWriter } from './writer.js';
|
|
4
|
+
export { getJobFailureWriter, jobFailuresPlugin } from './plugin.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,6BAA6B,EAC7B,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,EACX,eAAe,GAChB,MAAM,aAAa,CAAA;AAcpB,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAGpD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type BaseCorePluginOptions, type CorePlugin } from '@forumone/throughline-plugin-contract';
|
|
2
|
+
import { type JobFailuresCollectionOptions } from './collection.js';
|
|
3
|
+
import { type JobFailureWriter } from './writer.js';
|
|
4
|
+
export interface JobFailuresPluginOptions extends BaseCorePluginOptions, JobFailuresCollectionOptions {
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Adds the `job-failures` collection and attaches its writer to the Payload
|
|
8
|
+
* instance, where `getJobFailureWriter` — and the workflows package's failure
|
|
9
|
+
* handlers — find it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const jobFailuresPlugin: CorePlugin<JobFailuresPluginOptions>;
|
|
12
|
+
/**
|
|
13
|
+
* The writer `jobFailuresPlugin` attached, or `undefined` when the plugin is
|
|
14
|
+
* not registered.
|
|
15
|
+
*
|
|
16
|
+
* Unlike `getAuditWriter` this does not throw: it is called from failure
|
|
17
|
+
* handlers, which fall back to logging and reporting when there is nowhere
|
|
18
|
+
* to write.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getJobFailureWriter(payload: object): JobFailureWriter | undefined;
|
|
21
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/observability/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EAEhB,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAA+B,KAAK,4BAA4B,EAAE,MAAM,iBAAiB,CAAA;AAChG,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAO3E,MAAM,WAAW,wBACf,SAAQ,qBAAqB,EAAE,4BAA4B;CAAG;AAEhE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,UAAU,CAAC,wBAAwB,CA4BhE,CAAA;AAEH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAEjF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getPluginRegistry, } from '@forumone/throughline-plugin-contract';
|
|
2
|
+
import { createJobFailuresCollection } from './collection.js';
|
|
3
|
+
import { createJobFailureWriter } from './writer.js';
|
|
4
|
+
import { defaultLogger } from '../logger/index.js';
|
|
5
|
+
const PLUGIN_ID = '@forumone/throughline-core/observability';
|
|
6
|
+
const PLUGIN_VERSION = '0.1.0';
|
|
7
|
+
const WRITER_SYMBOL = Symbol.for('@forumone/throughline/job-failure-writer');
|
|
8
|
+
/**
|
|
9
|
+
* Adds the `job-failures` collection and attaches its writer to the Payload
|
|
10
|
+
* instance, where `getJobFailureWriter` — and the workflows package's failure
|
|
11
|
+
* handlers — find it.
|
|
12
|
+
*/
|
|
13
|
+
export const jobFailuresPlugin = (options) => (incomingConfig) => {
|
|
14
|
+
if (options.enabled === false)
|
|
15
|
+
return incomingConfig;
|
|
16
|
+
return {
|
|
17
|
+
...incomingConfig,
|
|
18
|
+
collections: [...(incomingConfig.collections ?? []), createJobFailuresCollection(options)],
|
|
19
|
+
onInit: async (payload) => {
|
|
20
|
+
if (incomingConfig.onInit)
|
|
21
|
+
await incomingConfig.onInit(payload);
|
|
22
|
+
Object.defineProperty(payload, WRITER_SYMBOL, {
|
|
23
|
+
value: createJobFailureWriter({
|
|
24
|
+
payload,
|
|
25
|
+
collectionSlug: options.slug,
|
|
26
|
+
logger: options.logger ?? defaultLogger,
|
|
27
|
+
}),
|
|
28
|
+
enumerable: false,
|
|
29
|
+
writable: false,
|
|
30
|
+
configurable: false,
|
|
31
|
+
});
|
|
32
|
+
getPluginRegistry(payload).register({
|
|
33
|
+
id: PLUGIN_ID,
|
|
34
|
+
version: PLUGIN_VERSION,
|
|
35
|
+
capabilities: ['job-failures'],
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The writer `jobFailuresPlugin` attached, or `undefined` when the plugin is
|
|
42
|
+
* not registered.
|
|
43
|
+
*
|
|
44
|
+
* Unlike `getAuditWriter` this does not throw: it is called from failure
|
|
45
|
+
* handlers, which fall back to logging and reporting when there is nowhere
|
|
46
|
+
* to write.
|
|
47
|
+
*/
|
|
48
|
+
export function getJobFailureWriter(payload) {
|
|
49
|
+
return payload[WRITER_SYMBOL];
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/observability/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,GAClB,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAAE,2BAA2B,EAAqC,MAAM,iBAAiB,CAAA;AAChG,OAAO,EAAE,sBAAsB,EAAyB,MAAM,aAAa,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,MAAM,SAAS,GAAG,0CAA0C,CAAA;AAC5D,MAAM,cAAc,GAAG,OAAO,CAAA;AAC9B,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAA;AAK5E;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAC5B,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,cAAc,EAAE,EAAE;IAC9B,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK;QAAE,OAAO,cAAc,CAAA;IAEpD,OAAO;QACL,GAAG,cAAc;QACjB,WAAW,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,2BAA2B,CAAC,OAAO,CAAC,CAAC;QAC1F,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACxB,IAAI,cAAc,CAAC,MAAM;gBAAE,MAAM,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAE/D,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE;gBAC5C,KAAK,EAAE,sBAAsB,CAAC;oBAC5B,OAAO;oBACP,cAAc,EAAE,OAAO,CAAC,IAAI;oBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,aAAa;iBACxC,CAAC;gBACF,UAAU,EAAE,KAAK;gBACjB,QAAQ,EAAE,KAAK;gBACf,YAAY,EAAE,KAAK;aACpB,CAAC,CAAA;YAEF,iBAAiB,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;gBAClC,EAAE,EAAE,SAAS;gBACb,OAAO,EAAE,cAAc;gBACvB,YAAY,EAAE,CAAC,cAAc,CAAC;aAC/B,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,OAAQ,OAAmC,CAAC,aAAa,CAAiC,CAAA;AAC5F,CAAC"}
|