@storyblok/management-api-client 0.5.1 → 0.6.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/README.md +3 -1
- package/dist/client.cjs +196 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +761 -0
- package/dist/client.d.mts +761 -0
- package/dist/client.mjs +195 -0
- package/dist/client.mjs.map +1 -0
- package/dist/error.cjs.map +1 -1
- package/dist/error.d.cts +12 -2
- package/dist/error.d.mts +12 -2
- package/dist/error.mjs.map +1 -1
- package/dist/generated/mapi/_internal.gen.d.cts +371 -0
- package/dist/generated/mapi/_internal.gen.d.mts +371 -0
- package/dist/generated/{shared → mapi}/client/client.gen.cjs +1 -1
- package/dist/generated/mapi/client/client.gen.cjs.map +1 -0
- package/dist/generated/{shared → mapi}/client/client.gen.mjs +1 -1
- package/dist/generated/mapi/client/client.gen.mjs.map +1 -0
- package/dist/generated/{shared → mapi}/client/types.gen.d.cts +1 -1
- package/dist/generated/{shared → mapi}/client/types.gen.d.mts +1 -1
- package/dist/generated/{shared → mapi}/client/utils.gen.cjs +1 -1
- package/dist/generated/mapi/client/utils.gen.cjs.map +1 -0
- package/dist/generated/{shared → mapi}/client/utils.gen.d.cts +1 -1
- package/dist/generated/{shared → mapi}/client/utils.gen.d.mts +1 -1
- package/dist/generated/{shared → mapi}/client/utils.gen.mjs +1 -1
- package/dist/generated/mapi/client/utils.gen.mjs.map +1 -0
- package/dist/generated/mapi/client.gen.cjs +10 -0
- package/dist/generated/mapi/client.gen.cjs.map +1 -0
- package/dist/generated/mapi/client.gen.mjs +10 -0
- package/dist/generated/mapi/client.gen.mjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/auth.gen.cjs +1 -1
- package/dist/generated/mapi/core/auth.gen.cjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/auth.gen.d.cts +1 -1
- package/dist/generated/{shared → mapi}/core/auth.gen.d.mts +1 -1
- package/dist/generated/{shared → mapi}/core/auth.gen.mjs +1 -1
- package/dist/generated/mapi/core/auth.gen.mjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/bodySerializer.gen.cjs +1 -1
- package/dist/generated/mapi/core/bodySerializer.gen.cjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/bodySerializer.gen.d.cts +1 -1
- package/dist/generated/{shared → mapi}/core/bodySerializer.gen.d.mts +1 -1
- package/dist/generated/{shared → mapi}/core/bodySerializer.gen.mjs +1 -1
- package/dist/generated/mapi/core/bodySerializer.gen.mjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/params.gen.cjs +1 -1
- package/dist/generated/mapi/core/params.gen.cjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/params.gen.mjs +1 -1
- package/dist/generated/mapi/core/params.gen.mjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/pathSerializer.gen.cjs +1 -1
- package/dist/generated/mapi/core/pathSerializer.gen.cjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/pathSerializer.gen.d.cts +1 -1
- package/dist/generated/{shared → mapi}/core/pathSerializer.gen.d.mts +1 -1
- package/dist/generated/{shared → mapi}/core/pathSerializer.gen.mjs +1 -1
- package/dist/generated/mapi/core/pathSerializer.gen.mjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/serverSentEvents.gen.cjs +1 -1
- package/dist/generated/mapi/core/serverSentEvents.gen.cjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/serverSentEvents.gen.d.cts +1 -1
- package/dist/generated/{shared → mapi}/core/serverSentEvents.gen.d.mts +1 -1
- package/dist/generated/{shared → mapi}/core/serverSentEvents.gen.mjs +1 -1
- package/dist/generated/mapi/core/serverSentEvents.gen.mjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/types.gen.d.cts +1 -1
- package/dist/generated/{shared → mapi}/core/types.gen.d.mts +1 -1
- package/dist/generated/{shared → mapi}/core/utils.gen.cjs +1 -1
- package/dist/generated/mapi/core/utils.gen.cjs.map +1 -0
- package/dist/generated/{shared → mapi}/core/utils.gen.mjs +1 -1
- package/dist/generated/mapi/core/utils.gen.mjs.map +1 -0
- package/dist/generated/mapi/sdk.gen.cjs +1477 -0
- package/dist/generated/mapi/sdk.gen.cjs.map +1 -0
- package/dist/generated/mapi/sdk.gen.mjs +1399 -0
- package/dist/generated/mapi/sdk.gen.mjs.map +1 -0
- package/dist/generated/mapi/types-aliased.gen.d.cts +1598 -0
- package/dist/generated/mapi/types-aliased.gen.d.mts +1598 -0
- package/dist/generated/mapi/types.gen.d.cts +5075 -0
- package/dist/generated/mapi/types.gen.d.mts +5075 -0
- package/dist/generated/overlay/_internal.gen.d.cts +850 -0
- package/dist/generated/overlay/_internal.gen.d.mts +850 -0
- package/dist/generated/types/_utils.d.cts +7 -0
- package/dist/generated/types/_utils.d.mts +7 -0
- package/dist/generated/types/block.d.cts +55 -0
- package/dist/generated/types/block.d.mts +55 -0
- package/dist/generated/types/field.d.cts +122 -0
- package/dist/generated/types/field.d.mts +122 -0
- package/dist/generated/types/mapi-story.d.cts +29 -0
- package/dist/generated/types/mapi-story.d.mts +29 -0
- package/dist/index.cjs +3 -181
- package/dist/index.d.cts +12 -650
- package/dist/index.d.mts +12 -649
- package/dist/index.mjs +2 -179
- package/dist/resources/asset-folders.cjs +9 -9
- package/dist/resources/asset-folders.cjs.map +1 -1
- package/dist/resources/asset-folders.mjs +9 -9
- package/dist/resources/asset-folders.mjs.map +1 -1
- package/dist/resources/assets.cjs +57 -50
- package/dist/resources/assets.cjs.map +1 -1
- package/dist/resources/assets.d.cts +23 -27
- package/dist/resources/assets.d.mts +23 -27
- package/dist/resources/assets.mjs +57 -50
- package/dist/resources/assets.mjs.map +1 -1
- package/dist/resources/component-folders.cjs +9 -9
- package/dist/resources/component-folders.cjs.map +1 -1
- package/dist/resources/component-folders.mjs +9 -9
- package/dist/resources/component-folders.mjs.map +1 -1
- package/dist/resources/components.cjs +28 -20
- package/dist/resources/components.cjs.map +1 -1
- package/dist/resources/components.d.cts +76 -0
- package/dist/resources/components.d.mts +76 -0
- package/dist/resources/components.mjs +28 -20
- package/dist/resources/components.mjs.map +1 -1
- package/dist/resources/datasource-entries.cjs +28 -34
- package/dist/resources/datasource-entries.cjs.map +1 -1
- package/dist/resources/datasource-entries.mjs +29 -35
- package/dist/resources/datasource-entries.mjs.map +1 -1
- package/dist/resources/datasources.cjs +27 -9
- package/dist/resources/datasources.cjs.map +1 -1
- package/dist/resources/datasources.mjs +27 -9
- package/dist/resources/datasources.mjs.map +1 -1
- package/dist/resources/experiments.cjs +31 -31
- package/dist/resources/experiments.cjs.map +1 -1
- package/dist/resources/experiments.mjs +31 -31
- package/dist/resources/experiments.mjs.map +1 -1
- package/dist/resources/internal-tags.cjs +7 -7
- package/dist/resources/internal-tags.cjs.map +1 -1
- package/dist/resources/internal-tags.mjs +7 -7
- package/dist/resources/internal-tags.mjs.map +1 -1
- package/dist/resources/presets.cjs +9 -9
- package/dist/resources/presets.cjs.map +1 -1
- package/dist/resources/presets.mjs +9 -9
- package/dist/resources/presets.mjs.map +1 -1
- package/dist/resources/shared-asset-folders.cjs.map +1 -1
- package/dist/resources/shared-asset-folders.d.cts +1 -1
- package/dist/resources/shared-asset-folders.d.mts +1 -1
- package/dist/resources/shared-asset-folders.mjs.map +1 -1
- package/dist/resources/shared-assets.cjs.map +1 -1
- package/dist/resources/shared-assets.d.cts +2 -2
- package/dist/resources/shared-assets.d.mts +2 -2
- package/dist/resources/shared-assets.mjs.map +1 -1
- package/dist/resources/shared-internal-tags.cjs.map +1 -1
- package/dist/resources/shared-internal-tags.mjs.map +1 -1
- package/dist/resources/shared.cjs +15 -0
- package/dist/resources/shared.cjs.map +1 -1
- package/dist/resources/shared.mjs +15 -1
- package/dist/resources/shared.mjs.map +1 -1
- package/dist/resources/spaces.cjs +8 -7
- package/dist/resources/spaces.cjs.map +1 -1
- package/dist/resources/spaces.d.cts +8 -0
- package/dist/resources/spaces.d.mts +7 -0
- package/dist/resources/spaces.mjs +8 -7
- package/dist/resources/spaces.mjs.map +1 -1
- package/dist/resources/stories.cjs +20 -16
- package/dist/resources/stories.cjs.map +1 -1
- package/dist/resources/stories.d.cts +93 -0
- package/dist/resources/stories.d.mts +93 -0
- package/dist/resources/stories.mjs +20 -16
- package/dist/resources/stories.mjs.map +1 -1
- package/dist/resources/users.cjs +3 -3
- package/dist/resources/users.cjs.map +1 -1
- package/dist/resources/users.mjs +3 -3
- package/dist/resources/users.mjs.map +1 -1
- package/dist/utils/query-serializer.cjs +54 -0
- package/dist/utils/query-serializer.cjs.map +1 -0
- package/dist/utils/query-serializer.mjs +54 -0
- package/dist/utils/query-serializer.mjs.map +1 -0
- package/dist/utils/rate-limit.cjs +3 -7
- package/dist/utils/rate-limit.cjs.map +1 -1
- package/dist/utils/rate-limit.mjs +3 -6
- package/dist/utils/rate-limit.mjs.map +1 -1
- package/dist/utils/throttle.cjs +57 -0
- package/dist/utils/throttle.cjs.map +1 -0
- package/dist/utils/throttle.mjs +56 -0
- package/dist/utils/throttle.mjs.map +1 -0
- package/package.json +17 -16
- package/playground/integration-tests/README.md +24 -0
- package/playground/integration-tests/eslint.config.js +5 -0
- package/playground/integration-tests/node_modules/.bin/eslint +16 -0
- package/playground/integration-tests/node_modules/.bin/tsc +16 -0
- package/playground/integration-tests/node_modules/.bin/tsserver +16 -0
- package/playground/integration-tests/node_modules/.bin/vitest +16 -0
- package/playground/integration-tests/package.json +24 -0
- package/playground/integration-tests/test/setup.e2e.ts +11 -0
- package/playground/integration-tests/test/specs/mapi-round-trip.spec.e2e.ts +510 -0
- package/playground/integration-tests/test/types/components.test-d.ts +74 -0
- package/playground/integration-tests/test/types/resources.test-d.ts +212 -0
- package/playground/integration-tests/test/types/stories.test-d.ts +310 -0
- package/playground/integration-tests/vitest.config.e2e.ts +25 -0
- package/playground/integration-tests/vitest.config.ts +13 -0
- package/test/GUIDE.md +59 -0
- package/vitest.config.ts +5 -0
- package/dist/generated/asset_folders/client.gen.cjs +0 -10
- package/dist/generated/asset_folders/client.gen.cjs.map +0 -1
- package/dist/generated/asset_folders/client.gen.mjs +0 -10
- package/dist/generated/asset_folders/client.gen.mjs.map +0 -1
- package/dist/generated/asset_folders/sdk.gen.cjs +0 -99
- package/dist/generated/asset_folders/sdk.gen.cjs.map +0 -1
- package/dist/generated/asset_folders/sdk.gen.mjs +0 -95
- package/dist/generated/asset_folders/sdk.gen.mjs.map +0 -1
- package/dist/generated/asset_folders/types.gen.d.cts +0 -156
- package/dist/generated/asset_folders/types.gen.d.mts +0 -156
- package/dist/generated/assets/client.gen.cjs +0 -10
- package/dist/generated/assets/client.gen.cjs.map +0 -1
- package/dist/generated/assets/client.gen.mjs +0 -10
- package/dist/generated/assets/client.gen.mjs.map +0 -1
- package/dist/generated/assets/sdk.gen.cjs +0 -179
- package/dist/generated/assets/sdk.gen.cjs.map +0 -1
- package/dist/generated/assets/sdk.gen.mjs +0 -171
- package/dist/generated/assets/sdk.gen.mjs.map +0 -1
- package/dist/generated/assets/types.gen.d.cts +0 -415
- package/dist/generated/assets/types.gen.d.mts +0 -415
- package/dist/generated/component_folders/client.gen.cjs +0 -10
- package/dist/generated/component_folders/client.gen.cjs.map +0 -1
- package/dist/generated/component_folders/client.gen.mjs +0 -10
- package/dist/generated/component_folders/client.gen.mjs.map +0 -1
- package/dist/generated/component_folders/sdk.gen.cjs +0 -99
- package/dist/generated/component_folders/sdk.gen.cjs.map +0 -1
- package/dist/generated/component_folders/sdk.gen.mjs +0 -95
- package/dist/generated/component_folders/sdk.gen.mjs.map +0 -1
- package/dist/generated/component_folders/types.gen.d.cts +0 -118
- package/dist/generated/component_folders/types.gen.d.mts +0 -118
- package/dist/generated/components/client.gen.cjs +0 -10
- package/dist/generated/components/client.gen.cjs.map +0 -1
- package/dist/generated/components/client.gen.mjs +0 -10
- package/dist/generated/components/client.gen.mjs.map +0 -1
- package/dist/generated/components/sdk.gen.cjs +0 -171
- package/dist/generated/components/sdk.gen.cjs.map +0 -1
- package/dist/generated/components/sdk.gen.mjs +0 -163
- package/dist/generated/components/sdk.gen.mjs.map +0 -1
- package/dist/generated/components/types.gen.d.cts +0 -855
- package/dist/generated/components/types.gen.d.mts +0 -855
- package/dist/generated/datasource_entries/client.gen.cjs +0 -10
- package/dist/generated/datasource_entries/client.gen.cjs.map +0 -1
- package/dist/generated/datasource_entries/client.gen.mjs +0 -10
- package/dist/generated/datasource_entries/client.gen.mjs.map +0 -1
- package/dist/generated/datasource_entries/sdk.gen.cjs +0 -89
- package/dist/generated/datasource_entries/sdk.gen.cjs.map +0 -1
- package/dist/generated/datasource_entries/sdk.gen.mjs +0 -85
- package/dist/generated/datasource_entries/sdk.gen.mjs.map +0 -1
- package/dist/generated/datasource_entries/types.gen.d.cts +0 -156
- package/dist/generated/datasource_entries/types.gen.d.mts +0 -156
- package/dist/generated/datasources/client.gen.cjs +0 -10
- package/dist/generated/datasources/client.gen.cjs.map +0 -1
- package/dist/generated/datasources/client.gen.mjs +0 -10
- package/dist/generated/datasources/client.gen.mjs.map +0 -1
- package/dist/generated/datasources/sdk.gen.cjs +0 -89
- package/dist/generated/datasources/sdk.gen.cjs.map +0 -1
- package/dist/generated/datasources/sdk.gen.mjs +0 -85
- package/dist/generated/datasources/sdk.gen.mjs.map +0 -1
- package/dist/generated/datasources/types.gen.d.cts +0 -186
- package/dist/generated/datasources/types.gen.d.mts +0 -186
- package/dist/generated/experiments/client.gen.cjs +0 -10
- package/dist/generated/experiments/client.gen.cjs.map +0 -1
- package/dist/generated/experiments/client.gen.mjs +0 -10
- package/dist/generated/experiments/client.gen.mjs.map +0 -1
- package/dist/generated/experiments/sdk.gen.cjs +0 -298
- package/dist/generated/experiments/sdk.gen.cjs.map +0 -1
- package/dist/generated/experiments/sdk.gen.mjs +0 -283
- package/dist/generated/experiments/sdk.gen.mjs.map +0 -1
- package/dist/generated/experiments/types.gen.d.cts +0 -522
- package/dist/generated/experiments/types.gen.d.mts +0 -522
- package/dist/generated/internal_tags/client.gen.cjs +0 -10
- package/dist/generated/internal_tags/client.gen.cjs.map +0 -1
- package/dist/generated/internal_tags/client.gen.mjs +0 -10
- package/dist/generated/internal_tags/client.gen.mjs.map +0 -1
- package/dist/generated/internal_tags/sdk.gen.cjs +0 -74
- package/dist/generated/internal_tags/sdk.gen.cjs.map +0 -1
- package/dist/generated/internal_tags/sdk.gen.mjs +0 -71
- package/dist/generated/internal_tags/sdk.gen.mjs.map +0 -1
- package/dist/generated/internal_tags/types.gen.d.cts +0 -106
- package/dist/generated/internal_tags/types.gen.d.mts +0 -106
- package/dist/generated/presets/client.gen.cjs +0 -10
- package/dist/generated/presets/client.gen.cjs.map +0 -1
- package/dist/generated/presets/client.gen.mjs +0 -10
- package/dist/generated/presets/client.gen.mjs.map +0 -1
- package/dist/generated/presets/sdk.gen.cjs +0 -99
- package/dist/generated/presets/sdk.gen.cjs.map +0 -1
- package/dist/generated/presets/sdk.gen.mjs +0 -95
- package/dist/generated/presets/sdk.gen.mjs.map +0 -1
- package/dist/generated/presets/types.gen.d.cts +0 -176
- package/dist/generated/presets/types.gen.d.mts +0 -176
- package/dist/generated/shared/client/client.gen.cjs.map +0 -1
- package/dist/generated/shared/client/client.gen.mjs.map +0 -1
- package/dist/generated/shared/client/utils.gen.cjs.map +0 -1
- package/dist/generated/shared/client/utils.gen.mjs.map +0 -1
- package/dist/generated/shared/core/auth.gen.cjs.map +0 -1
- package/dist/generated/shared/core/auth.gen.mjs.map +0 -1
- package/dist/generated/shared/core/bodySerializer.gen.cjs.map +0 -1
- package/dist/generated/shared/core/bodySerializer.gen.mjs.map +0 -1
- package/dist/generated/shared/core/params.gen.cjs.map +0 -1
- package/dist/generated/shared/core/params.gen.mjs.map +0 -1
- package/dist/generated/shared/core/pathSerializer.gen.cjs.map +0 -1
- package/dist/generated/shared/core/pathSerializer.gen.mjs.map +0 -1
- package/dist/generated/shared/core/serverSentEvents.gen.cjs.map +0 -1
- package/dist/generated/shared/core/serverSentEvents.gen.mjs.map +0 -1
- package/dist/generated/shared/core/utils.gen.cjs.map +0 -1
- package/dist/generated/shared/core/utils.gen.mjs.map +0 -1
- package/dist/generated/spaces/client.gen.cjs +0 -10
- package/dist/generated/spaces/client.gen.cjs.map +0 -1
- package/dist/generated/spaces/client.gen.mjs +0 -10
- package/dist/generated/spaces/client.gen.mjs.map +0 -1
- package/dist/generated/spaces/sdk.gen.cjs +0 -99
- package/dist/generated/spaces/sdk.gen.cjs.map +0 -1
- package/dist/generated/spaces/sdk.gen.mjs +0 -95
- package/dist/generated/spaces/sdk.gen.mjs.map +0 -1
- package/dist/generated/spaces/types.gen.d.cts +0 -544
- package/dist/generated/spaces/types.gen.d.mts +0 -544
- package/dist/generated/stories/client.gen.cjs +0 -10
- package/dist/generated/stories/client.gen.cjs.map +0 -1
- package/dist/generated/stories/client.gen.mjs +0 -10
- package/dist/generated/stories/client.gen.mjs.map +0 -1
- package/dist/generated/stories/sdk.gen.cjs +0 -138
- package/dist/generated/stories/sdk.gen.cjs.map +0 -1
- package/dist/generated/stories/sdk.gen.mjs +0 -131
- package/dist/generated/stories/sdk.gen.mjs.map +0 -1
- package/dist/generated/stories/types.gen.d.cts +0 -1306
- package/dist/generated/stories/types.gen.d.mts +0 -1306
- package/dist/generated/users/client.gen.cjs +0 -10
- package/dist/generated/users/client.gen.cjs.map +0 -1
- package/dist/generated/users/client.gen.mjs +0 -10
- package/dist/generated/users/client.gen.mjs.map +0 -1
- package/dist/generated/users/sdk.gen.cjs +0 -44
- package/dist/generated/users/sdk.gen.cjs.map +0 -1
- package/dist/generated/users/sdk.gen.mjs +0 -43
- package/dist/generated/users/sdk.gen.mjs.map +0 -1
- package/dist/generated/users/types.gen.d.cts +0 -348
- package/dist/generated/users/types.gen.d.mts +0 -348
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/types.d.cts +0 -130
- package/dist/types.d.mts +0 -130
- /package/dist/generated/{shared → mapi}/client/client.gen.d.mts +0 -0
- /package/dist/generated/{shared → mapi}/client/index.cjs +0 -0
- /package/dist/generated/{shared → mapi}/client/index.d.mts +0 -0
- /package/dist/generated/{shared → mapi}/client/index.mjs +0 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { createManagementApiClient } from '@storyblok/management-api-client';
|
|
2
|
+
import { describe, expectTypeOf, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
const CLIENT_CONFIG = { personalAccessToken: 'test-token', spaceId: 12345 };
|
|
5
|
+
|
|
6
|
+
describe('datasources type tests', () => {
|
|
7
|
+
it('should return datasource in response from create', async () => {
|
|
8
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
9
|
+
const result = await client.datasources.create({
|
|
10
|
+
body: { datasource: { name: 'Test', slug: 'test' } },
|
|
11
|
+
});
|
|
12
|
+
if (result.data) {
|
|
13
|
+
expectTypeOf(result.data).toHaveProperty('datasource');
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should return datasource in response from get', async () => {
|
|
18
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
19
|
+
const result = await client.datasources.get(1);
|
|
20
|
+
if (result.data) {
|
|
21
|
+
expectTypeOf(result.data).toHaveProperty('datasource');
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should return datasources array in response from list', async () => {
|
|
26
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
27
|
+
const result = await client.datasources.list();
|
|
28
|
+
if (result.data) {
|
|
29
|
+
expectTypeOf(result.data).toHaveProperty('datasources');
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('datasource entries type tests', () => {
|
|
35
|
+
it('should return datasource_entry in response from create', async () => {
|
|
36
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
37
|
+
const result = await client.datasourceEntries.create({
|
|
38
|
+
body: { datasource_entry: { name: 'red', value: '#ff0000', datasource_id: 42 } },
|
|
39
|
+
});
|
|
40
|
+
if (result.data) {
|
|
41
|
+
expectTypeOf(result.data).toHaveProperty('datasource_entry');
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should return datasource_entry in response from get', async () => {
|
|
46
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
47
|
+
const result = await client.datasourceEntries.get(1);
|
|
48
|
+
if (result.data) {
|
|
49
|
+
expectTypeOf(result.data).toHaveProperty('datasource_entry');
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should return datasource_entries array in response from list', async () => {
|
|
54
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
55
|
+
const result = await client.datasourceEntries.list();
|
|
56
|
+
if (result.data) {
|
|
57
|
+
expectTypeOf(result.data).toHaveProperty('datasource_entries');
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('asset folders type tests', () => {
|
|
63
|
+
it('should return asset_folder in response from create', async () => {
|
|
64
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
65
|
+
const result = await client.assetFolders.create({
|
|
66
|
+
body: { asset_folder: { name: 'Photos' } },
|
|
67
|
+
});
|
|
68
|
+
if (result.data) {
|
|
69
|
+
expectTypeOf(result.data).toHaveProperty('asset_folder');
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should return asset_folder in response from get', async () => {
|
|
74
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
75
|
+
const result = await client.assetFolders.get(1);
|
|
76
|
+
if (result.data) {
|
|
77
|
+
expectTypeOf(result.data).toHaveProperty('asset_folder');
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should return asset_folders array in response from list', async () => {
|
|
82
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
83
|
+
const result = await client.assetFolders.list();
|
|
84
|
+
if (result.data) {
|
|
85
|
+
expectTypeOf(result.data).toHaveProperty('asset_folders');
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('component folders type tests', () => {
|
|
91
|
+
it('should return component_group in response from create', async () => {
|
|
92
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
93
|
+
const result = await client.componentFolders.create({
|
|
94
|
+
body: { component_group: { name: 'Layout' } },
|
|
95
|
+
});
|
|
96
|
+
if (result.data) {
|
|
97
|
+
expectTypeOf(result.data).toHaveProperty('component_group');
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should return component_group in response from get', async () => {
|
|
102
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
103
|
+
const result = await client.componentFolders.get(1);
|
|
104
|
+
if (result.data) {
|
|
105
|
+
expectTypeOf(result.data).toHaveProperty('component_group');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should return component_groups array in response from list', async () => {
|
|
110
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
111
|
+
const result = await client.componentFolders.list();
|
|
112
|
+
if (result.data) {
|
|
113
|
+
expectTypeOf(result.data).toHaveProperty('component_groups');
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('internal tags type tests', () => {
|
|
119
|
+
it('should return internal_tag in response from create', async () => {
|
|
120
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
121
|
+
const result = await client.internalTags.create({
|
|
122
|
+
body: { internal_tag: { name: 'hero' } },
|
|
123
|
+
});
|
|
124
|
+
if (result.data) {
|
|
125
|
+
expectTypeOf(result.data).toHaveProperty('internal_tag');
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should return internal_tags array in response from list', async () => {
|
|
130
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
131
|
+
const result = await client.internalTags.list();
|
|
132
|
+
if (result.data) {
|
|
133
|
+
expectTypeOf(result.data).toHaveProperty('internal_tags');
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('presets type tests', () => {
|
|
139
|
+
it('should return preset in response from create', async () => {
|
|
140
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
141
|
+
const result = await client.presets.create({
|
|
142
|
+
body: { preset: { name: 'Hero Dark', component_id: 42 } },
|
|
143
|
+
});
|
|
144
|
+
if (result.data) {
|
|
145
|
+
expectTypeOf(result.data).toHaveProperty('preset');
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should return preset in response from get', async () => {
|
|
150
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
151
|
+
const result = await client.presets.get(1);
|
|
152
|
+
if (result.data) {
|
|
153
|
+
expectTypeOf(result.data).toHaveProperty('preset');
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should return presets array in response from list', async () => {
|
|
158
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
159
|
+
const result = await client.presets.list();
|
|
160
|
+
if (result.data) {
|
|
161
|
+
expectTypeOf(result.data).toHaveProperty('presets');
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('spaces type tests', () => {
|
|
167
|
+
it('should return space in response from create', async () => {
|
|
168
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
169
|
+
const result = await client.spaces.create({
|
|
170
|
+
body: { space: { name: 'Test Space' } },
|
|
171
|
+
});
|
|
172
|
+
if (result.data) {
|
|
173
|
+
expectTypeOf(result.data).toHaveProperty('space');
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should return space in response from get', async () => {
|
|
178
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
179
|
+
const result = await client.spaces.get();
|
|
180
|
+
if (result.data) {
|
|
181
|
+
expectTypeOf(result.data).toHaveProperty('space');
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should return spaces array in response from list', async () => {
|
|
186
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
187
|
+
const result = await client.spaces.list();
|
|
188
|
+
if (result.data) {
|
|
189
|
+
expectTypeOf(result.data).toHaveProperty('spaces');
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe('users type tests', () => {
|
|
195
|
+
it('should return user in response from updateMe', async () => {
|
|
196
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
197
|
+
const result = await client.users.updateMe({
|
|
198
|
+
body: { user: { firstname: 'Jane' } },
|
|
199
|
+
});
|
|
200
|
+
if (result.data) {
|
|
201
|
+
expectTypeOf(result.data).toHaveProperty('user');
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should return user in response from me', async () => {
|
|
206
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
207
|
+
const result = await client.users.me();
|
|
208
|
+
if (result.data) {
|
|
209
|
+
expectTypeOf(result.data).toHaveProperty('user');
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
});
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { defineBlock, defineField, defineSchema, type Schema as InferSchema } from '@storyblok/schema';
|
|
2
|
+
import { storyblokColorField } from '@storyblok/schema/field-plugins';
|
|
3
|
+
import { createManagementApiClient, type PluginFieldValue, type Story as StoryMapi } from '@storyblok/management-api-client';
|
|
4
|
+
import { describe, expectTypeOf, it } from 'vitest';
|
|
5
|
+
|
|
6
|
+
// Nestable block — not a root story type
|
|
7
|
+
const teaserComponent = defineBlock({
|
|
8
|
+
name: 'teaser',
|
|
9
|
+
fields: [
|
|
10
|
+
defineField('text', { type: 'text' }),
|
|
11
|
+
defineField('image', { type: 'asset' }),
|
|
12
|
+
],
|
|
13
|
+
id: 0,
|
|
14
|
+
created_at: '',
|
|
15
|
+
updated_at: '',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Root content type that is also nestable (can appear as both a story and inside bloks)
|
|
19
|
+
const heroComponent = defineBlock({
|
|
20
|
+
name: 'hero',
|
|
21
|
+
is_root: true,
|
|
22
|
+
fields: [
|
|
23
|
+
defineField('title', { type: 'text' }),
|
|
24
|
+
defineField('count', { type: 'number' }),
|
|
25
|
+
// bloks field without a whitelist — resolves to nestable components only
|
|
26
|
+
defineField('sections', { type: 'bloks' }),
|
|
27
|
+
],
|
|
28
|
+
id: 0,
|
|
29
|
+
created_at: '',
|
|
30
|
+
updated_at: '',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Root content type, not nestable
|
|
34
|
+
const _pageComponent = defineBlock({
|
|
35
|
+
name: 'page',
|
|
36
|
+
is_root: true,
|
|
37
|
+
is_nestable: false,
|
|
38
|
+
fields: [
|
|
39
|
+
defineField('headline', { type: 'text' }),
|
|
40
|
+
defineField('body', { type: 'richtext' }),
|
|
41
|
+
defineField('teasers', { type: 'bloks', allow: [teaserComponent.name] }),
|
|
42
|
+
defineField('hero', { type: 'bloks', allow: [heroComponent.name] }),
|
|
43
|
+
defineField('blocks', { type: 'bloks', allow: [heroComponent.name, teaserComponent.name] }),
|
|
44
|
+
],
|
|
45
|
+
id: 0,
|
|
46
|
+
created_at: '',
|
|
47
|
+
updated_at: '',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const CLIENT_CONFIG = { personalAccessToken: 'test-token', spaceId: 12345 };
|
|
51
|
+
|
|
52
|
+
interface StoryblokTypes {
|
|
53
|
+
components: typeof _pageComponent | typeof heroComponent | typeof teaserComponent;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe('createManagementApiClient without .withTypes()', () => {
|
|
57
|
+
it('should return StoryMapi from stories.get()', async () => {
|
|
58
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
59
|
+
const result = await client.stories.get(123);
|
|
60
|
+
if (result.data) {
|
|
61
|
+
expectTypeOf(result.data.story).toEqualTypeOf<StoryMapi | undefined>();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should return StoryMapi array from stories.list()', async () => {
|
|
66
|
+
const client = createManagementApiClient(CLIENT_CONFIG);
|
|
67
|
+
const result = await client.stories.list();
|
|
68
|
+
if (result.data) {
|
|
69
|
+
expectTypeOf(result.data.stories).toEqualTypeOf<StoryMapi[] | undefined>();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should infer ThrowOnError from config without .withTypes()', async () => {
|
|
74
|
+
const client = createManagementApiClient({ ...CLIENT_CONFIG, throwOnError: true });
|
|
75
|
+
const result = await client.stories.get(123);
|
|
76
|
+
// ThrowOnError=true means data is always defined (no optional chaining needed)
|
|
77
|
+
expectTypeOf(result.data.story).toEqualTypeOf<StoryMapi | undefined>();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should allow per-call throwOnError override to false', async () => {
|
|
81
|
+
const client = createManagementApiClient({ ...CLIENT_CONFIG, throwOnError: true });
|
|
82
|
+
const result = await client.stories.get(123, { throwOnError: false });
|
|
83
|
+
if (result.data) {
|
|
84
|
+
expectTypeOf(result.data.story).toEqualTypeOf<StoryMapi | undefined>();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('createManagementApiClient with .withTypes()', () => {
|
|
90
|
+
it('should narrow page content fields after component discriminant check on get()', async () => {
|
|
91
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
92
|
+
const result = await client.stories.get(123);
|
|
93
|
+
if (result.data?.story) {
|
|
94
|
+
const story = result.data.story;
|
|
95
|
+
if (story.content.component === 'page') {
|
|
96
|
+
expectTypeOf(story.content.headline).toEqualTypeOf<string | null | undefined>();
|
|
97
|
+
expectTypeOf(story.content.component).toEqualTypeOf<'page'>();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should narrow hero content fields after component discriminant check on get()', async () => {
|
|
103
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
104
|
+
const result = await client.stories.get(123);
|
|
105
|
+
if (result.data?.story) {
|
|
106
|
+
const story = result.data.story;
|
|
107
|
+
if (story.content.component === 'hero') {
|
|
108
|
+
expectTypeOf(story.content.title).toEqualTypeOf<string | null | undefined>();
|
|
109
|
+
expectTypeOf(story.content.count).toEqualTypeOf<number | null | undefined>();
|
|
110
|
+
expectTypeOf(story.content.component).toEqualTypeOf<'hero'>();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should have union of literal component names on content', async () => {
|
|
116
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
117
|
+
const result = await client.stories.get(123);
|
|
118
|
+
if (result.data?.story) {
|
|
119
|
+
// Only root components (is_root: true) appear in story content
|
|
120
|
+
expectTypeOf(result.data.story.content.component).toEqualTypeOf<'page' | 'hero'>();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should narrow discriminated union in stories.list()', async () => {
|
|
125
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
126
|
+
const result = await client.stories.list();
|
|
127
|
+
if (result.data?.stories) {
|
|
128
|
+
for (const story of result.data.stories) {
|
|
129
|
+
if (story.content.component === 'page') {
|
|
130
|
+
expectTypeOf(story.content.headline).toEqualTypeOf<string | null | undefined>();
|
|
131
|
+
}
|
|
132
|
+
if (story.content.component === 'hero') {
|
|
133
|
+
expectTypeOf(story.content.count).toEqualTypeOf<number | null | undefined>();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should narrow bloks field on page to whitelisted component names', async () => {
|
|
140
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
141
|
+
const result = await client.stories.get(123);
|
|
142
|
+
if (result.data?.story) {
|
|
143
|
+
const story = result.data.story;
|
|
144
|
+
if (story.content.component === 'page') {
|
|
145
|
+
if (story.content.teasers) {
|
|
146
|
+
for (const teaser of story.content.teasers) {
|
|
147
|
+
expectTypeOf(teaser.component).toEqualTypeOf<'teaser'>();
|
|
148
|
+
expectTypeOf(teaser.text).toEqualTypeOf<string | null | undefined>();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (story.content.hero) {
|
|
152
|
+
for (const hero of story.content.hero) {
|
|
153
|
+
expectTypeOf(hero.component).toEqualTypeOf<'hero'>();
|
|
154
|
+
expectTypeOf(hero.count).toEqualTypeOf<number | null | undefined>();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (story.content.blocks) {
|
|
158
|
+
for (const blok of story.content.blocks) {
|
|
159
|
+
// blocks whitelists both hero and teaser → union of the two
|
|
160
|
+
expectTypeOf(blok.component).toEqualTypeOf<'hero' | 'teaser'>();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should fall back to all schema components for bloks field without whitelist', async () => {
|
|
168
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
169
|
+
const result = await client.stories.get(123);
|
|
170
|
+
if (result.data?.story) {
|
|
171
|
+
const story = result.data.story;
|
|
172
|
+
if (story.content.component === 'hero' && story.content.sections) {
|
|
173
|
+
// sections has no component_whitelist — falls back to nestable (is_nestable: true)
|
|
174
|
+
// components only; page has is_nestable: false, so it is excluded
|
|
175
|
+
type Sections = typeof story.content.sections;
|
|
176
|
+
expectTypeOf<Sections[number]['component']>().toEqualTypeOf<'hero' | 'teaser'>();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should infer ThrowOnError alongside .withTypes()', async () => {
|
|
182
|
+
const client = createManagementApiClient({ ...CLIENT_CONFIG, throwOnError: true }).withTypes<StoryblokTypes>();
|
|
183
|
+
const result = await client.stories.get(123);
|
|
184
|
+
if (result.data.story) {
|
|
185
|
+
// ThrowOnError=true keeps data defined; only root components appear in content
|
|
186
|
+
expectTypeOf(result.data.story.content.component).toEqualTypeOf<'page' | 'hero'>();
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should allow per-call throwOnError override to false alongside .withTypes()', async () => {
|
|
191
|
+
const client = createManagementApiClient({ ...CLIENT_CONFIG, throwOnError: true }).withTypes<StoryblokTypes>();
|
|
192
|
+
const result = await client.stories.get(123, { throwOnError: false });
|
|
193
|
+
if (result.data?.story) {
|
|
194
|
+
expectTypeOf(result.data.story.content.component).toEqualTypeOf<'page' | 'hero'>();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should narrow story in create() response', async () => {
|
|
199
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
200
|
+
const result = await client.stories.create({
|
|
201
|
+
body: { story: { name: 'My Page', content: { component: 'page' } } },
|
|
202
|
+
});
|
|
203
|
+
if (result.data?.story) {
|
|
204
|
+
const story = result.data.story;
|
|
205
|
+
if (story.content.component === 'page') {
|
|
206
|
+
expectTypeOf(story.content.headline).toEqualTypeOf<string | null | undefined>();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('should narrow story in update() response', async () => {
|
|
212
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
213
|
+
const result = await client.stories.update(123, {
|
|
214
|
+
body: { story: { content: { component: 'hero' } } },
|
|
215
|
+
});
|
|
216
|
+
if (result.data?.story) {
|
|
217
|
+
const story = result.data.story;
|
|
218
|
+
if (story.content.component === 'hero') {
|
|
219
|
+
expectTypeOf(story.content.title).toEqualTypeOf<string | null | undefined>();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should narrow create() body story.content to component union', async () => {
|
|
225
|
+
const _client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
226
|
+
type CreateBodyType = Parameters<typeof _client.stories.create>[0]['body'];
|
|
227
|
+
type CreateStoryContent = NonNullable<CreateBodyType['story']['content']>;
|
|
228
|
+
// The write payload's content discriminant is narrowed to root component names too
|
|
229
|
+
expectTypeOf<CreateStoryContent['component']>().toEqualTypeOf<'page' | 'hero'>();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should narrow update() body story.content to component union', async () => {
|
|
233
|
+
const _client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
234
|
+
type UpdateBodyType = Parameters<typeof _client.stories.update>[1]['body'];
|
|
235
|
+
type UpdateStoryContent = NonNullable<UpdateBodyType['story']['content']>;
|
|
236
|
+
// update() is the second positional arg (id, body); content discriminant is the root union
|
|
237
|
+
expectTypeOf<UpdateStoryContent['component']>().toEqualTypeOf<'page' | 'hero'>();
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('withTypes() write-body narrowing', () => {
|
|
242
|
+
it('should reject nestable-only component name in create body content', () => {
|
|
243
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
244
|
+
client.stories.create({
|
|
245
|
+
// @ts-expect-error: teaser is nestable-only, not a root component
|
|
246
|
+
body: { story: { name: 'Bad', content: { component: 'teaser' } } },
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should reject wrong field value type in create body content', () => {
|
|
251
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
252
|
+
client.stories.create({
|
|
253
|
+
body: { story: { name: 'Bad', content: {
|
|
254
|
+
component: 'page',
|
|
255
|
+
// @ts-expect-error: headline must be string, not number
|
|
256
|
+
headline: 123,
|
|
257
|
+
} } },
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should return a typed story with content.component as discriminant from stories.get', async () => {
|
|
262
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<StoryblokTypes>();
|
|
263
|
+
const result = await client.stories.get(123);
|
|
264
|
+
|
|
265
|
+
if (result.data?.story) {
|
|
266
|
+
const story = result.data.story;
|
|
267
|
+
expectTypeOf(story.content.component).toEqualTypeOf<'page' | 'hero'>();
|
|
268
|
+
|
|
269
|
+
if (story.content.component === 'page') {
|
|
270
|
+
expectTypeOf(story.content.headline).toEqualTypeOf<string | null | undefined>();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
describe('createManagementApiClient with .withTypes() — field plugins', () => {
|
|
277
|
+
const _themedComponent = defineBlock({
|
|
278
|
+
name: 'themed',
|
|
279
|
+
is_root: true,
|
|
280
|
+
fields: [
|
|
281
|
+
defineField('bg', { type: 'custom', field_type: 'storyblok-colorpicker' }),
|
|
282
|
+
defineField('legacy', { type: 'custom', field_type: 'unregistered-plugin' }),
|
|
283
|
+
],
|
|
284
|
+
});
|
|
285
|
+
const _schema = defineSchema({
|
|
286
|
+
blocks: { themedComponent: _themedComponent },
|
|
287
|
+
fieldPlugins: { storyblokColorField },
|
|
288
|
+
});
|
|
289
|
+
type Schema = InferSchema<typeof _schema>;
|
|
290
|
+
|
|
291
|
+
it('resolves a registered custom field to the validator output merged with the plugin envelope', async () => {
|
|
292
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<Schema>();
|
|
293
|
+
const result = await client.stories.get(123);
|
|
294
|
+
if (result.data?.story && result.data.story.content.component === 'themed') {
|
|
295
|
+
expectTypeOf<NonNullable<typeof result.data.story.content.bg>>().toEqualTypeOf<{
|
|
296
|
+
color: string;
|
|
297
|
+
plugin: string;
|
|
298
|
+
_uid?: string;
|
|
299
|
+
}>();
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('leaves an unregistered custom field as PluginFieldValue', async () => {
|
|
304
|
+
const client = createManagementApiClient(CLIENT_CONFIG).withTypes<Schema>();
|
|
305
|
+
const result = await client.stories.get(123);
|
|
306
|
+
if (result.data?.story && result.data.story.content.component === 'themed') {
|
|
307
|
+
expectTypeOf<NonNullable<typeof result.data.story.content.legacy>>().toEqualTypeOf<PluginFieldValue>();
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// <reference types="vitest" />
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Vitest config for end-to-end tests that hit the real Storyblok Management API.
|
|
6
|
+
*
|
|
7
|
+
* These tests are NOT run in CI. Trigger them manually:
|
|
8
|
+
* pnpm --filter @storyblok/mapi-integration-tests test:e2e
|
|
9
|
+
*
|
|
10
|
+
* Prerequisites:
|
|
11
|
+
* - A .env.qa-engineer-manual file at the repo root with STORYBLOK_TOKEN and STORYBLOK_SPACE_ID.
|
|
12
|
+
* - The @storyblok/management-api-client package must be built.
|
|
13
|
+
*/
|
|
14
|
+
export default defineConfig({
|
|
15
|
+
test: {
|
|
16
|
+
include: ['./test/specs/**/*.spec.e2e.ts'],
|
|
17
|
+
setupFiles: ['./test/setup.e2e.ts'],
|
|
18
|
+
globals: true,
|
|
19
|
+
testTimeout: 60_000,
|
|
20
|
+
hookTimeout: 120_000,
|
|
21
|
+
sequence: {
|
|
22
|
+
concurrent: false,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="vitest" />
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
test: {
|
|
6
|
+
environment: 'node',
|
|
7
|
+
include: [],
|
|
8
|
+
typecheck: {
|
|
9
|
+
enabled: true,
|
|
10
|
+
include: ['./test/types/**/*.test-d.ts'],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
});
|
package/test/GUIDE.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Manually Test the @storyblok/management-api-client Package
|
|
2
|
+
|
|
3
|
+
`@storyblok/management-api-client` is the Management API (MAPI) client. The key things to validate manually are that the schema-aware `.withTypes()` integration correctly narrows story content, that every define helper produces a valid creation payload, and that Zod schemas accept real API responses.
|
|
4
|
+
|
|
5
|
+
## Automated e2e tests
|
|
6
|
+
|
|
7
|
+
The `@storyblok/mapi-integration-tests` package (`packages/mapi-client/playground/integration-tests`) covers the full round-trip against a real Storyblok space in `test/specs/mapi-round-trip.spec.e2e.ts`:
|
|
8
|
+
|
|
9
|
+
- Seeds components, datasources, internal tags, presets, and stories via the MAPI.
|
|
10
|
+
- Validates runtime values, type narrowing, nested bloks (two- and three-level), unwhitelisted bloks, and update round-trips.
|
|
11
|
+
- Validates MAPI Zod schemas (`componentSchema`, `storySchema`, `datasourceSchema`, `datasourceEntrySchema`) against real API responses.
|
|
12
|
+
|
|
13
|
+
Run manually:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm --filter @storyblok/mapi-integration-tests test:e2e
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Prerequisites
|
|
20
|
+
|
|
21
|
+
- A `.env.qa-engineer-manual` file at the repo root with `STORYBLOK_TOKEN` and `STORYBLOK_SPACE_ID`.
|
|
22
|
+
- `@storyblok/management-api-client` must be built first.
|
|
23
|
+
|
|
24
|
+
## Fetch via MAPI client and check content types
|
|
25
|
+
|
|
26
|
+
`stories.get(storyId)` takes a numeric/string ID as its first positional argument — there is no `getBySlug`. Fetch the ID from `stories.list` first:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { createManagementApiClient } from '@storyblok/management-api-client';
|
|
30
|
+
|
|
31
|
+
const client = createManagementApiClient({ personalAccessToken: process.env.STORYBLOK_TOKEN, spaceId });
|
|
32
|
+
const list = await client.stories.list({ query: { per_page: 100 } });
|
|
33
|
+
const story = list.data?.stories?.find(s => s.slug === 'home');
|
|
34
|
+
const result = await client.stories.get(story.id);
|
|
35
|
+
console.info(result.data?.story?.content);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Push component JSONs via the CLI
|
|
39
|
+
|
|
40
|
+
To push `defineComponent` components, serialize the component objects to JSON and stage them under `.storyblok/components/<space_id>/`:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
node packages/cli/dist/index.mjs components push \
|
|
44
|
+
--from qa-test \
|
|
45
|
+
--space $STORYBLOK_SPACE_ID \
|
|
46
|
+
--separate-files
|
|
47
|
+
```
|
|
48
|
+
|
|
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
|
+
|
|
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
|
+
|
|
53
|
+
## Known quirks
|
|
54
|
+
|
|
55
|
+
- **Stories require a content type component (`is_root: true`).** The MAPI rejects story creation with `"please select a content type component as your root component"` if the component used as the story root does not have `is_root: true`.
|
|
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
|
+
- **MAPI client constructor uses `personalAccessToken`:** `createManagementApiClient({ personalAccessToken: '...', spaceId: ... })`.
|
|
58
|
+
- **Delete methods are `delete`:** Use `client.RESOURCE.delete(id)`.
|
|
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.
|
package/vitest.config.ts
CHANGED
|
@@ -4,5 +4,10 @@ import { defineConfig } from 'vitest/config';
|
|
|
4
4
|
export default defineConfig({
|
|
5
5
|
test: {
|
|
6
6
|
environment: 'node',
|
|
7
|
+
exclude: ['**/node_modules/**', '**/dist/**', './playground/**'],
|
|
8
|
+
typecheck: {
|
|
9
|
+
enabled: true,
|
|
10
|
+
exclude: ['**/node_modules/**', '**/dist/**', './playground/**'],
|
|
11
|
+
},
|
|
7
12
|
},
|
|
8
13
|
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
const require_utils_gen = require('../shared/client/utils.gen.cjs');
|
|
2
|
-
const require_client_gen = require('../shared/client/client.gen.cjs');
|
|
3
|
-
require('../shared/client/index.cjs');
|
|
4
|
-
|
|
5
|
-
//#region src/generated/asset_folders/client.gen.ts
|
|
6
|
-
const client = require_client_gen.createClient(require_utils_gen.createConfig({ baseUrl: "https://mapi.storyblok.com" }));
|
|
7
|
-
|
|
8
|
-
//#endregion
|
|
9
|
-
exports.client = client;
|
|
10
|
-
//# sourceMappingURL=client.gen.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.gen.cjs","names":["createClient","createConfig"],"sources":["../../../src/generated/asset_folders/client.gen.ts"],"sourcesContent":["// This file is auto-generated by @hey-api/openapi-ts\n\nimport { type ClientOptions, type Config, createClient, createConfig } from '../shared/client';\nimport type { ClientOptions as ClientOptions2 } from './types.gen';\n\n/**\n * The `createClientConfig()` function will be called on client initialization\n * and the returned object will become the client's initial configuration.\n *\n * You may want to initialize your client this way instead of calling\n * `setConfig()`. This is useful for example if you're using Next.js\n * to ensure your client always has the correct values.\n */\nexport type CreateClientConfig<T extends ClientOptions = ClientOptions2> = (override?: Config<ClientOptions & T>) => Config<Required<ClientOptions> & T>;\n\nexport const client = createClient(createConfig<ClientOptions2>({ baseUrl: 'https://mapi.storyblok.com' }));\n"],"mappings":";;;;;AAeA,MAAa,SAASA,gCAAaC,+BAA6B,EAAE,SAAS,8BAA8B,CAAC,CAAC"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { createConfig } from "../shared/client/utils.gen.mjs";
|
|
2
|
-
import { createClient } from "../shared/client/client.gen.mjs";
|
|
3
|
-
import "../shared/client/index.mjs";
|
|
4
|
-
|
|
5
|
-
//#region src/generated/asset_folders/client.gen.ts
|
|
6
|
-
const client = createClient(createConfig({ baseUrl: "https://mapi.storyblok.com" }));
|
|
7
|
-
|
|
8
|
-
//#endregion
|
|
9
|
-
export { client };
|
|
10
|
-
//# sourceMappingURL=client.gen.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.gen.mjs","names":[],"sources":["../../../src/generated/asset_folders/client.gen.ts"],"sourcesContent":["// This file is auto-generated by @hey-api/openapi-ts\n\nimport { type ClientOptions, type Config, createClient, createConfig } from '../shared/client';\nimport type { ClientOptions as ClientOptions2 } from './types.gen';\n\n/**\n * The `createClientConfig()` function will be called on client initialization\n * and the returned object will become the client's initial configuration.\n *\n * You may want to initialize your client this way instead of calling\n * `setConfig()`. This is useful for example if you're using Next.js\n * to ensure your client always has the correct values.\n */\nexport type CreateClientConfig<T extends ClientOptions = ClientOptions2> = (override?: Config<ClientOptions & T>) => Config<Required<ClientOptions> & T>;\n\nexport const client = createClient(createConfig<ClientOptions2>({ baseUrl: 'https://mapi.storyblok.com' }));\n"],"mappings":";;;;;AAeA,MAAa,SAAS,aAAa,aAA6B,EAAE,SAAS,8BAA8B,CAAC,CAAC"}
|