payload-mcp-toolkit 0.7.0 → 0.7.5
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 +30 -9
- package/dist/api-keys.js +57 -21
- package/dist/api-keys.js.map +1 -1
- package/dist/auth-strategy.d.ts +18 -7
- package/dist/auth-strategy.js +54 -12
- package/dist/auth-strategy.js.map +1 -1
- package/dist/tools/_helpers.d.ts +34 -0
- package/dist/tools/_helpers.js +98 -0
- package/dist/tools/_helpers.js.map +1 -1
- package/dist/tools/create-document.js +8 -0
- package/dist/tools/create-document.js.map +1 -1
- package/dist/tools/delete-document.d.ts +1 -1
- package/dist/tools/delete-document.js +6 -6
- package/dist/tools/delete-document.js.map +1 -1
- package/dist/tools/find-document.d.ts +3 -3
- package/dist/tools/find-document.js +8 -8
- package/dist/tools/find-document.js.map +1 -1
- package/dist/tools/publish-draft.js +33 -1
- package/dist/tools/publish-draft.js.map +1 -1
- package/dist/tools/publish-global-draft.js +30 -1
- package/dist/tools/publish-global-draft.js.map +1 -1
- package/package.json +29 -15
- package/dist/__tests__/api-keys.test.js +0 -292
- package/dist/__tests__/api-keys.test.js.map +0 -1
- package/dist/__tests__/auth-strategy.test.js +0 -681
- package/dist/__tests__/auth-strategy.test.js.map +0 -1
- package/dist/__tests__/conflict-detection.test.js +0 -69
- package/dist/__tests__/conflict-detection.test.js.map +0 -1
- package/dist/__tests__/delete-document.test.js +0 -70
- package/dist/__tests__/delete-document.test.js.map +0 -1
- package/dist/__tests__/endpoint.test.js +0 -143
- package/dist/__tests__/endpoint.test.js.map +0 -1
- package/dist/__tests__/find-document.test.js +0 -178
- package/dist/__tests__/find-document.test.js.map +0 -1
- package/dist/__tests__/find-global.test.js +0 -173
- package/dist/__tests__/find-global.test.js.map +0 -1
- package/dist/__tests__/global-versions.test.js +0 -183
- package/dist/__tests__/global-versions.test.js.map +0 -1
- package/dist/__tests__/hash.test.js +0 -58
- package/dist/__tests__/hash.test.js.map +0 -1
- package/dist/__tests__/index-integration.test.js +0 -191
- package/dist/__tests__/index-integration.test.js.map +0 -1
- package/dist/__tests__/introspection.test.js +0 -659
- package/dist/__tests__/introspection.test.js.map +0 -1
- package/dist/__tests__/patch-global-layout.test.js +0 -474
- package/dist/__tests__/patch-global-layout.test.js.map +0 -1
- package/dist/__tests__/patch-layout.test.js +0 -171
- package/dist/__tests__/patch-layout.test.js.map +0 -1
- package/dist/__tests__/registry.test.js +0 -795
- package/dist/__tests__/registry.test.js.map +0 -1
- package/dist/__tests__/resources.test.js +0 -139
- package/dist/__tests__/resources.test.js.map +0 -1
- package/dist/__tests__/update-global.test.js +0 -157
- package/dist/__tests__/update-global.test.js.map +0 -1
- package/dist/__tests__/url-validator.test.js +0 -326
- package/dist/__tests__/url-validator.test.js.map +0 -1
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { createFindGlobalTool } from '../tools/find-global';
|
|
3
|
-
const fakeSchema = {
|
|
4
|
-
slug: 'site-settings',
|
|
5
|
-
fields: [],
|
|
6
|
-
hasDrafts: true,
|
|
7
|
-
hasLivePreview: false
|
|
8
|
-
};
|
|
9
|
-
const draftGlobalConfig = {
|
|
10
|
-
slug: 'site-settings',
|
|
11
|
-
admin: {
|
|
12
|
-
livePreview: {
|
|
13
|
-
url: ({ data })=>`/preview/globals/site-settings?v=${data.siteName ?? ''}`
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
fields: [],
|
|
17
|
-
versions: {
|
|
18
|
-
drafts: true
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
function buildReq() {
|
|
22
|
-
return {
|
|
23
|
-
payload: {
|
|
24
|
-
findGlobal: vi.fn(),
|
|
25
|
-
logger: {
|
|
26
|
-
info: vi.fn(),
|
|
27
|
-
warn: vi.fn(),
|
|
28
|
-
error: vi.fn()
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
context: {},
|
|
32
|
-
user: null
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
describe('findGlobal', ()=>{
|
|
36
|
-
const schemas = new Map([
|
|
37
|
-
[
|
|
38
|
-
'site-settings',
|
|
39
|
-
fakeSchema
|
|
40
|
-
]
|
|
41
|
-
]);
|
|
42
|
-
const drafts = new Set([
|
|
43
|
-
'site-settings'
|
|
44
|
-
]);
|
|
45
|
-
const configs = new Map([
|
|
46
|
-
[
|
|
47
|
-
'site-settings',
|
|
48
|
-
draftGlobalConfig
|
|
49
|
-
]
|
|
50
|
-
]);
|
|
51
|
-
it('calls findGlobal with overrideAccess:false', async ()=>{
|
|
52
|
-
const tool = createFindGlobalTool(schemas, drafts, configs, 'https://app.example.com');
|
|
53
|
-
const req = buildReq();
|
|
54
|
-
req.payload.findGlobal.mockResolvedValue({
|
|
55
|
-
siteName: 'Acme',
|
|
56
|
-
_status: 'published'
|
|
57
|
-
});
|
|
58
|
-
const result = await tool.handler({
|
|
59
|
-
slug: 'site-settings'
|
|
60
|
-
}, req, {});
|
|
61
|
-
expect(req.payload.findGlobal).toHaveBeenCalledWith(expect.objectContaining({
|
|
62
|
-
slug: 'site-settings',
|
|
63
|
-
overrideAccess: false,
|
|
64
|
-
draft: false
|
|
65
|
-
}));
|
|
66
|
-
expect(result.content[0].text).toContain('"siteName":"Acme"');
|
|
67
|
-
});
|
|
68
|
-
it('passes draft:true through when requested', async ()=>{
|
|
69
|
-
const tool = createFindGlobalTool(schemas, drafts, configs, undefined);
|
|
70
|
-
const req = buildReq();
|
|
71
|
-
req.payload.findGlobal.mockResolvedValue({
|
|
72
|
-
siteName: 'draft',
|
|
73
|
-
_status: 'draft'
|
|
74
|
-
});
|
|
75
|
-
await tool.handler({
|
|
76
|
-
slug: 'site-settings',
|
|
77
|
-
draft: true
|
|
78
|
-
}, req, {});
|
|
79
|
-
expect(req.payload.findGlobal).toHaveBeenCalledWith(expect.objectContaining({
|
|
80
|
-
slug: 'site-settings',
|
|
81
|
-
draft: true
|
|
82
|
-
}));
|
|
83
|
-
});
|
|
84
|
-
it('stamps a preview URL when the draft global has livePreview configured', async ()=>{
|
|
85
|
-
const tool = createFindGlobalTool(schemas, drafts, configs, 'https://app.example.com');
|
|
86
|
-
const req = buildReq();
|
|
87
|
-
req.payload.findGlobal.mockResolvedValue({
|
|
88
|
-
siteName: 'Acme',
|
|
89
|
-
_status: 'draft'
|
|
90
|
-
});
|
|
91
|
-
const result = await tool.handler({
|
|
92
|
-
slug: 'site-settings',
|
|
93
|
-
draft: true
|
|
94
|
-
}, req, {});
|
|
95
|
-
const allText = result.content.map((c)=>c.text).join('\n');
|
|
96
|
-
expect(allText).toContain('https://app.example.com/preview/globals/site-settings?v=Acme');
|
|
97
|
-
});
|
|
98
|
-
it('falls back to admin-panel hint when global has no preview function', async ()=>{
|
|
99
|
-
const noPreview = {
|
|
100
|
-
slug: 'site-settings',
|
|
101
|
-
fields: []
|
|
102
|
-
};
|
|
103
|
-
const tool = createFindGlobalTool(schemas, drafts, new Map([
|
|
104
|
-
[
|
|
105
|
-
'site-settings',
|
|
106
|
-
noPreview
|
|
107
|
-
]
|
|
108
|
-
]), undefined);
|
|
109
|
-
const req = buildReq();
|
|
110
|
-
req.payload.findGlobal.mockResolvedValue({
|
|
111
|
-
siteName: 'Acme',
|
|
112
|
-
_status: 'draft'
|
|
113
|
-
});
|
|
114
|
-
const result = await tool.handler({
|
|
115
|
-
slug: 'site-settings',
|
|
116
|
-
draft: true
|
|
117
|
-
}, req, {});
|
|
118
|
-
const allText = result.content.map((c)=>c.text).join('\n');
|
|
119
|
-
expect(allText).toMatch(/admin panel/i);
|
|
120
|
-
});
|
|
121
|
-
it('omits preview decoration entirely when previewDisabled is true', async ()=>{
|
|
122
|
-
const tool = createFindGlobalTool(schemas, drafts, configs, 'https://app.example.com', true);
|
|
123
|
-
const req = buildReq();
|
|
124
|
-
req.payload.findGlobal.mockResolvedValue({
|
|
125
|
-
siteName: 'Acme',
|
|
126
|
-
_status: 'draft'
|
|
127
|
-
});
|
|
128
|
-
const result = await tool.handler({
|
|
129
|
-
slug: 'site-settings',
|
|
130
|
-
draft: true
|
|
131
|
-
}, req, {});
|
|
132
|
-
expect(result.content).toHaveLength(1);
|
|
133
|
-
});
|
|
134
|
-
it('returns text error when the global slug is unknown', async ()=>{
|
|
135
|
-
const tool = createFindGlobalTool(schemas, drafts, configs, undefined);
|
|
136
|
-
const req = buildReq();
|
|
137
|
-
const result = await tool.handler({
|
|
138
|
-
slug: 'no-such-global'
|
|
139
|
-
}, req, {});
|
|
140
|
-
expect(result.content[0].text).toMatch(/Unknown global/);
|
|
141
|
-
});
|
|
142
|
-
it('catches errors and returns text error response, no exception', async ()=>{
|
|
143
|
-
const tool = createFindGlobalTool(schemas, drafts, configs, undefined);
|
|
144
|
-
const req = buildReq();
|
|
145
|
-
req.payload.findGlobal.mockRejectedValue(new Error('boom'));
|
|
146
|
-
const result = await tool.handler({
|
|
147
|
-
slug: 'site-settings'
|
|
148
|
-
}, req, {});
|
|
149
|
-
expect(result.content[0].text).toMatch(/Error reading global/);
|
|
150
|
-
});
|
|
151
|
-
it('slug enum errorMap surfaces friendly "unknown or excluded" message', ()=>{
|
|
152
|
-
const tool = createFindGlobalTool(schemas, drafts, configs, undefined);
|
|
153
|
-
const slugParam = tool.parameters.slug;
|
|
154
|
-
const res = slugParam.safeParse('secret-config');
|
|
155
|
-
expect(res.success).toBe(false);
|
|
156
|
-
expect(res.error.issues[0].message).toMatch(/Unknown or excluded/);
|
|
157
|
-
expect(res.error.issues[0].message).toContain('site-settings');
|
|
158
|
-
});
|
|
159
|
-
it('does not stamp preview for a published doc even when livePreview is set', async ()=>{
|
|
160
|
-
const tool = createFindGlobalTool(schemas, drafts, configs, 'https://app.example.com');
|
|
161
|
-
const req = buildReq();
|
|
162
|
-
req.payload.findGlobal.mockResolvedValue({
|
|
163
|
-
siteName: 'Acme',
|
|
164
|
-
_status: 'published'
|
|
165
|
-
});
|
|
166
|
-
const result = await tool.handler({
|
|
167
|
-
slug: 'site-settings'
|
|
168
|
-
}, req, {});
|
|
169
|
-
expect(result.content).toHaveLength(1);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
//# sourceMappingURL=find-global.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/__tests__/find-global.test.ts"],"sourcesContent":["import { describe, it, expect, vi } from 'vitest'\r\nimport type { GlobalConfig } from 'payload'\r\nimport { createFindGlobalTool } from '../tools/find-global'\r\nimport type { GlobalSchema } from '../types'\r\n\r\nconst fakeSchema: GlobalSchema = {\r\n slug: 'site-settings',\r\n fields: [],\r\n hasDrafts: true,\r\n hasLivePreview: false,\r\n}\r\n\r\nconst draftGlobalConfig: GlobalConfig = {\r\n slug: 'site-settings',\r\n admin: {\r\n livePreview: {\r\n url: ({ data }: { data: Record<string, unknown> }) =>\r\n `/preview/globals/site-settings?v=${data.siteName ?? ''}`,\r\n },\r\n } as never,\r\n fields: [],\r\n versions: { drafts: true },\r\n}\r\n\r\nfunction buildReq() {\r\n return {\r\n payload: {\r\n findGlobal: vi.fn(),\r\n logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },\r\n },\r\n context: {},\r\n user: null,\r\n }\r\n}\r\n\r\ndescribe('findGlobal', () => {\r\n const schemas = new Map([['site-settings', fakeSchema]])\r\n const drafts = new Set(['site-settings'])\r\n const configs = new Map([['site-settings', draftGlobalConfig]])\r\n\r\n it('calls findGlobal with overrideAccess:false', async () => {\r\n const tool = createFindGlobalTool(schemas, drafts, configs, 'https://app.example.com')\r\n const req = buildReq()\r\n req.payload.findGlobal.mockResolvedValue({ siteName: 'Acme', _status: 'published' })\r\n\r\n const result = await tool.handler({ slug: 'site-settings' }, req as never, {})\r\n expect(req.payload.findGlobal).toHaveBeenCalledWith(\r\n expect.objectContaining({ slug: 'site-settings', overrideAccess: false, draft: false }),\r\n )\r\n expect(result.content[0]!.text).toContain('\"siteName\":\"Acme\"')\r\n })\r\n\r\n it('passes draft:true through when requested', async () => {\r\n const tool = createFindGlobalTool(schemas, drafts, configs, undefined)\r\n const req = buildReq()\r\n req.payload.findGlobal.mockResolvedValue({ siteName: 'draft', _status: 'draft' })\r\n\r\n await tool.handler({ slug: 'site-settings', draft: true }, req as never, {})\r\n expect(req.payload.findGlobal).toHaveBeenCalledWith(\r\n expect.objectContaining({ slug: 'site-settings', draft: true }),\r\n )\r\n })\r\n\r\n it('stamps a preview URL when the draft global has livePreview configured', async () => {\r\n const tool = createFindGlobalTool(schemas, drafts, configs, 'https://app.example.com')\r\n const req = buildReq()\r\n req.payload.findGlobal.mockResolvedValue({ siteName: 'Acme', _status: 'draft' })\r\n\r\n const result = await tool.handler({ slug: 'site-settings', draft: true }, req as never, {})\r\n const allText = result.content.map((c) => c.text).join('\\n')\r\n expect(allText).toContain('https://app.example.com/preview/globals/site-settings?v=Acme')\r\n })\r\n\r\n it('falls back to admin-panel hint when global has no preview function', async () => {\r\n const noPreview: GlobalConfig = { slug: 'site-settings', fields: [] }\r\n const tool = createFindGlobalTool(\r\n schemas,\r\n drafts,\r\n new Map([['site-settings', noPreview]]),\r\n undefined,\r\n )\r\n const req = buildReq()\r\n req.payload.findGlobal.mockResolvedValue({ siteName: 'Acme', _status: 'draft' })\r\n\r\n const result = await tool.handler({ slug: 'site-settings', draft: true }, req as never, {})\r\n const allText = result.content.map((c) => c.text).join('\\n')\r\n expect(allText).toMatch(/admin panel/i)\r\n })\r\n\r\n it('omits preview decoration entirely when previewDisabled is true', async () => {\r\n const tool = createFindGlobalTool(schemas, drafts, configs, 'https://app.example.com', true)\r\n const req = buildReq()\r\n req.payload.findGlobal.mockResolvedValue({ siteName: 'Acme', _status: 'draft' })\r\n\r\n const result = await tool.handler({ slug: 'site-settings', draft: true }, req as never, {})\r\n expect(result.content).toHaveLength(1)\r\n })\r\n\r\n it('returns text error when the global slug is unknown', async () => {\r\n const tool = createFindGlobalTool(schemas, drafts, configs, undefined)\r\n const req = buildReq()\r\n const result = await tool.handler({ slug: 'no-such-global' as never }, req as never, {})\r\n expect(result.content[0]!.text).toMatch(/Unknown global/)\r\n })\r\n\r\n it('catches errors and returns text error response, no exception', async () => {\r\n const tool = createFindGlobalTool(schemas, drafts, configs, undefined)\r\n const req = buildReq()\r\n req.payload.findGlobal.mockRejectedValue(new Error('boom'))\r\n const result = await tool.handler({ slug: 'site-settings' }, req as never, {})\r\n expect(result.content[0]!.text).toMatch(/Error reading global/)\r\n })\r\n\r\n it('slug enum errorMap surfaces friendly \"unknown or excluded\" message', () => {\r\n const tool = createFindGlobalTool(schemas, drafts, configs, undefined)\r\n const slugParam = tool.parameters.slug as { safeParse: (v: unknown) => { success: boolean; error?: { issues: Array<{ message: string }> } } }\r\n const res = slugParam.safeParse('secret-config')\r\n expect(res.success).toBe(false)\r\n expect(res.error!.issues[0]!.message).toMatch(/Unknown or excluded/)\r\n expect(res.error!.issues[0]!.message).toContain('site-settings')\r\n })\r\n\r\n it('does not stamp preview for a published doc even when livePreview is set', async () => {\r\n const tool = createFindGlobalTool(schemas, drafts, configs, 'https://app.example.com')\r\n const req = buildReq()\r\n req.payload.findGlobal.mockResolvedValue({ siteName: 'Acme', _status: 'published' })\r\n\r\n const result = await tool.handler({ slug: 'site-settings' }, req as never, {})\r\n expect(result.content).toHaveLength(1)\r\n })\r\n})\r\n"],"names":["describe","it","expect","vi","createFindGlobalTool","fakeSchema","slug","fields","hasDrafts","hasLivePreview","draftGlobalConfig","admin","livePreview","url","data","siteName","versions","drafts","buildReq","payload","findGlobal","fn","logger","info","warn","error","context","user","schemas","Map","Set","configs","tool","req","mockResolvedValue","_status","result","handler","toHaveBeenCalledWith","objectContaining","overrideAccess","draft","content","text","toContain","undefined","allText","map","c","join","noPreview","toMatch","toHaveLength","mockRejectedValue","Error","slugParam","parameters","res","safeParse","success","toBe","issues","message"],"mappings":"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"}
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { createPublishGlobalDraftTool } from '../tools/publish-global-draft';
|
|
3
|
-
import { createListGlobalVersionsTool, createRestoreGlobalVersionTool } from '../tools/global-versions';
|
|
4
|
-
function buildReq() {
|
|
5
|
-
return {
|
|
6
|
-
payload: {
|
|
7
|
-
updateGlobal: vi.fn(),
|
|
8
|
-
findGlobal: vi.fn(),
|
|
9
|
-
findGlobalVersions: vi.fn(),
|
|
10
|
-
restoreGlobalVersion: vi.fn(),
|
|
11
|
-
logger: {
|
|
12
|
-
info: vi.fn(),
|
|
13
|
-
warn: vi.fn(),
|
|
14
|
-
error: vi.fn()
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
context: {},
|
|
18
|
-
user: null
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
describe('publishGlobalDraft', ()=>{
|
|
22
|
-
it('returns null when no global has drafts enabled', ()=>{
|
|
23
|
-
expect(createPublishGlobalDraftTool(new Set())).toBeNull();
|
|
24
|
-
});
|
|
25
|
-
it('promotes the draft to published via updateGlobal', async ()=>{
|
|
26
|
-
const tool = createPublishGlobalDraftTool(new Set([
|
|
27
|
-
'footer'
|
|
28
|
-
]));
|
|
29
|
-
const req = buildReq();
|
|
30
|
-
req.payload.updateGlobal.mockResolvedValue({});
|
|
31
|
-
const result = await tool.handler({
|
|
32
|
-
slug: 'footer'
|
|
33
|
-
}, req, {});
|
|
34
|
-
expect(req.payload.updateGlobal).toHaveBeenCalledWith(expect.objectContaining({
|
|
35
|
-
slug: 'footer',
|
|
36
|
-
data: {
|
|
37
|
-
_status: 'published'
|
|
38
|
-
},
|
|
39
|
-
overrideAccess: false
|
|
40
|
-
}));
|
|
41
|
-
expect(result.content[0].text).toMatch(/Successfully published global "footer"/);
|
|
42
|
-
});
|
|
43
|
-
it('refuses to publish a global that is not in the draft set', async ()=>{
|
|
44
|
-
const tool = createPublishGlobalDraftTool(new Set([
|
|
45
|
-
'footer'
|
|
46
|
-
]));
|
|
47
|
-
const req = buildReq();
|
|
48
|
-
const result = await tool.handler({
|
|
49
|
-
slug: 'other'
|
|
50
|
-
}, req, {});
|
|
51
|
-
expect(result.content[0].text).toMatch(/does not support drafts/i);
|
|
52
|
-
expect(req.payload.updateGlobal).not.toHaveBeenCalled();
|
|
53
|
-
});
|
|
54
|
-
it('catches Payload errors and returns text error', async ()=>{
|
|
55
|
-
const tool = createPublishGlobalDraftTool(new Set([
|
|
56
|
-
'footer'
|
|
57
|
-
]));
|
|
58
|
-
const req = buildReq();
|
|
59
|
-
req.payload.updateGlobal.mockRejectedValue(new Error('nope'));
|
|
60
|
-
const result = await tool.handler({
|
|
61
|
-
slug: 'footer'
|
|
62
|
-
}, req, {});
|
|
63
|
-
expect(result.content[0].text).toMatch(/Error publishing global "footer"/);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe('listGlobalVersions', ()=>{
|
|
67
|
-
it('returns null with no draft globals', ()=>{
|
|
68
|
-
expect(createListGlobalVersionsTool(new Set())).toBeNull();
|
|
69
|
-
});
|
|
70
|
-
it('returns version metadata newest-first via findGlobalVersions', async ()=>{
|
|
71
|
-
const tool = createListGlobalVersionsTool(new Set([
|
|
72
|
-
'footer'
|
|
73
|
-
]));
|
|
74
|
-
const req = buildReq();
|
|
75
|
-
req.payload.findGlobalVersions.mockResolvedValue({
|
|
76
|
-
totalDocs: 2,
|
|
77
|
-
docs: [
|
|
78
|
-
{
|
|
79
|
-
id: 'v2',
|
|
80
|
-
updatedAt: '2026-05-12',
|
|
81
|
-
createdAt: '2026-05-12',
|
|
82
|
-
version: {
|
|
83
|
-
_status: 'draft'
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
id: 'v1',
|
|
88
|
-
updatedAt: '2026-05-11',
|
|
89
|
-
createdAt: '2026-05-11',
|
|
90
|
-
version: {
|
|
91
|
-
_status: 'published'
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
]
|
|
95
|
-
});
|
|
96
|
-
const result = await tool.handler({
|
|
97
|
-
slug: 'footer',
|
|
98
|
-
limit: 5
|
|
99
|
-
}, req, {});
|
|
100
|
-
expect(req.payload.findGlobalVersions).toHaveBeenCalledWith(expect.objectContaining({
|
|
101
|
-
slug: 'footer',
|
|
102
|
-
sort: '-updatedAt',
|
|
103
|
-
limit: 5
|
|
104
|
-
}));
|
|
105
|
-
const body = JSON.parse(result.content[0].text);
|
|
106
|
-
expect(body.versions).toHaveLength(2);
|
|
107
|
-
expect(body.versions[0].id).toBe('v2');
|
|
108
|
-
expect(body.versions[0].status).toBe('draft');
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
describe('restoreGlobalVersion', ()=>{
|
|
112
|
-
it('returns null with no draft globals', ()=>{
|
|
113
|
-
expect(createRestoreGlobalVersionTool(new Set())).toBeNull();
|
|
114
|
-
});
|
|
115
|
-
it('calls restoreGlobalVersion and acknowledges the rollback', async ()=>{
|
|
116
|
-
const tool = createRestoreGlobalVersionTool(new Set([
|
|
117
|
-
'footer'
|
|
118
|
-
]));
|
|
119
|
-
const req = buildReq();
|
|
120
|
-
req.payload.restoreGlobalVersion.mockResolvedValue({});
|
|
121
|
-
const result = await tool.handler({
|
|
122
|
-
slug: 'footer',
|
|
123
|
-
versionId: 'v1'
|
|
124
|
-
}, req, {});
|
|
125
|
-
expect(req.payload.restoreGlobalVersion).toHaveBeenCalledWith(expect.objectContaining({
|
|
126
|
-
slug: 'footer',
|
|
127
|
-
id: 'v1'
|
|
128
|
-
}));
|
|
129
|
-
expect(result.content[0].text).toMatch(/Restored global "footer" from version v1/);
|
|
130
|
-
expect(result.content[0].text).toMatch(/publishGlobalDraft/);
|
|
131
|
-
});
|
|
132
|
-
it('expectedUpdatedAt mismatch rejects the restore', async ()=>{
|
|
133
|
-
const tool = createRestoreGlobalVersionTool(new Set([
|
|
134
|
-
'footer'
|
|
135
|
-
]));
|
|
136
|
-
const req = buildReq();
|
|
137
|
-
req.payload.findGlobal.mockResolvedValue({
|
|
138
|
-
updatedAt: '2026-01-02T00:00:00.000Z'
|
|
139
|
-
});
|
|
140
|
-
const result = await tool.handler({
|
|
141
|
-
slug: 'footer',
|
|
142
|
-
versionId: 'v1',
|
|
143
|
-
expectedUpdatedAt: '2026-01-01T00:00:00.000Z'
|
|
144
|
-
}, req, {});
|
|
145
|
-
expect(result.content[0].text).toMatch(/conflict/i);
|
|
146
|
-
expect(req.payload.restoreGlobalVersion).not.toHaveBeenCalled();
|
|
147
|
-
});
|
|
148
|
-
it('expectedUpdatedAt match proceeds with the restore', async ()=>{
|
|
149
|
-
const tool = createRestoreGlobalVersionTool(new Set([
|
|
150
|
-
'footer'
|
|
151
|
-
]));
|
|
152
|
-
const req = buildReq();
|
|
153
|
-
req.payload.findGlobal.mockResolvedValue({
|
|
154
|
-
updatedAt: '2026-01-02T00:00:00.000Z'
|
|
155
|
-
});
|
|
156
|
-
req.payload.restoreGlobalVersion.mockResolvedValue({});
|
|
157
|
-
await tool.handler({
|
|
158
|
-
slug: 'footer',
|
|
159
|
-
versionId: 'v1',
|
|
160
|
-
expectedUpdatedAt: '2026-01-02T00:00:00.000Z'
|
|
161
|
-
}, req, {});
|
|
162
|
-
expect(req.payload.restoreGlobalVersion).toHaveBeenCalled();
|
|
163
|
-
});
|
|
164
|
-
it('locale arg is forwarded to restoreGlobalVersion', async ()=>{
|
|
165
|
-
const tool = createRestoreGlobalVersionTool(new Set([
|
|
166
|
-
'footer'
|
|
167
|
-
]));
|
|
168
|
-
const req = buildReq();
|
|
169
|
-
req.payload.restoreGlobalVersion.mockResolvedValue({});
|
|
170
|
-
await tool.handler({
|
|
171
|
-
slug: 'footer',
|
|
172
|
-
versionId: 'v1',
|
|
173
|
-
locale: 'fr'
|
|
174
|
-
}, req, {});
|
|
175
|
-
expect(req.payload.restoreGlobalVersion).toHaveBeenCalledWith(expect.objectContaining({
|
|
176
|
-
slug: 'footer',
|
|
177
|
-
id: 'v1',
|
|
178
|
-
locale: 'fr'
|
|
179
|
-
}));
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
//# sourceMappingURL=global-versions.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/__tests__/global-versions.test.ts"],"sourcesContent":["import { describe, it, expect, vi } from 'vitest'\r\nimport { createPublishGlobalDraftTool } from '../tools/publish-global-draft'\r\nimport {\r\n createListGlobalVersionsTool,\r\n createRestoreGlobalVersionTool,\r\n} from '../tools/global-versions'\r\n\r\nfunction buildReq() {\r\n return {\r\n payload: {\r\n updateGlobal: vi.fn(),\r\n findGlobal: vi.fn(),\r\n findGlobalVersions: vi.fn(),\r\n restoreGlobalVersion: vi.fn(),\r\n logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },\r\n },\r\n context: {},\r\n user: null,\r\n }\r\n}\r\n\r\ndescribe('publishGlobalDraft', () => {\r\n it('returns null when no global has drafts enabled', () => {\r\n expect(createPublishGlobalDraftTool(new Set())).toBeNull()\r\n })\r\n\r\n it('promotes the draft to published via updateGlobal', async () => {\r\n const tool = createPublishGlobalDraftTool(new Set(['footer']))!\r\n const req = buildReq()\r\n req.payload.updateGlobal.mockResolvedValue({})\r\n\r\n const result = await tool.handler({ slug: 'footer' }, req as never, {})\r\n expect(req.payload.updateGlobal).toHaveBeenCalledWith(\r\n expect.objectContaining({\r\n slug: 'footer',\r\n data: { _status: 'published' },\r\n overrideAccess: false,\r\n }),\r\n )\r\n expect(result.content[0]!.text).toMatch(/Successfully published global \"footer\"/)\r\n })\r\n\r\n it('refuses to publish a global that is not in the draft set', async () => {\r\n const tool = createPublishGlobalDraftTool(new Set(['footer']))!\r\n const req = buildReq()\r\n const result = await tool.handler({ slug: 'other' as never }, req as never, {})\r\n expect(result.content[0]!.text).toMatch(/does not support drafts/i)\r\n expect(req.payload.updateGlobal).not.toHaveBeenCalled()\r\n })\r\n\r\n it('catches Payload errors and returns text error', async () => {\r\n const tool = createPublishGlobalDraftTool(new Set(['footer']))!\r\n const req = buildReq()\r\n req.payload.updateGlobal.mockRejectedValue(new Error('nope'))\r\n const result = await tool.handler({ slug: 'footer' }, req as never, {})\r\n expect(result.content[0]!.text).toMatch(/Error publishing global \"footer\"/)\r\n })\r\n})\r\n\r\ndescribe('listGlobalVersions', () => {\r\n it('returns null with no draft globals', () => {\r\n expect(createListGlobalVersionsTool(new Set())).toBeNull()\r\n })\r\n\r\n it('returns version metadata newest-first via findGlobalVersions', async () => {\r\n const tool = createListGlobalVersionsTool(new Set(['footer']))!\r\n const req = buildReq()\r\n req.payload.findGlobalVersions.mockResolvedValue({\r\n totalDocs: 2,\r\n docs: [\r\n { id: 'v2', updatedAt: '2026-05-12', createdAt: '2026-05-12', version: { _status: 'draft' } },\r\n { id: 'v1', updatedAt: '2026-05-11', createdAt: '2026-05-11', version: { _status: 'published' } },\r\n ],\r\n })\r\n\r\n const result = await tool.handler({ slug: 'footer', limit: 5 }, req as never, {})\r\n expect(req.payload.findGlobalVersions).toHaveBeenCalledWith(\r\n expect.objectContaining({ slug: 'footer', sort: '-updatedAt', limit: 5 }),\r\n )\r\n const body = JSON.parse(result.content[0]!.text)\r\n expect(body.versions).toHaveLength(2)\r\n expect(body.versions[0].id).toBe('v2')\r\n expect(body.versions[0].status).toBe('draft')\r\n })\r\n})\r\n\r\ndescribe('restoreGlobalVersion', () => {\r\n it('returns null with no draft globals', () => {\r\n expect(createRestoreGlobalVersionTool(new Set())).toBeNull()\r\n })\r\n\r\n it('calls restoreGlobalVersion and acknowledges the rollback', async () => {\r\n const tool = createRestoreGlobalVersionTool(new Set(['footer']))!\r\n const req = buildReq()\r\n req.payload.restoreGlobalVersion.mockResolvedValue({})\r\n\r\n const result = await tool.handler({ slug: 'footer', versionId: 'v1' }, req as never, {})\r\n expect(req.payload.restoreGlobalVersion).toHaveBeenCalledWith(\r\n expect.objectContaining({ slug: 'footer', id: 'v1' }),\r\n )\r\n expect(result.content[0]!.text).toMatch(/Restored global \"footer\" from version v1/)\r\n expect(result.content[0]!.text).toMatch(/publishGlobalDraft/)\r\n })\r\n\r\n it('expectedUpdatedAt mismatch rejects the restore', async () => {\r\n const tool = createRestoreGlobalVersionTool(new Set(['footer']))!\r\n const req = buildReq()\r\n req.payload.findGlobal.mockResolvedValue({ updatedAt: '2026-01-02T00:00:00.000Z' })\r\n\r\n const result = await tool.handler(\r\n {\r\n slug: 'footer',\r\n versionId: 'v1',\r\n expectedUpdatedAt: '2026-01-01T00:00:00.000Z',\r\n },\r\n req as never,\r\n {},\r\n )\r\n\r\n expect(result.content[0]!.text).toMatch(/conflict/i)\r\n expect(req.payload.restoreGlobalVersion).not.toHaveBeenCalled()\r\n })\r\n\r\n it('expectedUpdatedAt match proceeds with the restore', async () => {\r\n const tool = createRestoreGlobalVersionTool(new Set(['footer']))!\r\n const req = buildReq()\r\n req.payload.findGlobal.mockResolvedValue({ updatedAt: '2026-01-02T00:00:00.000Z' })\r\n req.payload.restoreGlobalVersion.mockResolvedValue({})\r\n\r\n await tool.handler(\r\n {\r\n slug: 'footer',\r\n versionId: 'v1',\r\n expectedUpdatedAt: '2026-01-02T00:00:00.000Z',\r\n },\r\n req as never,\r\n {},\r\n )\r\n\r\n expect(req.payload.restoreGlobalVersion).toHaveBeenCalled()\r\n })\r\n\r\n it('locale arg is forwarded to restoreGlobalVersion', async () => {\r\n const tool = createRestoreGlobalVersionTool(new Set(['footer']))!\r\n const req = buildReq()\r\n req.payload.restoreGlobalVersion.mockResolvedValue({})\r\n\r\n await tool.handler(\r\n { slug: 'footer', versionId: 'v1', locale: 'fr' },\r\n req as never,\r\n {},\r\n )\r\n\r\n expect(req.payload.restoreGlobalVersion).toHaveBeenCalledWith(\r\n expect.objectContaining({ slug: 'footer', id: 'v1', locale: 'fr' }),\r\n )\r\n })\r\n})\r\n"],"names":["describe","it","expect","vi","createPublishGlobalDraftTool","createListGlobalVersionsTool","createRestoreGlobalVersionTool","buildReq","payload","updateGlobal","fn","findGlobal","findGlobalVersions","restoreGlobalVersion","logger","info","warn","error","context","user","Set","toBeNull","tool","req","mockResolvedValue","result","handler","slug","toHaveBeenCalledWith","objectContaining","data","_status","overrideAccess","content","text","toMatch","not","toHaveBeenCalled","mockRejectedValue","Error","totalDocs","docs","id","updatedAt","createdAt","version","limit","sort","body","JSON","parse","versions","toHaveLength","toBe","status","versionId","expectedUpdatedAt","locale"],"mappings":"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"}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import crypto from 'crypto';
|
|
2
|
-
import { describe, it, expect } from 'vitest';
|
|
3
|
-
import { hashKey, verifyHash, extractBearerToken } from '../hash';
|
|
4
|
-
describe('hashKey', ()=>{
|
|
5
|
-
it('returns 64-char hex output', ()=>{
|
|
6
|
-
const out = hashKey('mcp_live_abcdefghijklmnopqrstuv', 'super-secret');
|
|
7
|
-
expect(out).toMatch(/^[a-f0-9]{64}$/);
|
|
8
|
-
});
|
|
9
|
-
it('matches the upstream/Payload-internal HMAC formula so v0.3.x rows still authenticate', ()=>{
|
|
10
|
-
const plaintext = 'some-existing-api-key';
|
|
11
|
-
const secret = 'shared-secret';
|
|
12
|
-
const expected = crypto.createHmac('sha256', secret).update(plaintext).digest('hex');
|
|
13
|
-
expect(hashKey(plaintext, secret)).toBe(expected);
|
|
14
|
-
});
|
|
15
|
-
it('is deterministic for the same inputs', ()=>{
|
|
16
|
-
expect(hashKey('a', 's')).toBe(hashKey('a', 's'));
|
|
17
|
-
});
|
|
18
|
-
it('produces different outputs for different secrets', ()=>{
|
|
19
|
-
expect(hashKey('a', 's1')).not.toBe(hashKey('a', 's2'));
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
describe('verifyHash', ()=>{
|
|
23
|
-
it('returns true for matching hashes', ()=>{
|
|
24
|
-
const a = hashKey('x', 's');
|
|
25
|
-
expect(verifyHash(a, a)).toBe(true);
|
|
26
|
-
});
|
|
27
|
-
it('returns false for non-matching hashes', ()=>{
|
|
28
|
-
expect(verifyHash(hashKey('x', 's'), hashKey('y', 's'))).toBe(false);
|
|
29
|
-
});
|
|
30
|
-
it('returns false on length mismatch without throwing', ()=>{
|
|
31
|
-
expect(verifyHash('a', 'ab')).toBe(false);
|
|
32
|
-
});
|
|
33
|
-
it('returns false on non-string input', ()=>{
|
|
34
|
-
expect(verifyHash(undefined, 'ab')).toBe(false);
|
|
35
|
-
expect(verifyHash('ab', null)).toBe(false);
|
|
36
|
-
});
|
|
37
|
-
it('returns false on empty strings', ()=>{
|
|
38
|
-
expect(verifyHash('', '')).toBe(false);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
describe('extractBearerToken', ()=>{
|
|
42
|
-
it('returns the trimmed token for a valid Bearer header', ()=>{
|
|
43
|
-
expect(extractBearerToken('Bearer abc-123')).toBe('abc-123');
|
|
44
|
-
expect(extractBearerToken('Bearer spaced-token ')).toBe('spaced-token');
|
|
45
|
-
});
|
|
46
|
-
it('returns null for non-Bearer schemes', ()=>{
|
|
47
|
-
expect(extractBearerToken('Basic abc')).toBeNull();
|
|
48
|
-
expect(extractBearerToken('users API-Key abc')).toBeNull();
|
|
49
|
-
});
|
|
50
|
-
it('returns null for missing or empty header values', ()=>{
|
|
51
|
-
expect(extractBearerToken(undefined)).toBeNull();
|
|
52
|
-
expect(extractBearerToken(null)).toBeNull();
|
|
53
|
-
expect(extractBearerToken('')).toBeNull();
|
|
54
|
-
expect(extractBearerToken('Bearer ')).toBeNull();
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
//# sourceMappingURL=hash.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/__tests__/hash.test.ts"],"sourcesContent":["import crypto from 'crypto'\r\nimport { describe, it, expect } from 'vitest'\r\nimport { hashKey, verifyHash, extractBearerToken } from '../hash'\r\n\r\ndescribe('hashKey', () => {\r\n it('returns 64-char hex output', () => {\r\n const out = hashKey('mcp_live_abcdefghijklmnopqrstuv', 'super-secret')\r\n expect(out).toMatch(/^[a-f0-9]{64}$/)\r\n })\r\n\r\n it('matches the upstream/Payload-internal HMAC formula so v0.3.x rows still authenticate', () => {\r\n const plaintext = 'some-existing-api-key'\r\n const secret = 'shared-secret'\r\n const expected = crypto.createHmac('sha256', secret).update(plaintext).digest('hex')\r\n expect(hashKey(plaintext, secret)).toBe(expected)\r\n })\r\n\r\n it('is deterministic for the same inputs', () => {\r\n expect(hashKey('a', 's')).toBe(hashKey('a', 's'))\r\n })\r\n\r\n it('produces different outputs for different secrets', () => {\r\n expect(hashKey('a', 's1')).not.toBe(hashKey('a', 's2'))\r\n })\r\n})\r\n\r\ndescribe('verifyHash', () => {\r\n it('returns true for matching hashes', () => {\r\n const a = hashKey('x', 's')\r\n expect(verifyHash(a, a)).toBe(true)\r\n })\r\n\r\n it('returns false for non-matching hashes', () => {\r\n expect(verifyHash(hashKey('x', 's'), hashKey('y', 's'))).toBe(false)\r\n })\r\n\r\n it('returns false on length mismatch without throwing', () => {\r\n expect(verifyHash('a', 'ab')).toBe(false)\r\n })\r\n\r\n it('returns false on non-string input', () => {\r\n expect(verifyHash(undefined as unknown as string, 'ab')).toBe(false)\r\n expect(verifyHash('ab', null as unknown as string)).toBe(false)\r\n })\r\n\r\n it('returns false on empty strings', () => {\r\n expect(verifyHash('', '')).toBe(false)\r\n })\r\n})\r\n\r\ndescribe('extractBearerToken', () => {\r\n it('returns the trimmed token for a valid Bearer header', () => {\r\n expect(extractBearerToken('Bearer abc-123')).toBe('abc-123')\r\n expect(extractBearerToken('Bearer spaced-token ')).toBe('spaced-token')\r\n })\r\n\r\n it('returns null for non-Bearer schemes', () => {\r\n expect(extractBearerToken('Basic abc')).toBeNull()\r\n expect(extractBearerToken('users API-Key abc')).toBeNull()\r\n })\r\n\r\n it('returns null for missing or empty header values', () => {\r\n expect(extractBearerToken(undefined)).toBeNull()\r\n expect(extractBearerToken(null)).toBeNull()\r\n expect(extractBearerToken('')).toBeNull()\r\n expect(extractBearerToken('Bearer ')).toBeNull()\r\n })\r\n})\r\n"],"names":["crypto","describe","it","expect","hashKey","verifyHash","extractBearerToken","out","toMatch","plaintext","secret","expected","createHmac","update","digest","toBe","not","a","undefined","toBeNull"],"mappings":"AAAA,OAAOA,YAAY,SAAQ;AAC3B,SAASC,QAAQ,EAAEC,EAAE,EAAEC,MAAM,QAAQ,SAAQ;AAC7C,SAASC,OAAO,EAAEC,UAAU,EAAEC,kBAAkB,QAAQ,UAAS;AAEjEL,SAAS,WAAW;IAClBC,GAAG,8BAA8B;QAC/B,MAAMK,MAAMH,QAAQ,mCAAmC;QACvDD,OAAOI,KAAKC,OAAO,CAAC;IACtB;IAEAN,GAAG,wFAAwF;QACzF,MAAMO,YAAY;QAClB,MAAMC,SAAS;QACf,MAAMC,WAAWX,OAAOY,UAAU,CAAC,UAAUF,QAAQG,MAAM,CAACJ,WAAWK,MAAM,CAAC;QAC9EX,OAAOC,QAAQK,WAAWC,SAASK,IAAI,CAACJ;IAC1C;IAEAT,GAAG,wCAAwC;QACzCC,OAAOC,QAAQ,KAAK,MAAMW,IAAI,CAACX,QAAQ,KAAK;IAC9C;IAEAF,GAAG,oDAAoD;QACrDC,OAAOC,QAAQ,KAAK,OAAOY,GAAG,CAACD,IAAI,CAACX,QAAQ,KAAK;IACnD;AACF;AAEAH,SAAS,cAAc;IACrBC,GAAG,oCAAoC;QACrC,MAAMe,IAAIb,QAAQ,KAAK;QACvBD,OAAOE,WAAWY,GAAGA,IAAIF,IAAI,CAAC;IAChC;IAEAb,GAAG,yCAAyC;QAC1CC,OAAOE,WAAWD,QAAQ,KAAK,MAAMA,QAAQ,KAAK,OAAOW,IAAI,CAAC;IAChE;IAEAb,GAAG,qDAAqD;QACtDC,OAAOE,WAAW,KAAK,OAAOU,IAAI,CAAC;IACrC;IAEAb,GAAG,qCAAqC;QACtCC,OAAOE,WAAWa,WAAgC,OAAOH,IAAI,CAAC;QAC9DZ,OAAOE,WAAW,MAAM,OAA4BU,IAAI,CAAC;IAC3D;IAEAb,GAAG,kCAAkC;QACnCC,OAAOE,WAAW,IAAI,KAAKU,IAAI,CAAC;IAClC;AACF;AAEAd,SAAS,sBAAsB;IAC7BC,GAAG,uDAAuD;QACxDC,OAAOG,mBAAmB,mBAAmBS,IAAI,CAAC;QAClDZ,OAAOG,mBAAmB,4BAA4BS,IAAI,CAAC;IAC7D;IAEAb,GAAG,uCAAuC;QACxCC,OAAOG,mBAAmB,cAAca,QAAQ;QAChDhB,OAAOG,mBAAmB,sBAAsBa,QAAQ;IAC1D;IAEAjB,GAAG,mDAAmD;QACpDC,OAAOG,mBAAmBY,YAAYC,QAAQ;QAC9ChB,OAAOG,mBAAmB,OAAOa,QAAQ;QACzChB,OAAOG,mBAAmB,KAAKa,QAAQ;QACvChB,OAAOG,mBAAmB,YAAYa,QAAQ;IAChD;AACF"}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { mcpToolkitPlugin } from '../index';
|
|
3
|
-
function baseConfig() {
|
|
4
|
-
return {
|
|
5
|
-
serverURL: 'https://app.example.com',
|
|
6
|
-
secret: 'test-secret',
|
|
7
|
-
admin: {
|
|
8
|
-
user: 'users'
|
|
9
|
-
},
|
|
10
|
-
collections: [
|
|
11
|
-
{
|
|
12
|
-
slug: 'users',
|
|
13
|
-
auth: true,
|
|
14
|
-
fields: [
|
|
15
|
-
{
|
|
16
|
-
name: 'email',
|
|
17
|
-
type: 'email',
|
|
18
|
-
required: true
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
slug: 'posts',
|
|
24
|
-
fields: [
|
|
25
|
-
{
|
|
26
|
-
name: 'title',
|
|
27
|
-
type: 'text'
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'slug',
|
|
31
|
-
type: 'text'
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
],
|
|
36
|
-
endpoints: []
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
describe('mcpToolkitPlugin integration', ()=>{
|
|
40
|
-
it('appends the api-keys collection and the MCP endpoints additively', ()=>{
|
|
41
|
-
const cfg = mcpToolkitPlugin()(baseConfig());
|
|
42
|
-
const slugs = (cfg.collections ?? []).map((c)=>c.slug);
|
|
43
|
-
expect(slugs).toContain('payload-mcp-api-keys');
|
|
44
|
-
expect(slugs).toContain('users');
|
|
45
|
-
expect(slugs).toContain('posts');
|
|
46
|
-
const endpointPaths = (cfg.endpoints ?? []).map((e)=>`${e.method.toUpperCase()} ${e.path}`);
|
|
47
|
-
expect(endpointPaths).toEqual(expect.arrayContaining([
|
|
48
|
-
'POST /mcp',
|
|
49
|
-
'GET /mcp'
|
|
50
|
-
]));
|
|
51
|
-
});
|
|
52
|
-
it('attaches the bearer strategy to the user collection without losing existing auth config', ()=>{
|
|
53
|
-
const cfg = mcpToolkitPlugin()(baseConfig());
|
|
54
|
-
const users = (cfg.collections ?? []).find((c)=>c.slug === 'users');
|
|
55
|
-
expect(users).toBeDefined();
|
|
56
|
-
const names = users.auth.strategies?.map((s)=>s.name) ?? [];
|
|
57
|
-
expect(names).toContain('mcp-toolkit-bearer');
|
|
58
|
-
});
|
|
59
|
-
it('preserves existing auth.strategies on the user collection', ()=>{
|
|
60
|
-
const cfg = baseConfig();
|
|
61
|
-
const otherStrategy = {
|
|
62
|
-
name: 'tenant-shared-strategy',
|
|
63
|
-
authenticate: async ()=>({
|
|
64
|
-
user: null
|
|
65
|
-
})
|
|
66
|
-
};
|
|
67
|
-
cfg.collections[0].auth = {
|
|
68
|
-
strategies: [
|
|
69
|
-
otherStrategy
|
|
70
|
-
]
|
|
71
|
-
};
|
|
72
|
-
const out = mcpToolkitPlugin()(cfg);
|
|
73
|
-
const users = (out.collections ?? []).find((c)=>c.slug === 'users');
|
|
74
|
-
const names = users.auth.strategies.map((s)=>s.name);
|
|
75
|
-
expect(names).toEqual([
|
|
76
|
-
'tenant-shared-strategy',
|
|
77
|
-
'mcp-toolkit-bearer'
|
|
78
|
-
]);
|
|
79
|
-
});
|
|
80
|
-
it('respects a custom user collection slug from incomingConfig.admin.user', ()=>{
|
|
81
|
-
const cfg = baseConfig();
|
|
82
|
-
cfg.admin = {
|
|
83
|
-
user: 'admins'
|
|
84
|
-
};
|
|
85
|
-
cfg.collections[0].slug = 'admins';
|
|
86
|
-
const out = mcpToolkitPlugin()(cfg);
|
|
87
|
-
const admins = (out.collections ?? []).find((c)=>c.slug === 'admins');
|
|
88
|
-
expect(admins.auth.strategies?.some((s)=>s.name === 'mcp-toolkit-bearer')).toBe(true);
|
|
89
|
-
});
|
|
90
|
-
it('throws when @payloadcms/plugin-mcp appears to also be registered', ()=>{
|
|
91
|
-
const cfg = baseConfig();
|
|
92
|
-
function mcpPlugin() {}
|
|
93
|
-
;
|
|
94
|
-
cfg.plugins = [
|
|
95
|
-
mcpPlugin
|
|
96
|
-
];
|
|
97
|
-
expect(()=>mcpToolkitPlugin()(cfg)).toThrow(/standalone successor/);
|
|
98
|
-
});
|
|
99
|
-
it('throws when an existing collection takes the api-keys slug', ()=>{
|
|
100
|
-
const cfg = baseConfig();
|
|
101
|
-
cfg.collections.push({
|
|
102
|
-
slug: 'payload-mcp-api-keys',
|
|
103
|
-
fields: []
|
|
104
|
-
});
|
|
105
|
-
expect(()=>mcpToolkitPlugin()(cfg)).toThrow(/payload-mcp-api-keys/);
|
|
106
|
-
});
|
|
107
|
-
it('honours a custom apiKeyCollection.slug', ()=>{
|
|
108
|
-
const cfg = mcpToolkitPlugin({
|
|
109
|
-
apiKeyCollection: {
|
|
110
|
-
slug: 'my-keys'
|
|
111
|
-
}
|
|
112
|
-
})(baseConfig());
|
|
113
|
-
const slugs = (cfg.collections ?? []).map((c)=>c.slug);
|
|
114
|
-
expect(slugs).toContain('my-keys');
|
|
115
|
-
expect(slugs).not.toContain('payload-mcp-api-keys');
|
|
116
|
-
});
|
|
117
|
-
it('a host config with no globals still registers the globalScopes field (matrix shows empty state)', ()=>{
|
|
118
|
-
const cfg = mcpToolkitPlugin()(baseConfig());
|
|
119
|
-
// The field always renders under Custom; the matrix component reports
|
|
120
|
-
// the absence via its own empty-state copy when availableGlobals is [].
|
|
121
|
-
const apiKeys = (cfg.collections ?? []).find((c)=>c.slug === 'payload-mcp-api-keys');
|
|
122
|
-
const globalScopes = apiKeys.fields.find((f)=>f.name === 'globalScopes');
|
|
123
|
-
expect(globalScopes.admin?.condition?.({
|
|
124
|
-
preset: 'custom'
|
|
125
|
-
})).toBe(true);
|
|
126
|
-
expect(globalScopes.admin?.condition?.({
|
|
127
|
-
preset: 'editor'
|
|
128
|
-
})).toBe(false);
|
|
129
|
-
expect(globalScopes.admin?.components?.Field?.clientProps?.availableGlobals).toEqual([]);
|
|
130
|
-
});
|
|
131
|
-
it('a host config with one plain global makes globalScopes UI render under Custom', ()=>{
|
|
132
|
-
const cfg = baseConfig();
|
|
133
|
-
cfg.globals = [
|
|
134
|
-
{
|
|
135
|
-
slug: 'site-settings',
|
|
136
|
-
fields: [
|
|
137
|
-
{
|
|
138
|
-
name: 'siteName',
|
|
139
|
-
type: 'text'
|
|
140
|
-
}
|
|
141
|
-
]
|
|
142
|
-
}
|
|
143
|
-
];
|
|
144
|
-
const out = mcpToolkitPlugin()(cfg);
|
|
145
|
-
const apiKeys = (out.collections ?? []).find((c)=>c.slug === 'payload-mcp-api-keys');
|
|
146
|
-
const globalScopes = apiKeys.fields.find((f)=>f.name === 'globalScopes');
|
|
147
|
-
expect(globalScopes.admin?.condition?.({
|
|
148
|
-
preset: 'custom'
|
|
149
|
-
})).toBe(true);
|
|
150
|
-
expect(globalScopes.admin?.components?.Field?.clientProps?.availableGlobals).toEqual([
|
|
151
|
-
'site-settings'
|
|
152
|
-
]);
|
|
153
|
-
});
|
|
154
|
-
it('excluded globals are filtered out of availableGlobals at registration time', ()=>{
|
|
155
|
-
const cfg = baseConfig();
|
|
156
|
-
cfg.globals = [
|
|
157
|
-
{
|
|
158
|
-
slug: 'site-settings',
|
|
159
|
-
fields: [
|
|
160
|
-
{
|
|
161
|
-
name: 'siteName',
|
|
162
|
-
type: 'text'
|
|
163
|
-
}
|
|
164
|
-
]
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
slug: 'secret-config',
|
|
168
|
-
fields: [
|
|
169
|
-
{
|
|
170
|
-
name: 'token',
|
|
171
|
-
type: 'text'
|
|
172
|
-
}
|
|
173
|
-
]
|
|
174
|
-
}
|
|
175
|
-
];
|
|
176
|
-
const out = mcpToolkitPlugin({
|
|
177
|
-
exclude: {
|
|
178
|
-
globals: [
|
|
179
|
-
'secret-config'
|
|
180
|
-
]
|
|
181
|
-
}
|
|
182
|
-
})(cfg);
|
|
183
|
-
const apiKeys = (out.collections ?? []).find((c)=>c.slug === 'payload-mcp-api-keys');
|
|
184
|
-
const globalScopes = apiKeys.fields.find((f)=>f.name === 'globalScopes');
|
|
185
|
-
expect(globalScopes.admin?.components?.Field?.clientProps?.availableGlobals).toEqual([
|
|
186
|
-
'site-settings'
|
|
187
|
-
]);
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
//# sourceMappingURL=index-integration.test.js.map
|