@storyblok/management-api-client 1.0.0-alpha.2 → 1.0.0-alpha.3

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.
@@ -1,44 +1,9 @@
1
- import {
2
- defineAssetFolderCreate,
3
- defineAssetFolderUpdate,
4
- defineBlockFolderCreate,
5
- defineBlockFolderUpdate,
6
- defineDatasourceCreate,
7
- defineDatasourceEntryCreate,
8
- defineDatasourceEntryUpdate,
9
- defineDatasourceUpdate,
10
- defineInternalTagCreate,
11
- defineInternalTagUpdate,
12
- definePresetCreate,
13
- definePresetUpdate,
14
- defineSpaceCreate,
15
- defineSpaceUpdate,
16
- defineUserUpdate,
17
- } from '@storyblok/schema';
18
1
  import { createManagementApiClient } from '@storyblok/management-api-client';
19
2
  import { describe, expectTypeOf, it } from 'vitest';
20
3
 
21
4
  const CLIENT_CONFIG = { personalAccessToken: 'test-token', spaceId: 12345 };
22
5
 
23
6
  describe('datasources type tests', () => {
24
- it('should produce a defineDatasourceCreate result assignable to datasources.create body', () => {
25
- const payload = defineDatasourceCreate({ name: 'Categories', slug: 'categories' });
26
-
27
- type CreateBody = Parameters<ReturnType<typeof createManagementApiClient>['datasources']['create']>[0]['body'];
28
- type InnerType = NonNullable<CreateBody['datasource']>;
29
-
30
- expectTypeOf(payload).toExtend<InnerType>();
31
- });
32
-
33
- it('should produce a defineDatasourceUpdate result assignable to datasources.update body', () => {
34
- const payload = defineDatasourceUpdate({ name: 'Updated Categories' });
35
-
36
- type UpdateBody = Parameters<ReturnType<typeof createManagementApiClient>['datasources']['update']>[1]['body'];
37
- type InnerType = NonNullable<UpdateBody['datasource']>;
38
-
39
- expectTypeOf(payload).toExtend<InnerType>();
40
- });
41
-
42
7
  it('should return datasource in response from create', async () => {
43
8
  const client = createManagementApiClient(CLIENT_CONFIG);
44
9
  const result = await client.datasources.create({
@@ -67,24 +32,6 @@ describe('datasources type tests', () => {
67
32
  });
68
33
 
69
34
  describe('datasource entries type tests', () => {
70
- it('should produce a defineDatasourceEntryCreate result assignable to datasourceEntries.create body', () => {
71
- const payload = defineDatasourceEntryCreate({ name: 'red', value: '#ff0000', datasource_id: 42 });
72
-
73
- type CreateBody = Parameters<ReturnType<typeof createManagementApiClient>['datasourceEntries']['create']>[0]['body'];
74
- type InnerType = NonNullable<CreateBody['datasource_entry']>;
75
-
76
- expectTypeOf(payload).toExtend<InnerType>();
77
- });
78
-
79
- it('should produce a defineDatasourceEntryUpdate result assignable to datasourceEntries.update body', () => {
80
- const payload = defineDatasourceEntryUpdate({ value: '#00ff00' });
81
-
82
- type UpdateBody = Parameters<ReturnType<typeof createManagementApiClient>['datasourceEntries']['update']>[1]['body'];
83
- type InnerType = NonNullable<UpdateBody['datasource_entry']>;
84
-
85
- expectTypeOf(payload).toExtend<InnerType>();
86
- });
87
-
88
35
  it('should return datasource_entry in response from create', async () => {
89
36
  const client = createManagementApiClient(CLIENT_CONFIG);
90
37
  const result = await client.datasourceEntries.create({
@@ -113,24 +60,6 @@ describe('datasource entries type tests', () => {
113
60
  });
114
61
 
115
62
  describe('asset folders type tests', () => {
116
- it('should produce a defineAssetFolderCreate result assignable to assetFolders.create body', () => {
117
- const payload = defineAssetFolderCreate({ name: 'Images' });
118
-
119
- type CreateBody = Parameters<ReturnType<typeof createManagementApiClient>['assetFolders']['create']>[0]['body'];
120
- type InnerType = NonNullable<CreateBody['asset_folder']>;
121
-
122
- expectTypeOf(payload).toExtend<InnerType>();
123
- });
124
-
125
- it('should produce a defineAssetFolderUpdate result assignable to assetFolders.update body', () => {
126
- const payload = defineAssetFolderUpdate({ name: 'Updated Images' });
127
-
128
- type UpdateBody = Parameters<ReturnType<typeof createManagementApiClient>['assetFolders']['update']>[1]['body'];
129
- type InnerType = NonNullable<UpdateBody['asset_folder']>;
130
-
131
- expectTypeOf(payload).toExtend<InnerType>();
132
- });
133
-
134
63
  it('should return asset_folder in response from create', async () => {
135
64
  const client = createManagementApiClient(CLIENT_CONFIG);
136
65
  const result = await client.assetFolders.create({
@@ -159,24 +88,6 @@ describe('asset folders type tests', () => {
159
88
  });
160
89
 
161
90
  describe('component folders type tests', () => {
162
- it('should produce a defineBlockFolderCreate result assignable to componentFolders.create body', () => {
163
- const payload = defineBlockFolderCreate({ name: 'Layout' });
164
-
165
- type CreateBody = Parameters<ReturnType<typeof createManagementApiClient>['componentFolders']['create']>[0]['body'];
166
- type InnerType = NonNullable<CreateBody['component_group']>;
167
-
168
- expectTypeOf(payload).toExtend<InnerType>();
169
- });
170
-
171
- it('should produce a defineBlockFolderUpdate result assignable to componentFolders.update body', () => {
172
- const payload = defineBlockFolderUpdate({ name: 'Updated Layout' });
173
-
174
- type UpdateBody = Parameters<ReturnType<typeof createManagementApiClient>['componentFolders']['update']>[1]['body'];
175
- type InnerType = NonNullable<UpdateBody['component_group']>;
176
-
177
- expectTypeOf(payload).toExtend<InnerType>();
178
- });
179
-
180
91
  it('should return component_group in response from create', async () => {
181
92
  const client = createManagementApiClient(CLIENT_CONFIG);
182
93
  const result = await client.componentFolders.create({
@@ -205,24 +116,6 @@ describe('component folders type tests', () => {
205
116
  });
206
117
 
207
118
  describe('internal tags type tests', () => {
208
- it('should produce a defineInternalTagCreate result assignable to internalTags.create body', () => {
209
- const payload = defineInternalTagCreate({ name: 'hero', object_type: 'asset' });
210
-
211
- type CreateBody = Parameters<ReturnType<typeof createManagementApiClient>['internalTags']['create']>[0]['body'];
212
- type InnerType = NonNullable<CreateBody['internal_tag']>;
213
-
214
- expectTypeOf(payload).toExtend<InnerType>();
215
- });
216
-
217
- it('should produce a defineInternalTagUpdate result assignable to internalTags.update body', () => {
218
- const payload = defineInternalTagUpdate({ name: 'hero-image' });
219
-
220
- type UpdateBody = Parameters<ReturnType<typeof createManagementApiClient>['internalTags']['update']>[1]['body'];
221
- type InnerType = NonNullable<UpdateBody['internal_tag']>;
222
-
223
- expectTypeOf(payload).toExtend<InnerType>();
224
- });
225
-
226
119
  it('should return internal_tag in response from create', async () => {
227
120
  const client = createManagementApiClient(CLIENT_CONFIG);
228
121
  const result = await client.internalTags.create({
@@ -243,24 +136,6 @@ describe('internal tags type tests', () => {
243
136
  });
244
137
 
245
138
  describe('presets type tests', () => {
246
- it('should produce a definePresetCreate result assignable to presets.create body', () => {
247
- const payload = definePresetCreate({ name: 'Hero Dark', component_id: 42 });
248
-
249
- type CreateBody = Parameters<ReturnType<typeof createManagementApiClient>['presets']['create']>[0]['body'];
250
- type InnerType = NonNullable<CreateBody['preset']>;
251
-
252
- expectTypeOf(payload).toExtend<InnerType>();
253
- });
254
-
255
- it('should produce a definePresetUpdate result assignable to presets.update body', () => {
256
- const payload = definePresetUpdate({ name: 'Hero Light' });
257
-
258
- type UpdateBody = Parameters<ReturnType<typeof createManagementApiClient>['presets']['update']>[1]['body'];
259
- type InnerType = NonNullable<UpdateBody['preset']>;
260
-
261
- expectTypeOf(payload).toExtend<InnerType>();
262
- });
263
-
264
139
  it('should return preset in response from create', async () => {
265
140
  const client = createManagementApiClient(CLIENT_CONFIG);
266
141
  const result = await client.presets.create({
@@ -289,24 +164,6 @@ describe('presets type tests', () => {
289
164
  });
290
165
 
291
166
  describe('spaces type tests', () => {
292
- it('should produce a defineSpaceCreate result assignable to spaces.create body', () => {
293
- const payload = defineSpaceCreate({ name: 'My New Space' });
294
-
295
- type CreateBody = Parameters<ReturnType<typeof createManagementApiClient>['spaces']['create']>[0]['body'];
296
- type InnerType = CreateBody['space'];
297
-
298
- expectTypeOf(payload).toExtend<InnerType>();
299
- });
300
-
301
- it('should produce a defineSpaceUpdate result assignable to spaces.update body', () => {
302
- const payload = defineSpaceUpdate({ name: 'Updated Space Name' });
303
-
304
- type UpdateBody = Parameters<ReturnType<typeof createManagementApiClient>['spaces']['update']>[0]['body'];
305
- type InnerType = UpdateBody['space'];
306
-
307
- expectTypeOf(payload).toExtend<InnerType>();
308
- });
309
-
310
167
  it('should return space in response from create', async () => {
311
168
  const client = createManagementApiClient(CLIENT_CONFIG);
312
169
  const result = await client.spaces.create({
@@ -335,15 +192,6 @@ describe('spaces type tests', () => {
335
192
  });
336
193
 
337
194
  describe('users type tests', () => {
338
- it('should produce a defineUserUpdate result assignable to users.updateMe body', () => {
339
- const payload = defineUserUpdate({ firstname: 'Jane', lastname: 'Doe' });
340
-
341
- type UpdateBody = Parameters<ReturnType<typeof createManagementApiClient>['users']['updateMe']>[0]['body'];
342
- type InnerType = UpdateBody['user'];
343
-
344
- expectTypeOf(payload).toExtend<InnerType>();
345
- });
346
-
347
195
  it('should return user in response from updateMe', async () => {
348
196
  const client = createManagementApiClient(CLIENT_CONFIG);
349
197
  const result = await client.users.updateMe({
@@ -1,11 +1,11 @@
1
- import { defineBlock, defineField, defineStoryCreate, defineStoryUpdate } from '@storyblok/schema';
1
+ import { defineBlock, defineField } from '@storyblok/schema';
2
2
  import { createManagementApiClient, type Story as StoryMapi } from '@storyblok/management-api-client';
3
3
  import { describe, expectTypeOf, it } from 'vitest';
4
4
 
5
5
  // Nestable block — not a root story type
6
6
  const teaserComponent = defineBlock({
7
7
  name: 'teaser',
8
- schema: [
8
+ fields: [
9
9
  defineField('text', { type: 'text' }),
10
10
  defineField('image', { type: 'asset' }),
11
11
  ],
@@ -18,7 +18,7 @@ const teaserComponent = defineBlock({
18
18
  const heroComponent = defineBlock({
19
19
  name: 'hero',
20
20
  is_root: true,
21
- schema: [
21
+ fields: [
22
22
  defineField('title', { type: 'text' }),
23
23
  defineField('count', { type: 'number' }),
24
24
  // bloks field without a whitelist — resolves to nestable components only
@@ -34,12 +34,12 @@ const _pageComponent = defineBlock({
34
34
  name: 'page',
35
35
  is_root: true,
36
36
  is_nestable: false,
37
- schema: [
37
+ fields: [
38
38
  defineField('headline', { type: 'text' }),
39
39
  defineField('body', { type: 'richtext' }),
40
- defineField('teasers', { type: 'bloks', component_whitelist: [teaserComponent.name] }),
41
- defineField('hero', { type: 'bloks', component_whitelist: [heroComponent.name] }),
42
- defineField('blocks', { type: 'bloks', component_whitelist: [heroComponent.name, teaserComponent.name] }),
40
+ defineField('teasers', { type: 'bloks', allow: [teaserComponent.name] }),
41
+ defineField('hero', { type: 'bloks', allow: [heroComponent.name] }),
42
+ defineField('blocks', { type: 'bloks', allow: [heroComponent.name, teaserComponent.name] }),
43
43
  ],
44
44
  id: 0,
45
45
  created_at: '',
@@ -237,36 +237,7 @@ describe('createManagementApiClient with .withTypes()', () => {
237
237
  });
238
238
  });
239
239
 
240
- describe('defineStoryCreate / defineStoryUpdate combined with mapi client', () => {
241
- it('should produce a defineStoryCreate result accepted by untyped stories.create', async () => {
242
- const createPayload = defineStoryCreate(_pageComponent, {
243
- name: 'My Page',
244
- content: { headline: 'Hello' },
245
- });
246
-
247
- const client = createManagementApiClient(CLIENT_CONFIG);
248
- await client.stories.create({ body: { story: createPayload } });
249
- });
250
-
251
- it('should produce a defineStoryUpdate result accepted by untyped stories.update', async () => {
252
- const updatePayload = defineStoryUpdate(_pageComponent, {
253
- content: { headline: 'Updated' },
254
- });
255
-
256
- const client = createManagementApiClient(CLIENT_CONFIG);
257
- await client.stories.update(1, { body: { story: updatePayload } });
258
- });
259
-
260
- it('should produce a defineStoryCreate result for hero component accepted by untyped stories.create', async () => {
261
- const createPayload = defineStoryCreate(heroComponent, {
262
- name: 'My Hero',
263
- content: { title: 'Welcome', count: 42, sections: [] },
264
- });
265
-
266
- const client = createManagementApiClient(CLIENT_CONFIG);
267
- await client.stories.create({ body: { story: createPayload } });
268
- });
269
-
240
+ describe('withTypes() write-body narrowing', () => {
270
241
  it('should reject nestable-only component name in create body content', () => {
271
242
  const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
272
243
  client.stories.create({
@@ -295,11 +266,7 @@ describe('defineStoryCreate / defineStoryUpdate combined with mapi client', () =
295
266
  expectTypeOf(story.content.component).toEqualTypeOf<'page' | 'hero'>();
296
267
 
297
268
  if (story.content.component === 'page') {
298
- const updatePayload = defineStoryUpdate(_pageComponent, {
299
- name: story.name,
300
- content: { headline: story.content.headline ?? 'Default' },
301
- });
302
- expectTypeOf(updatePayload).toMatchTypeOf<{ name?: string | null }>();
269
+ expectTypeOf(story.content.headline).toEqualTypeOf<string | null | undefined>();
303
270
  }
304
271
  }
305
272
  });
package/test/GUIDE.md CHANGED
@@ -48,7 +48,7 @@ node packages/cli/dist/index.mjs components push \
48
48
 
49
49
  **Always push components before stories.** The CLI validates that each story's `content.component` (and any nested block components) exist in the space. Pushing stories first fails if the referenced components are not yet present.
50
50
 
51
- You can do the same with stories and `defineStory`. **Story filename convention:** the CLI requires files named `{slug}_{uuid}.json` where the part after the last `_` exactly matches `story.uuid` in the JSON. Use hyphens (not underscores) in UUIDs. A mismatch causes Pass 2 of the push (reference mapping + content update) to silently skip all stories.
51
+ You can do the same with stories. **Story filename convention:** the CLI requires files named `{slug}_{uuid}.json` where the part after the last `_` exactly matches `story.uuid` in the JSON. Use hyphens (not underscores) in UUIDs. A mismatch causes Pass 2 of the push (reference mapping + content update) to silently skip all stories.
52
52
 
53
53
  ## Known quirks
54
54
 
@@ -56,4 +56,4 @@ You can do the same with stories and `defineStory`. **Story filename convention:
56
56
  - **MAPI `stories.get` takes a positional ID, not an options object:** `client.stories.get(id)` — there is no `getBySlug`. The `list` response does not include `content`; call `get(id)` for full content.
57
57
  - **MAPI client constructor uses `personalAccessToken`:** `createManagementApiClient({ personalAccessToken: '...', spaceId: ... })`.
58
58
  - **Delete methods are `delete`:** Use `client.RESOURCE.delete(id)`.
59
- - **Each story JSON must have a unique `id`.** `defineStory` defaults `id` to `1`. If multiple story files share the same `id`, the CLI's manifest maps all of them to the same `old_id` entry, causing "slug already taken" errors.
59
+ - **Each story JSON must have a unique `id`.** If multiple story files share the same `id`, the CLI's manifest maps all of them to the same `old_id` entry, causing "slug already taken" errors.