diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa6f6adf..83a317ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,10 +21,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/courier-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20' @@ -43,10 +43,10 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20' @@ -61,7 +61,7 @@ jobs: github.repository == 'stainless-sdks/courier-typescript' && !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: core.setOutput('github_token', await core.getIDToken()); @@ -80,10 +80,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/courier-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20' diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 0bd63d73..d4cee411 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -14,10 +14,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1 with: node-version: '20' diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 8fe0b398..ad46a4bd 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,11 +12,10 @@ jobs: if: github.repository == 'trycourier/courier-node' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check release environment run: | bash ./bin/check-release-environment env: NPM_TOKEN: ${{ secrets.COURIER_NPM_TOKEN || secrets.NPM_TOKEN }} - diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1c3fc076..1421b84e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.10.2" + ".": "7.11.0" } diff --git a/.stats.yml b/.stats.yml index effa635e..d43ae964 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 103 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier%2Fcourier-3f78581b4e078a1f620d9f587f18d77bcde6d20f56b0e4ae798648f4236494fb.yml -openapi_spec_hash: 6bd33e0396d85e11bb46f0d549af93a3 -config_hash: afcc4f6f8c33ca3f338589e32e086f56 +configured_endpoints: 117 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-ebe0d758a32897eaf20f252329168bbe2c2da7f580bb871357e63f4b451c684e.yml +openapi_spec_hash: ba0c3cf85aa82f17744e217258a55b2e +config_hash: 10bd597dd6cc89023541bc551b6532b8 diff --git a/CHANGELOG.md b/CHANGELOG.md index a61ec82d..2f7353b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 7.11.0 (2026-05-15) + +Full Changelog: [v7.10.2...v7.11.0](https://github.com/trycourier/courier-node/compare/v7.10.2...v7.11.0) + +### Features + +* [SUP-607] Add DELETE endpoint for Courier Create tenant templates ([c5769b4](https://github.com/trycourier/courier-node/commit/c5769b4bfd047d0b3914f35403a2a6bac9a207c4)) +* **api:** add journeys CRUD/publish/versioning, templates sub-resource, types ([297d6eb](https://github.com/trycourier/courier-node/commit/297d6eb106b494cb56f3722a124a096736f1f83a)) +* support setting headers via env ([e7a078f](https://github.com/trycourier/courier-node/commit/e7a078f8e44790bf9332c5c06891d3fa9b148ee7)) + + +### Chores + +* **format:** run eslint and prettier separately ([94cc158](https://github.com/trycourier/courier-node/commit/94cc1583b4dcfe832929c142efaf5bf8b371b42f)) +* **formatter:** run prettier and eslint separately ([ee1ac34](https://github.com/trycourier/courier-node/commit/ee1ac34270e0607eb8f6f6ea884b37a7c9167e3d)) +* **internal:** codegen related update ([6197029](https://github.com/trycourier/courier-node/commit/619702960b9076a75bc7138a5218d06f4b3c5dc3)) +* **internal:** more robust bootstrap script ([1625ecf](https://github.com/trycourier/courier-node/commit/1625ecf85ab5a9550217acb1b6655c9ea5611fa3)) +* redact api-key headers in debug logs ([ce91d48](https://github.com/trycourier/courier-node/commit/ce91d48d8a4be2500a03433a03bafd8142d78e08)) + ## 7.10.2 (2026-04-14) Full Changelog: [v7.10.1...v7.10.2](https://github.com/trycourier/courier-node/compare/v7.10.1...v7.10.2) diff --git a/api.md b/api.md index 3d9ffa24..d25051f7 100644 --- a/api.md +++ b/api.md @@ -178,15 +178,62 @@ Methods: Types: -- Journey -- JourneysInvokeRequest -- JourneysInvokeResponse -- JourneysListResponse +- CreateJourneyRequest +- Journey +- JourneyAINode +- JourneyAPIInvokeTriggerNode +- JourneyConditionAtom +- JourneyConditionGroup +- JourneyConditionNestedGroup +- JourneyConditionsField +- JourneyDelayDurationNode +- JourneyDelayUntilNode +- JourneyExitNode +- JourneyFetchGetDeleteNode +- JourneyFetchPostPutNode +- JourneyMergeStrategy +- JourneyNode +- JourneyPublishRequest +- JourneyResponse +- JourneySegmentTriggerNode +- JourneySendNode +- JourneyState +- JourneyTemplateCreateRequest +- JourneyTemplateGetResponse +- JourneyTemplateListResponse +- JourneyTemplatePublishRequest +- JourneyTemplateReplaceRequest +- JourneyTemplateSummary +- JourneyThrottleDynamicNode +- JourneyThrottleStaticNode +- JourneyVersionItem +- JourneyVersionsListResponse +- JourneysInvokeRequest +- JourneysInvokeResponse +- JourneysListResponse Methods: -- client.journeys.list({ ...params }) -> JourneysListResponse -- client.journeys.invoke(templateID, { ...params }) -> JourneysInvokeResponse +- client.journeys.create({ ...params }) -> JourneyResponse +- client.journeys.retrieve(templateID, { ...params }) -> JourneyResponse +- client.journeys.list({ ...params }) -> JourneysListResponse +- client.journeys.archive(templateID) -> void +- client.journeys.invoke(templateID, { ...params }) -> JourneysInvokeResponse +- client.journeys.listVersions(templateID) -> JourneyVersionsListResponse +- client.journeys.publish(templateID, { ...params }) -> JourneyResponse +- client.journeys.replace(templateID, { ...params }) -> JourneyResponse + +## Templates + +Methods: + +- client.journeys.templates.create(templateID, { ...params }) -> JourneyTemplateGetResponse +- client.journeys.templates.retrieve(notificationID, { ...params }) -> JourneyTemplateGetResponse +- client.journeys.templates.list(templateID, { ...params }) -> JourneyTemplateListResponse +- client.journeys.templates.archive(notificationID, { ...params }) -> void +- client.journeys.templates.listVersions(notificationID, { ...params }) -> NotificationTemplateVersionListResponse +- client.journeys.templates.publish(notificationID, { ...params }) -> void +- client.journeys.templates.replace(notificationID, { ...params }) -> JourneyTemplateGetResponse # Brands @@ -445,6 +492,7 @@ Methods: - client.tenants.templates.retrieve(templateID, { ...params }) -> BaseTemplateTenantAssociation - client.tenants.templates.list(tenantID, { ...params }) -> TemplateListResponse +- client.tenants.templates.delete(templateID, { ...params }) -> void - client.tenants.templates.publish(templateID, { ...params }) -> PostTenantTemplatePublishResponse - client.tenants.templates.replace(templateID, { ...params }) -> PutTenantTemplateResponse diff --git a/eslint.config.mjs b/eslint.config.mjs index 7850bf49..07b28b78 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,6 @@ // @ts-check import tseslint from 'typescript-eslint'; import unusedImports from 'eslint-plugin-unused-imports'; -import prettier from 'eslint-plugin-prettier'; export default tseslint.config( { @@ -14,11 +13,9 @@ export default tseslint.config( plugins: { '@typescript-eslint': tseslint.plugin, 'unused-imports': unusedImports, - prettier, }, rules: { 'no-unused-vars': 'off', - 'prettier/prettier': 'error', 'unused-imports/no-unused-imports': 'error', 'no-restricted-imports': [ 'error', diff --git a/package.json b/package.json index 8aeaadf7..d26d2840 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@trycourier/courier", - "version": "7.10.2", + "version": "7.11.0", "description": "The official TypeScript library for the Courier API", "author": "Courier ", "types": "dist/index.d.ts", @@ -36,7 +36,6 @@ "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", "eslint": "^9.39.1", - "eslint-plugin-prettier": "^5.4.1", "eslint-plugin-unused-imports": "^4.1.4", "iconv-lite": "^0.6.3", "jest": "^29.4.0", diff --git a/scripts/bootstrap b/scripts/bootstrap index a8b69ff3..2e315f53 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { echo -n "==> Install Homebrew dependencies? (y/N): " read -r response diff --git a/scripts/fast-format b/scripts/fast-format index 53721ac0..f1873aef 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -31,10 +31,7 @@ if ! [ -z "$ESLINT_FILES" ]; then fi echo "==> Running prettier --write" -# format things eslint didn't -PRETTIER_FILES="$(grep '\.\(js\|json\)$' "$FILE_LIST" || true)" -if ! [ -z "$PRETTIER_FILES" ]; then - echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \ - --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern \ - '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +if ! [ -z "$FILE_LIST" ]; then + cat "$FILE_LIST" | xargs ./node_modules/.bin/prettier \ + --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern --ignore-unknown fi diff --git a/scripts/format b/scripts/format index 7a756401..b1b2c17a 100755 --- a/scripts/format +++ b/scripts/format @@ -8,5 +8,4 @@ echo "==> Running eslint --fix" ./node_modules/.bin/eslint --fix . echo "==> Running prettier --write" -# format things eslint didn't -./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +./node_modules/.bin/prettier --write --cache --cache-strategy metadata . diff --git a/scripts/lint b/scripts/lint index 3ffb78a6..1f532548 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,6 +4,9 @@ set -e cd "$(dirname "$0")/.." +echo "==> Running prettier --check" +./node_modules/.bin/prettier --check . + echo "==> Running eslint" ./node_modules/.bin/eslint . diff --git a/scripts/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs index deae575e..a8cdeb7c 100644 --- a/scripts/utils/postprocess-files.cjs +++ b/scripts/utils/postprocess-files.cjs @@ -23,12 +23,19 @@ async function postprocess() { // strip out lib="dom", types="node", and types="react" references; these // are needed at build time, but would pollute the user's TS environment - const transformed = code.replace( + let transformed = code.replace( /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', ); + // TypeScript's declaration emitter collapses /** @ts-ignore */ onto the same + // line as the type declaration, which doesn't work. So we convert to // @ts-ignore + // on its own line to properly suppresses errors. + if (file.endsWith('.d.ts') || file.endsWith('.d.mts') || file.endsWith('.d.cts')) { + transformed = transformed.replace(/\/\*\* @ts-ignore\b[^*]*\*\/ /gm, '// @ts-ignore\n'); + } + if (transformed !== code) { console.error(`wrote ${path.relative(process.cwd(), file)}`); await fs.promises.writeFile(file, transformed, 'utf8'); diff --git a/src/client.ts b/src/client.ts index a55a0521..87734246 100644 --- a/src/client.ts +++ b/src/client.ts @@ -67,15 +67,6 @@ import { InboundBulkMessageUser, } from './resources/bulk'; import { Inbound, InboundTrackEventParams, InboundTrackEventResponse } from './resources/inbound'; -import { - Journey, - JourneyInvokeParams, - JourneyListParams, - Journeys, - JourneysInvokeRequest, - JourneysInvokeResponse, - JourneysListResponse, -} from './resources/journeys'; import { MessageContentResponse, MessageDetails, @@ -114,6 +105,48 @@ import { AutomationTemplateListResponse, Automations, } from './resources/automations/automations'; +import { + CreateJourneyRequest, + Journey, + JourneyAINode, + JourneyAPIInvokeTriggerNode, + JourneyConditionAtom, + JourneyConditionGroup, + JourneyConditionNestedGroup, + JourneyConditionsField, + JourneyCreateParams, + JourneyDelayDurationNode, + JourneyDelayUntilNode, + JourneyExitNode, + JourneyFetchGetDeleteNode, + JourneyFetchPostPutNode, + JourneyInvokeParams, + JourneyListParams, + JourneyMergeStrategy, + JourneyNode, + JourneyPublishParams, + JourneyPublishRequest, + JourneyReplaceParams, + JourneyResponse, + JourneyRetrieveParams, + JourneySegmentTriggerNode, + JourneySendNode, + JourneyState, + JourneyTemplateCreateRequest, + JourneyTemplateGetResponse, + JourneyTemplateListResponse, + JourneyTemplatePublishRequest, + JourneyTemplateReplaceRequest, + JourneyTemplateSummary, + JourneyThrottleDynamicNode, + JourneyThrottleStaticNode, + JourneyVersionItem, + JourneyVersionsListResponse, + Journeys, + JourneysInvokeRequest, + JourneysInvokeResponse, + JourneysListResponse, +} from './resources/journeys/journeys'; import { ListListParams, ListListResponse, @@ -344,6 +377,18 @@ export class Courier { this.fetch = options.fetch ?? Shims.getDefaultFetch(); this.#encoder = Opts.FallbackEncoder; + const customHeadersEnv = readEnv('COURIER_CUSTOM_HEADERS'); + if (customHeadersEnv) { + const parsed: Record = {}; + for (const line of customHeadersEnv.split('\n')) { + const colon = line.indexOf(':'); + if (colon >= 0) { + parsed[line.substring(0, colon).trim()] = line.substring(colon + 1).trim(); + } + } + options.defaultHeaders = { ...parsed, ...options.defaultHeaders }; + } + this._options = options; this.apiKey = apiKey; @@ -985,12 +1030,45 @@ export declare namespace Courier { export { Journeys as Journeys, + type CreateJourneyRequest as CreateJourneyRequest, type Journey as Journey, + type JourneyAINode as JourneyAINode, + type JourneyAPIInvokeTriggerNode as JourneyAPIInvokeTriggerNode, + type JourneyConditionAtom as JourneyConditionAtom, + type JourneyConditionGroup as JourneyConditionGroup, + type JourneyConditionNestedGroup as JourneyConditionNestedGroup, + type JourneyConditionsField as JourneyConditionsField, + type JourneyDelayDurationNode as JourneyDelayDurationNode, + type JourneyDelayUntilNode as JourneyDelayUntilNode, + type JourneyExitNode as JourneyExitNode, + type JourneyFetchGetDeleteNode as JourneyFetchGetDeleteNode, + type JourneyFetchPostPutNode as JourneyFetchPostPutNode, + type JourneyMergeStrategy as JourneyMergeStrategy, + type JourneyNode as JourneyNode, + type JourneyPublishRequest as JourneyPublishRequest, + type JourneyResponse as JourneyResponse, + type JourneySegmentTriggerNode as JourneySegmentTriggerNode, + type JourneySendNode as JourneySendNode, + type JourneyState as JourneyState, + type JourneyTemplateCreateRequest as JourneyTemplateCreateRequest, + type JourneyTemplateGetResponse as JourneyTemplateGetResponse, + type JourneyTemplateListResponse as JourneyTemplateListResponse, + type JourneyTemplatePublishRequest as JourneyTemplatePublishRequest, + type JourneyTemplateReplaceRequest as JourneyTemplateReplaceRequest, + type JourneyTemplateSummary as JourneyTemplateSummary, + type JourneyThrottleDynamicNode as JourneyThrottleDynamicNode, + type JourneyThrottleStaticNode as JourneyThrottleStaticNode, + type JourneyVersionItem as JourneyVersionItem, + type JourneyVersionsListResponse as JourneyVersionsListResponse, type JourneysInvokeRequest as JourneysInvokeRequest, type JourneysInvokeResponse as JourneysInvokeResponse, type JourneysListResponse as JourneysListResponse, + type JourneyCreateParams as JourneyCreateParams, + type JourneyRetrieveParams as JourneyRetrieveParams, type JourneyListParams as JourneyListParams, type JourneyInvokeParams as JourneyInvokeParams, + type JourneyPublishParams as JourneyPublishParams, + type JourneyReplaceParams as JourneyReplaceParams, }; export { diff --git a/src/internal/types.ts b/src/internal/types.ts index b668dfc0..a050513a 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -40,7 +40,6 @@ type OverloadedParameters = : T extends (...args: infer A) => unknown ? A : never; -/* eslint-disable */ /** * These imports attempt to get types from a parent package's dependencies. * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which @@ -63,19 +62,18 @@ type OverloadedParameters = * * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition */ -/** @ts-ignore For users with \@types/node */ +/** @ts-ignore For users with \@types/node */ /* prettier-ignore */ type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with undici */ +/** @ts-ignore For users with undici */ /* prettier-ignore */ type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with \@types/bun */ +/** @ts-ignore For users with \@types/bun */ /* prettier-ignore */ type BunRequestInit = globalThis.FetchRequestInit; -/** @ts-ignore For users with node-fetch@2 */ +/** @ts-ignore For users with node-fetch@2 */ /* prettier-ignore */ type NodeFetch2RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ +/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ /* prettier-ignore */ type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users who use Deno */ +/** @ts-ignore For users who use Deno */ /* prettier-ignore */ type FetchRequestInit = NonNullable[1]>; -/* eslint-enable */ type RequestInits = | NotAny diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index dbbb7b33..4ddc254a 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -107,6 +107,8 @@ export const formatRequestDetails = (details: { name, ( name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'api-key' || + name.toLowerCase() === 'x-api-key' || name.toLowerCase() === 'cookie' || name.toLowerCase() === 'set-cookie' ) ? diff --git a/src/resources/index.ts b/src/resources/index.ts index 39e3d90d..66263e95 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -60,13 +60,46 @@ export { export { Inbound, type InboundTrackEventResponse, type InboundTrackEventParams } from './inbound'; export { Journeys, + type CreateJourneyRequest, type Journey, + type JourneyAINode, + type JourneyAPIInvokeTriggerNode, + type JourneyConditionAtom, + type JourneyConditionGroup, + type JourneyConditionNestedGroup, + type JourneyConditionsField, + type JourneyDelayDurationNode, + type JourneyDelayUntilNode, + type JourneyExitNode, + type JourneyFetchGetDeleteNode, + type JourneyFetchPostPutNode, + type JourneyMergeStrategy, + type JourneyNode, + type JourneyPublishRequest, + type JourneyResponse, + type JourneySegmentTriggerNode, + type JourneySendNode, + type JourneyState, + type JourneyTemplateCreateRequest, + type JourneyTemplateGetResponse, + type JourneyTemplateListResponse, + type JourneyTemplatePublishRequest, + type JourneyTemplateReplaceRequest, + type JourneyTemplateSummary, + type JourneyThrottleDynamicNode, + type JourneyThrottleStaticNode, + type JourneyVersionItem, + type JourneyVersionsListResponse, type JourneysInvokeRequest, type JourneysInvokeResponse, type JourneysListResponse, + type JourneyCreateParams, + type JourneyRetrieveParams, type JourneyListParams, type JourneyInvokeParams, -} from './journeys'; + type JourneyPublishParams, + type JourneyReplaceParams, +} from './journeys/journeys'; export { Lists, type PutSubscriptionsRecipient, diff --git a/src/resources/journeys.ts b/src/resources/journeys.ts index a7157480..24b7a0b2 100644 --- a/src/resources/journeys.ts +++ b/src/resources/journeys.ts @@ -1,174 +1,3 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../core/resource'; -import { APIPromise } from '../core/api-promise'; -import { RequestOptions } from '../internal/request-options'; -import { path } from '../internal/utils/path'; - -export class Journeys extends APIResource { - /** - * Get the list of journeys. - * - * @example - * ```ts - * const journeysListResponse = await client.journeys.list(); - * ``` - */ - list( - query: JourneyListParams | null | undefined = {}, - options?: RequestOptions, - ): APIPromise { - return this._client.get('/journeys', { query, ...options }); - } - - /** - * Invoke a journey run from a journey template. - * - * @example - * ```ts - * const journeysInvokeResponse = await client.journeys.invoke( - * 'templateId', - * { - * data: { order_id: 'order-456', amount: 99.99 }, - * user_id: 'user-123', - * }, - * ); - * ``` - */ - invoke( - templateID: string, - body: JourneyInvokeParams, - options?: RequestOptions, - ): APIPromise { - return this._client.post(path`/journeys/${templateID}/invoke`, { body, ...options }); - } -} - -/** - * A journey template representing an automation workflow. - */ -export interface Journey { - /** - * The unique identifier of the journey. - */ - id: string; - - /** - * The name of the journey. - */ - name: string; - - /** - * The version of the journey (published or draft). - */ - version: 'published' | 'draft'; - - /** - * ISO 8601 timestamp when the journey was created. - */ - createdAt?: string; - - /** - * ISO 8601 timestamp when the journey was last updated. - */ - updatedAt?: string; -} - -/** - * Request body for invoking a journey. Requires either a user identifier or a - * profile with contact information. User identifiers can be provided via user_id - * field, or resolved from profile/data objects (user_id, userId, or anonymousId - * fields). - */ -export interface JourneysInvokeRequest { - /** - * Data payload passed to the journey. The expected shape can be predefined using - * the schema builder in the journey editor. This data is available in journey - * steps for condition evaluation and template variable interpolation. Can also - * contain user identifiers (user_id, userId, anonymousId) if not provided - * elsewhere. - */ - data?: { [key: string]: unknown }; - - /** - * Profile data for the user. Can contain contact information (email, - * phone_number), user identifiers (user_id, userId, anonymousId), or any custom - * profile fields. Profile fields are merged with any existing stored profile for - * the user. Include context.tenant_id to load a tenant-scoped profile for - * multi-tenant scenarios. - */ - profile?: { [key: string]: unknown }; - - /** - * A unique identifier for the user. If not provided, the system will attempt to - * resolve the user identifier from profile or data objects. - */ - user_id?: string; -} - -export interface JourneysInvokeResponse { - /** - * A unique identifier for the journey run that was created. - */ - runId: string; -} - -export interface JourneysListResponse { - /** - * A cursor token for pagination. Present when there are more results available. - */ - cursor?: string; - - templates?: Array; -} - -export interface JourneyListParams { - /** - * A cursor token for pagination. Use the cursor from the previous response to - * fetch the next page of results. - */ - cursor?: string; - - /** - * The version of journeys to retrieve. Accepted values are published (for - * published journeys) or draft (for draft journeys). Defaults to published. - */ - version?: 'published' | 'draft'; -} - -export interface JourneyInvokeParams { - /** - * Data payload passed to the journey. The expected shape can be predefined using - * the schema builder in the journey editor. This data is available in journey - * steps for condition evaluation and template variable interpolation. Can also - * contain user identifiers (user_id, userId, anonymousId) if not provided - * elsewhere. - */ - data?: { [key: string]: unknown }; - - /** - * Profile data for the user. Can contain contact information (email, - * phone_number), user identifiers (user_id, userId, anonymousId), or any custom - * profile fields. Profile fields are merged with any existing stored profile for - * the user. Include context.tenant_id to load a tenant-scoped profile for - * multi-tenant scenarios. - */ - profile?: { [key: string]: unknown }; - - /** - * A unique identifier for the user. If not provided, the system will attempt to - * resolve the user identifier from profile or data objects. - */ - user_id?: string; -} - -export declare namespace Journeys { - export { - type Journey as Journey, - type JourneysInvokeRequest as JourneysInvokeRequest, - type JourneysInvokeResponse as JourneysInvokeResponse, - type JourneysListResponse as JourneysListResponse, - type JourneyListParams as JourneyListParams, - type JourneyInvokeParams as JourneyInvokeParams, - }; -} +export * from './journeys/index'; diff --git a/src/resources/journeys/index.ts b/src/resources/journeys/index.ts new file mode 100644 index 00000000..3217441f --- /dev/null +++ b/src/resources/journeys/index.ts @@ -0,0 +1,54 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Journeys, + type CreateJourneyRequest, + type Journey, + type JourneyAINode, + type JourneyAPIInvokeTriggerNode, + type JourneyConditionAtom, + type JourneyConditionGroup, + type JourneyConditionNestedGroup, + type JourneyConditionsField, + type JourneyDelayDurationNode, + type JourneyDelayUntilNode, + type JourneyExitNode, + type JourneyFetchGetDeleteNode, + type JourneyFetchPostPutNode, + type JourneyMergeStrategy, + type JourneyNode, + type JourneyPublishRequest, + type JourneyResponse, + type JourneySegmentTriggerNode, + type JourneySendNode, + type JourneyState, + type JourneyTemplateCreateRequest, + type JourneyTemplateGetResponse, + type JourneyTemplateListResponse, + type JourneyTemplatePublishRequest, + type JourneyTemplateReplaceRequest, + type JourneyTemplateSummary, + type JourneyThrottleDynamicNode, + type JourneyThrottleStaticNode, + type JourneyVersionItem, + type JourneyVersionsListResponse, + type JourneysInvokeRequest, + type JourneysInvokeResponse, + type JourneysListResponse, + type JourneyCreateParams, + type JourneyRetrieveParams, + type JourneyListParams, + type JourneyInvokeParams, + type JourneyPublishParams, + type JourneyReplaceParams, +} from './journeys'; +export { + Templates, + type TemplateCreateParams, + type TemplateRetrieveParams, + type TemplateListParams, + type TemplateArchiveParams, + type TemplateListVersionsParams, + type TemplatePublishParams, + type TemplateReplaceParams, +} from './templates'; diff --git a/src/resources/journeys/journeys.ts b/src/resources/journeys/journeys.ts new file mode 100644 index 00000000..d0666e5a --- /dev/null +++ b/src/resources/journeys/journeys.ts @@ -0,0 +1,939 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as JourneysAPI from './journeys'; +import * as Shared from '../shared'; +import * as TemplatesAPI from './templates'; +import { + TemplateArchiveParams, + TemplateCreateParams, + TemplateListParams, + TemplateListVersionsParams, + TemplatePublishParams, + TemplateReplaceParams, + TemplateRetrieveParams, + Templates, +} from './templates'; +import { APIPromise } from '../../core/api-promise'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; + +export class Journeys extends APIResource { + templates: TemplatesAPI.Templates = new TemplatesAPI.Templates(this._client); + + /** + * Create a new journey. The journey is created in DRAFT state. Use POST + * /journeys/{templateId}/publish to make it live. + * + * @example + * ```ts + * const journeyResponse = await client.journeys.create({ + * name: 'Welcome Journey', + * nodes: [ + * { + * id: 'trigger-1', + * type: 'trigger', + * trigger_type: 'api', + * }, + * { id: 'send-1', type: 'send' }, + * ], + * enabled: true, + * state: 'DRAFT', + * }); + * ``` + */ + create(body: JourneyCreateParams, options?: RequestOptions): APIPromise { + return this._client.post('/journeys', { body, ...options }); + } + + /** + * Fetch a journey by id. Pass `?version=draft` (default `published`) to retrieve + * the working draft, or `?version=vN` to retrieve a historical version. + * + * @example + * ```ts + * const journeyResponse = await client.journeys.retrieve('x'); + * ``` + */ + retrieve( + templateID: string, + query: JourneyRetrieveParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get(path`/journeys/${templateID}`, { query, ...options }); + } + + /** + * Get the list of journeys. + * + * @example + * ```ts + * const journeysListResponse = await client.journeys.list(); + * ``` + */ + list( + query: JourneyListParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get('/journeys', { query, ...options }); + } + + /** + * Archive a journey. Archived journeys cannot be invoked. Existing journey runs + * continue to completion. + * + * @example + * ```ts + * await client.journeys.archive('x'); + * ``` + */ + archive(templateID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/journeys/${templateID}`, { + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + }); + } + + /** + * Invoke a journey run from a journey template. + * + * @example + * ```ts + * const journeysInvokeResponse = await client.journeys.invoke( + * 'templateId', + * { + * data: { order_id: 'order-456', amount: 99.99 }, + * user_id: 'user-123', + * }, + * ); + * ``` + */ + invoke( + templateID: string, + body: JourneyInvokeParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/journeys/${templateID}/invoke`, { body, ...options }); + } + + /** + * List published versions of a journey, ordered most recent first. + * + * @example + * ```ts + * const journeyVersionsListResponse = + * await client.journeys.listVersions('x'); + * ``` + */ + listVersions(templateID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/journeys/${templateID}/versions`, options); + } + + /** + * Publish the current draft as a new version. Optionally rollback to a prior + * version by passing `{ version: 'vN' }`. + * + * @example + * ```ts + * const journeyResponse = await client.journeys.publish('x'); + * ``` + */ + publish( + templateID: string, + body: JourneyPublishParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/journeys/${templateID}/publish`, { body, ...options }); + } + + /** + * Replace the journey draft. Updates the working draft only; call POST + * /journeys/{templateId}/publish to make it live. + * + * @example + * ```ts + * const journeyResponse = await client.journeys.replace('x', { + * name: 'Welcome Journey v2', + * nodes: [], + * enabled: true, + * state: 'DRAFT', + * }); + * ``` + */ + replace( + templateID: string, + body: JourneyReplaceParams, + options?: RequestOptions, + ): APIPromise { + return this._client.put(path`/journeys/${templateID}`, { body, ...options }); + } +} + +export interface CreateJourneyRequest { + name: string; + + nodes: Array; + + enabled?: boolean; + + state?: JourneyState; +} + +/** + * A journey template representing an automation workflow. + */ +export interface Journey { + /** + * The unique identifier of the journey. + */ + id: string; + + /** + * The name of the journey. + */ + name: string; + + /** + * The version of the journey (published or draft). + */ + version: 'published' | 'draft'; + + /** + * ISO 8601 timestamp when the journey was created. + */ + createdAt?: string; + + /** + * ISO 8601 timestamp when the journey was last updated. + */ + updatedAt?: string; +} + +export interface JourneyAINode { + /** + * A JSONSchema object (Draft-07-compatible). Validated at runtime by Ajv. + */ + output_schema: { [key: string]: unknown }; + + type: 'ai'; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; + + model?: string; + + user_prompt?: string; + + web_search?: boolean; +} + +export interface JourneyAPIInvokeTriggerNode { + trigger_type: 'api-invoke'; + + type: 'trigger'; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; + + /** + * A JSONSchema object (Draft-07-compatible). Validated at runtime by Ajv. + */ + schema?: { [key: string]: unknown }; +} + +/** + * A single condition expressed as a positional tuple of strings. + * + * - Binary form (3 elements): `[path, operator, value]` where `operator` is one of + * `is equal`, `is not equal`, `contains`, `does not contain`, `starts with`, + * `ends with`, `greater than`, `greater than or equal`, `less than`, + * `less than or equal`. + * + * Example: `["user.tier", "is equal", "gold"]`. + * + * - Unary form (2 elements): `[path, operator]` where `operator` is one of + * `exists`, `does not exist`. + * + * Example: `["user.email", "exists"]`. + * + * The first element is a non-empty dot-path. The second element is the operator + * (must come from one of the two operator sets above). For the binary form, the + * third element is the comparison value (string). Runtime validation of the + * operator value and arity is performed by the backend; SDKs surface this as a + * string list. + */ +export type JourneyConditionAtom = Array; + +/** + * A leaf condition group. Exactly one of `AND` or `OR` must be present at runtime; + * each is a list of `JourneyConditionAtom` tuples. + */ +export interface JourneyConditionGroup { + AND?: Array; + + OR?: Array; +} + +/** + * A nested condition group. Exactly one of `AND` or `OR` must be present at + * runtime; each is a list of `JourneyConditionGroup` items. + */ +export interface JourneyConditionNestedGroup { + AND?: Array; + + OR?: Array; +} + +/** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ +export type JourneyConditionsField = + | JourneyConditionAtom + | JourneyConditionGroup + | JourneyConditionNestedGroup; + +export interface JourneyDelayDurationNode { + duration: string; + + mode: 'duration'; + + type: 'delay'; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; +} + +export interface JourneyDelayUntilNode { + mode: 'until'; + + type: 'delay'; + + until: string; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; +} + +export interface JourneyExitNode { + type: 'exit'; + + id?: string; +} + +export interface JourneyFetchGetDeleteNode { + merge_strategy: JourneyMergeStrategy; + + method: 'get' | 'delete'; + + type: 'fetch'; + + url: string; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; + + headers?: { [key: string]: string }; + + query_params?: { [key: string]: string }; + + /** + * A JSONSchema object (Draft-07-compatible). Validated at runtime by Ajv. + */ + response_schema?: { [key: string]: unknown }; +} + +export interface JourneyFetchPostPutNode { + merge_strategy: JourneyMergeStrategy; + + method: 'post' | 'put'; + + type: 'fetch'; + + url: string; + + id?: string; + + body?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; + + headers?: { [key: string]: string }; + + query_params?: { [key: string]: string }; + + /** + * A JSONSchema object (Draft-07-compatible). Validated at runtime by Ajv. + */ + response_schema?: { [key: string]: unknown }; +} + +export type JourneyMergeStrategy = 'overwrite' | 'soft-merge' | 'replace' | 'none'; + +/** + * A single node in a journey DAG. Discriminated by `type` plus a secondary + * discriminator on some variants (`trigger_type` for trigger, `mode` for delay, + * `method` for fetch, `scope` for throttle). Each variant is exported as a + * separate schema for SDK type quality. + */ +export type JourneyNode = + | JourneyAPIInvokeTriggerNode + | JourneySegmentTriggerNode + | JourneySendNode + | JourneyDelayDurationNode + | JourneyDelayUntilNode + | JourneyFetchGetDeleteNode + | JourneyFetchPostPutNode + | JourneyAINode + | JourneyThrottleStaticNode + | JourneyThrottleDynamicNode + | JourneyExitNode + | JourneyNode.JourneyBranchNode; + +export namespace JourneyNode { + /** + * Branch node. Routes to one of `paths[]` whose `conditions` match, else falls + * through to `default.nodes`. Inlined rather than referenced so the recursive + * `nodes: JourneyNode[]` cycle stays within a single generated module (Stainless + * Python forward-ref resolution does not span modules well for this recursion + * shape). + */ + export interface JourneyBranchNode { + default: JourneyBranchNode.Default; + + paths: Array; + + type: 'branch'; + + id?: string; + } + + export namespace JourneyBranchNode { + export interface Default { + nodes: Array; + + label?: string; + } + + export interface Path { + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions: JourneysAPI.JourneyConditionsField; + + nodes: Array; + + label?: string; + } + } +} + +export interface JourneyPublishRequest { + version?: string; +} + +export interface JourneyResponse { + id: string; + + created: number | null; + + creator: string | null; + + enabled: boolean; + + name: string; + + nodes: Array; + + published: number | null; + + state: JourneyState; + + updated: number | null; + + updater: string | null; +} + +export interface JourneySegmentTriggerNode { + request_type: 'identify' | 'group' | 'track'; + + trigger_type: 'segment'; + + type: 'trigger'; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; + + event_id?: string; +} + +export interface JourneySendNode { + message: JourneySendNode.Message; + + type: 'send'; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; +} + +export namespace JourneySendNode { + export interface Message { + template: string; + + data?: { [key: string]: unknown }; + + delay?: Message.Delay; + + to?: Message.To; + } + + export namespace Message { + export interface Delay { + until: string; + + timezone?: string; + } + + export interface To { + email_override?: string; + + phone_number_override?: string; + + user_id_override?: string; + } + } +} + +export type JourneyState = 'DRAFT' | 'PUBLISHED'; + +export interface JourneyTemplateCreateRequest { + channel: string; + + notification: JourneyTemplateCreateRequest.Notification; + + providerKey?: string; + + state?: string; +} + +export namespace JourneyTemplateCreateRequest { + export interface Notification { + brand: Notification.Brand | null; + + content: Notification.Content; + + name: string; + + subscription: Notification.Subscription | null; + + tags: Array; + } + + export namespace Notification { + export interface Brand { + id: string; + } + + export interface Content { + elements: Array; + + version: '2022-01-01'; + + scope?: 'default' | 'strict'; + } + + export interface Subscription { + topic_id: string; + } + } +} + +export interface JourneyTemplateGetResponse { + id: string; + + brand: JourneyTemplateGetResponse.Brand | null; + + content: JourneyTemplateGetResponse.Content; + + created: number; + + creator: string; + + name: string; + + state: 'DRAFT' | 'PUBLISHED'; + + subscription: JourneyTemplateGetResponse.Subscription | null; + + tags: Array; + + updated?: number; + + updater?: string; +} + +export namespace JourneyTemplateGetResponse { + export interface Brand { + id: string; + } + + export interface Content { + elements: Array; + + version: '2022-01-01'; + + scope?: 'default' | 'strict'; + } + + export interface Subscription { + topic_id: string; + } +} + +export interface JourneyTemplateListResponse { + paging: Shared.Paging; + + results: Array; +} + +export interface JourneyTemplatePublishRequest { + version?: string; +} + +export interface JourneyTemplateReplaceRequest { + notification: JourneyTemplateReplaceRequest.Notification; + + state?: string; +} + +export namespace JourneyTemplateReplaceRequest { + export interface Notification { + brand: Notification.Brand | null; + + content: Notification.Content; + + name: string; + + subscription: Notification.Subscription | null; + + tags: Array; + } + + export namespace Notification { + export interface Brand { + id: string; + } + + export interface Content { + elements: Array; + + version: '2022-01-01'; + + scope?: 'default' | 'strict'; + } + + export interface Subscription { + topic_id: string; + } + } +} + +export interface JourneyTemplateSummary { + id: string; + + created: number; + + creator: string; + + name: string; + + state: string; + + tags: Array; + + updated?: number; + + updater?: string; +} + +export interface JourneyThrottleDynamicNode { + max_allowed: number; + + period: string; + + scope: 'dynamic'; + + throttle_key: string; + + type: 'throttle'; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; +} + +export interface JourneyThrottleStaticNode { + max_allowed: number; + + period: string; + + scope: 'user' | 'global'; + + type: 'throttle'; + + id?: string; + + /** + * Condition spec for a journey node. Accepts a single condition atom, an AND/OR + * group, or an AND/OR nested group. Omit the `conditions` property entirely to + * express "no conditions". + */ + conditions?: JourneyConditionsField; +} + +export interface JourneyVersionItem { + created: number | null; + + creator: string | null; + + name: string; + + published: number | null; + + version: string; +} + +export interface JourneyVersionsListResponse { + paging: Shared.Paging; + + results: Array; +} + +/** + * Request body for invoking a journey. Requires either a user identifier or a + * profile with contact information. User identifiers can be provided via user_id + * field, or resolved from profile/data objects (user_id, userId, or anonymousId + * fields). + */ +export interface JourneysInvokeRequest { + /** + * Data payload passed to the journey. The expected shape can be predefined using + * the schema builder in the journey editor. This data is available in journey + * steps for condition evaluation and template variable interpolation. Can also + * contain user identifiers (user_id, userId, anonymousId) if not provided + * elsewhere. + */ + data?: { [key: string]: unknown }; + + /** + * Profile data for the user. Can contain contact information (email, + * phone_number), user identifiers (user_id, userId, anonymousId), or any custom + * profile fields. Profile fields are merged with any existing stored profile for + * the user. Include context.tenant_id to load a tenant-scoped profile for + * multi-tenant scenarios. + */ + profile?: { [key: string]: unknown }; + + /** + * A unique identifier for the user. If not provided, the system will attempt to + * resolve the user identifier from profile or data objects. + */ + user_id?: string; +} + +export interface JourneysInvokeResponse { + /** + * A unique identifier for the journey run that was created. + */ + runId: string; +} + +export interface JourneysListResponse { + /** + * A cursor token for pagination. Present when there are more results available. + */ + cursor?: string; + + templates?: Array; +} + +export interface JourneyCreateParams { + name: string; + + nodes: Array; + + enabled?: boolean; + + state?: JourneyState; +} + +export interface JourneyRetrieveParams { + version?: string; +} + +export interface JourneyListParams { + /** + * A cursor token for pagination. Use the cursor from the previous response to + * fetch the next page of results. + */ + cursor?: string; + + /** + * The version of journeys to retrieve. Accepted values are published (for + * published journeys) or draft (for draft journeys). Defaults to published. + */ + version?: 'published' | 'draft'; +} + +export interface JourneyInvokeParams { + /** + * Data payload passed to the journey. The expected shape can be predefined using + * the schema builder in the journey editor. This data is available in journey + * steps for condition evaluation and template variable interpolation. Can also + * contain user identifiers (user_id, userId, anonymousId) if not provided + * elsewhere. + */ + data?: { [key: string]: unknown }; + + /** + * Profile data for the user. Can contain contact information (email, + * phone_number), user identifiers (user_id, userId, anonymousId), or any custom + * profile fields. Profile fields are merged with any existing stored profile for + * the user. Include context.tenant_id to load a tenant-scoped profile for + * multi-tenant scenarios. + */ + profile?: { [key: string]: unknown }; + + /** + * A unique identifier for the user. If not provided, the system will attempt to + * resolve the user identifier from profile or data objects. + */ + user_id?: string; +} + +export interface JourneyPublishParams { + version?: string; +} + +export interface JourneyReplaceParams { + name: string; + + nodes: Array; + + enabled?: boolean; + + state?: JourneyState; +} + +Journeys.Templates = Templates; + +export declare namespace Journeys { + export { + type CreateJourneyRequest as CreateJourneyRequest, + type Journey as Journey, + type JourneyAINode as JourneyAINode, + type JourneyAPIInvokeTriggerNode as JourneyAPIInvokeTriggerNode, + type JourneyConditionAtom as JourneyConditionAtom, + type JourneyConditionGroup as JourneyConditionGroup, + type JourneyConditionNestedGroup as JourneyConditionNestedGroup, + type JourneyConditionsField as JourneyConditionsField, + type JourneyDelayDurationNode as JourneyDelayDurationNode, + type JourneyDelayUntilNode as JourneyDelayUntilNode, + type JourneyExitNode as JourneyExitNode, + type JourneyFetchGetDeleteNode as JourneyFetchGetDeleteNode, + type JourneyFetchPostPutNode as JourneyFetchPostPutNode, + type JourneyMergeStrategy as JourneyMergeStrategy, + type JourneyNode as JourneyNode, + type JourneyPublishRequest as JourneyPublishRequest, + type JourneyResponse as JourneyResponse, + type JourneySegmentTriggerNode as JourneySegmentTriggerNode, + type JourneySendNode as JourneySendNode, + type JourneyState as JourneyState, + type JourneyTemplateCreateRequest as JourneyTemplateCreateRequest, + type JourneyTemplateGetResponse as JourneyTemplateGetResponse, + type JourneyTemplateListResponse as JourneyTemplateListResponse, + type JourneyTemplatePublishRequest as JourneyTemplatePublishRequest, + type JourneyTemplateReplaceRequest as JourneyTemplateReplaceRequest, + type JourneyTemplateSummary as JourneyTemplateSummary, + type JourneyThrottleDynamicNode as JourneyThrottleDynamicNode, + type JourneyThrottleStaticNode as JourneyThrottleStaticNode, + type JourneyVersionItem as JourneyVersionItem, + type JourneyVersionsListResponse as JourneyVersionsListResponse, + type JourneysInvokeRequest as JourneysInvokeRequest, + type JourneysInvokeResponse as JourneysInvokeResponse, + type JourneysListResponse as JourneysListResponse, + type JourneyCreateParams as JourneyCreateParams, + type JourneyRetrieveParams as JourneyRetrieveParams, + type JourneyListParams as JourneyListParams, + type JourneyInvokeParams as JourneyInvokeParams, + type JourneyPublishParams as JourneyPublishParams, + type JourneyReplaceParams as JourneyReplaceParams, + }; + + export { + Templates as Templates, + type TemplateCreateParams as TemplateCreateParams, + type TemplateRetrieveParams as TemplateRetrieveParams, + type TemplateListParams as TemplateListParams, + type TemplateArchiveParams as TemplateArchiveParams, + type TemplateListVersionsParams as TemplateListVersionsParams, + type TemplatePublishParams as TemplatePublishParams, + type TemplateReplaceParams as TemplateReplaceParams, + }; +} diff --git a/src/resources/journeys/templates.ts b/src/resources/journeys/templates.ts new file mode 100644 index 00000000..7e35922c --- /dev/null +++ b/src/resources/journeys/templates.ts @@ -0,0 +1,310 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as Shared from '../shared'; +import * as JourneysAPI from './journeys'; +import * as NotificationsAPI from '../notifications/notifications'; +import { APIPromise } from '../../core/api-promise'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; + +export class Templates extends APIResource { + /** + * Create a notification template scoped to this journey. The template is created + * in DRAFT state. + * + * @example + * ```ts + * const journeyTemplateGetResponse = + * await client.journeys.templates.create('x', { + * channel: 'email', + * notification: { + * name: 'Welcome email', + * tags: [], + * brand: null, + * subscription: null, + * content: { + * version: '2022-01-01', + * elements: [{ type: 'text' }], + * }, + * }, + * }); + * ``` + */ + create( + templateID: string, + body: TemplateCreateParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/journeys/${templateID}/templates`, { body, ...options }); + } + + /** + * Fetch a journey-scoped notification template by id. Pass `?version=draft` + * (default `published`) to retrieve the working draft, or `?version=vN` for a + * historical version. + * + * @example + * ```ts + * const journeyTemplateGetResponse = + * await client.journeys.templates.retrieve('x', { + * templateId: 'x', + * }); + * ``` + */ + retrieve( + notificationID: string, + params: TemplateRetrieveParams, + options?: RequestOptions, + ): APIPromise { + const { templateId } = params; + return this._client.get(path`/journeys/${templateId}/templates/${notificationID}`, options); + } + + /** + * List notification templates scoped to this journey. Templates scoped to a + * journey can only be referenced from `send` nodes of the same journey. + * + * @example + * ```ts + * const journeyTemplateListResponse = + * await client.journeys.templates.list('x'); + * ``` + */ + list( + templateID: string, + query: TemplateListParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get(path`/journeys/${templateID}/templates`, { query, ...options }); + } + + /** + * Archive a journey-scoped notification template. Archived templates cannot be + * sent. + * + * @example + * ```ts + * await client.journeys.templates.archive('x', { + * templateId: 'x', + * }); + * ``` + */ + archive(notificationID: string, params: TemplateArchiveParams, options?: RequestOptions): APIPromise { + const { templateId } = params; + return this._client.delete(path`/journeys/${templateId}/templates/${notificationID}`, { + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + }); + } + + /** + * List published versions of a journey-scoped notification template, ordered most + * recent first. + * + * @example + * ```ts + * const notificationTemplateVersionListResponse = + * await client.journeys.templates.listVersions('x', { + * templateId: 'x', + * }); + * ``` + */ + listVersions( + notificationID: string, + params: TemplateListVersionsParams, + options?: RequestOptions, + ): APIPromise { + const { templateId } = params; + return this._client.get(path`/journeys/${templateId}/templates/${notificationID}/versions`, options); + } + + /** + * Publish the current draft of a journey-scoped notification template. + * + * @example + * ```ts + * await client.journeys.templates.publish('x', { + * templateId: 'x', + * }); + * ``` + */ + publish(notificationID: string, params: TemplatePublishParams, options?: RequestOptions): APIPromise { + const { templateId, ...body } = params; + return this._client.post(path`/journeys/${templateId}/templates/${notificationID}/publish`, { + body, + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + }); + } + + /** + * Replace a journey-scoped notification template draft. + * + * @example + * ```ts + * const journeyTemplateGetResponse = + * await client.journeys.templates.replace('x', { + * templateId: 'x', + * notification: { + * brand: { id: 'id' }, + * content: { elements: [{}], version: '2022-01-01' }, + * name: 'name', + * subscription: { topic_id: 'topic_id' }, + * tags: ['string'], + * }, + * }); + * ``` + */ + replace( + notificationID: string, + params: TemplateReplaceParams, + options?: RequestOptions, + ): APIPromise { + const { templateId, ...body } = params; + return this._client.put(path`/journeys/${templateId}/templates/${notificationID}`, { body, ...options }); + } +} + +export interface TemplateCreateParams { + channel: string; + + notification: TemplateCreateParams.Notification; + + providerKey?: string; + + state?: string; +} + +export namespace TemplateCreateParams { + export interface Notification { + brand: Notification.Brand | null; + + content: Notification.Content; + + name: string; + + subscription: Notification.Subscription | null; + + tags: Array; + } + + export namespace Notification { + export interface Brand { + id: string; + } + + export interface Content { + elements: Array; + + version: '2022-01-01'; + + scope?: 'default' | 'strict'; + } + + export interface Subscription { + topic_id: string; + } + } +} + +export interface TemplateRetrieveParams { + /** + * Journey id + */ + templateId: string; +} + +export interface TemplateListParams { + cursor?: string; + + limit?: number; +} + +export interface TemplateArchiveParams { + /** + * Journey id + */ + templateId: string; +} + +export interface TemplateListVersionsParams { + /** + * Journey id + */ + templateId: string; +} + +export interface TemplatePublishParams { + /** + * Path param: Journey id + */ + templateId: string; + + /** + * Body param + */ + version?: string; +} + +export interface TemplateReplaceParams { + /** + * Path param: Journey id + */ + templateId: string; + + /** + * Body param + */ + notification: TemplateReplaceParams.Notification; + + /** + * Body param + */ + state?: string; +} + +export namespace TemplateReplaceParams { + export interface Notification { + brand: Notification.Brand | null; + + content: Notification.Content; + + name: string; + + subscription: Notification.Subscription | null; + + tags: Array; + } + + export namespace Notification { + export interface Brand { + id: string; + } + + export interface Content { + elements: Array; + + version: '2022-01-01'; + + scope?: 'default' | 'strict'; + } + + export interface Subscription { + topic_id: string; + } + } +} + +export declare namespace Templates { + export { + type TemplateCreateParams as TemplateCreateParams, + type TemplateRetrieveParams as TemplateRetrieveParams, + type TemplateListParams as TemplateListParams, + type TemplateArchiveParams as TemplateArchiveParams, + type TemplateListVersionsParams as TemplateListVersionsParams, + type TemplatePublishParams as TemplatePublishParams, + type TemplateReplaceParams as TemplateReplaceParams, + }; +} diff --git a/src/resources/tenants/index.ts b/src/resources/tenants/index.ts index c5216c97..8249babd 100644 --- a/src/resources/tenants/index.ts +++ b/src/resources/tenants/index.ts @@ -6,6 +6,7 @@ export { type TemplateListResponse, type TemplateRetrieveParams, type TemplateListParams, + type TemplateDeleteParams, type TemplatePublishParams, type TemplateReplaceParams, } from './templates/index'; diff --git a/src/resources/tenants/templates/index.ts b/src/resources/tenants/templates/index.ts index d4f43150..f56deb7e 100644 --- a/src/resources/tenants/templates/index.ts +++ b/src/resources/tenants/templates/index.ts @@ -5,6 +5,7 @@ export { type TemplateListResponse, type TemplateRetrieveParams, type TemplateListParams, + type TemplateDeleteParams, type TemplatePublishParams, type TemplateReplaceParams, } from './templates'; diff --git a/src/resources/tenants/templates/templates.ts b/src/resources/tenants/templates/templates.ts index 52e39d5b..262ca3d5 100644 --- a/src/resources/tenants/templates/templates.ts +++ b/src/resources/tenants/templates/templates.ts @@ -6,6 +6,7 @@ import * as TenantsAPI from '../tenants'; import * as VersionsAPI from './versions'; import { VersionRetrieveParams, Versions } from './versions'; import { APIPromise } from '../../../core/api-promise'; +import { buildHeaders } from '../../../internal/headers'; import { RequestOptions } from '../../../internal/request-options'; import { path } from '../../../internal/utils/path'; @@ -50,6 +51,29 @@ export class Templates extends APIResource { return this._client.get(path`/tenants/${tenantID}/templates`, { query, ...options }); } + /** + * Deletes the tenant's notification template with the given `template_id`. + * + * Returns **204 No Content** with an empty body on success. + * + * Returns **404** if there is no template with this ID for the tenant, including a + * second `DELETE` after a successful removal. + * + * @example + * ```ts + * await client.tenants.templates.delete('template_id', { + * tenant_id: 'tenant_id', + * }); + * ``` + */ + delete(templateID: string, params: TemplateDeleteParams, options?: RequestOptions): APIPromise { + const { tenant_id } = params; + return this._client.delete(path`/tenants/${tenant_id}/templates/${templateID}`, { + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + }); + } + /** * Publishes a specific version of a notification template for a tenant. * @@ -174,6 +198,13 @@ export interface TemplateListParams { limit?: number | null; } +export interface TemplateDeleteParams { + /** + * Id of the tenant that owns the template. + */ + tenant_id: string; +} + export interface TemplatePublishParams { /** * Path param: Id of the tenant that owns the template. @@ -214,6 +245,7 @@ export declare namespace Templates { type TemplateListResponse as TemplateListResponse, type TemplateRetrieveParams as TemplateRetrieveParams, type TemplateListParams as TemplateListParams, + type TemplateDeleteParams as TemplateDeleteParams, type TemplatePublishParams as TemplatePublishParams, type TemplateReplaceParams as TemplateReplaceParams, }; diff --git a/src/resources/tenants/tenants.ts b/src/resources/tenants/tenants.ts index 75aa7b31..1ac5e1f0 100644 --- a/src/resources/tenants/tenants.ts +++ b/src/resources/tenants/tenants.ts @@ -7,6 +7,7 @@ import * as PreferencesAPI from './preferences/preferences'; import { Preferences } from './preferences/preferences'; import * as TemplatesAPI from './templates/templates'; import { + TemplateDeleteParams, TemplateListParams, TemplateListResponse, TemplatePublishParams, @@ -463,6 +464,7 @@ export declare namespace Tenants { type TemplateListResponse as TemplateListResponse, type TemplateRetrieveParams as TemplateRetrieveParams, type TemplateListParams as TemplateListParams, + type TemplateDeleteParams as TemplateDeleteParams, type TemplatePublishParams as TemplatePublishParams, type TemplateReplaceParams as TemplateReplaceParams, }; diff --git a/src/version.ts b/src/version.ts index 4533200e..c00d803e 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '7.10.2'; // x-release-please-version +export const VERSION = '7.11.0'; // x-release-please-version diff --git a/tests/api-resources/journeys.test.ts b/tests/api-resources/journeys.test.ts deleted file mode 100644 index 92d4b7a5..00000000 --- a/tests/api-resources/journeys.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import Courier from '@trycourier/courier'; - -const client = new Courier({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); - -describe('resource journeys', () => { - // Mock server tests are disabled - test.skip('list', async () => { - const responsePromise = client.journeys.list(); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); - - // Mock server tests are disabled - test.skip('list: request options and params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.journeys.list({ cursor: 'cursor', version: 'published' }, { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(Courier.NotFoundError); - }); - - // Mock server tests are disabled - test.skip('invoke', async () => { - const responsePromise = client.journeys.invoke('templateId', {}); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); -}); diff --git a/tests/api-resources/journeys/journeys.test.ts b/tests/api-resources/journeys/journeys.test.ts new file mode 100644 index 00000000..621004b7 --- /dev/null +++ b/tests/api-resources/journeys/journeys.test.ts @@ -0,0 +1,182 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Courier from '@trycourier/courier'; + +const client = new Courier({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource journeys', () => { + // Mock server tests are disabled + test.skip('create: only required params', async () => { + const responsePromise = client.journeys.create({ + name: 'Welcome Journey', + nodes: [ + { trigger_type: 'api-invoke', type: 'trigger' }, + { trigger_type: 'api-invoke', type: 'trigger' }, + ], + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('create: required and optional params', async () => { + const response = await client.journeys.create({ + name: 'Welcome Journey', + nodes: [ + { + trigger_type: 'api-invoke', + type: 'trigger', + id: 'trigger-1', + conditions: ['string', 'string'], + schema: { foo: 'bar' }, + }, + { + trigger_type: 'api-invoke', + type: 'trigger', + id: 'send-1', + conditions: ['string', 'string'], + schema: { foo: 'bar' }, + }, + ], + enabled: true, + state: 'DRAFT', + }); + }); + + // Mock server tests are disabled + test.skip('retrieve', async () => { + const responsePromise = client.journeys.retrieve('x'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('retrieve: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.journeys.retrieve('x', { version: 'published' }, { path: '/_stainless_unknown_path' }), + ).rejects.toThrow(Courier.NotFoundError); + }); + + // Mock server tests are disabled + test.skip('list', async () => { + const responsePromise = client.journeys.list(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.journeys.list({ cursor: 'cursor', version: 'published' }, { path: '/_stainless_unknown_path' }), + ).rejects.toThrow(Courier.NotFoundError); + }); + + // Mock server tests are disabled + test.skip('archive', async () => { + const responsePromise = client.journeys.archive('x'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('invoke', async () => { + const responsePromise = client.journeys.invoke('templateId', {}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('listVersions', async () => { + const responsePromise = client.journeys.listVersions('x'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('publish', async () => { + const responsePromise = client.journeys.publish('x'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('publish: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.journeys.publish('x', { version: 'v321669910225' }, { path: '/_stainless_unknown_path' }), + ).rejects.toThrow(Courier.NotFoundError); + }); + + // Mock server tests are disabled + test.skip('replace: only required params', async () => { + const responsePromise = client.journeys.replace('x', { + name: 'Welcome Journey v2', + nodes: [{ trigger_type: 'api-invoke', type: 'trigger' }], + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('replace: required and optional params', async () => { + const response = await client.journeys.replace('x', { + name: 'Welcome Journey v2', + nodes: [ + { + trigger_type: 'api-invoke', + type: 'trigger', + id: 'x', + conditions: ['string', 'string'], + schema: { foo: 'bar' }, + }, + ], + enabled: true, + state: 'DRAFT', + }); + }); +}); diff --git a/tests/api-resources/journeys/templates.test.ts b/tests/api-resources/journeys/templates.test.ts new file mode 100644 index 00000000..608e7141 --- /dev/null +++ b/tests/api-resources/journeys/templates.test.ts @@ -0,0 +1,202 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Courier from '@trycourier/courier'; + +const client = new Courier({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource templates', () => { + // Mock server tests are disabled + test.skip('create: only required params', async () => { + const responsePromise = client.journeys.templates.create('x', { + channel: 'email', + notification: { + brand: { id: 'id' }, + content: { elements: [{}], version: '2022-01-01' }, + name: 'Welcome email', + subscription: { topic_id: 'topic_id' }, + tags: ['string'], + }, + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('create: required and optional params', async () => { + const response = await client.journeys.templates.create('x', { + channel: 'email', + notification: { + brand: { id: 'id' }, + content: { + elements: [ + { + channels: ['string'], + if: 'if', + loop: 'loop', + ref: 'ref', + type: 'text', + }, + ], + version: '2022-01-01', + scope: 'default', + }, + name: 'Welcome email', + subscription: { topic_id: 'topic_id' }, + tags: ['string'], + }, + providerKey: 'x', + state: 'state', + }); + }); + + // Mock server tests are disabled + test.skip('retrieve: only required params', async () => { + const responsePromise = client.journeys.templates.retrieve('x', { templateId: 'x' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('retrieve: required and optional params', async () => { + const response = await client.journeys.templates.retrieve('x', { templateId: 'x' }); + }); + + // Mock server tests are disabled + test.skip('list', async () => { + const responsePromise = client.journeys.templates.list('x'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.journeys.templates.list( + 'x', + { cursor: 'cursor', limit: 1 }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(Courier.NotFoundError); + }); + + // Mock server tests are disabled + test.skip('archive: only required params', async () => { + const responsePromise = client.journeys.templates.archive('x', { templateId: 'x' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('archive: required and optional params', async () => { + const response = await client.journeys.templates.archive('x', { templateId: 'x' }); + }); + + // Mock server tests are disabled + test.skip('listVersions: only required params', async () => { + const responsePromise = client.journeys.templates.listVersions('x', { templateId: 'x' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('listVersions: required and optional params', async () => { + const response = await client.journeys.templates.listVersions('x', { templateId: 'x' }); + }); + + // Mock server tests are disabled + test.skip('publish: only required params', async () => { + const responsePromise = client.journeys.templates.publish('x', { templateId: 'x' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('publish: required and optional params', async () => { + const response = await client.journeys.templates.publish('x', { + templateId: 'x', + version: 'v321669910225', + }); + }); + + // Mock server tests are disabled + test.skip('replace: only required params', async () => { + const responsePromise = client.journeys.templates.replace('x', { + templateId: 'x', + notification: { + brand: { id: 'id' }, + content: { elements: [{}], version: '2022-01-01' }, + name: 'name', + subscription: { topic_id: 'topic_id' }, + tags: ['string'], + }, + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('replace: required and optional params', async () => { + const response = await client.journeys.templates.replace('x', { + templateId: 'x', + notification: { + brand: { id: 'id' }, + content: { + elements: [ + { + channels: ['string'], + if: 'if', + loop: 'loop', + ref: 'ref', + type: 'text', + }, + ], + version: '2022-01-01', + scope: 'default', + }, + name: 'name', + subscription: { topic_id: 'topic_id' }, + tags: ['string'], + }, + state: 'state', + }); + }); +}); diff --git a/tests/api-resources/tenants/templates/templates.test.ts b/tests/api-resources/tenants/templates/templates.test.ts index 94e7ae8e..2230eb3f 100644 --- a/tests/api-resources/tenants/templates/templates.test.ts +++ b/tests/api-resources/tenants/templates/templates.test.ts @@ -49,6 +49,23 @@ describe('resource templates', () => { ).rejects.toThrow(Courier.NotFoundError); }); + // Mock server tests are disabled + test.skip('delete: only required params', async () => { + const responsePromise = client.tenants.templates.delete('template_id', { tenant_id: 'tenant_id' }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Mock server tests are disabled + test.skip('delete: required and optional params', async () => { + const response = await client.tenants.templates.delete('template_id', { tenant_id: 'tenant_id' }); + }); + // Mock server tests are disabled test.skip('publish: only required params', async () => { const responsePromise = client.tenants.templates.publish('template_id', { tenant_id: 'tenant_id' }); diff --git a/yarn.lock b/yarn.lock index f6eae3cd..18e7cbdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -709,11 +709,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgr/core@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" - integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== - "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -1515,14 +1510,6 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-prettier@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz#99b55d7dd70047886b2222fdd853665f180b36af" - integrity sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg== - dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.11.7" - eslint-plugin-unused-imports@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738" @@ -1674,11 +1661,6 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" @@ -2841,13 +2823,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - prettier@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" @@ -3144,13 +3119,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.11.7: - version "0.11.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" - integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== - dependencies: - "@pkgr/core" "^0.2.4" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"