@webiny/mcp 6.1.0 → 6.2.0-beta.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/index.d.ts +2 -0
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/package.json +4 -4
- package/skills/admin/admin-permissions/SKILL.md +227 -73
- package/skills/admin/ui-extensions/SKILL.md +11 -42
- package/skills/api/api-architect/SKILL.md +2 -1
- package/skills/api/http-route/SKILL.md +176 -0
- package/skills/api/permissions/SKILL.md +141 -59
- package/skills/dependency-injection/SKILL.md +200 -2
- package/skills/generated/admin/SKILL.md +6 -16
- package/skills/generated/admin/cms/SKILL.md +39 -1
- package/skills/generated/admin/languages/SKILL.md +29 -0
- package/skills/generated/admin/security/SKILL.md +34 -1
- package/skills/generated/admin/ui/SKILL.md +21 -1
- package/skills/generated/admin/website-builder/SKILL.md +16 -1
- package/skills/generated/api/SKILL.md +58 -1
- package/skills/generated/api/cms/SKILL.md +111 -1
- package/skills/generated/api/db/SKILL.md +34 -0
- package/skills/generated/api/languages/SKILL.md +31 -0
- package/skills/generated/api/security/SKILL.md +26 -1
- package/skills/local-development/SKILL.md +1 -1
- package/skills/webiny-sdk/SKILL.md +174 -60
|
@@ -6,8 +6,9 @@ description: >
|
|
|
6
6
|
Use this skill when the developer is building a Next.js, Vue, Node.js, or any external app
|
|
7
7
|
that needs to fetch or write content to Webiny, set up the SDK, use the Result pattern,
|
|
8
8
|
list/get/create/update/publish entries, filter and sort queries, use TypeScript generics
|
|
9
|
-
for type safety, work with the File Manager, or create API keys programmatically.
|
|
10
|
-
|
|
9
|
+
for type safety, work with the File Manager, list languages, or create API keys programmatically.
|
|
10
|
+
Covers read vs preview mode, the `values` wrapper requirement, correct method names,
|
|
11
|
+
and the `fields` required parameter.
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
# Webiny SDK
|
|
@@ -26,9 +27,9 @@ Initialize once and reuse:
|
|
|
26
27
|
|
|
27
28
|
```typescript
|
|
28
29
|
// lib/webiny.ts
|
|
29
|
-
import {
|
|
30
|
+
import { Webiny } from "@webiny/sdk";
|
|
30
31
|
|
|
31
|
-
export const
|
|
32
|
+
export const webiny = new Webiny({
|
|
32
33
|
token: process.env.WEBINY_API_TOKEN!,
|
|
33
34
|
endpoint: process.env.WEBINY_API_ENDPOINT!,
|
|
34
35
|
tenant: process.env.WEBINY_API_TENANT || "root"
|
|
@@ -36,30 +37,50 @@ export const sdk = new Sdk({
|
|
|
36
37
|
```
|
|
37
38
|
|
|
38
39
|
- `token` -- API key token generated in Webiny Admin (Settings > API Keys)
|
|
39
|
-
- `endpoint` -- The base
|
|
40
|
+
- `endpoint` -- The base API URL, **without a trailing slash**. Run `yarn webiny info` in your Webiny project to find the API URL. For Website Builder projects use `NEXT_PUBLIC_WEBSITE_BUILDER_API_HOST`.
|
|
40
41
|
- `tenant` -- Tenant ID, defaults to `"root"`
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
> **IMPORTANT:** Never add a trailing slash to `endpoint`. The SDK appends `/graphql` to the endpoint internally, so `https://xxx.cloudfront.net/` will break all requests.
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
## The `fields` Parameter (Required)
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
| ----------- | -------------- | ------------------------------------- | --------- | ----------------------------- |
|
|
48
|
-
| **Read** | `/cms/read` | Published entries only | No | Public-facing apps, SSG |
|
|
49
|
-
| **Manage** | `/cms/manage` | All revisions (drafts + published) | Yes | Admin tools, content creation |
|
|
50
|
-
| **Preview** | `/cms/preview` | Latest revisions (drafts + published) | No | Content preview |
|
|
47
|
+
Every SDK method requires a `fields` array that specifies which fields to return. Omitting it will cause a runtime error.
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
- Use `"values.<fieldId>"` for content fields: `"values.name"`, `"values.price"`
|
|
50
|
+
- Use top-level field names for metadata: `"id"`, `"entryId"`, `"createdOn"`, `"status"`
|
|
51
|
+
- Use dot notation for nested fields: `"values.author.name"`
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
```typescript
|
|
54
|
+
// Minimal fields -- just IDs
|
|
55
|
+
fields: ["id", "entryId"];
|
|
56
|
+
|
|
57
|
+
// Content fields
|
|
58
|
+
fields: ["id", "entryId", "values.name", "values.price", "values.description"];
|
|
59
|
+
|
|
60
|
+
// Nested reference fields
|
|
61
|
+
fields: ["id", "values.title", "values.author.name", "values.author.email"];
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## CMS: Read vs Preview Mode
|
|
65
|
+
|
|
66
|
+
`webiny.cms.listEntries` and `webiny.cms.getEntry` accept a `preview` parameter to control which revisions are returned:
|
|
67
|
+
|
|
68
|
+
| `preview` | Returns | Use For |
|
|
69
|
+
| ----------------- | ------------------------------------ | -------------------------------- |
|
|
70
|
+
| `false` (default) | Published entries only | Public-facing apps, SSG |
|
|
71
|
+
| `true` | Latest revision (draft or published) | Content preview, editorial tools |
|
|
72
|
+
|
|
73
|
+
Write operations (`createEntry`, `updateEntryRevision`, etc.) are not affected by `preview`.
|
|
56
74
|
|
|
57
75
|
## The Result Pattern
|
|
58
76
|
|
|
59
77
|
Every SDK method returns a `Result` object -- it never throws:
|
|
60
78
|
|
|
61
79
|
```typescript
|
|
62
|
-
const result = await
|
|
80
|
+
const result = await webiny.cms.listEntries({
|
|
81
|
+
modelId: "product",
|
|
82
|
+
fields: ["id", "values.name"]
|
|
83
|
+
});
|
|
63
84
|
|
|
64
85
|
if (result.isOk()) {
|
|
65
86
|
console.log(result.value.data); // success -- typed data
|
|
@@ -88,8 +109,9 @@ interface ProductCategory {
|
|
|
88
109
|
slug: string;
|
|
89
110
|
}
|
|
90
111
|
|
|
91
|
-
const result = await
|
|
92
|
-
modelId: "product"
|
|
112
|
+
const result = await webiny.cms.listEntries<Product>({
|
|
113
|
+
modelId: "product",
|
|
114
|
+
fields: ["id", "entryId", "values.name", "values.price", "values.sku"]
|
|
93
115
|
});
|
|
94
116
|
|
|
95
117
|
if (result.isOk()) {
|
|
@@ -106,9 +128,10 @@ Reference fields like `category` are typed as `CmsEntryData<T>`, which wraps ref
|
|
|
106
128
|
### List Entries
|
|
107
129
|
|
|
108
130
|
```typescript
|
|
109
|
-
const result = await
|
|
131
|
+
const result = await webiny.cms.listEntries<Product>({
|
|
110
132
|
modelId: "product",
|
|
111
|
-
|
|
133
|
+
fields: ["id", "entryId", "values.name", "values.price"],
|
|
134
|
+
sort: { "values.name": "asc" },
|
|
112
135
|
limit: 10
|
|
113
136
|
});
|
|
114
137
|
```
|
|
@@ -116,13 +139,14 @@ const result = await sdk.cms.listEntries<Product>({
|
|
|
116
139
|
### List with Filters
|
|
117
140
|
|
|
118
141
|
```typescript
|
|
119
|
-
const result = await
|
|
142
|
+
const result = await webiny.cms.listEntries<Product>({
|
|
120
143
|
modelId: "product",
|
|
144
|
+
fields: ["id", "entryId", "values.name", "values.price"],
|
|
121
145
|
where: {
|
|
122
146
|
"values.price_gte": 100,
|
|
123
147
|
"values.name_contains": "Pro"
|
|
124
148
|
},
|
|
125
|
-
sort:
|
|
149
|
+
sort: { "values.price": "desc" }
|
|
126
150
|
});
|
|
127
151
|
```
|
|
128
152
|
|
|
@@ -140,78 +164,151 @@ const result = await sdk.cms.listEntries<Product>({
|
|
|
140
164
|
|
|
141
165
|
### Sort Format
|
|
142
166
|
|
|
143
|
-
Sort
|
|
167
|
+
Sort is a `Record<string, "asc" | "desc">` object:
|
|
144
168
|
|
|
145
169
|
```typescript
|
|
146
|
-
sort:
|
|
147
|
-
sort:
|
|
148
|
-
sort:
|
|
170
|
+
sort: { "values.name": "asc" } // alphabetical
|
|
171
|
+
sort: { "values.price": "desc" } // highest price first
|
|
172
|
+
sort: { "values.createdOn": "desc" } // newest first
|
|
149
173
|
```
|
|
150
174
|
|
|
151
175
|
### Get Single Entry
|
|
152
176
|
|
|
177
|
+
Use `where` with either `id` (revision ID) or `entryId`:
|
|
178
|
+
|
|
153
179
|
```typescript
|
|
154
|
-
|
|
180
|
+
// By revision ID
|
|
181
|
+
const result = await webiny.cms.getEntry<Product>({
|
|
155
182
|
modelId: "product",
|
|
156
|
-
id: "abc123#0001"
|
|
183
|
+
where: { id: "abc123#0001" },
|
|
184
|
+
fields: ["id", "entryId", "values.name", "values.price"]
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// By entry ID (gets latest published revision)
|
|
188
|
+
const result = await webiny.cms.getEntry<Product>({
|
|
189
|
+
modelId: "product",
|
|
190
|
+
where: { entryId: "abc123" },
|
|
191
|
+
fields: ["id", "entryId", "values.name"]
|
|
157
192
|
});
|
|
158
193
|
```
|
|
159
194
|
|
|
160
|
-
###
|
|
195
|
+
### Preview Mode (Drafts)
|
|
161
196
|
|
|
162
|
-
|
|
197
|
+
Pass `preview: true` to `listEntries` or `getEntry` to access unpublished/draft content:
|
|
163
198
|
|
|
164
199
|
```typescript
|
|
165
|
-
const result = await
|
|
200
|
+
const result = await webiny.cms.listEntries<Product>({
|
|
166
201
|
modelId: "product",
|
|
167
|
-
fields: ["id", "
|
|
202
|
+
fields: ["id", "entryId", "values.name"],
|
|
203
|
+
preview: true // returns drafts + published
|
|
168
204
|
});
|
|
169
205
|
```
|
|
170
206
|
|
|
171
|
-
When omitted, all fields are returned. The `depth` parameter (default: `1`) controls how deeply reference fields are resolved.
|
|
172
|
-
|
|
173
207
|
## Writing Data
|
|
174
208
|
|
|
209
|
+
> **CRITICAL:** Content fields MUST be wrapped inside a `values` key in the `data` object. Passing fields directly (without `values`) will result in an empty or malformed entry.
|
|
210
|
+
|
|
175
211
|
### Create an Entry
|
|
176
212
|
|
|
177
213
|
```typescript
|
|
178
|
-
const result = await
|
|
214
|
+
const result = await webiny.cms.createEntry({
|
|
179
215
|
modelId: "contactSubmission",
|
|
180
216
|
data: {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
217
|
+
values: {
|
|
218
|
+
// ← REQUIRED: wrap all content fields in `values`
|
|
219
|
+
name: "John Doe",
|
|
220
|
+
email: "john@example.com",
|
|
221
|
+
message: "Hello from the contact form!"
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
fields: ["id", "entryId"]
|
|
185
225
|
});
|
|
186
226
|
```
|
|
187
227
|
|
|
188
|
-
### Update an Entry
|
|
228
|
+
### Update an Entry Revision
|
|
229
|
+
|
|
230
|
+
The method is `updateEntryRevision`, not `updateEntry`. Use `revisionId` (the full `entryId#revisionNumber`, e.g. `"abc123#0001"`):
|
|
189
231
|
|
|
190
232
|
```typescript
|
|
191
|
-
const result = await
|
|
233
|
+
const result = await webiny.cms.updateEntryRevision({
|
|
192
234
|
modelId: "product",
|
|
193
|
-
|
|
235
|
+
revisionId: "abc123#0001", // ← note: revisionId, not id
|
|
194
236
|
data: {
|
|
195
|
-
|
|
196
|
-
|
|
237
|
+
values: {
|
|
238
|
+
// ← REQUIRED: wrap fields in `values`
|
|
239
|
+
price: 29.99
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
fields: ["id", "entryId", "values.price"]
|
|
197
243
|
});
|
|
198
244
|
```
|
|
199
245
|
|
|
200
246
|
### Publish / Unpublish
|
|
201
247
|
|
|
248
|
+
The methods are `publishEntryRevision` and `unpublishEntryRevision`, not `publishEntry`/`unpublishEntry`. Both require `revisionId` and `fields`:
|
|
249
|
+
|
|
202
250
|
```typescript
|
|
203
|
-
await
|
|
204
|
-
|
|
251
|
+
await webiny.cms.publishEntryRevision({
|
|
252
|
+
modelId: "product",
|
|
253
|
+
revisionId: "abc123#0001",
|
|
254
|
+
fields: ["id", "entryId", "status"]
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
await webiny.cms.unpublishEntryRevision({
|
|
258
|
+
modelId: "product",
|
|
259
|
+
revisionId: "abc123#0001",
|
|
260
|
+
fields: ["id", "entryId", "status"]
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Delete an Entry Revision
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
await webiny.cms.deleteEntryRevision({
|
|
268
|
+
modelId: "product",
|
|
269
|
+
revisionId: "abc123#0001",
|
|
270
|
+
fields: []
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Languages
|
|
275
|
+
|
|
276
|
+
`webiny.languages.listLanguages()` returns all **enabled** languages — disabled languages are always filtered out server-side, so no filter parameter is needed.
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import type { Language } from "@webiny/sdk";
|
|
280
|
+
|
|
281
|
+
const result = await webiny.languages.listLanguages();
|
|
282
|
+
|
|
283
|
+
if (result.isOk()) {
|
|
284
|
+
const languages: Language[] = result.value;
|
|
285
|
+
// languages[0].code, .name, .direction, .isDefault
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The `Language` type:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
interface Language {
|
|
293
|
+
id: string;
|
|
294
|
+
code: string; // e.g. "en-US"
|
|
295
|
+
name: string; // e.g. "English (US)"
|
|
296
|
+
direction?: "ltr" | "rtl";
|
|
297
|
+
isDefault?: boolean;
|
|
298
|
+
}
|
|
205
299
|
```
|
|
206
300
|
|
|
207
301
|
## File Manager
|
|
208
302
|
|
|
209
303
|
```typescript
|
|
210
304
|
// List files
|
|
211
|
-
const files = await
|
|
305
|
+
const files = await webiny.fileManager.listFiles({
|
|
306
|
+
limit: 20,
|
|
307
|
+
fields: ["id", "key", "name", "size", "type", "src"]
|
|
308
|
+
});
|
|
212
309
|
|
|
213
|
-
// Upload a file
|
|
214
|
-
const uploaded = await
|
|
310
|
+
// Upload a file (returns presigned URL for direct S3 upload)
|
|
311
|
+
const uploaded = await webiny.fileManager.uploadFile({ file: myFile });
|
|
215
312
|
```
|
|
216
313
|
|
|
217
314
|
## Creating API Keys via Code
|
|
@@ -249,21 +346,38 @@ Register (**YOU MUST include the `.ts` file extension in the `src` prop** — om
|
|
|
249
346
|
|
|
250
347
|
## SDK Modules Reference
|
|
251
348
|
|
|
252
|
-
| Module
|
|
253
|
-
|
|
|
254
|
-
| `
|
|
255
|
-
| `
|
|
256
|
-
| `
|
|
349
|
+
| Module | Webiny App | What You Can Do |
|
|
350
|
+
| ---------------------- | ------------- | --------------------------------------------------------------------- |
|
|
351
|
+
| `webiny.cms` | Headless CMS | List, get, create, update, publish, unpublish, delete entry revisions |
|
|
352
|
+
| `webiny.fileManager` | File Manager | List, upload, and manage files and folders |
|
|
353
|
+
| `webiny.tenantManager` | Multi-tenancy | Create, install, enable, disable tenants |
|
|
354
|
+
| `webiny.languages` | Languages | List enabled languages (id, code, name, direction, isDefault) |
|
|
355
|
+
|
|
356
|
+
## Common Mistakes
|
|
357
|
+
|
|
358
|
+
| Mistake | Correct |
|
|
359
|
+
| --------------------------- | --------------------------------------- |
|
|
360
|
+
| `data: { name: "..." }` | `data: { values: { name: "..." } }` |
|
|
361
|
+
| `updateEntry(...)` | `updateEntryRevision(...)` |
|
|
362
|
+
| `publishEntry(...)` | `publishEntryRevision(...)` |
|
|
363
|
+
| `unpublishEntry(...)` | `unpublishEntryRevision(...)` |
|
|
364
|
+
| `sort: ["values.name_ASC"]` | `sort: { "values.name": "asc" }` |
|
|
365
|
+
| `getEntry({ id: "..." })` | `getEntry({ where: { id: "..." } })` |
|
|
366
|
+
| Omitting `fields` | Always provide `fields: [...]` |
|
|
367
|
+
| Trailing slash in endpoint | Remove trailing slash from endpoint URL |
|
|
257
368
|
|
|
258
369
|
## Quick Reference
|
|
259
370
|
|
|
260
371
|
```
|
|
261
|
-
Install:
|
|
262
|
-
Import:
|
|
263
|
-
Type import:
|
|
264
|
-
Initialize:
|
|
265
|
-
Result check:
|
|
266
|
-
API endpoint:
|
|
372
|
+
Install: npm install @webiny/sdk
|
|
373
|
+
Import: import { Webiny } from "@webiny/sdk";
|
|
374
|
+
Type import: import type { CmsEntryData } from "@webiny/sdk";
|
|
375
|
+
Initialize: new Webiny({ token, endpoint, tenant })
|
|
376
|
+
Result check: result.isOk() -> result.value.data / result.error.message
|
|
377
|
+
API endpoint: yarn webiny info (in your Webiny project) -- NO trailing slash
|
|
378
|
+
Preview mode: pass preview: true to listEntries / getEntry
|
|
379
|
+
fields required: every method needs a fields: string[] array
|
|
380
|
+
values wrapper: createEntry/updateEntryRevision data must use { values: { ... } }
|
|
267
381
|
```
|
|
268
382
|
|
|
269
383
|
## Related Skills
|