@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.mjs","names":["
|
|
1
|
+
{"version":3,"file":"users.mjs","names":["mapi.getCurrentUser","mapi.updateCurrentUser"],"sources":["../../src/resources/users.ts"],"sourcesContent":["import * as mapi from '../generated/mapi/sdk.gen';\nimport type {\n GetCurrentUserResponses,\n UpdateCurrentUserData,\n UpdateCurrentUserResponses,\n} from '../generated/mapi/types.gen';\nimport type { ApiResponse, FetchOptions, MapiResourceDeps } from '../client';\n\nexport function createUsersResource<DefaultThrowOnError extends boolean = false>(deps: Omit<MapiResourceDeps<DefaultThrowOnError>, 'spaceId'>) {\n const { client, wrapRequest } = deps;\n\n return {\n me<ThrowOnError extends boolean = DefaultThrowOnError>(options: { signal?: AbortSignal; throwOnError?: ThrowOnError; fetchOptions?: FetchOptions } = {}): Promise<ApiResponse<GetCurrentUserResponses[200], ThrowOnError>> {\n const { signal, throwOnError, fetchOptions } = options;\n return wrapRequest<GetCurrentUserResponses[200], ThrowOnError>(() =>\n mapi.getCurrentUser({ client, signal, ...(throwOnError === undefined ? {} : { throwOnError }), ...(fetchOptions ? { kyOptions: { ...client.getConfig().kyOptions, ...fetchOptions } } : {}) }), throwOnError);\n },\n updateMe<ThrowOnError extends boolean = DefaultThrowOnError>(options: { body: UpdateCurrentUserData['body']; signal?: AbortSignal; throwOnError?: ThrowOnError; fetchOptions?: FetchOptions }): Promise<ApiResponse<UpdateCurrentUserResponses[200], ThrowOnError>> {\n const { body, signal, throwOnError, fetchOptions } = options;\n return wrapRequest<UpdateCurrentUserResponses[200], ThrowOnError>(() =>\n mapi.updateCurrentUser({ client, body, signal, ...(throwOnError === undefined ? {} : { throwOnError }), ...(fetchOptions ? { kyOptions: { ...client.getConfig().kyOptions, ...fetchOptions } } : {}) }), throwOnError);\n },\n };\n}\n"],"mappings":";;;AAQA,SAAgB,oBAAiE,MAA8D;CAC7I,MAAM,EAAE,QAAQ,gBAAgB;AAEhC,QAAO;EACL,GAAuD,UAA8F,EAAE,EAAoE;GACzN,MAAM,EAAE,QAAQ,cAAc,iBAAiB;AAC/C,UAAO,kBACLA,eAAoB;IAAE;IAAQ;IAAQ,GAAI,iBAAiB,SAAY,EAAE,GAAG,EAAE,cAAc;IAAG,GAAI,eAAe,EAAE,WAAW;KAAE,GAAG,OAAO,WAAW,CAAC;KAAW,GAAG;KAAc,EAAE,GAAG,EAAE;IAAG,CAAC,EAAE,aAAa;;EAEjN,SAA6D,SAAuM;GAClQ,MAAM,EAAE,MAAM,QAAQ,cAAc,iBAAiB;AACrD,UAAO,kBACLC,kBAAuB;IAAE;IAAQ;IAAM;IAAQ,GAAI,iBAAiB,SAAY,EAAE,GAAG,EAAE,cAAc;IAAG,GAAI,eAAe,EAAE,WAAW;KAAE,GAAG,OAAO,WAAW,CAAC;KAAW,GAAG;KAAc,EAAE,GAAG,EAAE;IAAG,CAAC,EAAE,aAAa;;EAE3N"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const require_pathSerializer_gen = require('../generated/mapi/core/pathSerializer.gen.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/utils/query-serializer.ts
|
|
4
|
+
/**
|
|
5
|
+
* Query serializer for the Management API client.
|
|
6
|
+
*
|
|
7
|
+
* Behaves identically to the generated default for primitives, primitive
|
|
8
|
+
* arrays, and dates, but additionally serializes **nested objects** (and arrays
|
|
9
|
+
* of objects) into bracket notation — e.g. `filter_query[component][in]=hero`.
|
|
10
|
+
*
|
|
11
|
+
* The generated default serializer throws on this nesting ("Deeply-nested
|
|
12
|
+
* arrays/objects aren't supported. Provide your own `querySerializer()`"), yet
|
|
13
|
+
* MAPI requires `filter_query` as a nested hash and rejects flat strings. This
|
|
14
|
+
* mirrors the bracket serialization used by `storyblok-js-client`.
|
|
15
|
+
*/
|
|
16
|
+
function serialize(name, value, parts) {
|
|
17
|
+
if (value === void 0 || value === null) return;
|
|
18
|
+
if (value instanceof Date) {
|
|
19
|
+
parts.push(`${name}=${value.toISOString()}`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(value)) {
|
|
23
|
+
if (value.some((item) => item !== null && typeof item === "object")) {
|
|
24
|
+
for (const item of value) serialize(`${name}[]`, item, parts);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const serialized = require_pathSerializer_gen.serializeArrayParam({
|
|
28
|
+
explode: true,
|
|
29
|
+
name,
|
|
30
|
+
style: "form",
|
|
31
|
+
value
|
|
32
|
+
});
|
|
33
|
+
if (serialized) parts.push(serialized);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (typeof value === "object") {
|
|
37
|
+
for (const [key, child] of Object.entries(value)) serialize(`${name}[${key}]`, child, parts);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const serialized = require_pathSerializer_gen.serializePrimitiveParam({
|
|
41
|
+
name,
|
|
42
|
+
value
|
|
43
|
+
});
|
|
44
|
+
if (serialized) parts.push(serialized);
|
|
45
|
+
}
|
|
46
|
+
const querySerializer = (query) => {
|
|
47
|
+
const parts = [];
|
|
48
|
+
for (const [name, value] of Object.entries(query)) serialize(name, value, parts);
|
|
49
|
+
return parts.join("&");
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
exports.querySerializer = querySerializer;
|
|
54
|
+
//# sourceMappingURL=query-serializer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-serializer.cjs","names":["serializeArrayParam","serializePrimitiveParam"],"sources":["../../src/utils/query-serializer.ts"],"sourcesContent":["import type { QuerySerializer } from '../generated/mapi/core/bodySerializer.gen';\nimport { serializeArrayParam, serializePrimitiveParam } from '../generated/mapi/core/pathSerializer.gen';\n\n/**\n * Query serializer for the Management API client.\n *\n * Behaves identically to the generated default for primitives, primitive\n * arrays, and dates, but additionally serializes **nested objects** (and arrays\n * of objects) into bracket notation — e.g. `filter_query[component][in]=hero`.\n *\n * The generated default serializer throws on this nesting (\"Deeply-nested\n * arrays/objects aren't supported. Provide your own `querySerializer()`\"), yet\n * MAPI requires `filter_query` as a nested hash and rejects flat strings. This\n * mirrors the bracket serialization used by `storyblok-js-client`.\n */\nfunction serialize(name: string, value: unknown, parts: string[]): void {\n if (value === undefined || value === null) {\n return;\n }\n\n if (value instanceof Date) {\n parts.push(`${name}=${value.toISOString()}`);\n return;\n }\n\n if (Array.isArray(value)) {\n // Arrays containing objects (e.g. `filter_query.__or`) need per-item\n // bracket recursion; the default serializer cannot express them.\n if (value.some(item => item !== null && typeof item === 'object')) {\n for (const item of value) {\n serialize(`${name}[]`, item, parts);\n }\n return;\n }\n // Primitive arrays keep the generated default form (`name=a&name=b`).\n const serialized = serializeArrayParam({ explode: true, name, style: 'form', value });\n if (serialized) {\n parts.push(serialized);\n }\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value)) {\n serialize(`${name}[${key}]`, child, parts);\n }\n return;\n }\n\n const serialized = serializePrimitiveParam({ name, value: value as string });\n if (serialized) {\n parts.push(serialized);\n }\n}\n\nexport const querySerializer: QuerySerializer = (query) => {\n const parts: string[] = [];\n for (const [name, value] of Object.entries(query)) {\n serialize(name, value, parts);\n }\n return parts.join('&');\n};\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAS,UAAU,MAAc,OAAgB,OAAuB;AACtE,KAAI,UAAU,UAAa,UAAU,KACnC;AAGF,KAAI,iBAAiB,MAAM;AACzB,QAAM,KAAK,GAAG,KAAK,GAAG,MAAM,aAAa,GAAG;AAC5C;;AAGF,KAAI,MAAM,QAAQ,MAAM,EAAE;AAGxB,MAAI,MAAM,MAAK,SAAQ,SAAS,QAAQ,OAAO,SAAS,SAAS,EAAE;AACjE,QAAK,MAAM,QAAQ,MACjB,WAAU,GAAG,KAAK,KAAK,MAAM,MAAM;AAErC;;EAGF,MAAM,aAAaA,+CAAoB;GAAE,SAAS;GAAM;GAAM,OAAO;GAAQ;GAAO,CAAC;AACrF,MAAI,WACF,OAAM,KAAK,WAAW;AAExB;;AAGF,KAAI,OAAO,UAAU,UAAU;AAC7B,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,CAC9C,WAAU,GAAG,KAAK,GAAG,IAAI,IAAI,OAAO,MAAM;AAE5C;;CAGF,MAAM,aAAaC,mDAAwB;EAAE;EAAa;EAAiB,CAAC;AAC5E,KAAI,WACF,OAAM,KAAK,WAAW;;AAI1B,MAAa,mBAAoC,UAAU;CACzD,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,CAC/C,WAAU,MAAM,OAAO,MAAM;AAE/B,QAAO,MAAM,KAAK,IAAI"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { serializeArrayParam, serializePrimitiveParam } from "../generated/mapi/core/pathSerializer.gen.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/query-serializer.ts
|
|
4
|
+
/**
|
|
5
|
+
* Query serializer for the Management API client.
|
|
6
|
+
*
|
|
7
|
+
* Behaves identically to the generated default for primitives, primitive
|
|
8
|
+
* arrays, and dates, but additionally serializes **nested objects** (and arrays
|
|
9
|
+
* of objects) into bracket notation — e.g. `filter_query[component][in]=hero`.
|
|
10
|
+
*
|
|
11
|
+
* The generated default serializer throws on this nesting ("Deeply-nested
|
|
12
|
+
* arrays/objects aren't supported. Provide your own `querySerializer()`"), yet
|
|
13
|
+
* MAPI requires `filter_query` as a nested hash and rejects flat strings. This
|
|
14
|
+
* mirrors the bracket serialization used by `storyblok-js-client`.
|
|
15
|
+
*/
|
|
16
|
+
function serialize(name, value, parts) {
|
|
17
|
+
if (value === void 0 || value === null) return;
|
|
18
|
+
if (value instanceof Date) {
|
|
19
|
+
parts.push(`${name}=${value.toISOString()}`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(value)) {
|
|
23
|
+
if (value.some((item) => item !== null && typeof item === "object")) {
|
|
24
|
+
for (const item of value) serialize(`${name}[]`, item, parts);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const serialized = serializeArrayParam({
|
|
28
|
+
explode: true,
|
|
29
|
+
name,
|
|
30
|
+
style: "form",
|
|
31
|
+
value
|
|
32
|
+
});
|
|
33
|
+
if (serialized) parts.push(serialized);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (typeof value === "object") {
|
|
37
|
+
for (const [key, child] of Object.entries(value)) serialize(`${name}[${key}]`, child, parts);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const serialized = serializePrimitiveParam({
|
|
41
|
+
name,
|
|
42
|
+
value
|
|
43
|
+
});
|
|
44
|
+
if (serialized) parts.push(serialized);
|
|
45
|
+
}
|
|
46
|
+
const querySerializer = (query) => {
|
|
47
|
+
const parts = [];
|
|
48
|
+
for (const [name, value] of Object.entries(query)) serialize(name, value, parts);
|
|
49
|
+
return parts.join("&");
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
export { querySerializer };
|
|
54
|
+
//# sourceMappingURL=query-serializer.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-serializer.mjs","names":[],"sources":["../../src/utils/query-serializer.ts"],"sourcesContent":["import type { QuerySerializer } from '../generated/mapi/core/bodySerializer.gen';\nimport { serializeArrayParam, serializePrimitiveParam } from '../generated/mapi/core/pathSerializer.gen';\n\n/**\n * Query serializer for the Management API client.\n *\n * Behaves identically to the generated default for primitives, primitive\n * arrays, and dates, but additionally serializes **nested objects** (and arrays\n * of objects) into bracket notation — e.g. `filter_query[component][in]=hero`.\n *\n * The generated default serializer throws on this nesting (\"Deeply-nested\n * arrays/objects aren't supported. Provide your own `querySerializer()`\"), yet\n * MAPI requires `filter_query` as a nested hash and rejects flat strings. This\n * mirrors the bracket serialization used by `storyblok-js-client`.\n */\nfunction serialize(name: string, value: unknown, parts: string[]): void {\n if (value === undefined || value === null) {\n return;\n }\n\n if (value instanceof Date) {\n parts.push(`${name}=${value.toISOString()}`);\n return;\n }\n\n if (Array.isArray(value)) {\n // Arrays containing objects (e.g. `filter_query.__or`) need per-item\n // bracket recursion; the default serializer cannot express them.\n if (value.some(item => item !== null && typeof item === 'object')) {\n for (const item of value) {\n serialize(`${name}[]`, item, parts);\n }\n return;\n }\n // Primitive arrays keep the generated default form (`name=a&name=b`).\n const serialized = serializeArrayParam({ explode: true, name, style: 'form', value });\n if (serialized) {\n parts.push(serialized);\n }\n return;\n }\n\n if (typeof value === 'object') {\n for (const [key, child] of Object.entries(value)) {\n serialize(`${name}[${key}]`, child, parts);\n }\n return;\n }\n\n const serialized = serializePrimitiveParam({ name, value: value as string });\n if (serialized) {\n parts.push(serialized);\n }\n}\n\nexport const querySerializer: QuerySerializer = (query) => {\n const parts: string[] = [];\n for (const [name, value] of Object.entries(query)) {\n serialize(name, value, parts);\n }\n return parts.join('&');\n};\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAS,UAAU,MAAc,OAAgB,OAAuB;AACtE,KAAI,UAAU,UAAa,UAAU,KACnC;AAGF,KAAI,iBAAiB,MAAM;AACzB,QAAM,KAAK,GAAG,KAAK,GAAG,MAAM,aAAa,GAAG;AAC5C;;AAGF,KAAI,MAAM,QAAQ,MAAM,EAAE;AAGxB,MAAI,MAAM,MAAK,SAAQ,SAAS,QAAQ,OAAO,SAAS,SAAS,EAAE;AACjE,QAAK,MAAM,QAAQ,MACjB,WAAU,GAAG,KAAK,KAAK,MAAM,MAAM;AAErC;;EAGF,MAAM,aAAa,oBAAoB;GAAE,SAAS;GAAM;GAAM,OAAO;GAAQ;GAAO,CAAC;AACrF,MAAI,WACF,OAAM,KAAK,WAAW;AAExB;;AAGF,KAAI,OAAO,UAAU,UAAU;AAC7B,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,CAC9C,WAAU,GAAG,KAAK,GAAG,IAAI,IAAI,OAAO,MAAM;AAE5C;;CAGF,MAAM,aAAa,wBAAwB;EAAE;EAAa;EAAiB,CAAC;AAC5E,KAAI,WACF,OAAM,KAAK,WAAW;;AAI1B,MAAa,mBAAoC,UAAU;CACzD,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,CAC/C,WAAU,MAAM,OAAO,MAAM;AAE/B,QAAO,MAAM,KAAK,IAAI"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
let async_sema = require("async-sema");
|
|
1
|
+
const require_throttle = require('./throttle.cjs');
|
|
3
2
|
|
|
4
3
|
//#region src/utils/rate-limit.ts
|
|
5
4
|
const DEFAULT_REQUESTS_PER_SECOND = 6;
|
|
@@ -16,11 +15,8 @@ function createThrottleManager(config) {
|
|
|
16
15
|
if (config === false) return { execute: (fn) => fn() };
|
|
17
16
|
const { requestsPerSecond, maxConcurrency } = typeof config === "number" ? { requestsPerSecond: config } : config;
|
|
18
17
|
const rps = requestsPerSecond ?? maxConcurrency ?? DEFAULT_REQUESTS_PER_SECOND;
|
|
19
|
-
const
|
|
20
|
-
return { execute:
|
|
21
|
-
await rl();
|
|
22
|
-
return fn();
|
|
23
|
-
} };
|
|
18
|
+
const throttle = require_throttle.createThrottle(Math.min(rps, MAX_RATE_LIMIT));
|
|
19
|
+
return { execute: (fn) => throttle.execute(fn) };
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.cjs","names":[],"sources":["../../src/utils/rate-limit.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"rate-limit.cjs","names":["createThrottle"],"sources":["../../src/utils/rate-limit.ts"],"sourcesContent":["import { createThrottle } from './throttle';\n\nconst DEFAULT_REQUESTS_PER_SECOND = 6;\nconst MAX_RATE_LIMIT = 1_000;\n\nexport interface RateLimitConfig {\n /**\n * Maximum number of MAPI requests to start per second.\n * Defaults to 6. Capped at 1000.\n */\n requestsPerSecond?: number;\n /**\n * @deprecated Use `requestsPerSecond` instead.\n * @todo(next-major): Remove this field.\n */\n maxConcurrency?: number;\n}\n\nexport interface ThrottleManager {\n execute: <T>(fn: () => Promise<T>) => Promise<T>;\n}\n\n/**\n * Creates a `ThrottleManager` from the user-supplied `rateLimit` config.\n *\n * - `false` -> no throttling (passthrough)\n * - `number` -> N requests per second\n * - `{ requestsPerSecond: n }` -> N requests per second\n * - `{}` / `undefined` (default) -> DEFAULT_REQUESTS_PER_SECOND per second\n */\nexport function createThrottleManager(config: RateLimitConfig | number | false): ThrottleManager {\n if (config === false) {\n return { execute: fn => fn() };\n }\n\n const resolvedConfig: RateLimitConfig = typeof config === 'number' ? { requestsPerSecond: config } : config;\n const { requestsPerSecond, maxConcurrency } = resolvedConfig;\n const rps = requestsPerSecond ?? maxConcurrency ?? DEFAULT_REQUESTS_PER_SECOND;\n const throttle = createThrottle(Math.min(rps, MAX_RATE_LIMIT));\n\n return {\n execute: fn => throttle.execute(fn),\n };\n}\n"],"mappings":";;;AAEA,MAAM,8BAA8B;AACpC,MAAM,iBAAiB;;;;;;;;;AA2BvB,SAAgB,sBAAsB,QAA2D;AAC/F,KAAI,WAAW,MACb,QAAO,EAAE,UAAS,OAAM,IAAI,EAAE;CAIhC,MAAM,EAAE,mBAAmB,mBADa,OAAO,WAAW,WAAW,EAAE,mBAAmB,QAAQ,GAAG;CAErG,MAAM,MAAM,qBAAqB,kBAAkB;CACnD,MAAM,WAAWA,gCAAe,KAAK,IAAI,KAAK,eAAe,CAAC;AAE9D,QAAO,EACL,UAAS,OAAM,SAAS,QAAQ,GAAG,EACpC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createThrottle } from "./throttle.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/rate-limit.ts
|
|
4
4
|
const DEFAULT_REQUESTS_PER_SECOND = 6;
|
|
@@ -15,11 +15,8 @@ function createThrottleManager(config) {
|
|
|
15
15
|
if (config === false) return { execute: (fn) => fn() };
|
|
16
16
|
const { requestsPerSecond, maxConcurrency } = typeof config === "number" ? { requestsPerSecond: config } : config;
|
|
17
17
|
const rps = requestsPerSecond ?? maxConcurrency ?? DEFAULT_REQUESTS_PER_SECOND;
|
|
18
|
-
const
|
|
19
|
-
return { execute:
|
|
20
|
-
await rl();
|
|
21
|
-
return fn();
|
|
22
|
-
} };
|
|
18
|
+
const throttle = createThrottle(Math.min(rps, MAX_RATE_LIMIT));
|
|
19
|
+
return { execute: (fn) => throttle.execute(fn) };
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.mjs","names":[],"sources":["../../src/utils/rate-limit.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"rate-limit.mjs","names":[],"sources":["../../src/utils/rate-limit.ts"],"sourcesContent":["import { createThrottle } from './throttle';\n\nconst DEFAULT_REQUESTS_PER_SECOND = 6;\nconst MAX_RATE_LIMIT = 1_000;\n\nexport interface RateLimitConfig {\n /**\n * Maximum number of MAPI requests to start per second.\n * Defaults to 6. Capped at 1000.\n */\n requestsPerSecond?: number;\n /**\n * @deprecated Use `requestsPerSecond` instead.\n * @todo(next-major): Remove this field.\n */\n maxConcurrency?: number;\n}\n\nexport interface ThrottleManager {\n execute: <T>(fn: () => Promise<T>) => Promise<T>;\n}\n\n/**\n * Creates a `ThrottleManager` from the user-supplied `rateLimit` config.\n *\n * - `false` -> no throttling (passthrough)\n * - `number` -> N requests per second\n * - `{ requestsPerSecond: n }` -> N requests per second\n * - `{}` / `undefined` (default) -> DEFAULT_REQUESTS_PER_SECOND per second\n */\nexport function createThrottleManager(config: RateLimitConfig | number | false): ThrottleManager {\n if (config === false) {\n return { execute: fn => fn() };\n }\n\n const resolvedConfig: RateLimitConfig = typeof config === 'number' ? { requestsPerSecond: config } : config;\n const { requestsPerSecond, maxConcurrency } = resolvedConfig;\n const rps = requestsPerSecond ?? maxConcurrency ?? DEFAULT_REQUESTS_PER_SECOND;\n const throttle = createThrottle(Math.min(rps, MAX_RATE_LIMIT));\n\n return {\n execute: fn => throttle.execute(fn),\n };\n}\n"],"mappings":";;;AAEA,MAAM,8BAA8B;AACpC,MAAM,iBAAiB;;;;;;;;;AA2BvB,SAAgB,sBAAsB,QAA2D;AAC/F,KAAI,WAAW,MACb,QAAO,EAAE,UAAS,OAAM,IAAI,EAAE;CAIhC,MAAM,EAAE,mBAAmB,mBADa,OAAO,WAAW,WAAW,EAAE,mBAAmB,QAAQ,GAAG;CAErG,MAAM,MAAM,qBAAqB,kBAAkB;CACnD,MAAM,WAAW,eAAe,KAAK,IAAI,KAAK,eAAe,CAAC;AAE9D,QAAO,EACL,UAAS,OAAM,SAAS,QAAQ,GAAG,EACpC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/throttle.ts
|
|
3
|
+
/**
|
|
4
|
+
* Creates a per-second rate limiter. At most `limit` calls may start within any
|
|
5
|
+
* rolling one-second window; once the window is full, further calls wait until
|
|
6
|
+
* the oldest call in it ages out. This matches how the Storyblok API enforces
|
|
7
|
+
* its limits: a fixed number of requests per one-second window, not a cap on
|
|
8
|
+
* the number of simultaneous requests.
|
|
9
|
+
*
|
|
10
|
+
* The limiter holds only a list of recent start timestamps, pruned against
|
|
11
|
+
* `Date.now()` on every attempt, and every wait resolves the promise the caller
|
|
12
|
+
* already awaits. It therefore keeps no counter that a scheduled callback must
|
|
13
|
+
* decrement, and schedules no timer that outlives the awaited call. That is a
|
|
14
|
+
* hard requirement on runtimes which suspend between requests and drop pending
|
|
15
|
+
* timers (for example Cloudflare Workers): a shared limiter that released its
|
|
16
|
+
* slots from a detached timer would leak its in-flight count across requests
|
|
17
|
+
* until it deadlocked.
|
|
18
|
+
*
|
|
19
|
+
* A non-positive or non-finite `limit` disables throttling and lets every call
|
|
20
|
+
* through.
|
|
21
|
+
*/
|
|
22
|
+
function createThrottle(initialLimit) {
|
|
23
|
+
const intervalMs = 1e3;
|
|
24
|
+
let limit = initialLimit;
|
|
25
|
+
const starts = [];
|
|
26
|
+
const acquire = () => {
|
|
27
|
+
if (!Number.isFinite(limit) || limit <= 0) return Promise.resolve();
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
const attempt = () => {
|
|
30
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
31
|
+
resolve();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
while (starts.length > 0 && starts[0] <= now - intervalMs) starts.shift();
|
|
36
|
+
if (starts.length < limit) {
|
|
37
|
+
starts.push(now);
|
|
38
|
+
resolve();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const wait = starts[0] + intervalMs - now;
|
|
42
|
+
setTimeout(attempt, wait > 0 ? wait : 0);
|
|
43
|
+
};
|
|
44
|
+
attempt();
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
execute: (fn) => acquire().then(fn),
|
|
49
|
+
setLimit: (n) => {
|
|
50
|
+
limit = n;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
exports.createThrottle = createThrottle;
|
|
57
|
+
//# sourceMappingURL=throttle.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"throttle.cjs","names":[],"sources":["../../src/utils/throttle.ts"],"sourcesContent":["// This file is duplicated verbatim in @storyblok/api-client and\n// @storyblok/management-api-client. The two copies must stay identical; apply\n// any change to both. It is intentionally not extracted into a shared package\n// so the two independently published clients keep no shared runtime dependency.\n\nexport interface Throttle {\n /** Runs `fn` once a per-second slot is available and returns its result. */\n execute: <T>(fn: () => Promise<T>) => Promise<T>;\n /** Adjusts the per-second limit applied to subsequent windows. */\n setLimit: (limit: number) => void;\n}\n\n/**\n * Creates a per-second rate limiter. At most `limit` calls may start within any\n * rolling one-second window; once the window is full, further calls wait until\n * the oldest call in it ages out. This matches how the Storyblok API enforces\n * its limits: a fixed number of requests per one-second window, not a cap on\n * the number of simultaneous requests.\n *\n * The limiter holds only a list of recent start timestamps, pruned against\n * `Date.now()` on every attempt, and every wait resolves the promise the caller\n * already awaits. It therefore keeps no counter that a scheduled callback must\n * decrement, and schedules no timer that outlives the awaited call. That is a\n * hard requirement on runtimes which suspend between requests and drop pending\n * timers (for example Cloudflare Workers): a shared limiter that released its\n * slots from a detached timer would leak its in-flight count across requests\n * until it deadlocked.\n *\n * A non-positive or non-finite `limit` disables throttling and lets every call\n * through.\n */\nexport function createThrottle(initialLimit: number): Throttle {\n const intervalMs = 1000;\n let limit = initialLimit;\n // Start timestamps of the calls currently inside the rolling window.\n const starts: number[] = [];\n\n const acquire = (): Promise<void> => {\n if (!Number.isFinite(limit) || limit <= 0) {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve) => {\n const attempt = () => {\n // The limit can drop to a non-positive or non-finite value (via\n // setLimit) while this call is waiting. Re-check the disabled guard so\n // parked callers resolve instead of rescheduling forever.\n if (!Number.isFinite(limit) || limit <= 0) {\n resolve();\n return;\n }\n\n const now = Date.now();\n while (starts.length > 0 && starts[0] <= now - intervalMs) {\n starts.shift();\n }\n\n if (starts.length < limit) {\n starts.push(now);\n resolve();\n return;\n }\n\n // Window is full: retry once the oldest call ages out. The timer only\n // resolves the promise the caller awaits, so it is never orphaned.\n const wait = starts[0] + intervalMs - now;\n setTimeout(attempt, wait > 0 ? wait : 0);\n };\n\n attempt();\n });\n };\n\n return {\n execute: <T>(fn: () => Promise<T>): Promise<T> => acquire().then(fn),\n setLimit: (n: number) => {\n limit = n;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,eAAe,cAAgC;CAC7D,MAAM,aAAa;CACnB,IAAI,QAAQ;CAEZ,MAAM,SAAmB,EAAE;CAE3B,MAAM,gBAA+B;AACnC,MAAI,CAAC,OAAO,SAAS,MAAM,IAAI,SAAS,EACtC,QAAO,QAAQ,SAAS;AAG1B,SAAO,IAAI,SAAe,YAAY;GACpC,MAAM,gBAAgB;AAIpB,QAAI,CAAC,OAAO,SAAS,MAAM,IAAI,SAAS,GAAG;AACzC,cAAS;AACT;;IAGF,MAAM,MAAM,KAAK,KAAK;AACtB,WAAO,OAAO,SAAS,KAAK,OAAO,MAAM,MAAM,WAC7C,QAAO,OAAO;AAGhB,QAAI,OAAO,SAAS,OAAO;AACzB,YAAO,KAAK,IAAI;AAChB,cAAS;AACT;;IAKF,MAAM,OAAO,OAAO,KAAK,aAAa;AACtC,eAAW,SAAS,OAAO,IAAI,OAAO,EAAE;;AAG1C,YAAS;IACT;;AAGJ,QAAO;EACL,UAAa,OAAqC,SAAS,CAAC,KAAK,GAAG;EACpE,WAAW,MAAc;AACvB,WAAQ;;EAEX"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//#region src/utils/throttle.ts
|
|
2
|
+
/**
|
|
3
|
+
* Creates a per-second rate limiter. At most `limit` calls may start within any
|
|
4
|
+
* rolling one-second window; once the window is full, further calls wait until
|
|
5
|
+
* the oldest call in it ages out. This matches how the Storyblok API enforces
|
|
6
|
+
* its limits: a fixed number of requests per one-second window, not a cap on
|
|
7
|
+
* the number of simultaneous requests.
|
|
8
|
+
*
|
|
9
|
+
* The limiter holds only a list of recent start timestamps, pruned against
|
|
10
|
+
* `Date.now()` on every attempt, and every wait resolves the promise the caller
|
|
11
|
+
* already awaits. It therefore keeps no counter that a scheduled callback must
|
|
12
|
+
* decrement, and schedules no timer that outlives the awaited call. That is a
|
|
13
|
+
* hard requirement on runtimes which suspend between requests and drop pending
|
|
14
|
+
* timers (for example Cloudflare Workers): a shared limiter that released its
|
|
15
|
+
* slots from a detached timer would leak its in-flight count across requests
|
|
16
|
+
* until it deadlocked.
|
|
17
|
+
*
|
|
18
|
+
* A non-positive or non-finite `limit` disables throttling and lets every call
|
|
19
|
+
* through.
|
|
20
|
+
*/
|
|
21
|
+
function createThrottle(initialLimit) {
|
|
22
|
+
const intervalMs = 1e3;
|
|
23
|
+
let limit = initialLimit;
|
|
24
|
+
const starts = [];
|
|
25
|
+
const acquire = () => {
|
|
26
|
+
if (!Number.isFinite(limit) || limit <= 0) return Promise.resolve();
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
const attempt = () => {
|
|
29
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
30
|
+
resolve();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
while (starts.length > 0 && starts[0] <= now - intervalMs) starts.shift();
|
|
35
|
+
if (starts.length < limit) {
|
|
36
|
+
starts.push(now);
|
|
37
|
+
resolve();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const wait = starts[0] + intervalMs - now;
|
|
41
|
+
setTimeout(attempt, wait > 0 ? wait : 0);
|
|
42
|
+
};
|
|
43
|
+
attempt();
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
execute: (fn) => acquire().then(fn),
|
|
48
|
+
setLimit: (n) => {
|
|
49
|
+
limit = n;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { createThrottle };
|
|
56
|
+
//# sourceMappingURL=throttle.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"throttle.mjs","names":[],"sources":["../../src/utils/throttle.ts"],"sourcesContent":["// This file is duplicated verbatim in @storyblok/api-client and\n// @storyblok/management-api-client. The two copies must stay identical; apply\n// any change to both. It is intentionally not extracted into a shared package\n// so the two independently published clients keep no shared runtime dependency.\n\nexport interface Throttle {\n /** Runs `fn` once a per-second slot is available and returns its result. */\n execute: <T>(fn: () => Promise<T>) => Promise<T>;\n /** Adjusts the per-second limit applied to subsequent windows. */\n setLimit: (limit: number) => void;\n}\n\n/**\n * Creates a per-second rate limiter. At most `limit` calls may start within any\n * rolling one-second window; once the window is full, further calls wait until\n * the oldest call in it ages out. This matches how the Storyblok API enforces\n * its limits: a fixed number of requests per one-second window, not a cap on\n * the number of simultaneous requests.\n *\n * The limiter holds only a list of recent start timestamps, pruned against\n * `Date.now()` on every attempt, and every wait resolves the promise the caller\n * already awaits. It therefore keeps no counter that a scheduled callback must\n * decrement, and schedules no timer that outlives the awaited call. That is a\n * hard requirement on runtimes which suspend between requests and drop pending\n * timers (for example Cloudflare Workers): a shared limiter that released its\n * slots from a detached timer would leak its in-flight count across requests\n * until it deadlocked.\n *\n * A non-positive or non-finite `limit` disables throttling and lets every call\n * through.\n */\nexport function createThrottle(initialLimit: number): Throttle {\n const intervalMs = 1000;\n let limit = initialLimit;\n // Start timestamps of the calls currently inside the rolling window.\n const starts: number[] = [];\n\n const acquire = (): Promise<void> => {\n if (!Number.isFinite(limit) || limit <= 0) {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve) => {\n const attempt = () => {\n // The limit can drop to a non-positive or non-finite value (via\n // setLimit) while this call is waiting. Re-check the disabled guard so\n // parked callers resolve instead of rescheduling forever.\n if (!Number.isFinite(limit) || limit <= 0) {\n resolve();\n return;\n }\n\n const now = Date.now();\n while (starts.length > 0 && starts[0] <= now - intervalMs) {\n starts.shift();\n }\n\n if (starts.length < limit) {\n starts.push(now);\n resolve();\n return;\n }\n\n // Window is full: retry once the oldest call ages out. The timer only\n // resolves the promise the caller awaits, so it is never orphaned.\n const wait = starts[0] + intervalMs - now;\n setTimeout(attempt, wait > 0 ? wait : 0);\n };\n\n attempt();\n });\n };\n\n return {\n execute: <T>(fn: () => Promise<T>): Promise<T> => acquire().then(fn),\n setLimit: (n: number) => {\n limit = n;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,eAAe,cAAgC;CAC7D,MAAM,aAAa;CACnB,IAAI,QAAQ;CAEZ,MAAM,SAAmB,EAAE;CAE3B,MAAM,gBAA+B;AACnC,MAAI,CAAC,OAAO,SAAS,MAAM,IAAI,SAAS,EACtC,QAAO,QAAQ,SAAS;AAG1B,SAAO,IAAI,SAAe,YAAY;GACpC,MAAM,gBAAgB;AAIpB,QAAI,CAAC,OAAO,SAAS,MAAM,IAAI,SAAS,GAAG;AACzC,cAAS;AACT;;IAGF,MAAM,MAAM,KAAK,KAAK;AACtB,WAAO,OAAO,SAAS,KAAK,OAAO,MAAM,MAAM,WAC7C,QAAO,OAAO;AAGhB,QAAI,OAAO,SAAS,OAAO;AACzB,YAAO,KAAK,IAAI;AAChB,cAAS;AACT;;IAKF,MAAM,OAAO,OAAO,KAAK,aAAa;AACtC,eAAW,SAAS,OAAO,IAAI,OAAO,EAAE;;AAG1C,YAAS;IACT;;AAGJ,QAAO;EACL,UAAa,OAAqC,SAAS,CAAC,KAAK,GAAG;EACpE,WAAW,MAAc;AACvB,WAAQ;;EAEX"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storyblok/management-api-client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.1",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Storyblok Management API Client",
|
|
7
7
|
"author": "",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"homepage": "https://github.com/storyblok/monoblok/tree/main/packages/mapi-client#readme",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
|
-
"url": "https://github.com/storyblok/monoblok.git",
|
|
12
|
+
"url": "git+https://github.com/storyblok/monoblok.git",
|
|
13
13
|
"directory": "packages/mapi-client"
|
|
14
14
|
},
|
|
15
15
|
"bugs": {
|
|
@@ -30,37 +30,38 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"async-sema": "^3.1.1",
|
|
34
33
|
"ky": "^1.14.3",
|
|
35
34
|
"@storyblok/region-helper": "1.5.0"
|
|
36
35
|
},
|
|
37
36
|
"devDependencies": {
|
|
38
|
-
"@hey-api/openapi-ts": "^0.92.3",
|
|
39
|
-
"@msw/source": "^0.6.1",
|
|
40
37
|
"@types/node": "^24.1.0",
|
|
41
38
|
"eslint": "^9.39.2",
|
|
42
|
-
"glob": "^13.0.6",
|
|
43
39
|
"msw": "^2.12.9",
|
|
44
40
|
"pathe": "^2.0.3",
|
|
45
41
|
"tsdown": "^0.20.3",
|
|
46
42
|
"tsx": "^4.20.3",
|
|
47
|
-
"vitest": "^
|
|
48
|
-
"@storyblok/
|
|
49
|
-
"@storyblok/
|
|
43
|
+
"vitest": "^4.1.3",
|
|
44
|
+
"@storyblok/eslint-config": "0.6.0",
|
|
45
|
+
"@storyblok/openapi-codegen": "0.0.1"
|
|
50
46
|
},
|
|
51
47
|
"nx": {
|
|
52
48
|
"targets": {
|
|
53
49
|
"generate": {
|
|
54
|
-
"
|
|
55
|
-
"
|
|
50
|
+
"inputs": [
|
|
51
|
+
"{projectRoot}/scripts/generate.ts",
|
|
52
|
+
"{projectRoot}/package.json",
|
|
53
|
+
"openapiCodegen"
|
|
56
54
|
],
|
|
57
55
|
"outputs": [
|
|
58
56
|
"{projectRoot}/src/generated/**"
|
|
57
|
+
],
|
|
58
|
+
"cache": true,
|
|
59
|
+
"dependsOn": [
|
|
60
|
+
"@storyblok/openapi-codegen:build"
|
|
59
61
|
]
|
|
60
62
|
},
|
|
61
63
|
"build": {
|
|
62
64
|
"dependsOn": [
|
|
63
|
-
"generate",
|
|
64
65
|
"^build"
|
|
65
66
|
],
|
|
66
67
|
"outputs": [
|
|
@@ -72,10 +73,10 @@
|
|
|
72
73
|
"scripts": {
|
|
73
74
|
"generate": "tsx scripts/generate.ts",
|
|
74
75
|
"build": "tsdown",
|
|
75
|
-
"test": "vitest",
|
|
76
|
-
"test:
|
|
76
|
+
"test": "vitest run",
|
|
77
|
+
"test:types": "tsc --noEmit --skipLibCheck",
|
|
78
|
+
"coverage": "vitest run --coverage",
|
|
77
79
|
"lint": "eslint .",
|
|
78
|
-
"lint:fix": "eslint . --fix"
|
|
79
|
-
"typecheck": "tsc --noEmit"
|
|
80
|
+
"lint:fix": "eslint . --fix"
|
|
80
81
|
}
|
|
81
82
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @storyblok/mapi-integration-tests
|
|
2
|
+
|
|
3
|
+
Integration tests for [`@storyblok/management-api-client`](../../) paired with [`@storyblok/schema`](../../../schema).
|
|
4
|
+
|
|
5
|
+
This playground exists so the management-api-client package itself stays free of a runtime dependency on `@storyblok/schema`, while still letting us verify that the two packages line up.
|
|
6
|
+
|
|
7
|
+
## Type tests
|
|
8
|
+
|
|
9
|
+
`test/types/*.test-d.ts` assert that `defineBlock` / `defineX*` payloads from `@storyblok/schema` are assignable to the corresponding MAPI request bodies, and that `.withTypes()` narrows responses correctly. They run in CI:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm --filter @storyblok/mapi-integration-tests test
|
|
13
|
+
pnpm --filter @storyblok/mapi-integration-tests test:types
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## End-to-end tests
|
|
17
|
+
|
|
18
|
+
`test/specs/*.spec.e2e.ts` exercise a real round-trip against the Storyblok MAPI using a personal access token. Run manually only:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm --filter @storyblok/mapi-integration-tests test:e2e
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires `.env.qa-engineer-manual` at the repo root with `STORYBLOK_TOKEN` and `STORYBLOK_SPACE_ID`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -x "$basedir/node" ]; then
|
|
13
|
+
exec "$basedir/node" "$basedir/../eslint/bin/eslint.js" "$@"
|
|
14
|
+
else
|
|
15
|
+
exec node "$basedir/../eslint/bin/eslint.js" "$@"
|
|
16
|
+
fi
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -x "$basedir/node" ]; then
|
|
13
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
14
|
+
else
|
|
15
|
+
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
16
|
+
fi
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -x "$basedir/node" ]; then
|
|
13
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
14
|
+
else
|
|
15
|
+
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
16
|
+
fi
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -x "$basedir/node" ]; then
|
|
13
|
+
exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
|
|
14
|
+
else
|
|
15
|
+
exec node "$basedir/../vitest/vitest.mjs" "$@"
|
|
16
|
+
fi
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@storyblok/mapi-integration-tests",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"description": "Integration tests for @storyblok/management-api-client paired with @storyblok/schema",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "vitest run",
|
|
9
|
+
"test:types": "tsc --noEmit --skipLibCheck",
|
|
10
|
+
"test:e2e": "vitest run -c vitest.config.e2e.ts",
|
|
11
|
+
"lint": "eslint .",
|
|
12
|
+
"lint:fix": "eslint . --fix"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@storyblok/eslint-config": "workspace:*",
|
|
16
|
+
"@storyblok/management-api-client": "workspace:*",
|
|
17
|
+
"@storyblok/schema": "workspace:*",
|
|
18
|
+
"@types/node": "^24.1.0",
|
|
19
|
+
"dotenv": "^17.3.1",
|
|
20
|
+
"eslint": "^9.39.2",
|
|
21
|
+
"typescript": "5.8.3",
|
|
22
|
+
"vitest": "^4.1.3"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { config } from 'dotenv';
|
|
3
|
+
|
|
4
|
+
config({ path: resolve(import.meta.dirname, '../../../../../.env.qa-engineer-manual') });
|
|
5
|
+
|
|
6
|
+
if (!process.env.STORYBLOK_TOKEN || !process.env.STORYBLOK_SPACE_ID) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
'E2E tests require STORYBLOK_TOKEN and STORYBLOK_SPACE_ID.\n'
|
|
9
|
+
+ 'Create a .env.qa-engineer-manual file at the repo root with these variables.',
|
|
10
|
+
);
|
|
11
|
+
}
|