@kvasar/openclaw-storyblok-plugin 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +277 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +12 -4
- package/src/index.ts +0 -228
package/index.ts
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* index.ts — OpenClaw Storyblok Plugin
|
|
3
|
+
*
|
|
4
|
+
* Tools for interacting with Storyblok Management API and Delivery API.
|
|
5
|
+
* Authentication:
|
|
6
|
+
* - managementToken required for write operations
|
|
7
|
+
* - previewToken optional for read operations
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Type } from "@sinclair/typebox";
|
|
11
|
+
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
12
|
+
|
|
13
|
+
import { StoryblokClient } from "./src/client.js";
|
|
14
|
+
import { validateConfig, redactTokens } from "./src/config.js";
|
|
15
|
+
|
|
16
|
+
interface StoryblokPluginConfig {
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
spaceId?: string;
|
|
19
|
+
managementToken?: string;
|
|
20
|
+
previewToken?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function ok(data: unknown) {
|
|
24
|
+
return {
|
|
25
|
+
content: [
|
|
26
|
+
{
|
|
27
|
+
type: "text",
|
|
28
|
+
text: JSON.stringify(data, null, 2),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
metadata: { storyblok: true },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function fail(error: unknown) {
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: `❌ Storyblok: ${String(error)}`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function safeError(error: unknown, cfg: StoryblokPluginConfig) {
|
|
48
|
+
return fail(
|
|
49
|
+
redactTokens(String((error as any)?.message ?? error), cfg)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default definePluginEntry({
|
|
54
|
+
id: "openclaw-storyblok",
|
|
55
|
+
name: "Storyblok Integration",
|
|
56
|
+
description:
|
|
57
|
+
"Interact with Storyblok CMS: manage stories, components, and space information.",
|
|
58
|
+
|
|
59
|
+
register(api) {
|
|
60
|
+
const rawCfg = (
|
|
61
|
+
(api as { pluginConfig?: unknown; config?: unknown }).pluginConfig ??
|
|
62
|
+
(api as { pluginConfig?: unknown; config?: unknown }).config ??
|
|
63
|
+
{}
|
|
64
|
+
) as StoryblokPluginConfig;
|
|
65
|
+
|
|
66
|
+
const cfg: StoryblokPluginConfig = {
|
|
67
|
+
baseUrl: rawCfg.baseUrl ?? "https://api.storyblok.com",
|
|
68
|
+
spaceId: rawCfg.spaceId,
|
|
69
|
+
managementToken: rawCfg.managementToken,
|
|
70
|
+
previewToken: rawCfg.previewToken,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
validateConfig(cfg);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.warn(
|
|
77
|
+
"[openclaw-storyblok] Config validation warning:",
|
|
78
|
+
error
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const client = new StoryblokClient(cfg);
|
|
83
|
+
|
|
84
|
+
api.registerTool({
|
|
85
|
+
name: "storyblok_get_space",
|
|
86
|
+
description: "Retrieve Storyblok space details.",
|
|
87
|
+
parameters: Type.Object({}),
|
|
88
|
+
async execute() {
|
|
89
|
+
try {
|
|
90
|
+
return ok(await client.getSpace());
|
|
91
|
+
} catch (error) {
|
|
92
|
+
return safeError(error, cfg);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
api.registerTool({
|
|
98
|
+
name: "storyblok_get_story",
|
|
99
|
+
description:
|
|
100
|
+
"Retrieve a story by ID, UUID, or slug.",
|
|
101
|
+
parameters: Type.Object({
|
|
102
|
+
identifier: Type.String({
|
|
103
|
+
description: "Story ID, UUID, or slug",
|
|
104
|
+
}),
|
|
105
|
+
version: Type.Optional(
|
|
106
|
+
Type.String({
|
|
107
|
+
description: "'draft' or 'published'",
|
|
108
|
+
})
|
|
109
|
+
),
|
|
110
|
+
language: Type.Optional(Type.String()),
|
|
111
|
+
svg_render: Type.Optional(Type.Boolean()),
|
|
112
|
+
}),
|
|
113
|
+
async execute(
|
|
114
|
+
_id: string,
|
|
115
|
+
params: {
|
|
116
|
+
identifier: string;
|
|
117
|
+
version?: string;
|
|
118
|
+
language?: string;
|
|
119
|
+
svg_render?: boolean;
|
|
120
|
+
}
|
|
121
|
+
) {
|
|
122
|
+
try {
|
|
123
|
+
return ok(
|
|
124
|
+
await client.getStory(params.identifier, {
|
|
125
|
+
version: params.version,
|
|
126
|
+
language: params.language,
|
|
127
|
+
svg_render: params.svg_render,
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
return safeError(error, cfg);
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
api.registerTool({
|
|
137
|
+
name: "storyblok_list_stories",
|
|
138
|
+
description: "List stories with optional filters.",
|
|
139
|
+
parameters: Type.Object({
|
|
140
|
+
folder_id: Type.Optional(Type.Number()),
|
|
141
|
+
parent_id: Type.Optional(Type.Number()),
|
|
142
|
+
status: Type.Optional(Type.String()),
|
|
143
|
+
tag: Type.Optional(Type.String()),
|
|
144
|
+
per_page: Type.Optional(Type.Number()),
|
|
145
|
+
page: Type.Optional(Type.Number()),
|
|
146
|
+
sort_by: Type.Optional(Type.String()),
|
|
147
|
+
direction: Type.Optional(Type.String()),
|
|
148
|
+
}),
|
|
149
|
+
async execute(_id: string, params: Record<string, any>) {
|
|
150
|
+
try {
|
|
151
|
+
return ok(await client.listStories(params));
|
|
152
|
+
} catch (error) {
|
|
153
|
+
return safeError(error, cfg);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
api.registerTool({
|
|
159
|
+
name: "storyblok_create_story",
|
|
160
|
+
description: "Create a new story.",
|
|
161
|
+
parameters: Type.Object({
|
|
162
|
+
title: Type.String(),
|
|
163
|
+
slug: Type.Optional(Type.String()),
|
|
164
|
+
folder_id: Type.Optional(Type.Number()),
|
|
165
|
+
parent_id: Type.Optional(Type.Number()),
|
|
166
|
+
content: Type.Optional(
|
|
167
|
+
Type.Record(Type.String(), Type.Any())
|
|
168
|
+
),
|
|
169
|
+
tags: Type.Optional(Type.Array(Type.String())),
|
|
170
|
+
is_folder: Type.Optional(Type.Boolean()),
|
|
171
|
+
language: Type.Optional(Type.String()),
|
|
172
|
+
}),
|
|
173
|
+
async execute(_id: string, params: Record<string, any>) {
|
|
174
|
+
try {
|
|
175
|
+
return ok(await client.createStory(params));
|
|
176
|
+
} catch (error) {
|
|
177
|
+
return safeError(error, cfg);
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
api.registerTool({
|
|
183
|
+
name: "storyblok_update_story",
|
|
184
|
+
description: "Update an existing story.",
|
|
185
|
+
parameters: Type.Object({
|
|
186
|
+
story_id: Type.String(),
|
|
187
|
+
title: Type.Optional(Type.String()),
|
|
188
|
+
slug: Type.Optional(Type.String()),
|
|
189
|
+
content: Type.Optional(
|
|
190
|
+
Type.Record(Type.String(), Type.Any())
|
|
191
|
+
),
|
|
192
|
+
parent_id: Type.Optional(Type.Number()),
|
|
193
|
+
tags: Type.Optional(Type.Array(Type.String())),
|
|
194
|
+
language: Type.Optional(Type.String()),
|
|
195
|
+
version: Type.Optional(Type.String()),
|
|
196
|
+
}),
|
|
197
|
+
async execute(_id: string, params: Record<string, any>) {
|
|
198
|
+
try {
|
|
199
|
+
return ok(
|
|
200
|
+
await client.updateStory(
|
|
201
|
+
params.story_id,
|
|
202
|
+
params
|
|
203
|
+
)
|
|
204
|
+
);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
return safeError(error, cfg);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
api.registerTool({
|
|
212
|
+
name: "storyblok_publish_story",
|
|
213
|
+
description: "Publish a story.",
|
|
214
|
+
parameters: Type.Object({
|
|
215
|
+
story_id: Type.String(),
|
|
216
|
+
version: Type.Optional(Type.String()),
|
|
217
|
+
language: Type.Optional(Type.String()),
|
|
218
|
+
publish_notes: Type.Optional(Type.String()),
|
|
219
|
+
}),
|
|
220
|
+
async execute(_id: string, params: Record<string, any>) {
|
|
221
|
+
try {
|
|
222
|
+
return ok(
|
|
223
|
+
await client.publishStory(params.story_id, {
|
|
224
|
+
version: params.version,
|
|
225
|
+
language: params.language,
|
|
226
|
+
publish_notes: params.publish_notes,
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
return safeError(error, cfg);
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
api.registerTool({
|
|
236
|
+
name: "storyblok_unpublish_story",
|
|
237
|
+
description: "Unpublish a story.",
|
|
238
|
+
parameters: Type.Object({
|
|
239
|
+
story_id: Type.String(),
|
|
240
|
+
language: Type.Optional(Type.String()),
|
|
241
|
+
}),
|
|
242
|
+
async execute(_id: string, params: Record<string, any>) {
|
|
243
|
+
try {
|
|
244
|
+
return ok(
|
|
245
|
+
await client.unpublishStory(
|
|
246
|
+
params.story_id,
|
|
247
|
+
params.language
|
|
248
|
+
)
|
|
249
|
+
);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
return safeError(error, cfg);
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
api.registerTool({
|
|
257
|
+
name: "storyblok_get_components",
|
|
258
|
+
description: "Get component schemas.",
|
|
259
|
+
parameters: Type.Object({
|
|
260
|
+
version: Type.Optional(Type.String()),
|
|
261
|
+
language: Type.Optional(Type.String()),
|
|
262
|
+
}),
|
|
263
|
+
async execute(_id: string, params: Record<string, any>) {
|
|
264
|
+
try {
|
|
265
|
+
return ok(
|
|
266
|
+
await client.getComponents(
|
|
267
|
+
params.version,
|
|
268
|
+
params.language
|
|
269
|
+
)
|
|
270
|
+
);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
return safeError(error, cfg);
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
},
|
|
277
|
+
});
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "openclaw-storyblok",
|
|
3
3
|
"kind": "tool",
|
|
4
4
|
"name": "Storyblok Integration",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.1",
|
|
6
6
|
"description": "Provides tools to interact with Storyblok CMS via Management API and Delivery API. Supports stories, components, and space management.",
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kvasar/openclaw-storyblok-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "OpenClaw plugin — interact with Storyblok CMS via Management API and Delivery API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"index.ts",
|
|
9
9
|
"src/",
|
|
10
10
|
"openclaw.plugin.json",
|
|
11
|
+
"skills/",
|
|
11
12
|
"tsconfig.json",
|
|
12
13
|
"README.md"
|
|
13
14
|
],
|
|
@@ -19,7 +20,9 @@
|
|
|
19
20
|
"check": "tsc --noEmit && vitest run"
|
|
20
21
|
},
|
|
21
22
|
"openclaw": {
|
|
22
|
-
"extensions": [
|
|
23
|
+
"extensions": [
|
|
24
|
+
"./index.ts"
|
|
25
|
+
],
|
|
23
26
|
"tools": [
|
|
24
27
|
"storyblok_get_space",
|
|
25
28
|
"storyblok_get_story",
|
|
@@ -39,6 +42,11 @@
|
|
|
39
42
|
"@types/node": "^22.0.0",
|
|
40
43
|
"vitest": "^1.6.0"
|
|
41
44
|
},
|
|
42
|
-
"keywords": [
|
|
45
|
+
"keywords": [
|
|
46
|
+
"openclaw",
|
|
47
|
+
"plugin",
|
|
48
|
+
"storyblok",
|
|
49
|
+
"cms"
|
|
50
|
+
],
|
|
43
51
|
"license": "MIT"
|
|
44
|
-
}
|
|
52
|
+
}
|
package/src/index.ts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* index.ts — OpenClaw Storyblok Plugin
|
|
3
|
-
*
|
|
4
|
-
* Tools for interacting with Storyblok Management API and Delivery API.
|
|
5
|
-
* Authentication: Management token required for writes; preview token optional for reads.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { Type } from "@sinclair/typebox";
|
|
9
|
-
import { StoryblokClient } from "./client.js";
|
|
10
|
-
import { validateConfig, redactTokens } from "./config.js";
|
|
11
|
-
|
|
12
|
-
const definePluginEntry = <T>(def: T): T => def;
|
|
13
|
-
|
|
14
|
-
// Shared response helpers
|
|
15
|
-
function ok(data: any) {
|
|
16
|
-
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], metadata: { storyblok: true } };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function fail(error: string) {
|
|
20
|
-
return { content: [{ type: "text", text: `❌ Storyblok: ${error}` }], isError: true };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default definePluginEntry({
|
|
24
|
-
id: "openclaw-storyblok",
|
|
25
|
-
name: "Storyblok Integration",
|
|
26
|
-
description: "Interact with Storyblok CMS: manage stories, components, and space information.",
|
|
27
|
-
register(api: { config?: unknown; registerTool: (def: any, opts?: { optional?: boolean }) => void }) {
|
|
28
|
-
const rawCfg = (api.config ?? {}) as Record<string, any>;
|
|
29
|
-
validateConfig(rawCfg);
|
|
30
|
-
const cfg = {
|
|
31
|
-
baseUrl: rawCfg.baseUrl ?? "https://api.storyblok.com",
|
|
32
|
-
spaceId: rawCfg.spaceId,
|
|
33
|
-
managementToken: rawCfg.managementToken,
|
|
34
|
-
previewToken: rawCfg.previewToken,
|
|
35
|
-
};
|
|
36
|
-
const client = new StoryblokClient(cfg);
|
|
37
|
-
|
|
38
|
-
// ── storyblok_get_space ─────────────────────────────────────────────────────
|
|
39
|
-
api.registerTool({
|
|
40
|
-
name: "storyblok_get_space",
|
|
41
|
-
description: "Retrieve Storyblok space details.",
|
|
42
|
-
parameters: Type.Object({}),
|
|
43
|
-
async execute(_id: string, _params: {}) {
|
|
44
|
-
try {
|
|
45
|
-
const result = await client.getSpace();
|
|
46
|
-
return ok(result);
|
|
47
|
-
} catch (e: any) {
|
|
48
|
-
return fail(redactTokens(e.message, cfg));
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// ── storyblok_get_story ─────────────────────────────────────────────────────
|
|
54
|
-
api.registerTool({
|
|
55
|
-
name: "storyblok_get_story",
|
|
56
|
-
description: "Retrieve a story by ID, UUID, or slug. Use preview token for published version, management token for draft.",
|
|
57
|
-
parameters: Type.Object({
|
|
58
|
-
identifier: Type.String({ description: "Story ID, UUID, or slug" }),
|
|
59
|
-
version: Type.Optional(Type.String({ description: "Version to fetch: 'draft' (default) or 'published'" })),
|
|
60
|
-
language: Type.Optional(Type.String({ description: "Language code (e.g., 'en') for multilingual spaces" })),
|
|
61
|
-
svg_render: Type.Optional(Type.Boolean({ description: "If true, returns SVG render of the story (experimental)" })),
|
|
62
|
-
}),
|
|
63
|
-
async execute(_id: string, params: { identifier: string; version?: string; language?: string; svg_render?: boolean }) {
|
|
64
|
-
try {
|
|
65
|
-
const result = await client.getStory(params.identifier, { version: params.version, language: params.language, svg_render: params.svg_render });
|
|
66
|
-
return ok(result);
|
|
67
|
-
} catch (e: any) {
|
|
68
|
-
return fail(redactTokens(e.message, cfg));
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// ── storyblok_list_stories ───────────────────────────────────────────────────
|
|
74
|
-
api.registerTool({
|
|
75
|
-
name: "storyblok_list_stories",
|
|
76
|
-
description: "List stories with optional filters (folder, status, tags, etc.).",
|
|
77
|
-
parameters: Type.Object({
|
|
78
|
-
folder_id: Type.Optional(Type.Number({ description: "Filter by folder ID" })),
|
|
79
|
-
parent_id: Type.Optional(Type.Number({ description: "Filter by parent story ID" })),
|
|
80
|
-
status: Type.Optional(Type.String({ description: "Filter by status: 'draft', 'published'" })),
|
|
81
|
-
tag: Type.Optional(Type.String({ description: "Filter by tag" })),
|
|
82
|
-
per_page: Type.Optional(Type.Number({ description: "Number of results per page (max 100)", minimum: 1, maximum: 100 })),
|
|
83
|
-
page: Type.Optional(Type.Number({ description: "Page number (starting from 1)", minimum: 1 })),
|
|
84
|
-
sort_by: Type.Optional(Type.String({ description: "Sort field (e.g., 'created_at', 'published_at')" })),
|
|
85
|
-
direction: Type.Optional(Type.String({ description: "Sort direction: 'asc' or 'desc'" })),
|
|
86
|
-
}),
|
|
87
|
-
async execute(_id: string, params: {
|
|
88
|
-
folder_id?: number;
|
|
89
|
-
parent_id?: number;
|
|
90
|
-
status?: string;
|
|
91
|
-
tag?: string;
|
|
92
|
-
per_page?: number;
|
|
93
|
-
page?: number;
|
|
94
|
-
sort_by?: string;
|
|
95
|
-
direction?: string;
|
|
96
|
-
}) {
|
|
97
|
-
try {
|
|
98
|
-
const result = await client.listStories(params);
|
|
99
|
-
return ok(result);
|
|
100
|
-
} catch (e: any) {
|
|
101
|
-
return fail(redactTokens(e.message, cfg));
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// ── storyblok_create_story ───────────────────────────────────────────────────
|
|
107
|
-
api.registerTool({
|
|
108
|
-
name: "storyblok_create_story",
|
|
109
|
-
description: "Create a new story (optionally in a folder). By default creates a draft.",
|
|
110
|
-
parameters: Type.Object({
|
|
111
|
-
title: Type.String({ description: "Story title" }),
|
|
112
|
-
slug: Type.Optional(Type.String({ description: "URL slug (autogenerated if omitted)" })),
|
|
113
|
-
folder_id: Type.Optional(Type.Number({ description: "Folder ID to place the story in" })),
|
|
114
|
-
parent_id: Type.Optional(Type.Number({ description: "Parent story ID for nested stories" })),
|
|
115
|
-
content: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
116
|
-
tags: Type.Optional(Type.Array(Type.String())),
|
|
117
|
-
is_folder: Type.Optional(Type.Boolean({ description: "If true, creates a folder instead of a story" })),
|
|
118
|
-
language: Type.Optional(Type.String({ description: "Language code for multilingual spaces" })),
|
|
119
|
-
}),
|
|
120
|
-
async execute(_id: string, params: {
|
|
121
|
-
title: string;
|
|
122
|
-
slug?: string;
|
|
123
|
-
folder_id?: number;
|
|
124
|
-
parent_id?: number;
|
|
125
|
-
content?: Record<string, any>;
|
|
126
|
-
tags?: string[];
|
|
127
|
-
is_folder?: boolean;
|
|
128
|
-
language?: string;
|
|
129
|
-
}) {
|
|
130
|
-
try {
|
|
131
|
-
const result = await client.createStory(params);
|
|
132
|
-
return ok(result);
|
|
133
|
-
} catch (e: any) {
|
|
134
|
-
return fail(redactTokens(e.message, cfg));
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// ── storyblok_update_story ───────────────────────────────────────────────────
|
|
140
|
-
api.registerTool({
|
|
141
|
-
name: "storyblok_update_story",
|
|
142
|
-
description: "Update a story (draft or published). Use with caution on published stories.",
|
|
143
|
-
parameters: Type.Object({
|
|
144
|
-
story_id: Type.String({ description: "Story ID or UUID" }),
|
|
145
|
-
title: Type.Optional(Type.String({ description: "New title" })),
|
|
146
|
-
slug: Type.Optional(Type.String({ description: "New slug" })),
|
|
147
|
-
content: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
148
|
-
parent_id: Type.Optional(Type.Number({ description: "New parent ID" })),
|
|
149
|
-
tags: Type.Optional(Type.Array(Type.String())),
|
|
150
|
-
language: Type.Optional(Type.String({ description: "Language code" })),
|
|
151
|
-
version: Type.Optional(Type.String({ description: "Which version to update: 'draft' (default) or 'published'" })),
|
|
152
|
-
}),
|
|
153
|
-
async execute(_id: string, params: {
|
|
154
|
-
story_id: string;
|
|
155
|
-
title?: string;
|
|
156
|
-
slug?: string;
|
|
157
|
-
content?: Record<string, any>;
|
|
158
|
-
parent_id?: number;
|
|
159
|
-
tags?: string[];
|
|
160
|
-
language?: string;
|
|
161
|
-
version?: string;
|
|
162
|
-
}) {
|
|
163
|
-
try {
|
|
164
|
-
const result = await client.updateStory(params.story_id, params);
|
|
165
|
-
return ok(result);
|
|
166
|
-
} catch (e: any) {
|
|
167
|
-
return fail(redactTokens(e.message, cfg));
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
// ── storyblok_publish_story ──────────────────────────────────────────────────
|
|
173
|
-
api.registerTool({
|
|
174
|
-
name: "storyblok_publish_story",
|
|
175
|
-
description: "Publish a story (from draft). Optionally set a version note.",
|
|
176
|
-
parameters: Type.Object({
|
|
177
|
-
story_id: Type.String({ description: "Story ID or UUID" }),
|
|
178
|
-
version: Type.Optional(Type.String({ description: "Version to publish: usually 'draft' to publish the latest draft" })),
|
|
179
|
-
language: Type.Optional(Type.String({ description: "Language code" })),
|
|
180
|
-
publish_notes: Type.Optional(Type.String({ description: "Version note / changelog" })),
|
|
181
|
-
}),
|
|
182
|
-
async execute(_id: string, params: { story_id: string; version?: string; language?: string; publish_notes?: string }) {
|
|
183
|
-
try {
|
|
184
|
-
const result = await client.publishStory(params.story_id, { version: params.version, language: params.language, publish_notes: params.publish_notes });
|
|
185
|
-
return ok(result);
|
|
186
|
-
} catch (e: any) {
|
|
187
|
-
return fail(redactTokens(e.message, cfg));
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
// ── storyblok_unpublish_story ───────────────────────────────────────────────
|
|
193
|
-
api.registerTool({
|
|
194
|
-
name: "storyblok_unpublish_story",
|
|
195
|
-
description: "Unpublish a story (makes it draft-only).",
|
|
196
|
-
parameters: Type.Object({
|
|
197
|
-
story_id: Type.String({ description: "Story ID or UUID" }),
|
|
198
|
-
language: Type.Optional(Type.String({ description: "Language code" })),
|
|
199
|
-
}),
|
|
200
|
-
async execute(_id: string, params: { story_id: string; language?: string }) {
|
|
201
|
-
try {
|
|
202
|
-
const result = await client.unpublishStory(params.story_id, params.language);
|
|
203
|
-
return ok(result);
|
|
204
|
-
} catch (e: any) {
|
|
205
|
-
return fail(redactTokens(e.message, cfg));
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
// ── storyblok_get_components ─────────────────────────────────────────────────
|
|
211
|
-
api.registerTool({
|
|
212
|
-
name: "storyblok_get_components",
|
|
213
|
-
description: "Retrieve the list of component schemas (blok types) defined in the space.",
|
|
214
|
-
parameters: Type.Object({
|
|
215
|
-
version: Type.Optional(Type.String({ description: "Version: 'draft' (default) or 'published'" })),
|
|
216
|
-
language: Type.Optional(Type.String({ description: "Language code for localized component definitions" })),
|
|
217
|
-
}),
|
|
218
|
-
async execute(_id: string, params: { version?: string; language?: string }) {
|
|
219
|
-
try {
|
|
220
|
-
const result = await client.getComponents(params.version, params.language);
|
|
221
|
-
return ok(result);
|
|
222
|
-
} catch (e:any) {
|
|
223
|
-
return fail(redactTokens(e.message, cfg));
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
});
|
|
227
|
-
},
|
|
228
|
-
});
|