41 | }
42 |
--------------------------------------------------------------------------------
/lib/plain/as-iterator.ts:
--------------------------------------------------------------------------------
1 | import copy from 'fast-copy'
2 | import type { CollectionProp, QueryParams } from '../common-types'
3 |
4 | type IterableFn = (params: P) => Promise>
5 | type ParamsType = T extends (params: infer P) => any ? P : never
6 |
7 | export const asIterator = >(
8 | fn: F,
9 | params: ParamsType,
10 | ): AsyncIterable => {
11 | return {
12 | [Symbol.asyncIterator]() {
13 | let options = copy(params)
14 | const get = () => fn(copy(options))
15 | let currentResult = get()
16 |
17 | return {
18 | current: 0,
19 | async next() {
20 | const { total = 0, items = [], skip = 0, limit = 100 } = await currentResult
21 |
22 | if (total === this.current) {
23 | return { done: true, value: null }
24 | }
25 |
26 | const value = items[this.current++ - skip]
27 | const endOfPage = this.current % limit === 0
28 | const endOfList = this.current === total
29 |
30 | if (endOfPage && !endOfList) {
31 | options = {
32 | ...options,
33 | query: {
34 | ...options.query,
35 | skip: skip + limit,
36 | },
37 | }
38 | currentResult = get()
39 | }
40 |
41 | return { done: false, value }
42 | },
43 | }
44 | },
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/organization.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosInstance } from 'contentful-sdk-core'
2 | import type {
3 | CollectionProp,
4 | GetOrganizationParams,
5 | PaginationQueryParams,
6 | } from '../../../common-types'
7 | import type { OrganizationProps } from '../../../entities/organization'
8 | import type { RestEndpoint } from '../types'
9 | import * as raw from './raw'
10 |
11 | export const getMany: RestEndpoint<'Organization', 'getMany'> = (
12 | http: AxiosInstance,
13 | params?: PaginationQueryParams,
14 | ) => {
15 | return raw.get>(http, `/organizations`, {
16 | params: params?.query,
17 | })
18 | }
19 |
20 | export const get: RestEndpoint<'Organization', 'get'> = (
21 | http: AxiosInstance,
22 | params: GetOrganizationParams,
23 | ) => {
24 | return getMany(http, { query: { limit: 100 } }).then((data) => {
25 | const org = data.items.find((org) => org.sys.id === params.organizationId)
26 | if (!org) {
27 | const error = new Error(
28 | `No organization was found with the ID ${
29 | params.organizationId
30 | } instead got ${JSON.stringify(data)}`,
31 | )
32 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
33 | // @ts-ignore
34 | error.status = 404
35 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
36 | // @ts-ignore
37 | error.statusText = 'Not Found'
38 | return Promise.reject(error)
39 | }
40 | return org
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/environment-template-installation.ts:
--------------------------------------------------------------------------------
1 | import type { RawAxiosRequestHeaders } from 'axios'
2 | import type { RestEndpoint } from '../types'
3 | import * as raw from './raw'
4 |
5 | const apiPath = (organizationId: string, ...pathSegments: (number | string)[]) =>
6 | `/organizations/${organizationId}/environment_templates/` + pathSegments.join('/')
7 |
8 | export const getMany: RestEndpoint<'EnvironmentTemplateInstallation', 'getMany'> = (
9 | http,
10 | { organizationId, environmentTemplateId, spaceId, environmentId, ...otherProps },
11 | headers?: RawAxiosRequestHeaders,
12 | ) =>
13 | raw.get(http, apiPath(organizationId, environmentTemplateId, 'template_installations'), {
14 | params: {
15 | ...otherProps,
16 | ...(environmentId && { 'environment.sys.id': environmentId }),
17 | ...(spaceId && { 'space.sys.id': spaceId }),
18 | },
19 | headers,
20 | })
21 |
22 | export const getForEnvironment: RestEndpoint<
23 | 'EnvironmentTemplateInstallation',
24 | 'getForEnvironment'
25 | > = (
26 | http,
27 | { spaceId, environmentId, environmentTemplateId, installationId, ...paginationProps },
28 | headers?: RawAxiosRequestHeaders,
29 | ) =>
30 | raw.get(
31 | http,
32 | `/spaces/${spaceId}/environments/${environmentId}/template_installations/${environmentTemplateId}`,
33 | {
34 | params: {
35 | ...(installationId && { 'sys.id': installationId }),
36 | ...paginationProps,
37 | },
38 | headers,
39 | },
40 | )
41 |
--------------------------------------------------------------------------------
/test/integration/organization-invitation.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, test, expect, afterAll } from 'vitest'
2 | import { getTestOrganization, timeoutToCalmRateLimiting } from '../helpers'
3 | import type { Organization } from '../../lib/export-types'
4 |
5 | describe('OrganizationMembership Invitation API', () => {
6 | let organization: Organization
7 |
8 | beforeAll(async () => {
9 | organization = await getTestOrganization()
10 | })
11 |
12 | afterAll(timeoutToCalmRateLimiting)
13 |
14 | test('Creates, gets an invitation in the organization and removes membership after test', async () => {
15 | const response = await organization.createOrganizationInvitation({
16 | email: 'test.user@contentful.com',
17 | firstName: 'Test',
18 | lastName: 'User',
19 | role: 'developer',
20 | })
21 |
22 | const invitation = await organization.getOrganizationInvitation(response.sys.id)
23 |
24 | expect(invitation.sys.type).toBe('Invitation')
25 | expect(invitation.sys.status).toBe('open')
26 | expect(invitation.sys.user).toBe(null)
27 | expect(invitation.sys.organizationMembership.sys.type).toBe('Link')
28 | expect(invitation.sys.organizationMembership.sys.linkType).toBe('OrganizationMembership')
29 |
30 | const membership = await organization.getOrganizationMembership(
31 | invitation.sys.organizationMembership.sys.id,
32 | )
33 |
34 | // Delete membership, which also deletes the invitation for this user
35 | await membership.delete()
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | import eslint from '@eslint/js'
4 | import tseslint from 'typescript-eslint'
5 | import globals from 'globals'
6 |
7 | export default tseslint.config(
8 | eslint.configs.recommended,
9 | tseslint.configs.recommended,
10 | {
11 | languageOptions: {
12 | globals: {
13 | ...globals.node,
14 | ...globals.browser,
15 | createClient: true,
16 | },
17 | },
18 | },
19 | // Library
20 | {
21 | files: ['lib/**/*'],
22 | rules: {
23 | // Things we probably should fix at some point
24 | '@typescript-eslint/ban-ts-comment': 'warn',
25 | '@typescript-eslint/no-empty-object-type': 'warn',
26 | '@typescript-eslint/no-explicit-any': 'warn',
27 | '@typescript-eslint/no-unsafe-function-type': 'warn',
28 | '@typescript-eslint/no-unused-vars': 'warn',
29 | // Things we won't allow
30 | '@typescript-eslint/consistent-type-imports': 'error',
31 | '@typescript-eslint/no-this-alias': [
32 | 'error',
33 | {
34 | allowDestructuring: true, // Allow `const { props, state } = this`; false by default
35 | allowedNames: ['self'], // Allow `const self = this`; `[]` by default
36 | },
37 | ],
38 | },
39 | },
40 | // Tests
41 | {
42 | files: ['test/**/*'],
43 | rules: {
44 | '@typescript-eslint/no-unused-expressions': 'off',
45 | '@typescript-eslint/no-explicit-any': 'warn',
46 | '@typescript-eslint/ban-ts-comment': 'warn',
47 | },
48 | }
49 | )
50 |
--------------------------------------------------------------------------------
/test/integration/org-team-space-membership-integration.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, it, expect, afterAll } from 'vitest'
2 | import { getTestOrganization, timeoutToCalmRateLimiting } from '../helpers'
3 | import { TestDefaults } from '../defaults'
4 | import type { Organization } from '../../lib/export-types'
5 |
6 | const { teamId, teamSpaceMembershipId } = TestDefaults
7 |
8 | describe('TeamSpaceMembership API', () => {
9 | let organization: Organization
10 |
11 | beforeAll(async () => {
12 | organization = await getTestOrganization()
13 | })
14 |
15 | afterAll(timeoutToCalmRateLimiting)
16 |
17 | it('Gets a single Team Space Membership', async () => {
18 | const response = await organization.getTeamSpaceMembership(teamSpaceMembershipId)
19 | expect(response.sys.type).toBe('TeamSpaceMembership')
20 | expect(response.sys.team).toBeTruthy()
21 | expect(response.roles).toBeTruthy()
22 | })
23 |
24 | it('Gets all Team Space Memberships in organization', async () => {
25 | const response = await organization.getTeamSpaceMemberships()
26 | expect(response.sys).toBeTruthy()
27 | expect(response.items).toBeTruthy()
28 | expect(response.items[0].sys.type).toBe('TeamSpaceMembership')
29 | })
30 |
31 | it('Gets all Team Space Memberships in a team', async () => {
32 | const response = await organization.getTeamSpaceMemberships({ teamId })
33 | expect(response.sys).toBeTruthy()
34 | expect(response.items).toBeTruthy()
35 | expect(response.items[0].sys.type).toBe('TeamSpaceMembership')
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/function-log.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosInstance } from 'contentful-sdk-core'
2 | import * as raw from './raw'
3 | import type {
4 | CollectionProp,
5 | GetFunctionLogParams,
6 | GetManyFunctionLogParams,
7 | } from '../../../common-types'
8 | import type { RestEndpoint } from '../types'
9 | import type { FunctionLogProps } from '../../../entities/function-log'
10 |
11 | const FunctionLogAlphaHeaders = {
12 | 'x-contentful-enable-alpha-feature': 'function-logs',
13 | }
14 |
15 | const baseURL = (params: GetManyFunctionLogParams) =>
16 | `/spaces/${params.spaceId}/environments/${params.environmentId}/app_installations/${params.appInstallationId}/functions/${params.functionId}/logs`
17 |
18 | const getURL = (params: GetFunctionLogParams) =>
19 | `/spaces/${params.spaceId}/environments/${params.environmentId}/app_installations/${params.appInstallationId}/functions/${params.functionId}/logs/${params.logId}`
20 |
21 | export const get: RestEndpoint<'FunctionLog', 'get'> = (
22 | http: AxiosInstance,
23 | params: GetFunctionLogParams,
24 | ) => {
25 | return raw.get(http, getURL(params), {
26 | headers: {
27 | ...FunctionLogAlphaHeaders,
28 | },
29 | })
30 | }
31 |
32 | export const getMany: RestEndpoint<'FunctionLog', 'getMany'> = (
33 | http: AxiosInstance,
34 | params: GetManyFunctionLogParams,
35 | ) => {
36 | return raw.get>(http, baseURL(params), {
37 | params: params.query,
38 | headers: {
39 | ...FunctionLogAlphaHeaders,
40 | },
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/release-action.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosInstance } from 'contentful-sdk-core'
2 | import type { GetReleaseParams, GetSpaceEnvironmentParams } from '../../../common-types'
3 | import type { ReleaseActionQueryOptions } from '../../../entities/release-action'
4 | import type { RestEndpoint } from '../types'
5 | import * as raw from './raw'
6 |
7 | export const get: RestEndpoint<'ReleaseAction', 'get'> = (
8 | http: AxiosInstance,
9 | params: GetReleaseParams & { actionId: string },
10 | ) => {
11 | return raw.get(
12 | http,
13 | `/spaces/${params.spaceId}/environments/${params.environmentId}/releases/${params.releaseId}/actions/${params.actionId}`,
14 | )
15 | }
16 |
17 | export const getMany: RestEndpoint<'ReleaseAction', 'getMany'> = (
18 | http: AxiosInstance,
19 | params: GetSpaceEnvironmentParams & { query?: ReleaseActionQueryOptions },
20 | ) => {
21 | return raw.get(
22 | http,
23 | `/spaces/${params.spaceId}/environments/${params.environmentId}/release_actions`,
24 | {
25 | params: params.query,
26 | },
27 | )
28 | }
29 |
30 | export const queryForRelease: RestEndpoint<'ReleaseAction', 'queryForRelease'> = (
31 | http: AxiosInstance,
32 | params: GetReleaseParams & { query?: ReleaseActionQueryOptions },
33 | ) => {
34 | return raw.get(
35 | http,
36 | `/spaces/${params.spaceId}/environments/${params.environmentId}/release_actions`,
37 | {
38 | params: {
39 | 'sys.release.sys.id[in]': params.releaseId,
40 | ...params.query,
41 | },
42 | },
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/test/integration/app-upload-integration.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, describe, test, beforeAll, afterAll } from 'vitest'
2 | import { readFileSync } from 'fs'
3 | import { getTestOrganization, timeoutToCalmRateLimiting } from '../helpers'
4 | import type { Organization } from '../../lib/contentful-management'
5 |
6 | describe('AppUpload api', { sequential: true }, () => {
7 | let organization: Organization
8 |
9 | beforeAll(async () => {
10 | organization = await getTestOrganization()
11 | })
12 |
13 | afterAll(timeoutToCalmRateLimiting)
14 |
15 | test('createAppUpload', async () => {
16 | const appUpload = await organization.createAppUpload(
17 | readFileSync(`${__dirname}/fixtures/build.zip`),
18 | )
19 |
20 | expect(appUpload.sys.type).toBe('AppUpload')
21 |
22 | await appUpload.delete()
23 | })
24 |
25 | test('getAppUpload', async () => {
26 | const appUpload = await organization.createAppUpload(
27 | readFileSync(`${__dirname}/fixtures/build.zip`),
28 | )
29 |
30 | const fetchedAppUpload = await organization.getAppUpload(appUpload.sys.id)
31 |
32 | expect(appUpload.sys.id).toBe(fetchedAppUpload.sys.id)
33 |
34 | await appUpload.delete()
35 | })
36 |
37 | test('delete', async () => {
38 | const appUpload = await organization.createAppUpload(
39 | readFileSync(`${__dirname}/fixtures/build.zip`),
40 | )
41 |
42 | await appUpload.delete()
43 |
44 | await expect(organization.getAppUpload(appUpload.sys.id)).rejects.toThrow(
45 | 'The resource could not be found',
46 | )
47 | })
48 | })
49 |
--------------------------------------------------------------------------------
/lib/entities/space.ts:
--------------------------------------------------------------------------------
1 | import { freezeSys, toPlainObject } from 'contentful-sdk-core'
2 | import copy from 'fast-copy'
3 | import type { BasicMetaSysProps, DefaultElements, MakeRequest } from '../common-types'
4 | import { wrapCollection } from '../common-utils'
5 | import type { ContentfulSpaceAPI } from '../create-space-api'
6 | import createSpaceApi from '../create-space-api'
7 | import enhanceWithMethods from '../enhance-with-methods'
8 |
9 | export type SpaceProps = {
10 | sys: BasicMetaSysProps & { organization: { sys: { id: string } }; archivedAt?: string }
11 | name: string
12 | }
13 |
14 | export type Space = SpaceProps & DefaultElements & ContentfulSpaceAPI
15 |
16 | /**
17 | * This method creates the API for the given space with all the methods for
18 | * reading and creating other entities. It also passes down a clone of the
19 | * http client with a space id, so the base path for requests now has the
20 | * space id already set.
21 | * @private
22 | * @param makeRequest - function to make requests via an adapter
23 | * @param data - API response for a Space
24 | * @return {Space}
25 | */
26 | export function wrapSpace(makeRequest: MakeRequest, data: SpaceProps): Space {
27 | const space = toPlainObject(copy(data))
28 | const spaceApi = createSpaceApi(makeRequest)
29 | const enhancedSpace = enhanceWithMethods(space, spaceApi)
30 | return freezeSys(enhancedSpace)
31 | }
32 |
33 | /**
34 | * This method wraps each space in a collection with the space API. See wrapSpace
35 | * above for more details.
36 | * @private
37 | */
38 | export const wrapSpaceCollection = wrapCollection(wrapSpace)
39 |
--------------------------------------------------------------------------------
/lib/entities/user-ui-config.ts:
--------------------------------------------------------------------------------
1 | import { freezeSys, toPlainObject } from 'contentful-sdk-core'
2 | import copy from 'fast-copy'
3 | import type { BasicMetaSysProps, DefaultElements, MakeRequest, SysLink } from '../common-types'
4 | import createUserUIConfigApi from '../create-user-ui-config-api'
5 | import enhanceWithMethods from '../enhance-with-methods'
6 |
7 | export type UserUIConfigProps = {
8 | /**
9 | * System metadata
10 | */
11 | sys: UserUIConfigSysProps
12 |
13 | assetListViews: ViewFolder[]
14 | entryListViews: ViewFolder[]
15 | }
16 |
17 | export interface UserUIConfigSysProps extends BasicMetaSysProps {
18 | space: SysLink
19 | environment: SysLink
20 | }
21 |
22 | interface ViewFolder {
23 | id: string
24 | title: string
25 | views: View[]
26 | }
27 |
28 | interface View {
29 | id: string
30 | title: string
31 | order?: {
32 | fieldId: string
33 | direction: 'ascending' | 'descending'
34 | }
35 | displayedFieldIds?: string[]
36 | contentTypeId: string | null
37 | searchText?: string
38 | searchFilters?: [string, string, string][]
39 | }
40 |
41 | export interface UserUIConfig extends UserUIConfigProps, DefaultElements {}
42 |
43 | /**
44 | * @private
45 | * @param makeRequest - function to make requests via an adapter
46 | * @param data - Raw data
47 | * @return Wrapped UserUIConfig
48 | */
49 | export function wrapUserUIConfig(makeRequest: MakeRequest, data: UserUIConfigProps) {
50 | const user = toPlainObject(copy(data))
51 | const userWithMethods = enhanceWithMethods(user, createUserUIConfigApi(makeRequest))
52 | return freezeSys(userWithMethods)
53 | }
54 |
--------------------------------------------------------------------------------
/lib/plain/entities/resource.ts:
--------------------------------------------------------------------------------
1 | import type { OptionalDefaults } from '../wrappers/wrap'
2 | import type { CursorPaginatedCollectionProp, GetResourceParams } from '../../common-types'
3 | import type { ResourceProps, ResourceQueryOptions } from '../../entities/resource'
4 |
5 | export type ResourcePlainAPI = {
6 | /**
7 | * Fetches all Resources.
8 | * Supports fetching specific Resources by URNs or searching by a text query.
9 | * @param params entity IDs to identify the Resources
10 | * @params optional query params for search or lookup events
11 | * @returns the Resources collection
12 | * @throws if the request fails or the Resource Type is not found
13 | * @example
14 | * ```javascript
15 | * // Lookup example
16 | * const resources = await client.resource.getMany({
17 | * spaceId: '',
18 | * environmentId: '',
19 | * resourceTypeId: ':',
20 | * query: {
21 | * 'sys.urn[in]': ',',
22 | * limit': ,
23 | * }
24 | * });
25 | *
26 | * // Search example
27 | * const resources = await client.resource.getMany({
28 | * spaceId: '',
29 | * environmentId: '',
30 | * resourceTypeId: ':',
31 | * query: {
32 | * 'query': 'text',
33 | * 'limit': ,
34 | * }
35 | * });
36 | * ```
37 | */
38 | getMany(
39 | params: OptionalDefaults & { query?: ResourceQueryOptions },
40 | ): Promise>
41 | }
42 |
--------------------------------------------------------------------------------
/test/unit/entities/team.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'vitest'
2 | import { cloneMock } from '../mocks/entities'
3 | import setupMakeRequest from '../mocks/makeRequest'
4 | import { wrapTeam, wrapTeamCollection } from '../../../lib/entities/team'
5 | import {
6 | entityWrappedTest,
7 | entityCollectionWrappedTest,
8 | failingActionTest,
9 | entityUpdateTest,
10 | entityDeleteTest,
11 | } from '../test-creators/instance-entity-methods'
12 |
13 | function setup(promise) {
14 | return {
15 | makeRequest: setupMakeRequest(promise),
16 | entityMock: cloneMock('team'),
17 | }
18 | }
19 |
20 | describe('Entity TeamSpaceMembership', () => {
21 | test('Team is wrapped', async () => {
22 | return entityWrappedTest(setup, {
23 | wrapperMethod: wrapTeam,
24 | })
25 | })
26 |
27 | test('Team collection is wrapped', async () => {
28 | return entityCollectionWrappedTest(setup, {
29 | wrapperMethod: wrapTeamCollection,
30 | })
31 | })
32 |
33 | test('Team update', async () => {
34 | return entityUpdateTest(setup, {
35 | wrapperMethod: wrapTeam,
36 | })
37 | })
38 |
39 | test('Team update fails', async () => {
40 | return failingActionTest(setup, {
41 | wrapperMethod: wrapTeam,
42 | actionMethod: 'update',
43 | })
44 | })
45 |
46 | test('Team delete', async () => {
47 | return entityDeleteTest(setup, {
48 | wrapperMethod: wrapTeam,
49 | })
50 | })
51 |
52 | test('Team delete fails', async () => {
53 | return failingActionTest(setup, {
54 | wrapperMethod: wrapTeam,
55 | actionMethod: 'delete',
56 | })
57 | })
58 | })
59 |
--------------------------------------------------------------------------------
/lib/entities/resource.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | BasicCursorPaginationOptions,
3 | CursorPaginatedCollectionProp,
4 | MakeRequest,
5 | SysLink,
6 | } from '../common-types'
7 | import { wrapCursorPaginatedCollection } from '../common-utils'
8 | import { freezeSys, toPlainObject } from 'contentful-sdk-core'
9 |
10 | export type ResourceQueryOptions = LookupQueryOptions | SearchQueryOptions
11 |
12 | type LookupQueryOptions = {
13 | 'sys.urn[in]': string
14 | locale?: string
15 | referencingEntryId?: string
16 | } & BasicCursorPaginationOptions
17 |
18 | type SearchQueryOptions = {
19 | query: string
20 | locale?: string
21 | referencingEntryId?: string
22 | } & BasicCursorPaginationOptions
23 |
24 | export type ResourceProps = {
25 | sys: {
26 | type: 'Resource'
27 | urn: string
28 | resourceType: SysLink
29 | resourceProvider: SysLink
30 | appDefinition: SysLink
31 | }
32 | fields: {
33 | title: string
34 | subtitle?: string
35 | description?: string
36 | externalUrl?: string
37 | image?: {
38 | url: string
39 | altText?: string
40 | }
41 | badge?: {
42 | label: string
43 | variant: 'primary' | 'negative' | 'positive' | 'warning' | 'secondary'
44 | }
45 | }
46 | }
47 | export function wrapResource(makeRequest: MakeRequest, data: ResourceProps) {
48 | const resource = toPlainObject(data)
49 | return freezeSys(resource)
50 | }
51 | export const wrapResourceCollection: (
52 | makeRequest: MakeRequest,
53 | data: CursorPaginatedCollectionProp,
54 | ) => CursorPaginatedCollectionProp = wrapCursorPaginatedCollection(wrapResource)
55 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/app-key.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosInstance } from 'contentful-sdk-core'
2 | import type { CreateAppKeyProps, AppKeyProps } from '../../../entities/app-key'
3 | import * as raw from './raw'
4 | import type { RestEndpoint } from '../types'
5 | import type { CollectionProp, GetAppDefinitionParams, GetAppKeyParams } from '../../../common-types'
6 |
7 | export const get: RestEndpoint<'AppKey', 'get'> = (
8 | http: AxiosInstance,
9 | params: GetAppKeyParams,
10 | ) => {
11 | return raw.get(
12 | http,
13 | `/organizations/${params.organizationId}/app_definitions/${params.appDefinitionId}/keys/${params.fingerprint}`,
14 | )
15 | }
16 |
17 | export const getMany: RestEndpoint<'AppKey', 'getMany'> = (
18 | http: AxiosInstance,
19 | params: GetAppDefinitionParams,
20 | ) => {
21 | return raw.get>(
22 | http,
23 | `/organizations/${params.organizationId}/app_definitions/${params.appDefinitionId}/keys`,
24 | )
25 | }
26 |
27 | export const create: RestEndpoint<'AppKey', 'create'> = (
28 | http: AxiosInstance,
29 | params: GetAppDefinitionParams,
30 | data: CreateAppKeyProps,
31 | ) => {
32 | return raw.post(
33 | http,
34 | `/organizations/${params.organizationId}/app_definitions/${params.appDefinitionId}/keys`,
35 | data,
36 | )
37 | }
38 |
39 | export const del: RestEndpoint<'AppKey', 'delete'> = (
40 | http: AxiosInstance,
41 | params: GetAppKeyParams,
42 | ) => {
43 | return raw.del(
44 | http,
45 | `/organizations/${params.organizationId}/app_definitions/${params.appDefinitionId}/keys/${params.fingerprint}`,
46 | )
47 | }
48 |
--------------------------------------------------------------------------------
/test/unit/entities/role.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'vitest'
2 | import { cloneMock } from '../mocks/entities'
3 | import setupMakeRequest from '../mocks/makeRequest'
4 | import { wrapRole, wrapRoleCollection } from '../../../lib/entities/role'
5 | import {
6 | entityCollectionWrappedTest,
7 | entityDeleteTest,
8 | entityUpdateTest,
9 | entityWrappedTest,
10 | failingActionTest,
11 | failingVersionActionTest,
12 | } from '../test-creators/instance-entity-methods'
13 |
14 | function setup(promise) {
15 | return {
16 | makeRequest: setupMakeRequest(promise),
17 | entityMock: cloneMock('role'),
18 | }
19 | }
20 |
21 | describe('Entity Role', () => {
22 | test('Role is wrapped', async () => {
23 | return entityWrappedTest(setup, {
24 | wrapperMethod: wrapRole,
25 | })
26 | })
27 |
28 | test('Role collection is wrapped', async () => {
29 | return entityCollectionWrappedTest(setup, {
30 | wrapperMethod: wrapRoleCollection,
31 | })
32 | })
33 |
34 | test('Role update', async () => {
35 | return entityUpdateTest(setup, {
36 | wrapperMethod: wrapRole,
37 | })
38 | })
39 |
40 | test('Role update fails', async () => {
41 | return failingVersionActionTest(setup, {
42 | wrapperMethod: wrapRole,
43 | actionMethod: 'update',
44 | })
45 | })
46 |
47 | test('Role delete', async () => {
48 | return entityDeleteTest(setup, {
49 | wrapperMethod: wrapRole,
50 | })
51 | })
52 |
53 | test('Role delete fails', async () => {
54 | return failingActionTest(setup, {
55 | wrapperMethod: wrapRole,
56 | actionMethod: 'delete',
57 | })
58 | })
59 | })
60 |
--------------------------------------------------------------------------------
/test/unit/entities/task.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'vitest'
2 | import { wrapTask, wrapTaskCollection } from '../../../lib/entities/task'
3 | import { cloneMock } from '../mocks/entities'
4 | import setupMakeRequest from '../mocks/makeRequest'
5 | import {
6 | entityCollectionWrappedTest,
7 | entityDeleteTest,
8 | entityUpdateTest,
9 | entityWrappedTest,
10 | failingActionTest,
11 | failingVersionActionTest,
12 | } from '../test-creators/instance-entity-methods'
13 |
14 | function setup(promise) {
15 | return {
16 | makeRequest: setupMakeRequest(promise),
17 | entityMock: cloneMock('task'),
18 | }
19 | }
20 |
21 | describe('Entity Task', () => {
22 | test('Task is wrapped', async () => {
23 | return entityWrappedTest(setup, {
24 | wrapperMethod: wrapTask,
25 | })
26 | })
27 |
28 | test('Task collection is wrapped', async () => {
29 | return entityCollectionWrappedTest(setup, {
30 | wrapperMethod: wrapTaskCollection,
31 | })
32 | })
33 |
34 | test('Task update', async () => {
35 | return entityUpdateTest(setup, {
36 | wrapperMethod: wrapTask,
37 | })
38 | })
39 |
40 | test('Task update fails', async () => {
41 | return failingVersionActionTest(setup, {
42 | wrapperMethod: wrapTask,
43 | actionMethod: 'update',
44 | })
45 | })
46 |
47 | test('Task delete', async () => {
48 | return entityDeleteTest(setup, {
49 | wrapperMethod: wrapTask,
50 | })
51 | })
52 |
53 | test('Task delete fails', async () => {
54 | return failingActionTest(setup, {
55 | wrapperMethod: wrapTask,
56 | actionMethod: 'delete',
57 | })
58 | })
59 | })
60 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/function.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosInstance } from 'contentful-sdk-core'
2 | import * as raw from './raw'
3 | import type {
4 | CollectionProp,
5 | GetFunctionForEnvParams,
6 | GetFunctionParams,
7 | GetManyFunctionParams,
8 | } from '../../../common-types'
9 | import type { RestEndpoint } from '../types'
10 | import type { FunctionProps } from '../../../entities/function'
11 |
12 | // Base URL
13 | const getManyUrl = (params: GetManyFunctionParams) =>
14 | `/organizations/${params.organizationId}/app_definitions/${params.appDefinitionId}/functions`
15 |
16 | const getFunctionUrl = (params: GetFunctionParams) => `${getManyUrl(params)}/${params.functionId}`
17 |
18 | const getFunctionsEnvURL = (params: GetFunctionForEnvParams) => {
19 | return `/spaces/${params.spaceId}/environments/${params.environmentId}/app_installations/${params.appInstallationId}/functions`
20 | }
21 |
22 | export const get: RestEndpoint<'Function', 'get'> = (
23 | http: AxiosInstance,
24 | params: GetFunctionParams,
25 | ) => {
26 | return raw.get(http, getFunctionUrl(params))
27 | }
28 |
29 | export const getMany: RestEndpoint<'Function', 'getMany'> = (
30 | http: AxiosInstance,
31 | params: GetManyFunctionParams,
32 | ) => {
33 | return raw.get>(http, getManyUrl(params), { params: params.query })
34 | }
35 |
36 | export const getManyForEnvironment: RestEndpoint<'Function', 'getManyForEnvironment'> = (
37 | http: AxiosInstance,
38 | params: GetFunctionForEnvParams,
39 | ) => {
40 | return raw.get>(http, getFunctionsEnvURL(params), {
41 | params: params.query,
42 | })
43 | }
44 |
--------------------------------------------------------------------------------
/test/integration/organization-membership-integration.test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, test, expect } from 'vitest'
2 | import { getTestOrganization, timeoutToCalmRateLimiting } from '../helpers'
3 | import type { Organization } from '../../lib/export-types'
4 | import { TestDefaults } from '../defaults'
5 |
6 | const { organizationMembershipId } = TestDefaults
7 |
8 | describe('OrganizationMembership Api', function () {
9 | let organization: Organization
10 |
11 | beforeAll(async () => {
12 | organization = await getTestOrganization()
13 | })
14 |
15 | afterAll(timeoutToCalmRateLimiting)
16 |
17 | test('Gets organizationMemberships', async () => {
18 | return organization.getOrganizationMemberships().then((response) => {
19 | expect(response.sys, 'sys').ok
20 | expect(response.items, 'fields').ok
21 | })
22 | })
23 |
24 | test('Gets organizationMembership', async () => {
25 | return organization.getOrganizationMembership(organizationMembershipId).then((response) => {
26 | expect(response.sys, 'sys').ok
27 | expect(response.sys.id).equals(organizationMembershipId)
28 | expect(response.sys.type).equals('OrganizationMembership')
29 | })
30 | })
31 |
32 | test('Gets organizationMemberships paged', async () => {
33 | return organization
34 | .getOrganizationMemberships({
35 | query: {
36 | limit: 1,
37 | skip: 1,
38 | },
39 | })
40 | .then((response) => {
41 | expect(response.sys, 'sys').ok
42 | expect(response.limit).equals(1)
43 | expect(response.skip).equals(1)
44 | expect(response.items.length).equals(1)
45 | })
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/app-upload.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosInstance } from 'contentful-sdk-core'
2 | import type { Stream } from 'stream'
3 | import * as raw from './raw'
4 | import type { GetAppUploadParams, GetOrganizationParams } from '../../../common-types'
5 | import type { RestEndpoint } from '../types'
6 | import type { AppUploadProps } from '../../../entities/app-upload'
7 | import { getUploadHttpClient } from '../../../upload-http-client'
8 |
9 | const getBaseUrl = (params: GetOrganizationParams) =>
10 | `/organizations/${params.organizationId}/app_uploads`
11 |
12 | const getAppUploadUrl = (params: GetAppUploadParams) =>
13 | `${getBaseUrl(params)}/${params.appUploadId}`
14 |
15 | export const get: RestEndpoint<'AppUpload', 'get'> = (
16 | http: AxiosInstance,
17 | params: GetAppUploadParams,
18 | ) => {
19 | const httpUpload = getUploadHttpClient(http)
20 |
21 | return raw.get(httpUpload, getAppUploadUrl(params))
22 | }
23 |
24 | export const del: RestEndpoint<'AppUpload', 'delete'> = (
25 | http: AxiosInstance,
26 | params: GetAppUploadParams,
27 | ) => {
28 | const httpUpload = getUploadHttpClient(http)
29 |
30 | return raw.del(httpUpload, getAppUploadUrl(params))
31 | }
32 |
33 | export const create: RestEndpoint<'AppUpload', 'create'> = (
34 | http: AxiosInstance,
35 | params: GetOrganizationParams,
36 | payload: { file: string | ArrayBuffer | Stream },
37 | ) => {
38 | const httpUpload = getUploadHttpClient(http)
39 |
40 | const { file } = payload
41 |
42 | return raw.post(httpUpload, getBaseUrl(params), file, {
43 | headers: {
44 | 'Content-Type': 'application/octet-stream',
45 | },
46 | })
47 | }
48 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/organization-invitation.ts:
--------------------------------------------------------------------------------
1 | import type { RawAxiosRequestHeaders } from 'axios'
2 | import type { AxiosInstance } from 'contentful-sdk-core'
3 | import type {
4 | CreateOrganizationInvitationProps,
5 | OrganizationInvitationProps,
6 | } from '../../../entities/organization-invitation'
7 | import type { RestEndpoint } from '../types'
8 | import * as raw from './raw'
9 |
10 | const OrganizationUserManagementAlphaHeaders = {
11 | 'x-contentful-enable-alpha-feature': 'organization-user-management-api',
12 | }
13 |
14 | const InvitationAlphaHeaders = {
15 | 'x-contentful-enable-alpha-feature': 'pending-org-membership',
16 | }
17 |
18 | export const create: RestEndpoint<'OrganizationInvitation', 'create'> = (
19 | http: AxiosInstance,
20 | params: { organizationId: string },
21 | data: CreateOrganizationInvitationProps,
22 | headers?: RawAxiosRequestHeaders,
23 | ) => {
24 | return raw.post(
25 | http,
26 | `/organizations/${params.organizationId}/invitations`,
27 | data,
28 | {
29 | headers: {
30 | ...InvitationAlphaHeaders,
31 | ...headers,
32 | },
33 | },
34 | )
35 | }
36 |
37 | export const get: RestEndpoint<'OrganizationInvitation', 'get'> = (
38 | http: AxiosInstance,
39 | params: { organizationId: string; invitationId: string },
40 | headers?: RawAxiosRequestHeaders,
41 | ) => {
42 | return raw.get(
43 | http,
44 | `/organizations/${params.organizationId}/invitations/${params.invitationId}`,
45 | {
46 | headers: {
47 | ...OrganizationUserManagementAlphaHeaders,
48 | ...headers,
49 | },
50 | },
51 | )
52 | }
53 |
--------------------------------------------------------------------------------
/lib/plain/entities/ui-config.ts:
--------------------------------------------------------------------------------
1 | import type { GetUIConfigParams } from '../../common-types'
2 | import type { UIConfigProps } from '../../entities/ui-config'
3 | import type { OptionalDefaults } from '../wrappers/wrap'
4 |
5 | export type UIConfigPlainClientAPI = {
6 | /**
7 | * Fetch the UI Config for a given Space and Environment
8 | * @param params entity IDs to identify the UI Config
9 | * @returns the UI Config
10 | * @throws if the request fails, or the UI Config is not found
11 | * @example
12 | * ```javascript
13 | * const uiConfig = await client.uiConfig.get({
14 | * spaceId: "",
15 | * environmentId: "",
16 | * });
17 | * ```
18 | */
19 | get(params: OptionalDefaults): Promise
20 | /**
21 | * Update the UI Config for a given Space and Environment
22 | * @param params entity IDs to identify the UI Config
23 | * @param rawData the UI Config update
24 | * @returns the updated UI Config
25 | * @throws if the request fails, the UI Config is not found, or the update payload is malformed
26 | * @example
27 | * ```javascript
28 | * await client.uiConfig.update({
29 | * spaceId: "",
30 | * environmentId: "",
31 | * }, {
32 | * ...currentUIConfig,
33 | * entryListViews: [
34 | * ...currentUIConfig.entryListViews,
35 | * {
36 | * id: 'newFolder',
37 | * title: 'New Folder',
38 | * views: []
39 | * }
40 | * ],
41 | * });
42 | * ```
43 | */
44 | update(
45 | params: OptionalDefaults,
46 | rawData: UIConfigProps,
47 | ): Promise
48 | }
49 |
--------------------------------------------------------------------------------
/test/unit/entities/locale.test.ts:
--------------------------------------------------------------------------------
1 | import { cloneMock } from '../mocks/entities'
2 | import setupMakeRequest from '../mocks/makeRequest'
3 | import { wrapLocale, wrapLocaleCollection } from '../../../lib/entities/locale'
4 | import {
5 | entityCollectionWrappedTest,
6 | entityDeleteTest,
7 | entityUpdateTest,
8 | entityWrappedTest,
9 | failingActionTest,
10 | failingVersionActionTest,
11 | } from '../test-creators/instance-entity-methods'
12 | import { describe, test } from 'vitest'
13 |
14 | function setup(promise) {
15 | return {
16 | makeRequest: setupMakeRequest(promise),
17 | entityMock: cloneMock('locale'),
18 | }
19 | }
20 |
21 | describe('Entity Locale', () => {
22 | test('Locale is wrapped', async () => {
23 | return entityWrappedTest(setup, {
24 | wrapperMethod: wrapLocale,
25 | })
26 | })
27 |
28 | test('Locale collection is wrapped', async () => {
29 | return entityCollectionWrappedTest(setup, {
30 | wrapperMethod: wrapLocaleCollection,
31 | })
32 | })
33 |
34 | test('Locale update', async () => {
35 | return entityUpdateTest(setup, {
36 | wrapperMethod: wrapLocale,
37 | })
38 | })
39 |
40 | test('Locale update fails', async () => {
41 | return failingVersionActionTest(setup, {
42 | wrapperMethod: wrapLocale,
43 | actionMethod: 'update',
44 | })
45 | })
46 |
47 | test('Locale delete', async () => {
48 | return entityDeleteTest(setup, {
49 | wrapperMethod: wrapLocale,
50 | })
51 | })
52 |
53 | test('Locale delete fails', async () => {
54 | return failingActionTest(setup, {
55 | wrapperMethod: wrapLocale,
56 | actionMethod: 'delete',
57 | })
58 | })
59 | })
60 |
--------------------------------------------------------------------------------
/test/unit/entities/api-key.test.ts:
--------------------------------------------------------------------------------
1 | import { cloneMock } from '../mocks/entities'
2 | import setupMakeRequest from '../mocks/makeRequest'
3 | import { wrapApiKey, wrapApiKeyCollection } from '../../../lib/entities/api-key'
4 | import {
5 | entityCollectionWrappedTest,
6 | entityDeleteTest,
7 | entityUpdateTest,
8 | entityWrappedTest,
9 | failingActionTest,
10 | failingVersionActionTest,
11 | } from '../test-creators/instance-entity-methods'
12 | import { describe, test } from 'vitest'
13 |
14 | function setup(promise) {
15 | return {
16 | makeRequest: setupMakeRequest(promise),
17 | entityMock: cloneMock('apiKey'),
18 | }
19 | }
20 |
21 | describe('Entity ApiKey', () => {
22 | test('ApiKey is wrapped', async () => {
23 | return entityWrappedTest(setup, {
24 | wrapperMethod: wrapApiKey,
25 | })
26 | })
27 |
28 | test('ApiKey collection is wrapped', async () => {
29 | return entityCollectionWrappedTest(setup, {
30 | wrapperMethod: wrapApiKeyCollection,
31 | })
32 | })
33 |
34 | test('ApiKey update', async () => {
35 | return entityUpdateTest(setup, {
36 | wrapperMethod: wrapApiKey,
37 | })
38 | })
39 |
40 | test('ApiKey update fails', async () => {
41 | return failingVersionActionTest(setup, {
42 | wrapperMethod: wrapApiKey,
43 | actionMethod: 'update',
44 | })
45 | })
46 |
47 | test('ApiKey delete', async () => {
48 | return entityDeleteTest(setup, {
49 | wrapperMethod: wrapApiKey,
50 | })
51 | })
52 |
53 | test('ApiKey delete fails', async () => {
54 | return failingActionTest(setup, {
55 | wrapperMethod: wrapApiKey,
56 | actionMethod: 'delete',
57 | })
58 | })
59 | })
60 |
--------------------------------------------------------------------------------
/lib/adapters/REST/endpoints/http.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-explicit-any */
2 | import type { AxiosInstance, RawAxiosRequestConfig } from 'axios'
3 | import type { RestEndpoint } from '../types'
4 | import * as raw from './raw'
5 |
6 | export const get: RestEndpoint<'Http', 'get'> = (
7 | http: AxiosInstance,
8 | { url, config }: { url: string; config?: RawAxiosRequestConfig },
9 | ) => {
10 | return raw.get(http, url, config)
11 | }
12 |
13 | export const post: RestEndpoint<'Http', 'post'> = (
14 | http: AxiosInstance,
15 | { url, config }: { url: string; config?: RawAxiosRequestConfig },
16 | payload?: any,
17 | ) => {
18 | return raw.post(http, url, payload, config)
19 | }
20 |
21 | export const put: RestEndpoint<'Http', 'put'> = (
22 | http: AxiosInstance,
23 | { url, config }: { url: string; config?: RawAxiosRequestConfig },
24 | payload?: any,
25 | ) => {
26 | return raw.put(http, url, payload, config)
27 | }
28 |
29 | export const patch: RestEndpoint<'Http', 'patch'> = (
30 | http: AxiosInstance,
31 | { url, config }: { url: string; config?: RawAxiosRequestConfig },
32 | payload?: any,
33 | ) => {
34 | return raw.patch(http, url, payload, config)
35 | }
36 |
37 | export const del: RestEndpoint<'Http', 'delete'> = (
38 | http: AxiosInstance,
39 | { url, config }: { url: string; config?: RawAxiosRequestConfig },
40 | ) => {
41 | return raw.del(http, url, config)
42 | }
43 |
44 | export const request: RestEndpoint<'Http', 'request'> = (
45 | http: AxiosInstance,
46 | { url, config }: { url: string; config?: RawAxiosRequestConfig },
47 | ) => {
48 | return raw.http(http, url, config)
49 | }
50 |
--------------------------------------------------------------------------------
/test/unit/entities/comment.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'vitest'
2 | import { wrapComment, wrapCommentCollection } from '../../../lib/entities/comment'
3 | import { cloneMock } from '../mocks/entities'
4 | import setupMakeRequest from '../mocks/makeRequest'
5 | import {
6 | entityCollectionWrappedTest,
7 | entityDeleteTest,
8 | entityUpdateTest,
9 | entityWrappedTest,
10 | failingActionTest,
11 | failingVersionActionTest,
12 | } from '../test-creators/instance-entity-methods'
13 |
14 | function setup(promise) {
15 | return {
16 | makeRequest: setupMakeRequest(promise),
17 | entityMock: cloneMock('comment'),
18 | }
19 | }
20 |
21 | describe('Entity Comment', () => {
22 | test('Comment is wrapped', async () => {
23 | return entityWrappedTest(setup, {
24 | wrapperMethod: wrapComment,
25 | })
26 | })
27 |
28 | test('Comment collection is wrapped', async () => {
29 | return entityCollectionWrappedTest(setup, {
30 | wrapperMethod: wrapCommentCollection,
31 | })
32 | })
33 |
34 | test('Comment update', async () => {
35 | return entityUpdateTest(setup, {
36 | wrapperMethod: wrapComment,
37 | })
38 | })
39 |
40 | test('Comment update fails', async () => {
41 | return failingVersionActionTest(setup, {
42 | wrapperMethod: wrapComment,
43 | actionMethod: 'update',
44 | })
45 | })
46 |
47 | test('Comment delete', async () => {
48 | return entityDeleteTest(setup, {
49 | wrapperMethod: wrapComment,
50 | })
51 | })
52 |
53 | test('Comment delete fails', async () => {
54 | return failingActionTest(setup, {
55 | wrapperMethod: wrapComment,
56 | actionMethod: 'delete',
57 | })
58 | })
59 | })
60 |
--------------------------------------------------------------------------------
/test/unit/entities/webhook.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'vitest'
2 | import { wrapWebhook, wrapWebhookCollection } from '../../../lib/entities/webhook'
3 | import { cloneMock } from '../mocks/entities'
4 | import setupMakeRequest from '../mocks/makeRequest'
5 | import {
6 | entityCollectionWrappedTest,
7 | entityDeleteTest,
8 | entityUpdateTest,
9 | entityWrappedTest,
10 | failingActionTest,
11 | failingVersionActionTest,
12 | } from '../test-creators/instance-entity-methods'
13 |
14 | function setup(promise) {
15 | return {
16 | makeRequest: setupMakeRequest(promise),
17 | entityMock: cloneMock('webhook'),
18 | }
19 | }
20 |
21 | describe('Entity Webhook', () => {
22 | test('Webhook is wrapped', async () => {
23 | return entityWrappedTest(setup, {
24 | wrapperMethod: wrapWebhook,
25 | })
26 | })
27 |
28 | test('Webhook collection is wrapped', async () => {
29 | return entityCollectionWrappedTest(setup, {
30 | wrapperMethod: wrapWebhookCollection,
31 | })
32 | })
33 |
34 | test('Webhook update', async () => {
35 | return entityUpdateTest(setup, {
36 | wrapperMethod: wrapWebhook,
37 | })
38 | })
39 |
40 | test('Webhook update fails', async () => {
41 | return failingVersionActionTest(setup, {
42 | wrapperMethod: wrapWebhook,
43 | actionMethod: 'update',
44 | })
45 | })
46 |
47 | test('Webhook delete', async () => {
48 | return entityDeleteTest(setup, {
49 | wrapperMethod: wrapWebhook,
50 | })
51 | })
52 |
53 | test('Webhook delete fails', async () => {
54 | return failingActionTest(setup, {
55 | wrapperMethod: wrapWebhook,
56 | actionMethod: 'delete',
57 | })
58 | })
59 | })
60 |
--------------------------------------------------------------------------------
/test/unit/mocks/http.ts:
--------------------------------------------------------------------------------
1 | import type { Mock } from 'vitest'
2 | import { vi } from 'vitest'
3 |
4 | interface MockedHttp extends Mock<[T], R> {
5 | get?: Mock<[T], R>
6 | post?: Mock<[T], R>
7 | put?: Mock<[T], R>
8 | patch?: Mock<[T], R>
9 | delete?: Mock<[T], R>
10 | defaults?: { baseURL: string }
11 | httpClientParams?: { hostUpload: string }
12 | cloneWithNewParams?: () => MockedHttp
13 | }
14 |
15 | export default function setupHttpMock(promise = Promise.resolve({ data: {} })) {
16 | const mock: MockedHttp