@webiny/api-headless-cms-testing 0.0.0-unstable.5387e5f7c8 → 0.0.0-unstable.9609e4e0c9

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.
@@ -6,6 +6,12 @@ export interface CmsTestHandlerParams {
6
6
  /** Identity for the request. `undefined` → a default admin; `null` → anonymous. */
7
7
  identity?: IdentityData | null;
8
8
  permissions?: SecurityPermission[];
9
+ /**
10
+ * Permissions of other identities, by identity id, for code that evaluates another user
11
+ * through `IdentityContext.withIdentity`. The request identity gets `permissions`; other
12
+ * identities not listed here get none.
13
+ */
14
+ permissionsByIdentity?: Record<string, SecurityPermission[]>;
9
15
  testProjectLicense?: DecryptedWcpProjectLicense;
10
16
  /** CMS endpoint type to build. Defaults to "manage". */
11
17
  cmsType?: "manage" | "read" | "preview";
@@ -28,7 +28,8 @@ const createCmsTestHandler = (params = {})=>{
28
28
  const setupRoot = (container)=>{
29
29
  container.registerInstance(TestIdentity, identity);
30
30
  container.registerInstance(TestPermissions, {
31
- list: permissions
31
+ list: permissions,
32
+ byIdentity: params.permissionsByIdentity
32
33
  });
33
34
  container.register(TestAuthenticator);
34
35
  container.register(TestAuthorizer);
@@ -1 +1 @@
1
- {"version":3,"file":"createCmsTestHandler.js","sources":["../src/createCmsTestHandler.ts"],"sourcesContent":["import { createTestHttpHandler } from \"@webiny/event-handler-core/features/testing\";\nimport type { Container } from \"@webiny/di\";\nimport { ApiCoreFeature, registerApiCoreStorageOperations } from \"@webiny/api-core\";\nimport { GraphQLSchemaCacheFeature } from \"@webiny/api-graphql\";\nimport { GraphQLSchemaKeyVerificationFeature } from \"@webiny/api-graphql\";\nimport { EncryptionKeyCacheFeature } from \"@webiny/api-core/features/encryption/index.js\";\nimport { JwksStoreFeature } from \"@webiny/api-core/idp/index.js\";\nimport { GraphQLEngineFeature } from \"@webiny/api-graphql\";\nimport { WcpLicenseLoader } from \"@webiny/api-core/features/wcp/WcpLicenseLoader.js\";\nimport { getStorageOps } from \"@webiny/api-core/testing/environment.js\";\nimport { createTestWcpLicense } from \"@webiny/wcp/testing/createTestWcpLicense.js\";\nimport { getIntrospectionQuery } from \"graphql\";\nimport type { ApiCoreStorageOperations } from \"@webiny/api-core/types/core.js\";\nimport type { IdentityData } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport type { SecurityPermission } from \"@webiny/api-core/types/security.js\";\nimport type { DecryptedWcpProjectLicense } from \"@webiny/wcp/types.js\";\nimport { HeadlessCmsFeature } from \"@webiny/api-headless-cms/HeadlessCmsFeature.js\";\nimport { TestIdentity, TestAuthenticator } from \"@webiny/api-core-testing\";\nimport { TestPermissions, TestAuthorizer } from \"@webiny/api-core-testing\";\nimport { AuthTriggerHandler } from \"@webiny/api-core-testing\";\nimport { RootTenantInitializer } from \"@webiny/api-core-testing\";\nimport { processLegacyPlugins } from \"./processLegacyPlugins.js\";\n\nconst DEFAULT_IDENTITY: IdentityData = {\n id: \"id-12345678\",\n type: \"admin\",\n displayName: \"John Doe\"\n};\n\nexport interface CmsTestHandlerParams {\n /** Identity for the request. `undefined` → a default admin; `null` → anonymous. */\n identity?: IdentityData | null;\n permissions?: SecurityPermission[];\n testProjectLicense?: DecryptedWcpProjectLicense;\n /** CMS endpoint type to build. Defaults to \"manage\". */\n cmsType?: \"manage\" | \"read\" | \"preview\";\n /** Plugins forwarded to `HeadlessCmsFeature.register` as `extraPlugins` (e.g. CMS model plugins). */\n extraCmsPlugins?: any[];\n /**\n * Legacy escape hatch (being retired — prefer `setup`). A mixed array, dispatched like the old\n * `useContextHandler`:\n * - RegisterExtensionPlugins are applied at register() time (DI registration);\n * - static plugins (CmsModelPlugin, GraphQLSchemaPlugin, …) are forwarded to HeadlessCmsFeature\n * as extraPlugins so their models reach the container before any initializer caches them;\n * - plain `container => {}` functions run LAST (after `setup`), so they can override defaults.\n */\n legacyPlugins?: any;\n /**\n * Register the consuming package's own features here (e.g. AcoFeature, FileModel, plus its own\n * getStorageOps presets via processLegacyPlugins). Runs in the request phase AFTER ApiCore + CMS\n * storage + HeadlessCmsFeature, and BEFORE the GraphQL engine — i.e. before any initializer or\n * resolver, the same window the real app handler uses.\n */\n setup?: (container: Container) => void | Promise<void>;\n}\n\nexport interface InvokeParams {\n httpMethod?: \"POST\";\n type?: string;\n body: { query: string; variables?: Record<string, any> };\n headers?: Record<string, string>;\n}\n\n/**\n * Shared integration test handler that wires the real CMS base (ApiCore + HeadlessCms + GraphQL\n * engine + the CMS manage route) the same way the AWS app handler does — auth via Test\n * authenticator/authorizer, root tenant seeded, storage via getStorageOps. Consuming packages add\n * their own features through `params.setup` and build their SDKs on top of `invoke`/`invokeCms`,\n * or grab the fully-initialized request context via `getContext()`.\n */\nexport const createCmsTestHandler = (params: CmsTestHandlerParams = {}) => {\n const apiCoreStorage = getStorageOps<ApiCoreStorageOperations>(\"apiCore\");\n const cmsStorage = getStorageOps(\"cms\");\n\n const identity = params.identity === undefined ? DEFAULT_IDENTITY : params.identity;\n const permissions = params.permissions === undefined ? [{ name: \"*\" }] : params.permissions;\n const cmsType = params.cmsType ?? \"manage\";\n\n const setupRoot = (container: Container) => {\n container.registerInstance(TestIdentity, identity);\n container.registerInstance(TestPermissions, { list: permissions });\n container.register(TestAuthenticator);\n container.register(TestAuthorizer);\n container.registerDecorator(AuthTriggerHandler);\n container.registerDecorator(RootTenantInitializer);\n // Same as the real handlers, so every request after the first reuses the built schema.\n GraphQLSchemaCacheFeature.register(container);\n // Fails a test when a schema factory's output changes under the same schema key.\n GraphQLSchemaKeyVerificationFeature.register(container);\n // Same as the real handlers, so the encryption key is derived once, not per request.\n EncryptionKeyCacheFeature.register(container);\n // Root, so identity providers' signing keys are fetched once per process, not per request.\n JwksStoreFeature.register(container);\n };\n\n // Everything up to (but not including) the GraphQL engine — shared by the HTTP handler and the\n // context-capture handler.\n const setupRequest = async (container: Container) => {\n const wcpLicense = await WcpLicenseLoader.load(\n params.testProjectLicense ?? createTestWcpLicense()\n );\n\n registerApiCoreStorageOperations(container, apiCoreStorage.storageOperations);\n ApiCoreFeature.register(container, { wcpLicense });\n\n // CMS storage preset. All storage presets are RegisterExtensionPlugins (registerDynamoDBCore,\n // registerCmsOpenSearchStorageOperations, dbPlugins, ...); processLegacyPlugins runs them at\n // register() time — before HeadlessCmsFeature builds storage, mirroring the real app's\n // registerExtensions.\n processLegacyPlugins(container, cmsStorage.plugins);\n\n // `legacyPlugins` is a mixed bag: plain `container => {}` functions (called last, after\n // `setup`) plus legacy plugin objects — RegisterExtensionPlugins (register-time) or static\n // Plugins (extraPlugins).\n const legacyItems = [params.legacyPlugins].flat(Infinity as 1).filter(Boolean);\n const isFn = (p: any) => typeof p === \"function\" && !p.prototype;\n\n const legacyObjects = legacyItems.filter(p => !isFn(p));\n processLegacyPlugins(container, legacyObjects);\n const staticPlugins = legacyObjects.filter(\n p => typeof (p as any).apply !== \"function\" && typeof p !== \"function\"\n );\n HeadlessCmsFeature.register(container, {\n type: cmsType,\n extraPlugins: [...(params.extraCmsPlugins ?? []), ...staticPlugins]\n });\n\n await params.setup?.(container);\n\n // Function plugins in `legacyPlugins` run LAST — after the consuming package's own `setup` —\n // so they can override defaults it registered (last-wins).\n for (const plugin of legacyItems.filter(isFn)) {\n (plugin as (container: any) => void)(container);\n }\n };\n\n const handler = createTestHttpHandler({\n root: setupRoot,\n child: async container => {\n await setupRequest(container);\n GraphQLEngineFeature.register(container);\n }\n });\n\n const invoke = async ({ httpMethod = \"POST\", body, headers = {} }: InvokeParams) => {\n const response = await handler({\n method: httpMethod,\n path: \"/graphql\",\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\", ...headers },\n body\n });\n return [response.body, response] as const;\n };\n\n const invokeCms = async ({\n httpMethod = \"POST\",\n type = \"manage\",\n body,\n headers = {}\n }: InvokeParams) => {\n const response = await handler({\n method: httpMethod,\n path: `/cms/${type}`,\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\", ...headers },\n body\n });\n return [response.body, response] as const;\n };\n\n /**\n * Build the request once and return the fully-initialized context (after auth, tenant, CMS and\n * all consumer features): the request container, captured when the handler creates it, after\n * one request has run through it. For tests that resolve services directly from the container\n * rather than issuing GraphQL queries.\n */\n const getContext = async <\n C extends Record<string, any> = Record<string, any>\n >(): Promise<C> => {\n let requestContainer: Container | undefined;\n\n const ctxHandler = createTestHttpHandler({\n root: setupRoot,\n child: async container => {\n await setupRequest(container);\n GraphQLEngineFeature.register(container);\n requestContainer = container;\n }\n });\n\n await ctxHandler({\n method: \"POST\",\n path: \"/graphql\",\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\" },\n body: { query: \"{ __typename }\" }\n });\n\n return { container: requestContainer } as unknown as C;\n };\n\n // Convenience wrappers mirroring the retired `useGraphQLHandler` — thin builders over `invoke`\n // (the main `/graphql` endpoint) so consumers can issue typed queries/mutations directly.\n const createQuery = <T extends Record<string, any> = Record<string, any>>(query: string) => {\n return (variables?: Record<string, any>, headers: Record<string, string> = {}) =>\n invoke({ body: { query, variables: variables || undefined }, headers }) as Promise<\n readonly [T, any]\n >;\n };\n\n const createMutation = <T extends Record<string, any> = Record<string, any>>(\n mutation: string\n ) => {\n return (variables?: Record<string, any>, headers: Record<string, string> = {}) =>\n invoke({\n body: { query: mutation, variables: variables || undefined },\n headers\n }) as Promise<readonly [T, any]>;\n };\n\n const introspect = () => invoke({ body: { query: getIntrospectionQuery() } });\n\n return {\n handler,\n invoke,\n invokeCms,\n getContext,\n createQuery,\n createMutation,\n introspect,\n identity,\n tenant: { id: \"root\", name: \"Root\", parent: null }\n };\n};\n"],"names":["DEFAULT_IDENTITY","createCmsTestHandler","params","apiCoreStorage","getStorageOps","cmsStorage","identity","undefined","permissions","cmsType","setupRoot","container","TestIdentity","TestPermissions","TestAuthenticator","TestAuthorizer","AuthTriggerHandler","RootTenantInitializer","GraphQLSchemaCacheFeature","GraphQLSchemaKeyVerificationFeature","EncryptionKeyCacheFeature","JwksStoreFeature","setupRequest","wcpLicense","WcpLicenseLoader","createTestWcpLicense","registerApiCoreStorageOperations","ApiCoreFeature","processLegacyPlugins","legacyItems","Infinity","Boolean","isFn","p","legacyObjects","staticPlugins","HeadlessCmsFeature","plugin","handler","createTestHttpHandler","GraphQLEngineFeature","invoke","httpMethod","body","headers","response","invokeCms","type","getContext","requestContainer","ctxHandler","createQuery","query","variables","createMutation","mutation","introspect","getIntrospectionQuery"],"mappings":"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"}
1
+ {"version":3,"file":"createCmsTestHandler.js","sources":["../src/createCmsTestHandler.ts"],"sourcesContent":["import { createTestHttpHandler } from \"@webiny/event-handler-core/features/testing\";\nimport type { Container } from \"@webiny/di\";\nimport { ApiCoreFeature, registerApiCoreStorageOperations } from \"@webiny/api-core\";\nimport { GraphQLSchemaCacheFeature } from \"@webiny/api-graphql\";\nimport { GraphQLSchemaKeyVerificationFeature } from \"@webiny/api-graphql\";\nimport { EncryptionKeyCacheFeature } from \"@webiny/api-core/features/encryption/index.js\";\nimport { JwksStoreFeature } from \"@webiny/api-core/idp/index.js\";\nimport { GraphQLEngineFeature } from \"@webiny/api-graphql\";\nimport { WcpLicenseLoader } from \"@webiny/api-core/features/wcp/WcpLicenseLoader.js\";\nimport { getStorageOps } from \"@webiny/api-core/testing/environment.js\";\nimport { createTestWcpLicense } from \"@webiny/wcp/testing/createTestWcpLicense.js\";\nimport { getIntrospectionQuery } from \"graphql\";\nimport type { ApiCoreStorageOperations } from \"@webiny/api-core/types/core.js\";\nimport type { IdentityData } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport type { SecurityPermission } from \"@webiny/api-core/types/security.js\";\nimport type { DecryptedWcpProjectLicense } from \"@webiny/wcp/types.js\";\nimport { HeadlessCmsFeature } from \"@webiny/api-headless-cms/HeadlessCmsFeature.js\";\nimport { TestIdentity, TestAuthenticator } from \"@webiny/api-core-testing\";\nimport { TestPermissions, TestAuthorizer } from \"@webiny/api-core-testing\";\nimport { AuthTriggerHandler } from \"@webiny/api-core-testing\";\nimport { RootTenantInitializer } from \"@webiny/api-core-testing\";\nimport { processLegacyPlugins } from \"./processLegacyPlugins.js\";\n\nconst DEFAULT_IDENTITY: IdentityData = {\n id: \"id-12345678\",\n type: \"admin\",\n displayName: \"John Doe\"\n};\n\nexport interface CmsTestHandlerParams {\n /** Identity for the request. `undefined` → a default admin; `null` → anonymous. */\n identity?: IdentityData | null;\n permissions?: SecurityPermission[];\n /**\n * Permissions of other identities, by identity id, for code that evaluates another user\n * through `IdentityContext.withIdentity`. The request identity gets `permissions`; other\n * identities not listed here get none.\n */\n permissionsByIdentity?: Record<string, SecurityPermission[]>;\n testProjectLicense?: DecryptedWcpProjectLicense;\n /** CMS endpoint type to build. Defaults to \"manage\". */\n cmsType?: \"manage\" | \"read\" | \"preview\";\n /** Plugins forwarded to `HeadlessCmsFeature.register` as `extraPlugins` (e.g. CMS model plugins). */\n extraCmsPlugins?: any[];\n /**\n * Legacy escape hatch (being retired — prefer `setup`). A mixed array, dispatched like the old\n * `useContextHandler`:\n * - RegisterExtensionPlugins are applied at register() time (DI registration);\n * - static plugins (CmsModelPlugin, GraphQLSchemaPlugin, …) are forwarded to HeadlessCmsFeature\n * as extraPlugins so their models reach the container before any initializer caches them;\n * - plain `container => {}` functions run LAST (after `setup`), so they can override defaults.\n */\n legacyPlugins?: any;\n /**\n * Register the consuming package's own features here (e.g. AcoFeature, FileModel, plus its own\n * getStorageOps presets via processLegacyPlugins). Runs in the request phase AFTER ApiCore + CMS\n * storage + HeadlessCmsFeature, and BEFORE the GraphQL engine — i.e. before any initializer or\n * resolver, the same window the real app handler uses.\n */\n setup?: (container: Container) => void | Promise<void>;\n}\n\nexport interface InvokeParams {\n httpMethod?: \"POST\";\n type?: string;\n body: { query: string; variables?: Record<string, any> };\n headers?: Record<string, string>;\n}\n\n/**\n * Shared integration test handler that wires the real CMS base (ApiCore + HeadlessCms + GraphQL\n * engine + the CMS manage route) the same way the AWS app handler does — auth via Test\n * authenticator/authorizer, root tenant seeded, storage via getStorageOps. Consuming packages add\n * their own features through `params.setup` and build their SDKs on top of `invoke`/`invokeCms`,\n * or grab the fully-initialized request context via `getContext()`.\n */\nexport const createCmsTestHandler = (params: CmsTestHandlerParams = {}) => {\n const apiCoreStorage = getStorageOps<ApiCoreStorageOperations>(\"apiCore\");\n const cmsStorage = getStorageOps(\"cms\");\n\n const identity = params.identity === undefined ? DEFAULT_IDENTITY : params.identity;\n const permissions = params.permissions === undefined ? [{ name: \"*\" }] : params.permissions;\n const cmsType = params.cmsType ?? \"manage\";\n\n const setupRoot = (container: Container) => {\n container.registerInstance(TestIdentity, identity);\n container.registerInstance(TestPermissions, {\n list: permissions,\n byIdentity: params.permissionsByIdentity\n });\n container.register(TestAuthenticator);\n container.register(TestAuthorizer);\n container.registerDecorator(AuthTriggerHandler);\n container.registerDecorator(RootTenantInitializer);\n // Same as the real handlers, so every request after the first reuses the built schema.\n GraphQLSchemaCacheFeature.register(container);\n // Fails a test when a schema factory's output changes under the same schema key.\n GraphQLSchemaKeyVerificationFeature.register(container);\n // Same as the real handlers, so the encryption key is derived once, not per request.\n EncryptionKeyCacheFeature.register(container);\n // Root, so identity providers' signing keys are fetched once per process, not per request.\n JwksStoreFeature.register(container);\n };\n\n // Everything up to (but not including) the GraphQL engine — shared by the HTTP handler and the\n // context-capture handler.\n const setupRequest = async (container: Container) => {\n const wcpLicense = await WcpLicenseLoader.load(\n params.testProjectLicense ?? createTestWcpLicense()\n );\n\n registerApiCoreStorageOperations(container, apiCoreStorage.storageOperations);\n ApiCoreFeature.register(container, { wcpLicense });\n\n // CMS storage preset. All storage presets are RegisterExtensionPlugins (registerDynamoDBCore,\n // registerCmsOpenSearchStorageOperations, dbPlugins, ...); processLegacyPlugins runs them at\n // register() time — before HeadlessCmsFeature builds storage, mirroring the real app's\n // registerExtensions.\n processLegacyPlugins(container, cmsStorage.plugins);\n\n // `legacyPlugins` is a mixed bag: plain `container => {}` functions (called last, after\n // `setup`) plus legacy plugin objects — RegisterExtensionPlugins (register-time) or static\n // Plugins (extraPlugins).\n const legacyItems = [params.legacyPlugins].flat(Infinity as 1).filter(Boolean);\n const isFn = (p: any) => typeof p === \"function\" && !p.prototype;\n\n const legacyObjects = legacyItems.filter(p => !isFn(p));\n processLegacyPlugins(container, legacyObjects);\n const staticPlugins = legacyObjects.filter(\n p => typeof (p as any).apply !== \"function\" && typeof p !== \"function\"\n );\n HeadlessCmsFeature.register(container, {\n type: cmsType,\n extraPlugins: [...(params.extraCmsPlugins ?? []), ...staticPlugins]\n });\n\n await params.setup?.(container);\n\n // Function plugins in `legacyPlugins` run LAST — after the consuming package's own `setup` —\n // so they can override defaults it registered (last-wins).\n for (const plugin of legacyItems.filter(isFn)) {\n (plugin as (container: any) => void)(container);\n }\n };\n\n const handler = createTestHttpHandler({\n root: setupRoot,\n child: async container => {\n await setupRequest(container);\n GraphQLEngineFeature.register(container);\n }\n });\n\n const invoke = async ({ httpMethod = \"POST\", body, headers = {} }: InvokeParams) => {\n const response = await handler({\n method: httpMethod,\n path: \"/graphql\",\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\", ...headers },\n body\n });\n return [response.body, response] as const;\n };\n\n const invokeCms = async ({\n httpMethod = \"POST\",\n type = \"manage\",\n body,\n headers = {}\n }: InvokeParams) => {\n const response = await handler({\n method: httpMethod,\n path: `/cms/${type}`,\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\", ...headers },\n body\n });\n return [response.body, response] as const;\n };\n\n /**\n * Build the request once and return the fully-initialized context (after auth, tenant, CMS and\n * all consumer features): the request container, captured when the handler creates it, after\n * one request has run through it. For tests that resolve services directly from the container\n * rather than issuing GraphQL queries.\n */\n const getContext = async <\n C extends Record<string, any> = Record<string, any>\n >(): Promise<C> => {\n let requestContainer: Container | undefined;\n\n const ctxHandler = createTestHttpHandler({\n root: setupRoot,\n child: async container => {\n await setupRequest(container);\n GraphQLEngineFeature.register(container);\n requestContainer = container;\n }\n });\n\n await ctxHandler({\n method: \"POST\",\n path: \"/graphql\",\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\" },\n body: { query: \"{ __typename }\" }\n });\n\n return { container: requestContainer } as unknown as C;\n };\n\n // Convenience wrappers mirroring the retired `useGraphQLHandler` — thin builders over `invoke`\n // (the main `/graphql` endpoint) so consumers can issue typed queries/mutations directly.\n const createQuery = <T extends Record<string, any> = Record<string, any>>(query: string) => {\n return (variables?: Record<string, any>, headers: Record<string, string> = {}) =>\n invoke({ body: { query, variables: variables || undefined }, headers }) as Promise<\n readonly [T, any]\n >;\n };\n\n const createMutation = <T extends Record<string, any> = Record<string, any>>(\n mutation: string\n ) => {\n return (variables?: Record<string, any>, headers: Record<string, string> = {}) =>\n invoke({\n body: { query: mutation, variables: variables || undefined },\n headers\n }) as Promise<readonly [T, any]>;\n };\n\n const introspect = () => invoke({ body: { query: getIntrospectionQuery() } });\n\n return {\n handler,\n invoke,\n invokeCms,\n getContext,\n createQuery,\n createMutation,\n introspect,\n identity,\n tenant: { id: \"root\", name: \"Root\", parent: null }\n };\n};\n"],"names":["DEFAULT_IDENTITY","createCmsTestHandler","params","apiCoreStorage","getStorageOps","cmsStorage","identity","undefined","permissions","cmsType","setupRoot","container","TestIdentity","TestPermissions","TestAuthenticator","TestAuthorizer","AuthTriggerHandler","RootTenantInitializer","GraphQLSchemaCacheFeature","GraphQLSchemaKeyVerificationFeature","EncryptionKeyCacheFeature","JwksStoreFeature","setupRequest","wcpLicense","WcpLicenseLoader","createTestWcpLicense","registerApiCoreStorageOperations","ApiCoreFeature","processLegacyPlugins","legacyItems","Infinity","Boolean","isFn","p","legacyObjects","staticPlugins","HeadlessCmsFeature","plugin","handler","createTestHttpHandler","GraphQLEngineFeature","invoke","httpMethod","body","headers","response","invokeCms","type","getContext","requestContainer","ctxHandler","createQuery","query","variables","createMutation","mutation","introspect","getIntrospectionQuery"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/api-headless-cms-testing",
3
- "version": "0.0.0-unstable.5387e5f7c8",
3
+ "version": "0.0.0-unstable.9609e4e0c9",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -15,17 +15,17 @@
15
15
  "author": "Webiny Ltd.",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
- "@webiny/api-core": "0.0.0-unstable.5387e5f7c8",
19
- "@webiny/api-core-testing": "0.0.0-unstable.5387e5f7c8",
20
- "@webiny/api-graphql": "0.0.0-unstable.5387e5f7c8",
21
- "@webiny/api-headless-cms": "0.0.0-unstable.5387e5f7c8",
18
+ "@webiny/api-core": "0.0.0-unstable.9609e4e0c9",
19
+ "@webiny/api-core-testing": "0.0.0-unstable.9609e4e0c9",
20
+ "@webiny/api-graphql": "0.0.0-unstable.9609e4e0c9",
21
+ "@webiny/api-headless-cms": "0.0.0-unstable.9609e4e0c9",
22
22
  "@webiny/di": "2.0.0",
23
- "@webiny/event-handler-core": "0.0.0-unstable.5387e5f7c8",
24
- "@webiny/wcp": "0.0.0-unstable.5387e5f7c8",
23
+ "@webiny/event-handler-core": "0.0.0-unstable.9609e4e0c9",
24
+ "@webiny/wcp": "0.0.0-unstable.9609e4e0c9",
25
25
  "graphql": "16.14.2"
26
26
  },
27
27
  "devDependencies": {
28
- "@webiny/build-tools": "0.0.0-unstable.5387e5f7c8",
28
+ "@webiny/build-tools": "0.0.0-unstable.9609e4e0c9",
29
29
  "rimraf": "6.1.3",
30
30
  "typescript": "7.0.2"
31
31
  },