payload-mcp-toolkit 0.3.3 → 0.7.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/README.md +232 -150
- package/dist/__tests__/api-keys.test.js +292 -0
- package/dist/__tests__/api-keys.test.js.map +1 -0
- package/dist/__tests__/auth-strategy.test.js +681 -0
- package/dist/__tests__/auth-strategy.test.js.map +1 -0
- package/dist/__tests__/conflict-detection.test.js +69 -0
- package/dist/__tests__/conflict-detection.test.js.map +1 -0
- package/dist/__tests__/delete-document.test.js +70 -0
- package/dist/__tests__/delete-document.test.js.map +1 -0
- package/dist/__tests__/endpoint.test.js +143 -0
- package/dist/__tests__/endpoint.test.js.map +1 -0
- package/dist/__tests__/find-document.test.js +178 -0
- package/dist/__tests__/find-document.test.js.map +1 -0
- package/dist/__tests__/find-global.test.js +173 -0
- package/dist/__tests__/find-global.test.js.map +1 -0
- package/dist/__tests__/global-versions.test.js +183 -0
- package/dist/__tests__/global-versions.test.js.map +1 -0
- package/dist/__tests__/hash.test.js +58 -0
- package/dist/__tests__/hash.test.js.map +1 -0
- package/dist/__tests__/index-integration.test.js +191 -0
- package/dist/__tests__/index-integration.test.js.map +1 -0
- package/dist/__tests__/introspection.test.js +201 -1
- package/dist/__tests__/introspection.test.js.map +1 -1
- package/dist/__tests__/patch-global-layout.test.js +474 -0
- package/dist/__tests__/patch-global-layout.test.js.map +1 -0
- package/dist/__tests__/patch-layout.test.js +171 -0
- package/dist/__tests__/patch-layout.test.js.map +1 -0
- package/dist/__tests__/registry.test.js +795 -0
- package/dist/__tests__/registry.test.js.map +1 -0
- package/dist/__tests__/resources.test.js +139 -0
- package/dist/__tests__/resources.test.js.map +1 -0
- package/dist/__tests__/update-global.test.js +157 -0
- package/dist/__tests__/update-global.test.js.map +1 -0
- package/dist/api-keys.d.ts +46 -0
- package/dist/api-keys.js +272 -0
- package/dist/api-keys.js.map +1 -0
- package/dist/auth-strategy.d.ts +85 -0
- package/dist/auth-strategy.js +219 -0
- package/dist/auth-strategy.js.map +1 -0
- package/dist/components/CollectionScopesMatrix.d.ts +8 -0
- package/dist/components/CollectionScopesMatrix.js +32 -0
- package/dist/components/CollectionScopesMatrix.js.map +1 -0
- package/dist/components/GlobalScopesMatrix.d.ts +8 -0
- package/dist/components/GlobalScopesMatrix.js +28 -0
- package/dist/components/GlobalScopesMatrix.js.map +1 -0
- package/dist/components/ScopesTable.d.ts +19 -0
- package/dist/components/ScopesTable.js +285 -0
- package/dist/components/ScopesTable.js.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +4 -0
- package/dist/components/index.js.map +1 -0
- package/dist/conflict-detection.d.ts +13 -0
- package/dist/conflict-detection.js +41 -0
- package/dist/conflict-detection.js.map +1 -0
- package/dist/draft-workflow.d.ts +46 -47
- package/dist/draft-workflow.js +53 -130
- package/dist/draft-workflow.js.map +1 -1
- package/dist/endpoint.d.ts +35 -0
- package/dist/endpoint.js +105 -0
- package/dist/endpoint.js.map +1 -0
- package/dist/hash.d.ts +21 -0
- package/dist/hash.js +36 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.js +168 -68
- package/dist/index.js.map +1 -1
- package/dist/introspection.d.ts +17 -3
- package/dist/introspection.js +95 -36
- package/dist/introspection.js.map +1 -1
- package/dist/prompts.js +5 -5
- package/dist/prompts.js.map +1 -1
- package/dist/registry.d.ts +50 -0
- package/dist/registry.js +169 -0
- package/dist/registry.js.map +1 -0
- package/dist/resources.d.ts +5 -3
- package/dist/resources.js +23 -11
- package/dist/resources.js.map +1 -1
- package/dist/scope/audit-log.d.ts +18 -0
- package/dist/scope/audit-log.js +50 -0
- package/dist/scope/audit-log.js.map +1 -0
- package/dist/scope/policy.d.ts +73 -0
- package/dist/scope/policy.js +218 -0
- package/dist/scope/policy.js.map +1 -0
- package/dist/tools/_helpers.d.ts +28 -1
- package/dist/tools/_helpers.js +83 -0
- package/dist/tools/_helpers.js.map +1 -1
- package/dist/tools/_layout-helpers.d.ts +43 -0
- package/dist/tools/_layout-helpers.js +159 -0
- package/dist/tools/_layout-helpers.js.map +1 -0
- package/dist/tools/create-document.d.ts +36 -0
- package/dist/tools/create-document.js +83 -0
- package/dist/tools/create-document.js.map +1 -0
- package/dist/tools/delete-document.d.ts +25 -0
- package/dist/tools/delete-document.js +49 -0
- package/dist/tools/delete-document.js.map +1 -0
- package/dist/tools/find-document.d.ts +33 -0
- package/dist/tools/find-document.js +97 -0
- package/dist/tools/find-document.js.map +1 -0
- package/dist/tools/find-global.d.ts +26 -0
- package/dist/tools/find-global.js +122 -0
- package/dist/tools/find-global.js.map +1 -0
- package/dist/tools/global-versions.d.ts +39 -0
- package/dist/tools/global-versions.js +132 -0
- package/dist/tools/global-versions.js.map +1 -0
- package/dist/tools/patch-global-layout.d.ts +31 -0
- package/dist/tools/patch-global-layout.js +127 -0
- package/dist/tools/patch-global-layout.js.map +1 -0
- package/dist/tools/patch-layout.d.ts +5 -8
- package/dist/tools/patch-layout.js +18 -100
- package/dist/tools/patch-layout.js.map +1 -1
- package/dist/tools/publish-draft.d.ts +5 -4
- package/dist/tools/publish-draft.js +6 -1
- package/dist/tools/publish-draft.js.map +1 -1
- package/dist/tools/publish-global-draft.d.ts +20 -0
- package/dist/tools/publish-global-draft.js +50 -0
- package/dist/tools/publish-global-draft.js.map +1 -0
- package/dist/tools/resolve-reference.d.ts +5 -4
- package/dist/tools/resolve-reference.js +4 -0
- package/dist/tools/resolve-reference.js.map +1 -1
- package/dist/tools/safe-delete.d.ts +5 -5
- package/dist/tools/safe-delete.js +20 -15
- package/dist/tools/safe-delete.js.map +1 -1
- package/dist/tools/schedule-publish.d.ts +5 -5
- package/dist/tools/schedule-publish.js +23 -19
- package/dist/tools/schedule-publish.js.map +1 -1
- package/dist/tools/search-content.d.ts +5 -9
- package/dist/tools/search-content.js +16 -12
- package/dist/tools/search-content.js.map +1 -1
- package/dist/tools/update-document.d.ts +5 -5
- package/dist/tools/update-document.js +10 -5
- package/dist/tools/update-document.js.map +1 -1
- package/dist/tools/update-global.d.ts +27 -0
- package/dist/tools/update-global.js +72 -0
- package/dist/tools/update-global.js.map +1 -0
- package/dist/tools/upload-media.d.ts +5 -4
- package/dist/tools/upload-media.js +6 -1
- package/dist/tools/upload-media.js.map +1 -1
- package/dist/tools/versions.d.ts +10 -9
- package/dist/tools/versions.js +15 -7
- package/dist/tools/versions.js.map +1 -1
- package/dist/types.d.ts +56 -3
- package/dist/types.js +13 -6
- package/dist/types.js.map +1 -1
- package/package.json +11 -4
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ScopesTable } from './ScopesTable';
|
|
5
|
+
const ACTIONS = [
|
|
6
|
+
'read',
|
|
7
|
+
'create',
|
|
8
|
+
'update',
|
|
9
|
+
'delete'
|
|
10
|
+
];
|
|
11
|
+
const ACTION_LABELS = {
|
|
12
|
+
read: 'Read',
|
|
13
|
+
create: 'Create',
|
|
14
|
+
update: 'Update',
|
|
15
|
+
delete: 'Delete'
|
|
16
|
+
};
|
|
17
|
+
function CollectionScopesMatrix(props) {
|
|
18
|
+
const items = Array.isArray(props.availableCollections) ? props.availableCollections : [];
|
|
19
|
+
return /*#__PURE__*/ _jsx(ScopesTable, {
|
|
20
|
+
path: props.path,
|
|
21
|
+
items: items,
|
|
22
|
+
actions: ACTIONS,
|
|
23
|
+
actionLabels: ACTION_LABELS,
|
|
24
|
+
itemHeader: "Collection",
|
|
25
|
+
title: "Collection scopes",
|
|
26
|
+
description: 'Check the actions this key may perform on each collection. Unchecked rows are denied outright. Configured under the "Custom" preset; once set, these overrides apply to this key regardless of which preset is later selected.',
|
|
27
|
+
emptyMessage: "No collections are available to scope. Add collections to your Payload config and restart the dev server."
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export default CollectionScopesMatrix;
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=CollectionScopesMatrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/CollectionScopesMatrix.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { ScopesTable } from './ScopesTable'\r\n\r\nconst ACTIONS = ['read', 'create', 'update', 'delete']\r\nconst ACTION_LABELS: Record<string, string> = {\r\n read: 'Read',\r\n create: 'Create',\r\n update: 'Update',\r\n delete: 'Delete',\r\n}\r\n\r\nexport interface CollectionScopesMatrixProps {\r\n path: string\r\n /** Forwarded via `clientProps` from `api-keys.ts`. */\r\n availableCollections?: string[]\r\n}\r\n\r\nfunction CollectionScopesMatrix(props: CollectionScopesMatrixProps): React.ReactElement {\r\n const items = Array.isArray(props.availableCollections) ? props.availableCollections : []\r\n return (\r\n <ScopesTable\r\n path={props.path}\r\n items={items}\r\n actions={ACTIONS}\r\n actionLabels={ACTION_LABELS}\r\n itemHeader=\"Collection\"\r\n title=\"Collection scopes\"\r\n description='Check the actions this key may perform on each collection. Unchecked rows are denied outright. Configured under the \"Custom\" preset; once set, these overrides apply to this key regardless of which preset is later selected.'\r\n emptyMessage=\"No collections are available to scope. Add collections to your Payload config and restart the dev server.\"\r\n />\r\n )\r\n}\r\n\r\nexport default CollectionScopesMatrix\r\n"],"names":["React","ScopesTable","ACTIONS","ACTION_LABELS","read","create","update","delete","CollectionScopesMatrix","props","items","Array","isArray","availableCollections","path","actions","actionLabels","itemHeader","title","description","emptyMessage"],"mappings":"AAAA;;AAEA,YAAYA,WAAW,QAAO;AAC9B,SAASC,WAAW,QAAQ,gBAAe;AAE3C,MAAMC,UAAU;IAAC;IAAQ;IAAU;IAAU;CAAS;AACtD,MAAMC,gBAAwC;IAC5CC,MAAM;IACNC,QAAQ;IACRC,QAAQ;IACRC,QAAQ;AACV;AAQA,SAASC,uBAAuBC,KAAkC;IAChE,MAAMC,QAAQC,MAAMC,OAAO,CAACH,MAAMI,oBAAoB,IAAIJ,MAAMI,oBAAoB,GAAG,EAAE;IACzF,qBACE,KAACZ;QACCa,MAAML,MAAMK,IAAI;QAChBJ,OAAOA;QACPK,SAASb;QACTc,cAAcb;QACdc,YAAW;QACXC,OAAM;QACNC,aAAY;QACZC,cAAa;;AAGnB;AAEA,eAAeZ,uBAAsB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface GlobalScopesMatrixProps {
|
|
3
|
+
path: string;
|
|
4
|
+
/** Forwarded via `clientProps` from `api-keys.ts`. */
|
|
5
|
+
availableGlobals?: string[];
|
|
6
|
+
}
|
|
7
|
+
declare function GlobalScopesMatrix(props: GlobalScopesMatrixProps): React.ReactElement;
|
|
8
|
+
export default GlobalScopesMatrix;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ScopesTable } from './ScopesTable';
|
|
5
|
+
const ACTIONS = [
|
|
6
|
+
'read',
|
|
7
|
+
'update'
|
|
8
|
+
];
|
|
9
|
+
const ACTION_LABELS = {
|
|
10
|
+
read: 'Read',
|
|
11
|
+
update: 'Update'
|
|
12
|
+
};
|
|
13
|
+
function GlobalScopesMatrix(props) {
|
|
14
|
+
const items = Array.isArray(props.availableGlobals) ? props.availableGlobals : [];
|
|
15
|
+
return /*#__PURE__*/ _jsx(ScopesTable, {
|
|
16
|
+
path: props.path,
|
|
17
|
+
items: items,
|
|
18
|
+
actions: ACTIONS,
|
|
19
|
+
actionLabels: ACTION_LABELS,
|
|
20
|
+
itemHeader: "Global",
|
|
21
|
+
title: "Global scopes",
|
|
22
|
+
description: 'Check the actions this key may perform on each global. Globals only support Read and Update (singletons cannot be created or deleted). Configured under the "Custom" preset; once set, these overrides apply to this key regardless of which preset is later selected.',
|
|
23
|
+
emptyMessage: "No globals are available to scope. Add globals to your Payload config and restart the dev server."
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export default GlobalScopesMatrix;
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=GlobalScopesMatrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/GlobalScopesMatrix.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { ScopesTable } from './ScopesTable'\r\n\r\nconst ACTIONS = ['read', 'update']\r\nconst ACTION_LABELS: Record<string, string> = {\r\n read: 'Read',\r\n update: 'Update',\r\n}\r\n\r\nexport interface GlobalScopesMatrixProps {\r\n path: string\r\n /** Forwarded via `clientProps` from `api-keys.ts`. */\r\n availableGlobals?: string[]\r\n}\r\n\r\nfunction GlobalScopesMatrix(props: GlobalScopesMatrixProps): React.ReactElement {\r\n const items = Array.isArray(props.availableGlobals) ? props.availableGlobals : []\r\n return (\r\n <ScopesTable\r\n path={props.path}\r\n items={items}\r\n actions={ACTIONS}\r\n actionLabels={ACTION_LABELS}\r\n itemHeader=\"Global\"\r\n title=\"Global scopes\"\r\n description='Check the actions this key may perform on each global. Globals only support Read and Update (singletons cannot be created or deleted). Configured under the \"Custom\" preset; once set, these overrides apply to this key regardless of which preset is later selected.'\r\n emptyMessage=\"No globals are available to scope. Add globals to your Payload config and restart the dev server.\"\r\n />\r\n )\r\n}\r\n\r\nexport default GlobalScopesMatrix\r\n"],"names":["React","ScopesTable","ACTIONS","ACTION_LABELS","read","update","GlobalScopesMatrix","props","items","Array","isArray","availableGlobals","path","actions","actionLabels","itemHeader","title","description","emptyMessage"],"mappings":"AAAA;;AAEA,YAAYA,WAAW,QAAO;AAC9B,SAASC,WAAW,QAAQ,gBAAe;AAE3C,MAAMC,UAAU;IAAC;IAAQ;CAAS;AAClC,MAAMC,gBAAwC;IAC5CC,MAAM;IACNC,QAAQ;AACV;AAQA,SAASC,mBAAmBC,KAA8B;IACxD,MAAMC,QAAQC,MAAMC,OAAO,CAACH,MAAMI,gBAAgB,IAAIJ,MAAMI,gBAAgB,GAAG,EAAE;IACjF,qBACE,KAACV;QACCW,MAAML,MAAMK,IAAI;QAChBJ,OAAOA;QACPK,SAASX;QACTY,cAAcX;QACdY,YAAW;QACXC,OAAM;QACNC,aAAY;QACZC,cAAa;;AAGnB;AAEA,eAAeZ,mBAAkB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface ScopesTableProps {
|
|
3
|
+
path: string;
|
|
4
|
+
/** Slugs to render as rows. */
|
|
5
|
+
items: string[];
|
|
6
|
+
/** Action columns shown to the operator. */
|
|
7
|
+
actions: string[];
|
|
8
|
+
/** Display label per action (e.g. { read: 'Read', update: 'Update' }). */
|
|
9
|
+
actionLabels: Record<string, string>;
|
|
10
|
+
/** Header label for the leftmost column. */
|
|
11
|
+
itemHeader: string;
|
|
12
|
+
/** Page-level title rendered above the table. */
|
|
13
|
+
title: string;
|
|
14
|
+
/** Helper sentence rendered between title and table. */
|
|
15
|
+
description: string;
|
|
16
|
+
/** Copy shown when `items` is empty. */
|
|
17
|
+
emptyMessage: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function ScopesTable(props: ScopesTableProps): React.ReactElement;
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { CheckboxInput, useField } from '@payloadcms/ui';
|
|
5
|
+
import { toWords } from 'payload/shared';
|
|
6
|
+
function rowsToMap(value, allowedActions) {
|
|
7
|
+
const map = new Map();
|
|
8
|
+
if (!Array.isArray(value)) return map;
|
|
9
|
+
for (const row of value){
|
|
10
|
+
if (!row || typeof row.slug !== 'string') continue;
|
|
11
|
+
const slug = row.slug;
|
|
12
|
+
const actions = new Set();
|
|
13
|
+
if (Array.isArray(row.actions)) {
|
|
14
|
+
for (const a of row.actions){
|
|
15
|
+
if (typeof a === 'string' && allowedActions.has(a)) actions.add(a);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
map.set(slug, actions);
|
|
19
|
+
}
|
|
20
|
+
return map;
|
|
21
|
+
}
|
|
22
|
+
function mapToRows(map, items, actions) {
|
|
23
|
+
const rows = [];
|
|
24
|
+
for (const slug of items){
|
|
25
|
+
const set = map.get(slug);
|
|
26
|
+
if (!set || set.size === 0) continue;
|
|
27
|
+
rows.push({
|
|
28
|
+
slug,
|
|
29
|
+
actions: actions.filter((a)=>set.has(a))
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return rows;
|
|
33
|
+
}
|
|
34
|
+
const cellStyle = {
|
|
35
|
+
textAlign: 'center',
|
|
36
|
+
padding: '0.5rem 0.5rem',
|
|
37
|
+
borderLeft: '1px solid var(--theme-elevation-100)',
|
|
38
|
+
verticalAlign: 'middle'
|
|
39
|
+
};
|
|
40
|
+
const headerCellStyle = {
|
|
41
|
+
...cellStyle,
|
|
42
|
+
background: 'var(--theme-elevation-50)',
|
|
43
|
+
borderBottom: '1px solid var(--theme-elevation-150)',
|
|
44
|
+
fontWeight: 600
|
|
45
|
+
};
|
|
46
|
+
const labelCellStyle = {
|
|
47
|
+
textAlign: 'left',
|
|
48
|
+
padding: '0.5rem 0.75rem',
|
|
49
|
+
verticalAlign: 'middle'
|
|
50
|
+
};
|
|
51
|
+
export function ScopesTable(props) {
|
|
52
|
+
const { value, setValue } = useField({
|
|
53
|
+
path: props.path,
|
|
54
|
+
hasRows: false
|
|
55
|
+
});
|
|
56
|
+
const allowedActionsSet = React.useMemo(()=>new Set(props.actions), [
|
|
57
|
+
props.actions
|
|
58
|
+
]);
|
|
59
|
+
const map = React.useMemo(()=>rowsToMap(value, allowedActionsSet), [
|
|
60
|
+
value,
|
|
61
|
+
allowedActionsSet
|
|
62
|
+
]);
|
|
63
|
+
const update = React.useCallback((mutator)=>{
|
|
64
|
+
const next = new Map();
|
|
65
|
+
for (const [k, v] of map)next.set(k, new Set(v));
|
|
66
|
+
mutator(next);
|
|
67
|
+
setValue(mapToRows(next, props.items, props.actions));
|
|
68
|
+
}, [
|
|
69
|
+
map,
|
|
70
|
+
props.items,
|
|
71
|
+
props.actions,
|
|
72
|
+
setValue
|
|
73
|
+
]);
|
|
74
|
+
const isCellChecked = (slug, action)=>!!map.get(slug)?.has(action);
|
|
75
|
+
const isRowFull = (slug)=>{
|
|
76
|
+
const set = map.get(slug);
|
|
77
|
+
return !!set && props.actions.every((a)=>set.has(a));
|
|
78
|
+
};
|
|
79
|
+
const isRowPartial = (slug)=>{
|
|
80
|
+
const set = map.get(slug);
|
|
81
|
+
return !!set && set.size > 0 && set.size < props.actions.length;
|
|
82
|
+
};
|
|
83
|
+
const isColumnFull = (action)=>props.items.length > 0 && props.items.every((s)=>map.get(s)?.has(action));
|
|
84
|
+
const isColumnPartial = (action)=>{
|
|
85
|
+
if (props.items.length === 0) return false;
|
|
86
|
+
const checked = props.items.filter((s)=>map.get(s)?.has(action)).length;
|
|
87
|
+
return checked > 0 && checked < props.items.length;
|
|
88
|
+
};
|
|
89
|
+
const allCheckedCount = props.items.reduce((sum, s)=>sum + (map.get(s)?.size ?? 0), 0);
|
|
90
|
+
const allTotalCount = props.items.length * props.actions.length;
|
|
91
|
+
const isAllFull = allTotalCount > 0 && allCheckedCount === allTotalCount;
|
|
92
|
+
const isAllPartial = allCheckedCount > 0 && allCheckedCount < allTotalCount;
|
|
93
|
+
const toggleCell = (slug, action, checked)=>update((m)=>{
|
|
94
|
+
const set = m.get(slug) ?? new Set();
|
|
95
|
+
if (checked) set.add(action);
|
|
96
|
+
else set.delete(action);
|
|
97
|
+
m.set(slug, set);
|
|
98
|
+
});
|
|
99
|
+
const toggleRow = (slug, checked)=>update((m)=>{
|
|
100
|
+
m.set(slug, checked ? new Set(props.actions) : new Set());
|
|
101
|
+
});
|
|
102
|
+
const toggleColumn = (action, checked)=>update((m)=>{
|
|
103
|
+
for (const slug of props.items){
|
|
104
|
+
const set = m.get(slug) ?? new Set();
|
|
105
|
+
if (checked) set.add(action);
|
|
106
|
+
else set.delete(action);
|
|
107
|
+
m.set(slug, set);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
const toggleAll = (checked)=>update((m)=>{
|
|
111
|
+
for (const slug of props.items)m.set(slug, checked ? new Set(props.actions) : new Set());
|
|
112
|
+
});
|
|
113
|
+
if (props.items.length === 0) {
|
|
114
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
115
|
+
className: "field-type",
|
|
116
|
+
style: {
|
|
117
|
+
padding: '0.5rem 0'
|
|
118
|
+
},
|
|
119
|
+
children: [
|
|
120
|
+
/*#__PURE__*/ _jsx("label", {
|
|
121
|
+
className: "field-label",
|
|
122
|
+
children: props.title
|
|
123
|
+
}),
|
|
124
|
+
/*#__PURE__*/ _jsx("p", {
|
|
125
|
+
style: {
|
|
126
|
+
color: 'var(--theme-elevation-500)',
|
|
127
|
+
fontSize: '0.85rem',
|
|
128
|
+
margin: '0.25rem 0 0'
|
|
129
|
+
},
|
|
130
|
+
children: props.emptyMessage
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
136
|
+
className: "field-type",
|
|
137
|
+
style: {
|
|
138
|
+
padding: '0.5rem 0'
|
|
139
|
+
},
|
|
140
|
+
children: [
|
|
141
|
+
/*#__PURE__*/ _jsx("label", {
|
|
142
|
+
className: "field-label",
|
|
143
|
+
htmlFor: `${props.path}-matrix`,
|
|
144
|
+
children: props.title
|
|
145
|
+
}),
|
|
146
|
+
/*#__PURE__*/ _jsx("p", {
|
|
147
|
+
style: {
|
|
148
|
+
color: 'var(--theme-elevation-500)',
|
|
149
|
+
fontSize: '0.85rem',
|
|
150
|
+
margin: '0.25rem 0 0.75rem'
|
|
151
|
+
},
|
|
152
|
+
children: props.description
|
|
153
|
+
}),
|
|
154
|
+
/*#__PURE__*/ _jsxs("table", {
|
|
155
|
+
id: `${props.path}-matrix`,
|
|
156
|
+
style: {
|
|
157
|
+
width: '100%',
|
|
158
|
+
borderCollapse: 'collapse',
|
|
159
|
+
fontSize: '0.9rem',
|
|
160
|
+
background: 'var(--theme-input-bg)',
|
|
161
|
+
border: '1px solid var(--theme-elevation-150)',
|
|
162
|
+
borderRadius: '4px',
|
|
163
|
+
overflow: 'hidden'
|
|
164
|
+
},
|
|
165
|
+
children: [
|
|
166
|
+
/*#__PURE__*/ _jsx("thead", {
|
|
167
|
+
children: /*#__PURE__*/ _jsxs("tr", {
|
|
168
|
+
children: [
|
|
169
|
+
/*#__PURE__*/ _jsx("th", {
|
|
170
|
+
style: {
|
|
171
|
+
...headerCellStyle,
|
|
172
|
+
textAlign: 'left'
|
|
173
|
+
},
|
|
174
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
175
|
+
style: {
|
|
176
|
+
display: 'flex',
|
|
177
|
+
flexDirection: 'column',
|
|
178
|
+
gap: '0.35rem'
|
|
179
|
+
},
|
|
180
|
+
children: [
|
|
181
|
+
/*#__PURE__*/ _jsx("span", {
|
|
182
|
+
children: props.itemHeader
|
|
183
|
+
}),
|
|
184
|
+
/*#__PURE__*/ _jsx(CheckboxInput, {
|
|
185
|
+
checked: isAllFull,
|
|
186
|
+
partialChecked: isAllPartial && !isAllFull,
|
|
187
|
+
onToggle: (e)=>toggleAll(e.currentTarget.checked),
|
|
188
|
+
label: "All"
|
|
189
|
+
})
|
|
190
|
+
]
|
|
191
|
+
})
|
|
192
|
+
}),
|
|
193
|
+
props.actions.map((action)=>/*#__PURE__*/ _jsx("th", {
|
|
194
|
+
style: headerCellStyle,
|
|
195
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
196
|
+
style: {
|
|
197
|
+
display: 'flex',
|
|
198
|
+
flexDirection: 'column',
|
|
199
|
+
alignItems: 'center',
|
|
200
|
+
gap: '0.35rem'
|
|
201
|
+
},
|
|
202
|
+
children: [
|
|
203
|
+
/*#__PURE__*/ _jsx("span", {
|
|
204
|
+
children: props.actionLabels[action] ?? action
|
|
205
|
+
}),
|
|
206
|
+
/*#__PURE__*/ _jsx(CheckboxInput, {
|
|
207
|
+
checked: isColumnFull(action),
|
|
208
|
+
partialChecked: isColumnPartial(action) && !isColumnFull(action),
|
|
209
|
+
onToggle: (e)=>toggleColumn(action, e.currentTarget.checked)
|
|
210
|
+
})
|
|
211
|
+
]
|
|
212
|
+
})
|
|
213
|
+
}, action))
|
|
214
|
+
]
|
|
215
|
+
})
|
|
216
|
+
}),
|
|
217
|
+
/*#__PURE__*/ _jsx("tbody", {
|
|
218
|
+
children: props.items.map((slug, idx)=>{
|
|
219
|
+
const niceName = toWords(slug);
|
|
220
|
+
return /*#__PURE__*/ _jsxs("tr", {
|
|
221
|
+
style: {
|
|
222
|
+
background: idx % 2 === 0 ? 'var(--theme-input-bg)' : 'var(--theme-elevation-25)'
|
|
223
|
+
},
|
|
224
|
+
children: [
|
|
225
|
+
/*#__PURE__*/ _jsx("td", {
|
|
226
|
+
style: {
|
|
227
|
+
...labelCellStyle,
|
|
228
|
+
borderTop: idx === 0 ? 'none' : '1px solid var(--theme-elevation-100)'
|
|
229
|
+
},
|
|
230
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
231
|
+
style: {
|
|
232
|
+
display: 'flex',
|
|
233
|
+
alignItems: 'center',
|
|
234
|
+
gap: '0.6rem'
|
|
235
|
+
},
|
|
236
|
+
children: [
|
|
237
|
+
/*#__PURE__*/ _jsx(CheckboxInput, {
|
|
238
|
+
checked: isRowFull(slug),
|
|
239
|
+
partialChecked: isRowPartial(slug) && !isRowFull(slug),
|
|
240
|
+
onToggle: (e)=>toggleRow(slug, e.currentTarget.checked)
|
|
241
|
+
}),
|
|
242
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
243
|
+
style: {
|
|
244
|
+
display: 'flex',
|
|
245
|
+
flexDirection: 'column'
|
|
246
|
+
},
|
|
247
|
+
children: [
|
|
248
|
+
/*#__PURE__*/ _jsx("span", {
|
|
249
|
+
children: niceName
|
|
250
|
+
}),
|
|
251
|
+
/*#__PURE__*/ _jsx("code", {
|
|
252
|
+
style: {
|
|
253
|
+
fontSize: '0.75rem',
|
|
254
|
+
color: 'var(--theme-elevation-500)',
|
|
255
|
+
background: 'transparent',
|
|
256
|
+
padding: 0
|
|
257
|
+
},
|
|
258
|
+
children: slug
|
|
259
|
+
})
|
|
260
|
+
]
|
|
261
|
+
})
|
|
262
|
+
]
|
|
263
|
+
})
|
|
264
|
+
}),
|
|
265
|
+
props.actions.map((action)=>/*#__PURE__*/ _jsx("td", {
|
|
266
|
+
style: {
|
|
267
|
+
...cellStyle,
|
|
268
|
+
borderTop: idx === 0 ? 'none' : '1px solid var(--theme-elevation-100)'
|
|
269
|
+
},
|
|
270
|
+
children: /*#__PURE__*/ _jsx(CheckboxInput, {
|
|
271
|
+
checked: isCellChecked(slug, action),
|
|
272
|
+
onToggle: (e)=>toggleCell(slug, action, e.currentTarget.checked)
|
|
273
|
+
})
|
|
274
|
+
}, action))
|
|
275
|
+
]
|
|
276
|
+
}, slug);
|
|
277
|
+
})
|
|
278
|
+
})
|
|
279
|
+
]
|
|
280
|
+
})
|
|
281
|
+
]
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
//# sourceMappingURL=ScopesTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/ScopesTable.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { CheckboxInput, useField } from '@payloadcms/ui'\r\nimport { toWords } from 'payload/shared'\r\n\r\n/**\r\n * Reusable matrix renderer for \"items × actions\" scope tables.\r\n *\r\n * Used by both CollectionScopesMatrix (collections × 4 actions) and\r\n * GlobalScopesMatrix (globals × 2 actions). The stored shape is\r\n * `Array<{ slug: string; actions: string[] }>` — the parent field name\r\n * (`collectionScopes` vs `globalScopes`) already encodes which axis the\r\n * slugs belong to, so the row payload no longer mirrors that distinction.\r\n */\r\n\r\ninterface RowValue {\r\n slug?: unknown\r\n actions?: unknown\r\n}\r\ntype MatrixValue = RowValue[]\r\n\r\nexport interface ScopesTableProps {\r\n path: string\r\n /** Slugs to render as rows. */\r\n items: string[]\r\n /** Action columns shown to the operator. */\r\n actions: string[]\r\n /** Display label per action (e.g. { read: 'Read', update: 'Update' }). */\r\n actionLabels: Record<string, string>\r\n /** Header label for the leftmost column. */\r\n itemHeader: string\r\n /** Page-level title rendered above the table. */\r\n title: string\r\n /** Helper sentence rendered between title and table. */\r\n description: string\r\n /** Copy shown when `items` is empty. */\r\n emptyMessage: string\r\n}\r\n\r\nfunction rowsToMap(\r\n value: MatrixValue | null | undefined,\r\n allowedActions: Set<string>,\r\n): Map<string, Set<string>> {\r\n const map = new Map<string, Set<string>>()\r\n if (!Array.isArray(value)) return map\r\n for (const row of value) {\r\n if (!row || typeof row.slug !== 'string') continue\r\n const slug = row.slug\r\n const actions = new Set<string>()\r\n if (Array.isArray(row.actions)) {\r\n for (const a of row.actions) {\r\n if (typeof a === 'string' && allowedActions.has(a)) actions.add(a)\r\n }\r\n }\r\n map.set(slug, actions)\r\n }\r\n return map\r\n}\r\n\r\nfunction mapToRows(\r\n map: Map<string, Set<string>>,\r\n items: string[],\r\n actions: string[],\r\n): MatrixValue {\r\n const rows: MatrixValue = []\r\n for (const slug of items) {\r\n const set = map.get(slug)\r\n if (!set || set.size === 0) continue\r\n rows.push({\r\n slug,\r\n actions: actions.filter((a) => set.has(a)),\r\n })\r\n }\r\n return rows\r\n}\r\n\r\nconst cellStyle: React.CSSProperties = {\r\n textAlign: 'center',\r\n padding: '0.5rem 0.5rem',\r\n borderLeft: '1px solid var(--theme-elevation-100)',\r\n verticalAlign: 'middle',\r\n}\r\n\r\nconst headerCellStyle: React.CSSProperties = {\r\n ...cellStyle,\r\n background: 'var(--theme-elevation-50)',\r\n borderBottom: '1px solid var(--theme-elevation-150)',\r\n fontWeight: 600,\r\n}\r\n\r\nconst labelCellStyle: React.CSSProperties = {\r\n textAlign: 'left',\r\n padding: '0.5rem 0.75rem',\r\n verticalAlign: 'middle',\r\n}\r\n\r\nexport function ScopesTable(props: ScopesTableProps): React.ReactElement {\r\n const { value, setValue } = useField<MatrixValue>({ path: props.path, hasRows: false })\r\n const allowedActionsSet = React.useMemo(() => new Set(props.actions), [props.actions])\r\n\r\n const map = React.useMemo(\r\n () => rowsToMap(value, allowedActionsSet),\r\n [value, allowedActionsSet],\r\n )\r\n\r\n const update = React.useCallback(\r\n (mutator: (m: Map<string, Set<string>>) => void) => {\r\n const next = new Map<string, Set<string>>()\r\n for (const [k, v] of map) next.set(k, new Set(v))\r\n mutator(next)\r\n setValue(mapToRows(next, props.items, props.actions))\r\n },\r\n [map, props.items, props.actions, setValue],\r\n )\r\n\r\n const isCellChecked = (slug: string, action: string): boolean =>\r\n !!map.get(slug)?.has(action)\r\n const isRowFull = (slug: string): boolean => {\r\n const set = map.get(slug)\r\n return !!set && props.actions.every((a) => set.has(a))\r\n }\r\n const isRowPartial = (slug: string): boolean => {\r\n const set = map.get(slug)\r\n return !!set && set.size > 0 && set.size < props.actions.length\r\n }\r\n const isColumnFull = (action: string): boolean =>\r\n props.items.length > 0 && props.items.every((s) => map.get(s)?.has(action))\r\n const isColumnPartial = (action: string): boolean => {\r\n if (props.items.length === 0) return false\r\n const checked = props.items.filter((s) => map.get(s)?.has(action)).length\r\n return checked > 0 && checked < props.items.length\r\n }\r\n const allCheckedCount = props.items.reduce((sum, s) => sum + (map.get(s)?.size ?? 0), 0)\r\n const allTotalCount = props.items.length * props.actions.length\r\n const isAllFull = allTotalCount > 0 && allCheckedCount === allTotalCount\r\n const isAllPartial = allCheckedCount > 0 && allCheckedCount < allTotalCount\r\n\r\n const toggleCell = (slug: string, action: string, checked: boolean) =>\r\n update((m) => {\r\n const set = m.get(slug) ?? new Set<string>()\r\n if (checked) set.add(action)\r\n else set.delete(action)\r\n m.set(slug, set)\r\n })\r\n\r\n const toggleRow = (slug: string, checked: boolean) =>\r\n update((m) => {\r\n m.set(slug, checked ? new Set(props.actions) : new Set())\r\n })\r\n\r\n const toggleColumn = (action: string, checked: boolean) =>\r\n update((m) => {\r\n for (const slug of props.items) {\r\n const set = m.get(slug) ?? new Set<string>()\r\n if (checked) set.add(action)\r\n else set.delete(action)\r\n m.set(slug, set)\r\n }\r\n })\r\n\r\n const toggleAll = (checked: boolean) =>\r\n update((m) => {\r\n for (const slug of props.items) m.set(slug, checked ? new Set(props.actions) : new Set())\r\n })\r\n\r\n if (props.items.length === 0) {\r\n return (\r\n <div className=\"field-type\" style={{ padding: '0.5rem 0' }}>\r\n <label className=\"field-label\">{props.title}</label>\r\n <p style={{ color: 'var(--theme-elevation-500)', fontSize: '0.85rem', margin: '0.25rem 0 0' }}>\r\n {props.emptyMessage}\r\n </p>\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <div className=\"field-type\" style={{ padding: '0.5rem 0' }}>\r\n <label className=\"field-label\" htmlFor={`${props.path}-matrix`}>\r\n {props.title}\r\n </label>\r\n <p\r\n style={{\r\n color: 'var(--theme-elevation-500)',\r\n fontSize: '0.85rem',\r\n margin: '0.25rem 0 0.75rem',\r\n }}\r\n >\r\n {props.description}\r\n </p>\r\n <table\r\n id={`${props.path}-matrix`}\r\n style={{\r\n width: '100%',\r\n borderCollapse: 'collapse',\r\n fontSize: '0.9rem',\r\n background: 'var(--theme-input-bg)',\r\n border: '1px solid var(--theme-elevation-150)',\r\n borderRadius: '4px',\r\n overflow: 'hidden',\r\n }}\r\n >\r\n <thead>\r\n <tr>\r\n <th style={{ ...headerCellStyle, textAlign: 'left' }}>\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '0.35rem' }}>\r\n <span>{props.itemHeader}</span>\r\n <CheckboxInput\r\n checked={isAllFull}\r\n partialChecked={isAllPartial && !isAllFull}\r\n onToggle={(e) => toggleAll(e.currentTarget.checked)}\r\n label=\"All\"\r\n />\r\n </div>\r\n </th>\r\n {props.actions.map((action) => (\r\n <th key={action} style={headerCellStyle}>\r\n <div\r\n style={{\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n gap: '0.35rem',\r\n }}\r\n >\r\n <span>{props.actionLabels[action] ?? action}</span>\r\n <CheckboxInput\r\n checked={isColumnFull(action)}\r\n partialChecked={isColumnPartial(action) && !isColumnFull(action)}\r\n onToggle={(e) => toggleColumn(action, e.currentTarget.checked)}\r\n />\r\n </div>\r\n </th>\r\n ))}\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {props.items.map((slug, idx) => {\r\n const niceName = toWords(slug)\r\n return (\r\n <tr\r\n key={slug}\r\n style={{\r\n background:\r\n idx % 2 === 0 ? 'var(--theme-input-bg)' : 'var(--theme-elevation-25)',\r\n }}\r\n >\r\n <td\r\n style={{\r\n ...labelCellStyle,\r\n borderTop: idx === 0 ? 'none' : '1px solid var(--theme-elevation-100)',\r\n }}\r\n >\r\n <div style={{ display: 'flex', alignItems: 'center', gap: '0.6rem' }}>\r\n <CheckboxInput\r\n checked={isRowFull(slug)}\r\n partialChecked={isRowPartial(slug) && !isRowFull(slug)}\r\n onToggle={(e) => toggleRow(slug, e.currentTarget.checked)}\r\n />\r\n <div style={{ display: 'flex', flexDirection: 'column' }}>\r\n <span>{niceName}</span>\r\n <code\r\n style={{\r\n fontSize: '0.75rem',\r\n color: 'var(--theme-elevation-500)',\r\n background: 'transparent',\r\n padding: 0,\r\n }}\r\n >\r\n {slug}\r\n </code>\r\n </div>\r\n </div>\r\n </td>\r\n {props.actions.map((action) => (\r\n <td\r\n key={action}\r\n style={{\r\n ...cellStyle,\r\n borderTop: idx === 0 ? 'none' : '1px solid var(--theme-elevation-100)',\r\n }}\r\n >\r\n <CheckboxInput\r\n checked={isCellChecked(slug, action)}\r\n onToggle={(e) => toggleCell(slug, action, e.currentTarget.checked)}\r\n />\r\n </td>\r\n ))}\r\n </tr>\r\n )\r\n })}\r\n </tbody>\r\n </table>\r\n </div>\r\n )\r\n}\r\n"],"names":["React","CheckboxInput","useField","toWords","rowsToMap","value","allowedActions","map","Map","Array","isArray","row","slug","actions","Set","a","has","add","set","mapToRows","items","rows","get","size","push","filter","cellStyle","textAlign","padding","borderLeft","verticalAlign","headerCellStyle","background","borderBottom","fontWeight","labelCellStyle","ScopesTable","props","setValue","path","hasRows","allowedActionsSet","useMemo","update","useCallback","mutator","next","k","v","isCellChecked","action","isRowFull","every","isRowPartial","length","isColumnFull","s","isColumnPartial","checked","allCheckedCount","reduce","sum","allTotalCount","isAllFull","isAllPartial","toggleCell","m","delete","toggleRow","toggleColumn","toggleAll","div","className","style","label","title","p","color","fontSize","margin","emptyMessage","htmlFor","description","table","id","width","borderCollapse","border","borderRadius","overflow","thead","tr","th","display","flexDirection","gap","span","itemHeader","partialChecked","onToggle","e","currentTarget","alignItems","actionLabels","tbody","idx","niceName","td","borderTop","code"],"mappings":"AAAA;;AAEA,YAAYA,WAAW,QAAO;AAC9B,SAASC,aAAa,EAAEC,QAAQ,QAAQ,iBAAgB;AACxD,SAASC,OAAO,QAAQ,iBAAgB;AAoCxC,SAASC,UACPC,KAAqC,EACrCC,cAA2B;IAE3B,MAAMC,MAAM,IAAIC;IAChB,IAAI,CAACC,MAAMC,OAAO,CAACL,QAAQ,OAAOE;IAClC,KAAK,MAAMI,OAAON,MAAO;QACvB,IAAI,CAACM,OAAO,OAAOA,IAAIC,IAAI,KAAK,UAAU;QAC1C,MAAMA,OAAOD,IAAIC,IAAI;QACrB,MAAMC,UAAU,IAAIC;QACpB,IAAIL,MAAMC,OAAO,CAACC,IAAIE,OAAO,GAAG;YAC9B,KAAK,MAAME,KAAKJ,IAAIE,OAAO,CAAE;gBAC3B,IAAI,OAAOE,MAAM,YAAYT,eAAeU,GAAG,CAACD,IAAIF,QAAQI,GAAG,CAACF;YAClE;QACF;QACAR,IAAIW,GAAG,CAACN,MAAMC;IAChB;IACA,OAAON;AACT;AAEA,SAASY,UACPZ,GAA6B,EAC7Ba,KAAe,EACfP,OAAiB;IAEjB,MAAMQ,OAAoB,EAAE;IAC5B,KAAK,MAAMT,QAAQQ,MAAO;QACxB,MAAMF,MAAMX,IAAIe,GAAG,CAACV;QACpB,IAAI,CAACM,OAAOA,IAAIK,IAAI,KAAK,GAAG;QAC5BF,KAAKG,IAAI,CAAC;YACRZ;YACAC,SAASA,QAAQY,MAAM,CAAC,CAACV,IAAMG,IAAIF,GAAG,CAACD;QACzC;IACF;IACA,OAAOM;AACT;AAEA,MAAMK,YAAiC;IACrCC,WAAW;IACXC,SAAS;IACTC,YAAY;IACZC,eAAe;AACjB;AAEA,MAAMC,kBAAuC;IAC3C,GAAGL,SAAS;IACZM,YAAY;IACZC,cAAc;IACdC,YAAY;AACd;AAEA,MAAMC,iBAAsC;IAC1CR,WAAW;IACXC,SAAS;IACTE,eAAe;AACjB;AAEA,OAAO,SAASM,YAAYC,KAAuB;IACjD,MAAM,EAAEhC,KAAK,EAAEiC,QAAQ,EAAE,GAAGpC,SAAsB;QAAEqC,MAAMF,MAAME,IAAI;QAAEC,SAAS;IAAM;IACrF,MAAMC,oBAAoBzC,MAAM0C,OAAO,CAAC,IAAM,IAAI5B,IAAIuB,MAAMxB,OAAO,GAAG;QAACwB,MAAMxB,OAAO;KAAC;IAErF,MAAMN,MAAMP,MAAM0C,OAAO,CACvB,IAAMtC,UAAUC,OAAOoC,oBACvB;QAACpC;QAAOoC;KAAkB;IAG5B,MAAME,SAAS3C,MAAM4C,WAAW,CAC9B,CAACC;QACC,MAAMC,OAAO,IAAItC;QACjB,KAAK,MAAM,CAACuC,GAAGC,EAAE,IAAIzC,IAAKuC,KAAK5B,GAAG,CAAC6B,GAAG,IAAIjC,IAAIkC;QAC9CH,QAAQC;QACRR,SAASnB,UAAU2B,MAAMT,MAAMjB,KAAK,EAAEiB,MAAMxB,OAAO;IACrD,GACA;QAACN;QAAK8B,MAAMjB,KAAK;QAAEiB,MAAMxB,OAAO;QAAEyB;KAAS;IAG7C,MAAMW,gBAAgB,CAACrC,MAAcsC,SACnC,CAAC,CAAC3C,IAAIe,GAAG,CAACV,OAAOI,IAAIkC;IACvB,MAAMC,YAAY,CAACvC;QACjB,MAAMM,MAAMX,IAAIe,GAAG,CAACV;QACpB,OAAO,CAAC,CAACM,OAAOmB,MAAMxB,OAAO,CAACuC,KAAK,CAAC,CAACrC,IAAMG,IAAIF,GAAG,CAACD;IACrD;IACA,MAAMsC,eAAe,CAACzC;QACpB,MAAMM,MAAMX,IAAIe,GAAG,CAACV;QACpB,OAAO,CAAC,CAACM,OAAOA,IAAIK,IAAI,GAAG,KAAKL,IAAIK,IAAI,GAAGc,MAAMxB,OAAO,CAACyC,MAAM;IACjE;IACA,MAAMC,eAAe,CAACL,SACpBb,MAAMjB,KAAK,CAACkC,MAAM,GAAG,KAAKjB,MAAMjB,KAAK,CAACgC,KAAK,CAAC,CAACI,IAAMjD,IAAIe,GAAG,CAACkC,IAAIxC,IAAIkC;IACrE,MAAMO,kBAAkB,CAACP;QACvB,IAAIb,MAAMjB,KAAK,CAACkC,MAAM,KAAK,GAAG,OAAO;QACrC,MAAMI,UAAUrB,MAAMjB,KAAK,CAACK,MAAM,CAAC,CAAC+B,IAAMjD,IAAIe,GAAG,CAACkC,IAAIxC,IAAIkC,SAASI,MAAM;QACzE,OAAOI,UAAU,KAAKA,UAAUrB,MAAMjB,KAAK,CAACkC,MAAM;IACpD;IACA,MAAMK,kBAAkBtB,MAAMjB,KAAK,CAACwC,MAAM,CAAC,CAACC,KAAKL,IAAMK,MAAOtD,CAAAA,IAAIe,GAAG,CAACkC,IAAIjC,QAAQ,CAAA,GAAI;IACtF,MAAMuC,gBAAgBzB,MAAMjB,KAAK,CAACkC,MAAM,GAAGjB,MAAMxB,OAAO,CAACyC,MAAM;IAC/D,MAAMS,YAAYD,gBAAgB,KAAKH,oBAAoBG;IAC3D,MAAME,eAAeL,kBAAkB,KAAKA,kBAAkBG;IAE9D,MAAMG,aAAa,CAACrD,MAAcsC,QAAgBQ,UAChDf,OAAO,CAACuB;YACN,MAAMhD,MAAMgD,EAAE5C,GAAG,CAACV,SAAS,IAAIE;YAC/B,IAAI4C,SAASxC,IAAID,GAAG,CAACiC;iBAChBhC,IAAIiD,MAAM,CAACjB;YAChBgB,EAAEhD,GAAG,CAACN,MAAMM;QACd;IAEF,MAAMkD,YAAY,CAACxD,MAAc8C,UAC/Bf,OAAO,CAACuB;YACNA,EAAEhD,GAAG,CAACN,MAAM8C,UAAU,IAAI5C,IAAIuB,MAAMxB,OAAO,IAAI,IAAIC;QACrD;IAEF,MAAMuD,eAAe,CAACnB,QAAgBQ,UACpCf,OAAO,CAACuB;YACN,KAAK,MAAMtD,QAAQyB,MAAMjB,KAAK,CAAE;gBAC9B,MAAMF,MAAMgD,EAAE5C,GAAG,CAACV,SAAS,IAAIE;gBAC/B,IAAI4C,SAASxC,IAAID,GAAG,CAACiC;qBAChBhC,IAAIiD,MAAM,CAACjB;gBAChBgB,EAAEhD,GAAG,CAACN,MAAMM;YACd;QACF;IAEF,MAAMoD,YAAY,CAACZ,UACjBf,OAAO,CAACuB;YACN,KAAK,MAAMtD,QAAQyB,MAAMjB,KAAK,CAAE8C,EAAEhD,GAAG,CAACN,MAAM8C,UAAU,IAAI5C,IAAIuB,MAAMxB,OAAO,IAAI,IAAIC;QACrF;IAEF,IAAIuB,MAAMjB,KAAK,CAACkC,MAAM,KAAK,GAAG;QAC5B,qBACE,MAACiB;YAAIC,WAAU;YAAaC,OAAO;gBAAE7C,SAAS;YAAW;;8BACvD,KAAC8C;oBAAMF,WAAU;8BAAenC,MAAMsC,KAAK;;8BAC3C,KAACC;oBAAEH,OAAO;wBAAEI,OAAO;wBAA8BC,UAAU;wBAAWC,QAAQ;oBAAc;8BACzF1C,MAAM2C,YAAY;;;;IAI3B;IAEA,qBACE,MAACT;QAAIC,WAAU;QAAaC,OAAO;YAAE7C,SAAS;QAAW;;0BACvD,KAAC8C;gBAAMF,WAAU;gBAAcS,SAAS,GAAG5C,MAAME,IAAI,CAAC,OAAO,CAAC;0BAC3DF,MAAMsC,KAAK;;0BAEd,KAACC;gBACCH,OAAO;oBACLI,OAAO;oBACPC,UAAU;oBACVC,QAAQ;gBACV;0BAEC1C,MAAM6C,WAAW;;0BAEpB,MAACC;gBACCC,IAAI,GAAG/C,MAAME,IAAI,CAAC,OAAO,CAAC;gBAC1BkC,OAAO;oBACLY,OAAO;oBACPC,gBAAgB;oBAChBR,UAAU;oBACV9C,YAAY;oBACZuD,QAAQ;oBACRC,cAAc;oBACdC,UAAU;gBACZ;;kCAEA,KAACC;kCACC,cAAA,MAACC;;8CACC,KAACC;oCAAGnB,OAAO;wCAAE,GAAG1C,eAAe;wCAAEJ,WAAW;oCAAO;8CACjD,cAAA,MAAC4C;wCAAIE,OAAO;4CAAEoB,SAAS;4CAAQC,eAAe;4CAAUC,KAAK;wCAAU;;0DACrE,KAACC;0DAAM3D,MAAM4D,UAAU;;0DACvB,KAAChG;gDACCyD,SAASK;gDACTmC,gBAAgBlC,gBAAgB,CAACD;gDACjCoC,UAAU,CAACC,IAAM9B,UAAU8B,EAAEC,aAAa,CAAC3C,OAAO;gDAClDgB,OAAM;;;;;gCAIXrC,MAAMxB,OAAO,CAACN,GAAG,CAAC,CAAC2C,uBAClB,KAAC0C;wCAAgBnB,OAAO1C;kDACtB,cAAA,MAACwC;4CACCE,OAAO;gDACLoB,SAAS;gDACTC,eAAe;gDACfQ,YAAY;gDACZP,KAAK;4CACP;;8DAEA,KAACC;8DAAM3D,MAAMkE,YAAY,CAACrD,OAAO,IAAIA;;8DACrC,KAACjD;oDACCyD,SAASH,aAAaL;oDACtBgD,gBAAgBzC,gBAAgBP,WAAW,CAACK,aAAaL;oDACzDiD,UAAU,CAACC,IAAM/B,aAAanB,QAAQkD,EAAEC,aAAa,CAAC3C,OAAO;;;;uCAb1DR;;;;kCAoBf,KAACsD;kCACEnE,MAAMjB,KAAK,CAACb,GAAG,CAAC,CAACK,MAAM6F;4BACtB,MAAMC,WAAWvG,QAAQS;4BACzB,qBACE,MAAC+E;gCAEClB,OAAO;oCACLzC,YACEyE,MAAM,MAAM,IAAI,0BAA0B;gCAC9C;;kDAEA,KAACE;wCACClC,OAAO;4CACL,GAAGtC,cAAc;4CACjByE,WAAWH,QAAQ,IAAI,SAAS;wCAClC;kDAEA,cAAA,MAAClC;4CAAIE,OAAO;gDAAEoB,SAAS;gDAAQS,YAAY;gDAAUP,KAAK;4CAAS;;8DACjE,KAAC9F;oDACCyD,SAASP,UAAUvC;oDACnBsF,gBAAgB7C,aAAazC,SAAS,CAACuC,UAAUvC;oDACjDuF,UAAU,CAACC,IAAMhC,UAAUxD,MAAMwF,EAAEC,aAAa,CAAC3C,OAAO;;8DAE1D,MAACa;oDAAIE,OAAO;wDAAEoB,SAAS;wDAAQC,eAAe;oDAAS;;sEACrD,KAACE;sEAAMU;;sEACP,KAACG;4DACCpC,OAAO;gEACLK,UAAU;gEACVD,OAAO;gEACP7C,YAAY;gEACZJ,SAAS;4DACX;sEAEChB;;;;;;;oCAKRyB,MAAMxB,OAAO,CAACN,GAAG,CAAC,CAAC2C,uBAClB,KAACyD;4CAEClC,OAAO;gDACL,GAAG/C,SAAS;gDACZkF,WAAWH,QAAQ,IAAI,SAAS;4CAClC;sDAEA,cAAA,KAACxG;gDACCyD,SAAST,cAAcrC,MAAMsC;gDAC7BiD,UAAU,CAACC,IAAMnC,WAAWrD,MAAMsC,QAAQkD,EAAEC,aAAa,CAAC3C,OAAO;;2CAR9DR;;+BAnCJtC;wBAiDX;;;;;;AAKV"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/index.ts"],"sourcesContent":["export { default as CollectionScopesMatrix } from './CollectionScopesMatrix'\r\nexport { default as GlobalScopesMatrix } from './GlobalScopesMatrix'\r\n"],"names":["default","CollectionScopesMatrix","GlobalScopesMatrix"],"mappings":"AAAA,SAASA,WAAWC,sBAAsB,QAAQ,2BAA0B;AAC5E,SAASD,WAAWE,kBAAkB,QAAQ,uBAAsB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CollectionConfig, Plugin } from 'payload';
|
|
2
|
+
/**
|
|
3
|
+
* Throws if `@payloadcms/plugin-mcp` is also registered in the host config.
|
|
4
|
+
* Two MCP plugins racing for the same collection slug produces a confusing
|
|
5
|
+
* boot crash inside Payload — this surfaces a clearer migration message.
|
|
6
|
+
*/
|
|
7
|
+
export declare function assertNoUpstreamPlugin(plugins: Plugin[] | undefined): void;
|
|
8
|
+
/**
|
|
9
|
+
* Throws if a collection with the api-keys slug is already in
|
|
10
|
+
* `incomingConfig.collections` from another source. Prevents duplicate-slug
|
|
11
|
+
* boot errors and gives the user actionable text.
|
|
12
|
+
*/
|
|
13
|
+
export declare function assertNoSlugConflict(collections: CollectionConfig[] | undefined, apiKeysSlug?: string): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { API_KEYS_DEFAULT_SLUG } from './api-keys';
|
|
2
|
+
const UPGRADE_HINT = 'payload-mcp-toolkit v0.4 is the standalone successor to @payloadcms/plugin-mcp. ' + 'Remove the upstream `mcpPlugin(...)` from your `plugins[]` (and the package from your dependencies) before upgrading. ' + 'See README "Upgrading from 0.3.x".';
|
|
3
|
+
/**
|
|
4
|
+
* Returns true when the supplied plugin reference looks like the upstream
|
|
5
|
+
* `mcpPlugin(...)` invocation (function name, source-string sniff, or wrapped
|
|
6
|
+
* config probing). Heuristic: covers the three common ways the upstream
|
|
7
|
+
* plugin shows up in `plugins[]`.
|
|
8
|
+
*/ function looksLikeUpstreamPlugin(plugin) {
|
|
9
|
+
if (typeof plugin !== 'function') return false;
|
|
10
|
+
const fn = plugin;
|
|
11
|
+
const fnName = (fn.name ?? '').toString();
|
|
12
|
+
if (fnName === 'mcpPlugin' || fnName === 'withMcp') return true;
|
|
13
|
+
const src = fn.toString();
|
|
14
|
+
return /@payloadcms\/plugin-mcp/.test(src) || /payload-mcp-api-keys/.test(src);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Throws if `@payloadcms/plugin-mcp` is also registered in the host config.
|
|
18
|
+
* Two MCP plugins racing for the same collection slug produces a confusing
|
|
19
|
+
* boot crash inside Payload — this surfaces a clearer migration message.
|
|
20
|
+
*/ export function assertNoUpstreamPlugin(plugins) {
|
|
21
|
+
if (!plugins || plugins.length === 0) return;
|
|
22
|
+
for (const plugin of plugins){
|
|
23
|
+
if (looksLikeUpstreamPlugin(plugin)) {
|
|
24
|
+
throw new Error(UPGRADE_HINT);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Throws if a collection with the api-keys slug is already in
|
|
30
|
+
* `incomingConfig.collections` from another source. Prevents duplicate-slug
|
|
31
|
+
* boot errors and gives the user actionable text.
|
|
32
|
+
*/ export function assertNoSlugConflict(collections, apiKeysSlug = API_KEYS_DEFAULT_SLUG) {
|
|
33
|
+
if (!collections || collections.length === 0) return;
|
|
34
|
+
for (const c of collections){
|
|
35
|
+
if (c?.slug === apiKeysSlug) {
|
|
36
|
+
throw new Error(`payload-mcp-toolkit: a collection with slug "${apiKeysSlug}" is already registered. ` + 'This is usually the upstream `@payloadcms/plugin-mcp` still being active. ' + 'Remove it before upgrading to v0.4, or pass a different slug via `apiKeyCollection.slug`.');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=conflict-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/conflict-detection.ts"],"sourcesContent":["import type { CollectionConfig, Plugin } from 'payload'\r\nimport { API_KEYS_DEFAULT_SLUG } from './api-keys'\r\n\r\nconst UPGRADE_HINT =\r\n 'payload-mcp-toolkit v0.4 is the standalone successor to @payloadcms/plugin-mcp. ' +\r\n 'Remove the upstream `mcpPlugin(...)` from your `plugins[]` (and the package from your dependencies) before upgrading. ' +\r\n 'See README \"Upgrading from 0.3.x\".'\r\n\r\n/**\r\n * Returns true when the supplied plugin reference looks like the upstream\r\n * `mcpPlugin(...)` invocation (function name, source-string sniff, or wrapped\r\n * config probing). Heuristic: covers the three common ways the upstream\r\n * plugin shows up in `plugins[]`.\r\n */\r\nfunction looksLikeUpstreamPlugin(plugin: unknown): boolean {\r\n if (typeof plugin !== 'function') return false\r\n const fn = plugin as (...args: unknown[]) => unknown\r\n const fnName = (fn.name ?? '').toString()\r\n if (fnName === 'mcpPlugin' || fnName === 'withMcp') return true\r\n\r\n const src = fn.toString()\r\n return /@payloadcms\\/plugin-mcp/.test(src) || /payload-mcp-api-keys/.test(src)\r\n}\r\n\r\n/**\r\n * Throws if `@payloadcms/plugin-mcp` is also registered in the host config.\r\n * Two MCP plugins racing for the same collection slug produces a confusing\r\n * boot crash inside Payload — this surfaces a clearer migration message.\r\n */\r\nexport function assertNoUpstreamPlugin(plugins: Plugin[] | undefined): void {\r\n if (!plugins || plugins.length === 0) return\r\n for (const plugin of plugins) {\r\n if (looksLikeUpstreamPlugin(plugin)) {\r\n throw new Error(UPGRADE_HINT)\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Throws if a collection with the api-keys slug is already in\r\n * `incomingConfig.collections` from another source. Prevents duplicate-slug\r\n * boot errors and gives the user actionable text.\r\n */\r\nexport function assertNoSlugConflict(\r\n collections: CollectionConfig[] | undefined,\r\n apiKeysSlug: string = API_KEYS_DEFAULT_SLUG,\r\n): void {\r\n if (!collections || collections.length === 0) return\r\n for (const c of collections) {\r\n if (c?.slug === apiKeysSlug) {\r\n throw new Error(\r\n `payload-mcp-toolkit: a collection with slug \"${apiKeysSlug}\" is already registered. ` +\r\n 'This is usually the upstream `@payloadcms/plugin-mcp` still being active. ' +\r\n 'Remove it before upgrading to v0.4, or pass a different slug via `apiKeyCollection.slug`.',\r\n )\r\n }\r\n }\r\n}\r\n"],"names":["API_KEYS_DEFAULT_SLUG","UPGRADE_HINT","looksLikeUpstreamPlugin","plugin","fn","fnName","name","toString","src","test","assertNoUpstreamPlugin","plugins","length","Error","assertNoSlugConflict","collections","apiKeysSlug","c","slug"],"mappings":"AACA,SAASA,qBAAqB,QAAQ,aAAY;AAElD,MAAMC,eACJ,qFACA,2HACA;AAEF;;;;;CAKC,GACD,SAASC,wBAAwBC,MAAe;IAC9C,IAAI,OAAOA,WAAW,YAAY,OAAO;IACzC,MAAMC,KAAKD;IACX,MAAME,SAAS,AAACD,CAAAA,GAAGE,IAAI,IAAI,EAAC,EAAGC,QAAQ;IACvC,IAAIF,WAAW,eAAeA,WAAW,WAAW,OAAO;IAE3D,MAAMG,MAAMJ,GAAGG,QAAQ;IACvB,OAAO,0BAA0BE,IAAI,CAACD,QAAQ,uBAAuBC,IAAI,CAACD;AAC5E;AAEA;;;;CAIC,GACD,OAAO,SAASE,uBAAuBC,OAA6B;IAClE,IAAI,CAACA,WAAWA,QAAQC,MAAM,KAAK,GAAG;IACtC,KAAK,MAAMT,UAAUQ,QAAS;QAC5B,IAAIT,wBAAwBC,SAAS;YACnC,MAAM,IAAIU,MAAMZ;QAClB;IACF;AACF;AAEA;;;;CAIC,GACD,OAAO,SAASa,qBACdC,WAA2C,EAC3CC,cAAsBhB,qBAAqB;IAE3C,IAAI,CAACe,eAAeA,YAAYH,MAAM,KAAK,GAAG;IAC9C,KAAK,MAAMK,KAAKF,YAAa;QAC3B,IAAIE,GAAGC,SAASF,aAAa;YAC3B,MAAM,IAAIH,MACR,CAAC,6CAA6C,EAAEG,YAAY,yBAAyB,CAAC,GACpF,+EACA;QAEN;IACF;AACF"}
|
package/dist/draft-workflow.d.ts
CHANGED
|
@@ -1,37 +1,11 @@
|
|
|
1
|
-
import type { CollectionConfig,
|
|
2
|
-
|
|
3
|
-
interface McpResponse {
|
|
4
|
-
content: Array<{
|
|
5
|
-
text: string;
|
|
6
|
-
type: string;
|
|
7
|
-
}>;
|
|
8
|
-
}
|
|
9
|
-
/** Per-collection MCP config with enabled operations and optional overrideResponse */
|
|
10
|
-
interface McpCollectionConfig {
|
|
11
|
-
description: string;
|
|
12
|
-
enabled: {
|
|
13
|
-
create: boolean;
|
|
14
|
-
delete: boolean;
|
|
15
|
-
find: boolean;
|
|
16
|
-
update: boolean;
|
|
17
|
-
};
|
|
18
|
-
overrideResponse?: (response: McpResponse, doc: Record<string, unknown>, req: PayloadRequest) => McpResponse | Promise<McpResponse>;
|
|
19
|
-
}
|
|
20
|
-
interface GenerateOptions {
|
|
21
|
-
/**
|
|
22
|
-
* Optional absolute base URL prepended to relative preview paths returned
|
|
23
|
-
* by the collection's own preview URL function. Resolved upstream from
|
|
24
|
-
* (in order): `options.preview.siteUrl`, `incomingConfig.serverURL`,
|
|
25
|
-
* `process.env.NEXT_PUBLIC_SERVER_URL`, `process.env.SITE_URL`. May be
|
|
26
|
-
* undefined — relative-path returns will then be skipped.
|
|
27
|
-
*/
|
|
28
|
-
siteUrl?: string;
|
|
1
|
+
import type { CollectionConfig, GlobalConfig } from 'payload';
|
|
2
|
+
interface ComputeDraftCollectionsOptions {
|
|
29
3
|
/** Per-collection draft behavior overrides */
|
|
30
4
|
draftBehavior?: Record<string, 'always-draft' | 'always-publish'>;
|
|
31
|
-
/** Collection slugs to exclude from MCP */
|
|
5
|
+
/** Collection slugs to exclude from MCP entirely */
|
|
32
6
|
excludeCollections?: string[];
|
|
33
|
-
/**
|
|
34
|
-
|
|
7
|
+
/** API-keys collection slug — always excluded from the MCP surface */
|
|
8
|
+
apiKeysSlug?: string;
|
|
35
9
|
}
|
|
36
10
|
/**
|
|
37
11
|
* Determines the draft behavior for a collection.
|
|
@@ -43,24 +17,49 @@ interface GenerateOptions {
|
|
|
43
17
|
export declare function getDraftBehavior(collection: CollectionConfig, options?: {
|
|
44
18
|
draftBehavior?: Record<string, 'always-draft' | 'always-publish'>;
|
|
45
19
|
}): 'always-draft' | 'always-publish' | 'publish';
|
|
20
|
+
export interface DraftCollectionsResult {
|
|
21
|
+
/** Slugs of collections that participate in the draft workflow. */
|
|
22
|
+
draftCollections: Set<string>;
|
|
23
|
+
/** Slugs of collections excluded from the MCP surface entirely. */
|
|
24
|
+
excluded: Set<string>;
|
|
25
|
+
}
|
|
46
26
|
/**
|
|
47
|
-
*
|
|
27
|
+
* Walks the collection list and returns:
|
|
28
|
+
* - `draftCollections`: slugs whose `versions.drafts` is on (or whose
|
|
29
|
+
* behavior override is `'always-draft'`).
|
|
30
|
+
* - `excluded`: slugs to hide from the MCP surface entirely (the api-keys
|
|
31
|
+
* collection itself, anything with `auth: true`, anything in
|
|
32
|
+
* `excludeCollections`).
|
|
48
33
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
34
|
+
* Replaces the v0.3.x `generateMcpCollectionConfigs` shape now that the
|
|
35
|
+
* toolkit owns the endpoint and tool dispatch directly — no need to produce
|
|
36
|
+
* an upstream `mcpCollections` config object.
|
|
37
|
+
*/
|
|
38
|
+
export declare function computeDraftCollections(collections: CollectionConfig[], options?: ComputeDraftCollectionsOptions): DraftCollectionsResult;
|
|
39
|
+
interface ComputeDraftGlobalsOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Per-resource draft behavior overrides. Shared with collections: a single
|
|
42
|
+
* record may contain both collection slugs and global slugs. Collisions
|
|
43
|
+
* are unambiguous in practice — Payload's slug registry forbids a global
|
|
44
|
+
* and a collection sharing a slug.
|
|
45
|
+
*/
|
|
46
|
+
draftBehavior?: Record<string, 'always-draft' | 'always-publish'>;
|
|
47
|
+
/** Global slugs to exclude from the MCP surface entirely */
|
|
48
|
+
excludeGlobals?: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface DraftGlobalsResult {
|
|
51
|
+
draftGlobals: Set<string>;
|
|
52
|
+
excluded: Set<string>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Peer of `computeDraftCollections` for globals. Returns the slugs whose
|
|
56
|
+
* draft workflow is on (i.e. `versions.drafts` enabled, with optional
|
|
57
|
+
* `'always-publish'` override turning it off), and the set excluded from
|
|
58
|
+
* the MCP surface entirely.
|
|
59
59
|
*
|
|
60
|
-
*
|
|
60
|
+
* Mirrors the collection rule: `versions.drafts: true` defaults to
|
|
61
|
+
* `'always-draft'` so raw publish is locked and `updateGlobal` / patch
|
|
62
|
+
* routes preserve draft semantics.
|
|
61
63
|
*/
|
|
62
|
-
export declare function
|
|
63
|
-
mcpCollections: Record<string, McpCollectionConfig>;
|
|
64
|
-
draftCollections: Set<string>;
|
|
65
|
-
};
|
|
64
|
+
export declare function computeDraftGlobals(globals: GlobalConfig[], options?: ComputeDraftGlobalsOptions): DraftGlobalsResult;
|
|
66
65
|
export {};
|