From f6edc85bd4123f18f6ecacb04e9ab207a462f67d Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Wed, 24 Jan 2024 15:34:54 +0100 Subject: [PATCH 01/19] Provide options for unexploded parameters --- .../rest/v1/active-number/active-number-api.ts | 4 +++- .../v1/available-number/available-number-api.ts | 2 +- packages/sdk-client/src/api/api-client.ts | 14 ++++++++++---- .../src/client/api-client-pagination-helper.ts | 5 ++++- packages/sdk-client/tests/api/api-client.test.ts | 15 +++++++++++++-- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/numbers/src/rest/v1/active-number/active-number-api.ts b/packages/numbers/src/rest/v1/active-number/active-number-api.ts index 8f2296f1..92dc1aca 100644 --- a/packages/numbers/src/rest/v1/active-number/active-number-api.ts +++ b/packages/numbers/src/rest/v1/active-number/active-number-api.ts @@ -139,7 +139,9 @@ export class ActiveNumberApi extends NumbersApi { const listPromise = buildPageResultPromise( this.client, requestOptionsPromise, - operationProperties); + operationProperties, + false, + ';'); // Add properties to the Promise to offer the possibility to use it as an iterator Object.assign( diff --git a/packages/numbers/src/rest/v1/available-number/available-number-api.ts b/packages/numbers/src/rest/v1/available-number/available-number-api.ts index 86afff9f..bc7d48a0 100644 --- a/packages/numbers/src/rest/v1/available-number/available-number-api.ts +++ b/packages/numbers/src/rest/v1/available-number/available-number-api.ts @@ -122,7 +122,7 @@ export class AvailableNumberApi extends NumbersApi { headers, body || undefined, ); - const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams, false, ';'); return this.client.processCall({ url, diff --git a/packages/sdk-client/src/api/api-client.ts b/packages/sdk-client/src/api/api-client.ts index 59f4c636..c0f219ba 100644 --- a/packages/sdk-client/src/api/api-client.ts +++ b/packages/sdk-client/src/api/api-client.ts @@ -77,7 +77,7 @@ export class ApiClient { const prop = data[name]; acc[name] = typeof prop.toJSON === 'function' ? prop.toJSON() - : Array.isArray(prop) ? prop.join(';') : prop.toString(); + : Array.isArray(prop) ? prop.join(',') : prop.toString(); return acc; }, {} as { [p in keyof T]: string }, @@ -128,16 +128,18 @@ export class ApiClient { * @param {string} url - The base url to be used. * @param {Object.} queryParameters - Key-value pair with the parameters. If the value is undefined, the key is dropped. * @param {boolean} repeatParamArray - create as many single parameters with each value of the array + * @param {string} unexplodedSeparator - the separator to use between values when `explode` is false (default is ',') * @return {string} The prepared URL as a string. */ prepareUrl( url: string, queryParameters: { [key: string]: string | undefined } = {}, repeatParamArray?: boolean, + unexplodedSeparator?: string, ): string { const queryPart = Object.keys(queryParameters) .filter((name) => typeof queryParameters[name] !== 'undefined') - .map((name) => this.formatQueryParameter(name, queryParameters, repeatParamArray)) + .map((name) => this.formatQueryParameter(name, queryParameters, repeatParamArray, unexplodedSeparator)) .join('&'); const paramsPrefix = url.indexOf('?') > -1 ? '&' : '?'; @@ -150,20 +152,24 @@ export class ApiClient { * @param {string} name - The parameter name * @param {Object.} queryParameters - Key-value pair with the parameters. If the value is undefined, the key is dropped. * @param {boolean}repeatParamArray - Create as many single parameters with each value of the array + * @param {string} unexplodedSeparator - the separator to use between values when `explode` is false (default is `,`) * @return {string} The query parameter formatted as required by the API */ private formatQueryParameter = ( name: string, queryParameters: { [key: string]: string | undefined } = {}, repeatParamArray?: boolean, + unexplodedSeparator?: string, ): string => { const defaultFormat = `${name}=${queryParameters[name]!}`; if(repeatParamArray) { const parameterValue = queryParameters[name]; - if (parameterValue && parameterValue.indexOf(';') > 0) { - const parameterValues = parameterValue.split(';'); + if (parameterValue && parameterValue.indexOf(',') > 0) { + const parameterValues = parameterValue.split(','); return parameterValues.map((value) => `${name}=${value}`).join('&'); } + } else if (unexplodedSeparator !== undefined) { + return defaultFormat.replaceAll(',', unexplodedSeparator); } return defaultFormat; }; diff --git a/packages/sdk-client/src/client/api-client-pagination-helper.ts b/packages/sdk-client/src/client/api-client-pagination-helper.ts index c2d0b9e0..d101523f 100644 --- a/packages/sdk-client/src/client/api-client-pagination-helper.ts +++ b/packages/sdk-client/src/client/api-client-pagination-helper.ts @@ -206,10 +206,13 @@ export const buildPageResultPromise = async ( client: ApiClient, requestOptionsPromise: Promise, operationProperties: PaginatedApiProperties, + repeatParamArray?: boolean, + unexplodedSeparator?: string, ): Promise> => { // Await the promise in this async method and store the result in client so that they can be reused const requestOptions = await requestOptionsPromise; - const url = client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + const url = client.prepareUrl( + requestOptions.basePath, requestOptions.queryParams, repeatParamArray, unexplodedSeparator); return client.processCallWithPagination({ url, diff --git a/packages/sdk-client/tests/api/api-client.test.ts b/packages/sdk-client/tests/api/api-client.test.ts index 9b46172d..4f495be4 100644 --- a/packages/sdk-client/tests/api/api-client.test.ts +++ b/packages/sdk-client/tests/api/api-client.test.ts @@ -26,10 +26,21 @@ describe('API client', () => { const url = 'https://example.com'; const parameters = { foo: 'fooValue', - bar: '1;2', + bar: '1,2', baz: undefined, }; const formattedUrl = apiClient.prepareUrl(url, parameters); + expect(formattedUrl).toBe('https://example.com?foo=fooValue&bar=1,2'); + }); + + it('should format the URL with array parameters and a custom separator', () => { + const url = 'https://example.com'; + const parameters = { + foo: 'fooValue', + bar: '1,2', + baz: undefined, + }; + const formattedUrl = apiClient.prepareUrl(url, parameters, false, ';'); expect(formattedUrl).toBe('https://example.com?foo=fooValue&bar=1;2'); }); @@ -37,7 +48,7 @@ describe('API client', () => { const url = 'https://example.com'; const parameters = { foo: 'fooValue', - bar: '1;2', + bar: '1,2', baz: undefined, }; const formattedUrl = apiClient.prepareUrl(url, parameters, true); From 68a1117e8672fdda0d862d7c62b057b3bac253c7 Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Wed, 24 Jan 2024 19:21:08 +0100 Subject: [PATCH 02/19] DEVEXP-272: Conversation API - First commit --- packages/conversation/CHANGELOG.md | 3 + packages/conversation/README.md | 111 +++++++ packages/conversation/package.json | 37 +++ packages/conversation/src/index.ts | 3 + packages/conversation/src/models/index.ts | 1 + .../agent-joined-event/agent-joined-event.ts | 12 + .../src/models/v1/agent-joined-event/index.ts | 1 + .../v1/agent-left-event/agent-left-event.ts | 12 + .../src/models/v1/agent-left-event/index.ts | 1 + .../conversation/src/models/v1/agent/agent.ts | 12 + .../conversation/src/models/v1/agent/index.ts | 1 + .../app-create-request/app-create-request.ts | 30 ++ .../src/models/v1/app-create-request/index.ts | 1 + .../src/models/v1/app-event/app-event.ts | 17 + .../src/models/v1/app-event/index.ts | 1 + .../app-message-additional-properties.ts | 8 + .../index.ts | 1 + .../app-message-message.ts | 18 ++ .../models/v1/app-message-message/index.ts | 1 + .../src/models/v1/app-message/app-message.ts | 15 + .../src/models/v1/app-message/index.ts | 1 + .../models/v1/app-response/app-response.ts | 56 ++++ .../src/models/v1/app-response/index.ts | 1 + .../app-update-request/app-update-request.ts | 30 ++ .../src/models/v1/app-update-request/index.ts | 1 + .../basic-auth-credential.ts | 10 + .../models/v1/basic-auth-credential/index.ts | 1 + .../models/v1/call-message/call-message.ts | 10 + .../src/models/v1/call-message/index.ts | 1 + .../v1/callback-settings/callback-settings.ts | 8 + .../src/models/v1/callback-settings/index.ts | 1 + .../src/models/v1/card-height/card-height.ts | 4 + .../src/models/v1/card-height/index.ts | 1 + .../models/v1/card-message/card-message.ts | 26 ++ .../src/models/v1/card-message/index.ts | 1 + .../v1/carousel-message/carousel-message.ts | 19 ++ .../src/models/v1/carousel-message/index.ts | 1 + .../channel-identities/channel-identities.ts | 7 + .../src/models/v1/channel-identities/index.ts | 1 + .../v1/channel-identity/channel-identity.ts | 14 + .../src/models/v1/channel-identity/index.ts | 1 + .../channel-recipient-identity.ts | 9 + .../v1/channel-recipient-identity/index.ts | 1 + .../src/models/v1/choice-item/choice-item.ts | 13 + .../src/models/v1/choice-item/index.ts | 1 + .../v1/choice-message/choice-message.ts | 19 ++ .../src/models/v1/choice-message/index.ts | 1 + .../choice-response-message.ts | 10 + .../v1/choice-response-message/index.ts | 1 + .../src/models/v1/choice/choice.ts | 23 ++ .../src/models/v1/choice/index.ts | 1 + .../client-credentials/client-credentials.ts | 12 + .../src/models/v1/client-credentials/index.ts | 1 + .../comment-reply-event.ts | 11 + .../models/v1/comment-reply-event/index.ts | 1 + .../composing-end-event.ts | 5 + .../models/v1/composing-end-event/index.ts | 1 + .../v1/composing-event/composing-event.ts | 5 + .../src/models/v1/composing-event/index.ts | 1 + .../contact-create-request.ts | 24 ++ .../models/v1/contact-create-request/index.ts | 1 + .../src/models/v1/contact-id/contact-id.ts | 5 + .../src/models/v1/contact-id/index.ts | 1 + .../v1/contact-language/contact-language.ts | 71 ++++ .../src/models/v1/contact-language/index.ts | 1 + .../v1/contact-message/contact-message.ts | 28 ++ .../src/models/v1/contact-message/index.ts | 1 + .../src/models/v1/contact/contact.ts | 26 ++ .../src/models/v1/contact/index.ts | 1 + .../conversation-channel-credential.ts | 45 +++ .../conversation-channel-credential/index.ts | 1 + .../conversation-channel.ts | 17 + .../models/v1/conversation-channel/index.ts | 1 + .../conversation-direction.ts | 1 + .../models/v1/conversation-direction/index.ts | 1 + .../conversation-merge-strategy.ts | 1 + .../v1/conversation-merge-strategy/index.ts | 1 + .../conversation-message-injected.ts | 25 ++ .../v1/conversation-message-injected/index.ts | 1 + .../conversation-message.ts | 31 ++ .../models/v1/conversation-message/index.ts | 1 + .../conversation-messages-view.ts | 1 + .../v1/conversation-messages-view/index.ts | 1 + .../conversation-metadata-report-view.ts | 1 + .../index.ts | 1 + .../conversation-metadata-update-strategy.ts | 1 + .../index.ts | 1 + .../models/v1/conversation/conversation.ts | 24 ++ .../src/models/v1/conversation/index.ts | 1 + .../src/models/v1/coordinates/coordinates.ts | 7 + .../src/models/v1/coordinates/index.ts | 1 + .../create-conversation-request.ts | 22 ++ .../v1/create-conversation-request/index.ts | 1 + .../dispatch-retention-policy-type.ts | 1 + .../dispatch-retention-policy-type/index.ts | 1 + .../dispatch-retention-policy.ts | 12 + .../v1/dispatch-retention-policy/index.ts | 1 + packages/conversation/src/models/v1/enums.ts | 1 + .../models/v1/error-detail/error-detail.ts | 5 + .../src/models/v1/error-detail/index.ts | 1 + .../v1/fallback-message/fallback-message.ts | 12 + .../src/models/v1/fallback-message/index.ts | 1 + .../models/v1/generic-event/generic-event.ts | 9 + .../src/models/v1/generic-event/index.ts | 1 + ...et-channel-profile-conversation-channel.ts | 4 + .../index.ts | 1 + .../get-channel-profile-request.ts | 12 + .../v1/get-channel-profile-request/index.ts | 1 + .../get-channel-profile-response.ts | 5 + .../v1/get-channel-profile-response/index.ts | 1 + .../models/v1/identified-by/identified-by.ts | 13 + .../src/models/v1/identified-by/index.ts | 1 + packages/conversation/src/models/v1/index.ts | 99 ++++++ .../models/v1/kakao-talk-credentials/index.ts | 1 + .../kakao-talk-credentials.ts | 10 + .../src/models/v1/line-credentials/index.ts | 1 + .../v1/line-credentials/line-credentials.ts | 10 + .../src/models/v1/list-apps-response/index.ts | 1 + .../list-apps-response/list-apps-response.ts | 7 + .../src/models/v1/list-item/index.ts | 1 + .../src/models/v1/list-item/list-item.ts | 10 + .../list-message-message-properties/index.ts | 1 + .../list-message-message-properties.ts | 10 + .../src/models/v1/list-message/index.ts | 1 + .../models/v1/list-message/list-message.ts | 23 ++ .../models/v1/list-messages-response/index.ts | 1 + .../list-messages-response.ts | 10 + .../src/models/v1/list-section/index.ts | 1 + .../models/v1/list-section/list-section.ts | 12 + .../models/v1/list-webhooks-response/index.ts | 1 + .../list-webhooks-response.ts | 7 + .../src/models/v1/location-message/index.ts | 1 + .../v1/location-message/location-message.ts | 19 ++ .../src/models/v1/media-card-message/index.ts | 1 + .../media-card-message/media-card-message.ts | 10 + .../models/v1/media-carousel-message/index.ts | 1 + .../media-carousel-message.ts | 8 + .../src/models/v1/media-message/index.ts | 1 + .../models/v1/media-message/media-message.ts | 17 + .../models/v1/merge-contact-request/index.ts | 1 + .../merge-contact-request.ts | 9 + .../src/models/v1/message-queue/index.ts | 1 + .../models/v1/message-queue/message-queue.ts | 4 + .../src/models/v1/mms-credentials/index.ts | 1 + .../v1/mms-credentials/mms-credentials.ts | 14 + .../src/models/v1/processing-mode/index.ts | 1 + .../v1/processing-mode/processing-mode.ts | 1 + .../models/v1/processing-strategy/index.ts | 1 + .../processing-strategy.ts | 1 + .../src/models/v1/product/index.ts | 1 + .../src/models/v1/product/product.ts | 22 ++ .../v1/query-capability-response/index.ts | 1 + .../query-capability-response.ts | 14 + .../src/models/v1/query-capability/index.ts | 1 + .../v1/query-capability/query-capability.ts | 11 + .../src/models/v1/queue-stats/index.ts | 1 + .../src/models/v1/queue-stats/queue-stats.ts | 7 + .../src/models/v1/rate-limits/index.ts | 1 + .../src/models/v1/rate-limits/rate-limits.ts | 9 + .../src/models/v1/reason/index.ts | 1 + .../src/models/v1/reason/reason.ts | 40 +++ .../src/models/v1/recipient/index.ts | 1 + .../src/models/v1/recipient/recipient.ts | 7 + .../src/models/v1/reply-to/index.ts | 1 + .../src/models/v1/reply-to/reply-to.ts | 8 + .../src/models/v1/retention-policy/index.ts | 1 + .../v1/retention-policy/retention-policy.ts | 9 + .../src/models/v1/runtime-error/index.ts | 1 + .../models/v1/runtime-error/runtime-error.ts | 11 + .../src/models/v1/send-event-request/index.ts | 1 + .../send-event-request/send-event-request.ts | 22 ++ .../models/v1/send-event-response/index.ts | 1 + .../send-event-response.ts | 7 + .../models/v1/send-message-request/index.ts | 1 + .../send-message-request.ts | 39 +++ .../models/v1/send-message-response/index.ts | 1 + .../send-message-response.ts | 7 + .../src/models/v1/smart-conversation/index.ts | 1 + .../smart-conversation/smart-conversation.ts | 8 + .../v1/static-bearer-credential/index.ts | 1 + .../static-bearer-credential.ts | 10 + .../v1/static-token-credential/index.ts | 1 + .../static-token-credential.ts | 8 + .../models/v1/telegram-credentials/index.ts | 1 + .../telegram-credentials.ts | 8 + .../src/models/v1/template-message/index.ts | 1 + .../v1/template-message/template-message.ts | 15 + .../src/models/v1/template-reference/index.ts | 1 + .../template-reference/template-reference.ts | 14 + .../src/models/v1/text-message/index.ts | 1 + .../models/v1/text-message/text-message.ts | 14 + .../v1/transcode-message-request/index.ts | 1 + .../transcode-message-request.ts | 16 + .../v1/transcode-message-response/index.ts | 1 + .../transcode-message-response.ts | 5 + .../src/models/v1/url-message/index.ts | 1 + .../src/models/v1/url-message/url-message.ts | 10 + .../models/v1/webhook-target-type/index.ts | 1 + .../webhook-target-type.ts | 1 + .../src/models/v1/webhook-trigger/index.ts | 1 + .../v1/webhook-trigger/webhook-trigger.ts | 35 ++ .../src/models/v1/webhook/index.ts | 1 + .../src/models/v1/webhook/webhook.ts | 24 ++ .../src/models/v1/wechat-credentials/index.ts | 1 + .../wechat-credentials/wechat-credentials.ts | 14 + packages/conversation/src/rest/index.ts | 1 + .../src/rest/v1/app/app-api.jest.fixture.ts | 28 ++ .../conversation/src/rest/v1/app/app-api.ts | 189 +++++++++++ .../conversation/src/rest/v1/app/index.ts | 2 + .../capability/capability-api.jest.fixture.ts | 11 + .../src/rest/v1/capability/capability-api.ts | 55 ++++ .../src/rest/v1/capability/index.ts | 2 + .../v1/contact/contact-api.jest.fixture.ts | 37 +++ .../src/rest/v1/contact/contact-api.ts | 284 ++++++++++++++++ .../conversation/src/rest/v1/contact/index.ts | 2 + .../src/rest/v1/conversation-domain-api.ts | 81 +++++ .../src/rest/v1/conversation-domain.ts | 47 +++ .../conversation-api.jest.fixture.ts | 36 +++ .../rest/v1/conversation/conversation-api.ts | 304 ++++++++++++++++++ .../src/rest/v1/conversation/index.ts | 2 + packages/conversation/src/rest/v1/enums.ts | 1 + .../rest/v1/events/events-api.jest.fixture.ts | 11 + .../src/rest/v1/events/events-api.ts | 55 ++++ .../conversation/src/rest/v1/events/index.ts | 2 + packages/conversation/src/rest/v1/index.ts | 10 + .../src/rest/v1/messages/index.ts | 2 + .../v1/messages/messages-api.jest.fixture.ts | 25 ++ .../src/rest/v1/messages/messages-api.ts | 218 +++++++++++++ .../src/rest/v1/transcoding/index.ts | 2 + .../transcoding-api.jest.fixture.ts | 11 + .../rest/v1/transcoding/transcoding-api.ts | 56 ++++ .../src/rest/v1/webhooks/index.ts | 2 + .../v1/webhooks/webhooks-api.jest.fixture.ts | 28 ++ .../src/rest/v1/webhooks/webhooks-api.ts | 189 +++++++++++ packages/conversation/tsconfig.build.json | 17 + packages/conversation/tsconfig.json | 11 + packages/conversation/tsconfig.tests.json | 17 + .../client/api-client-pagination-helper.ts | 4 +- packages/sdk-core/package.json | 1 + packages/sdk-core/src/index.ts | 1 + packages/sdk-core/src/sinch-client.ts | 5 + 241 files changed, 3496 insertions(+), 2 deletions(-) create mode 100644 packages/conversation/CHANGELOG.md create mode 100644 packages/conversation/README.md create mode 100644 packages/conversation/package.json create mode 100644 packages/conversation/src/index.ts create mode 100644 packages/conversation/src/models/index.ts create mode 100644 packages/conversation/src/models/v1/agent-joined-event/agent-joined-event.ts create mode 100644 packages/conversation/src/models/v1/agent-joined-event/index.ts create mode 100644 packages/conversation/src/models/v1/agent-left-event/agent-left-event.ts create mode 100644 packages/conversation/src/models/v1/agent-left-event/index.ts create mode 100644 packages/conversation/src/models/v1/agent/agent.ts create mode 100644 packages/conversation/src/models/v1/agent/index.ts create mode 100644 packages/conversation/src/models/v1/app-create-request/app-create-request.ts create mode 100644 packages/conversation/src/models/v1/app-create-request/index.ts create mode 100644 packages/conversation/src/models/v1/app-event/app-event.ts create mode 100644 packages/conversation/src/models/v1/app-event/index.ts create mode 100644 packages/conversation/src/models/v1/app-message-additional-properties/app-message-additional-properties.ts create mode 100644 packages/conversation/src/models/v1/app-message-additional-properties/index.ts create mode 100644 packages/conversation/src/models/v1/app-message-message/app-message-message.ts create mode 100644 packages/conversation/src/models/v1/app-message-message/index.ts create mode 100644 packages/conversation/src/models/v1/app-message/app-message.ts create mode 100644 packages/conversation/src/models/v1/app-message/index.ts create mode 100644 packages/conversation/src/models/v1/app-response/app-response.ts create mode 100644 packages/conversation/src/models/v1/app-response/index.ts create mode 100644 packages/conversation/src/models/v1/app-update-request/app-update-request.ts create mode 100644 packages/conversation/src/models/v1/app-update-request/index.ts create mode 100644 packages/conversation/src/models/v1/basic-auth-credential/basic-auth-credential.ts create mode 100644 packages/conversation/src/models/v1/basic-auth-credential/index.ts create mode 100644 packages/conversation/src/models/v1/call-message/call-message.ts create mode 100644 packages/conversation/src/models/v1/call-message/index.ts create mode 100644 packages/conversation/src/models/v1/callback-settings/callback-settings.ts create mode 100644 packages/conversation/src/models/v1/callback-settings/index.ts create mode 100644 packages/conversation/src/models/v1/card-height/card-height.ts create mode 100644 packages/conversation/src/models/v1/card-height/index.ts create mode 100644 packages/conversation/src/models/v1/card-message/card-message.ts create mode 100644 packages/conversation/src/models/v1/card-message/index.ts create mode 100644 packages/conversation/src/models/v1/carousel-message/carousel-message.ts create mode 100644 packages/conversation/src/models/v1/carousel-message/index.ts create mode 100644 packages/conversation/src/models/v1/channel-identities/channel-identities.ts create mode 100644 packages/conversation/src/models/v1/channel-identities/index.ts create mode 100644 packages/conversation/src/models/v1/channel-identity/channel-identity.ts create mode 100644 packages/conversation/src/models/v1/channel-identity/index.ts create mode 100644 packages/conversation/src/models/v1/channel-recipient-identity/channel-recipient-identity.ts create mode 100644 packages/conversation/src/models/v1/channel-recipient-identity/index.ts create mode 100644 packages/conversation/src/models/v1/choice-item/choice-item.ts create mode 100644 packages/conversation/src/models/v1/choice-item/index.ts create mode 100644 packages/conversation/src/models/v1/choice-message/choice-message.ts create mode 100644 packages/conversation/src/models/v1/choice-message/index.ts create mode 100644 packages/conversation/src/models/v1/choice-response-message/choice-response-message.ts create mode 100644 packages/conversation/src/models/v1/choice-response-message/index.ts create mode 100644 packages/conversation/src/models/v1/choice/choice.ts create mode 100644 packages/conversation/src/models/v1/choice/index.ts create mode 100644 packages/conversation/src/models/v1/client-credentials/client-credentials.ts create mode 100644 packages/conversation/src/models/v1/client-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/comment-reply-event/comment-reply-event.ts create mode 100644 packages/conversation/src/models/v1/comment-reply-event/index.ts create mode 100644 packages/conversation/src/models/v1/composing-end-event/composing-end-event.ts create mode 100644 packages/conversation/src/models/v1/composing-end-event/index.ts create mode 100644 packages/conversation/src/models/v1/composing-event/composing-event.ts create mode 100644 packages/conversation/src/models/v1/composing-event/index.ts create mode 100644 packages/conversation/src/models/v1/contact-create-request/contact-create-request.ts create mode 100644 packages/conversation/src/models/v1/contact-create-request/index.ts create mode 100644 packages/conversation/src/models/v1/contact-id/contact-id.ts create mode 100644 packages/conversation/src/models/v1/contact-id/index.ts create mode 100644 packages/conversation/src/models/v1/contact-language/contact-language.ts create mode 100644 packages/conversation/src/models/v1/contact-language/index.ts create mode 100644 packages/conversation/src/models/v1/contact-message/contact-message.ts create mode 100644 packages/conversation/src/models/v1/contact-message/index.ts create mode 100644 packages/conversation/src/models/v1/contact/contact.ts create mode 100644 packages/conversation/src/models/v1/contact/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts create mode 100644 packages/conversation/src/models/v1/conversation-channel-credential/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts create mode 100644 packages/conversation/src/models/v1/conversation-channel/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-direction/conversation-direction.ts create mode 100644 packages/conversation/src/models/v1/conversation-direction/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-merge-strategy/conversation-merge-strategy.ts create mode 100644 packages/conversation/src/models/v1/conversation-merge-strategy/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-message-injected/conversation-message-injected.ts create mode 100644 packages/conversation/src/models/v1/conversation-message-injected/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-message/conversation-message.ts create mode 100644 packages/conversation/src/models/v1/conversation-message/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-messages-view/conversation-messages-view.ts create mode 100644 packages/conversation/src/models/v1/conversation-messages-view/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-metadata-report-view/conversation-metadata-report-view.ts create mode 100644 packages/conversation/src/models/v1/conversation-metadata-report-view/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-metadata-update-strategy/conversation-metadata-update-strategy.ts create mode 100644 packages/conversation/src/models/v1/conversation-metadata-update-strategy/index.ts create mode 100644 packages/conversation/src/models/v1/conversation/conversation.ts create mode 100644 packages/conversation/src/models/v1/conversation/index.ts create mode 100644 packages/conversation/src/models/v1/coordinates/coordinates.ts create mode 100644 packages/conversation/src/models/v1/coordinates/index.ts create mode 100644 packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts create mode 100644 packages/conversation/src/models/v1/create-conversation-request/index.ts create mode 100644 packages/conversation/src/models/v1/dispatch-retention-policy-type/dispatch-retention-policy-type.ts create mode 100644 packages/conversation/src/models/v1/dispatch-retention-policy-type/index.ts create mode 100644 packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts create mode 100644 packages/conversation/src/models/v1/dispatch-retention-policy/index.ts create mode 100644 packages/conversation/src/models/v1/enums.ts create mode 100644 packages/conversation/src/models/v1/error-detail/error-detail.ts create mode 100644 packages/conversation/src/models/v1/error-detail/index.ts create mode 100644 packages/conversation/src/models/v1/fallback-message/fallback-message.ts create mode 100644 packages/conversation/src/models/v1/fallback-message/index.ts create mode 100644 packages/conversation/src/models/v1/generic-event/generic-event.ts create mode 100644 packages/conversation/src/models/v1/generic-event/index.ts create mode 100644 packages/conversation/src/models/v1/get-channel-profile-conversation-channel/get-channel-profile-conversation-channel.ts create mode 100644 packages/conversation/src/models/v1/get-channel-profile-conversation-channel/index.ts create mode 100644 packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts create mode 100644 packages/conversation/src/models/v1/get-channel-profile-request/index.ts create mode 100644 packages/conversation/src/models/v1/get-channel-profile-response/get-channel-profile-response.ts create mode 100644 packages/conversation/src/models/v1/get-channel-profile-response/index.ts create mode 100644 packages/conversation/src/models/v1/identified-by/identified-by.ts create mode 100644 packages/conversation/src/models/v1/identified-by/index.ts create mode 100644 packages/conversation/src/models/v1/index.ts create mode 100644 packages/conversation/src/models/v1/kakao-talk-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/kakao-talk-credentials/kakao-talk-credentials.ts create mode 100644 packages/conversation/src/models/v1/line-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/line-credentials/line-credentials.ts create mode 100644 packages/conversation/src/models/v1/list-apps-response/index.ts create mode 100644 packages/conversation/src/models/v1/list-apps-response/list-apps-response.ts create mode 100644 packages/conversation/src/models/v1/list-item/index.ts create mode 100644 packages/conversation/src/models/v1/list-item/list-item.ts create mode 100644 packages/conversation/src/models/v1/list-message-message-properties/index.ts create mode 100644 packages/conversation/src/models/v1/list-message-message-properties/list-message-message-properties.ts create mode 100644 packages/conversation/src/models/v1/list-message/index.ts create mode 100644 packages/conversation/src/models/v1/list-message/list-message.ts create mode 100644 packages/conversation/src/models/v1/list-messages-response/index.ts create mode 100644 packages/conversation/src/models/v1/list-messages-response/list-messages-response.ts create mode 100644 packages/conversation/src/models/v1/list-section/index.ts create mode 100644 packages/conversation/src/models/v1/list-section/list-section.ts create mode 100644 packages/conversation/src/models/v1/list-webhooks-response/index.ts create mode 100644 packages/conversation/src/models/v1/list-webhooks-response/list-webhooks-response.ts create mode 100644 packages/conversation/src/models/v1/location-message/index.ts create mode 100644 packages/conversation/src/models/v1/location-message/location-message.ts create mode 100644 packages/conversation/src/models/v1/media-card-message/index.ts create mode 100644 packages/conversation/src/models/v1/media-card-message/media-card-message.ts create mode 100644 packages/conversation/src/models/v1/media-carousel-message/index.ts create mode 100644 packages/conversation/src/models/v1/media-carousel-message/media-carousel-message.ts create mode 100644 packages/conversation/src/models/v1/media-message/index.ts create mode 100644 packages/conversation/src/models/v1/media-message/media-message.ts create mode 100644 packages/conversation/src/models/v1/merge-contact-request/index.ts create mode 100644 packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts create mode 100644 packages/conversation/src/models/v1/message-queue/index.ts create mode 100644 packages/conversation/src/models/v1/message-queue/message-queue.ts create mode 100644 packages/conversation/src/models/v1/mms-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts create mode 100644 packages/conversation/src/models/v1/processing-mode/index.ts create mode 100644 packages/conversation/src/models/v1/processing-mode/processing-mode.ts create mode 100644 packages/conversation/src/models/v1/processing-strategy/index.ts create mode 100644 packages/conversation/src/models/v1/processing-strategy/processing-strategy.ts create mode 100644 packages/conversation/src/models/v1/product/index.ts create mode 100644 packages/conversation/src/models/v1/product/product.ts create mode 100644 packages/conversation/src/models/v1/query-capability-response/index.ts create mode 100644 packages/conversation/src/models/v1/query-capability-response/query-capability-response.ts create mode 100644 packages/conversation/src/models/v1/query-capability/index.ts create mode 100644 packages/conversation/src/models/v1/query-capability/query-capability.ts create mode 100644 packages/conversation/src/models/v1/queue-stats/index.ts create mode 100644 packages/conversation/src/models/v1/queue-stats/queue-stats.ts create mode 100644 packages/conversation/src/models/v1/rate-limits/index.ts create mode 100644 packages/conversation/src/models/v1/rate-limits/rate-limits.ts create mode 100644 packages/conversation/src/models/v1/reason/index.ts create mode 100644 packages/conversation/src/models/v1/reason/reason.ts create mode 100644 packages/conversation/src/models/v1/recipient/index.ts create mode 100644 packages/conversation/src/models/v1/recipient/recipient.ts create mode 100644 packages/conversation/src/models/v1/reply-to/index.ts create mode 100644 packages/conversation/src/models/v1/reply-to/reply-to.ts create mode 100644 packages/conversation/src/models/v1/retention-policy/index.ts create mode 100644 packages/conversation/src/models/v1/retention-policy/retention-policy.ts create mode 100644 packages/conversation/src/models/v1/runtime-error/index.ts create mode 100644 packages/conversation/src/models/v1/runtime-error/runtime-error.ts create mode 100644 packages/conversation/src/models/v1/send-event-request/index.ts create mode 100644 packages/conversation/src/models/v1/send-event-request/send-event-request.ts create mode 100644 packages/conversation/src/models/v1/send-event-response/index.ts create mode 100644 packages/conversation/src/models/v1/send-event-response/send-event-response.ts create mode 100644 packages/conversation/src/models/v1/send-message-request/index.ts create mode 100644 packages/conversation/src/models/v1/send-message-request/send-message-request.ts create mode 100644 packages/conversation/src/models/v1/send-message-response/index.ts create mode 100644 packages/conversation/src/models/v1/send-message-response/send-message-response.ts create mode 100644 packages/conversation/src/models/v1/smart-conversation/index.ts create mode 100644 packages/conversation/src/models/v1/smart-conversation/smart-conversation.ts create mode 100644 packages/conversation/src/models/v1/static-bearer-credential/index.ts create mode 100644 packages/conversation/src/models/v1/static-bearer-credential/static-bearer-credential.ts create mode 100644 packages/conversation/src/models/v1/static-token-credential/index.ts create mode 100644 packages/conversation/src/models/v1/static-token-credential/static-token-credential.ts create mode 100644 packages/conversation/src/models/v1/telegram-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/telegram-credentials/telegram-credentials.ts create mode 100644 packages/conversation/src/models/v1/template-message/index.ts create mode 100644 packages/conversation/src/models/v1/template-message/template-message.ts create mode 100644 packages/conversation/src/models/v1/template-reference/index.ts create mode 100644 packages/conversation/src/models/v1/template-reference/template-reference.ts create mode 100644 packages/conversation/src/models/v1/text-message/index.ts create mode 100644 packages/conversation/src/models/v1/text-message/text-message.ts create mode 100644 packages/conversation/src/models/v1/transcode-message-request/index.ts create mode 100644 packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts create mode 100644 packages/conversation/src/models/v1/transcode-message-response/index.ts create mode 100644 packages/conversation/src/models/v1/transcode-message-response/transcode-message-response.ts create mode 100644 packages/conversation/src/models/v1/url-message/index.ts create mode 100644 packages/conversation/src/models/v1/url-message/url-message.ts create mode 100644 packages/conversation/src/models/v1/webhook-target-type/index.ts create mode 100644 packages/conversation/src/models/v1/webhook-target-type/webhook-target-type.ts create mode 100644 packages/conversation/src/models/v1/webhook-trigger/index.ts create mode 100644 packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts create mode 100644 packages/conversation/src/models/v1/webhook/index.ts create mode 100644 packages/conversation/src/models/v1/webhook/webhook.ts create mode 100644 packages/conversation/src/models/v1/wechat-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/wechat-credentials/wechat-credentials.ts create mode 100644 packages/conversation/src/rest/index.ts create mode 100644 packages/conversation/src/rest/v1/app/app-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/app/app-api.ts create mode 100644 packages/conversation/src/rest/v1/app/index.ts create mode 100644 packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/capability/capability-api.ts create mode 100644 packages/conversation/src/rest/v1/capability/index.ts create mode 100644 packages/conversation/src/rest/v1/contact/contact-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/contact/contact-api.ts create mode 100644 packages/conversation/src/rest/v1/contact/index.ts create mode 100644 packages/conversation/src/rest/v1/conversation-domain-api.ts create mode 100644 packages/conversation/src/rest/v1/conversation-domain.ts create mode 100644 packages/conversation/src/rest/v1/conversation/conversation-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/conversation/conversation-api.ts create mode 100644 packages/conversation/src/rest/v1/conversation/index.ts create mode 100644 packages/conversation/src/rest/v1/enums.ts create mode 100644 packages/conversation/src/rest/v1/events/events-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/events/events-api.ts create mode 100644 packages/conversation/src/rest/v1/events/index.ts create mode 100644 packages/conversation/src/rest/v1/index.ts create mode 100644 packages/conversation/src/rest/v1/messages/index.ts create mode 100644 packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/messages/messages-api.ts create mode 100644 packages/conversation/src/rest/v1/transcoding/index.ts create mode 100644 packages/conversation/src/rest/v1/transcoding/transcoding-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/transcoding/transcoding-api.ts create mode 100644 packages/conversation/src/rest/v1/webhooks/index.ts create mode 100644 packages/conversation/src/rest/v1/webhooks/webhooks-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/webhooks/webhooks-api.ts create mode 100644 packages/conversation/tsconfig.build.json create mode 100644 packages/conversation/tsconfig.json create mode 100644 packages/conversation/tsconfig.tests.json diff --git a/packages/conversation/CHANGELOG.md b/packages/conversation/CHANGELOG.md new file mode 100644 index 00000000..a23468f0 --- /dev/null +++ b/packages/conversation/CHANGELOG.md @@ -0,0 +1,3 @@ +# Version X.Y.Z + + - Initial version diff --git a/packages/conversation/README.md b/packages/conversation/README.md new file mode 100644 index 00000000..3adcdf07 --- /dev/null +++ b/packages/conversation/README.md @@ -0,0 +1,111 @@ +# Sinch Conversation SDK for Node.js + +This package contains the Sinch Conversation SDK for Node.js for use with [Sinch APIs](https://developers.sinch.com/). To use it, you will need a Sinch account. Please [sign up](https://dashboard.sinch.com/signup) or [log in](https://dashboard.sinch.com/login) if you already have one. + +Warning: +**This SDK is currently available for preview purposes only. It should not be used in production environments.** + +## Installation + +We recommend to use this SDK as part of the `@sinch/sdk-core` package as it will take care about the authentication plugins to use. + +However, it's still possible to use this SDK standalone is you need to access the Conversation API only. + +### With NPM + +```bash +npm install @sinch/conversation +``` + +### With Yarn + +```bash +yarn add @sinch/conversation +``` + +## Usage + +### Credentials + +The `Conversation` API uses the Sinch unified authentication with OAuth2. You will need to provide the following credentials: +- projectId: can be found in the [Account Dashboard](https://dashboard.sinch.com/settings/access-keys) +- keyId:: can be found in your Access key list in the [Account Dashboard](https://dashboard.sinch.com/settings/access-keys) +- keySecret: can be found **ONLY** when generating a new access key: keep it safe! + +### As part of the Sinch SDK + +If you are using this SDK as part of the Sinch SDK (`@sinch/sdk-core`) you can access it as the `conversation` property of the client that you would have instantiated. + +```typescript +import { + SinchClient, + SinchClientParameters, +} from '@sinch/sdk-core'; + +const credentials: SinchClientParameters = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', +}; + +const sinch = new SinchClient(credentials); + +const requestData: any = { +}; + +// Access the 'conversation' domain registered on the Sinch Client +const result: any + = await sinch.conversation.tag.method(requestData); +``` + +### Standalone + +The SDK can be used standalone if you need to use only the Conversation APIs. + +```typescript +import { + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + +} from '@sinch/conversation'; + +const credentials: SinchClientParameters = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', +}; + +// Declare the 'conversation' service in a standalone way + const conversation = new Conversation(options); + +const requestData: any = { +}; + +// Use the standalone declaration of the 'conversation' domain +const result: any + = await sinch.conversation.tag.method(requestData); +``` + +## Promises + +All the methods that interact with the Sinch APIs use Promises. You can use `await` in an `async` method to wait for the response or you can resolve them yourself with `then()` / `catch()`. + +```typescript +// Method 1: Wait for the Promise to complete +let result: any; +try { + result = await sinch.conversation.tag.method(requestData); + console.log(``); +} catch (error: any) { + console.error(`ERROR ${error.statusCode}: `); +} + +// Method 2: Resolve the promise +sinch.conversation.tag.method(requestData) + .then(response => console.log(``)) + .catch(error => console.error(`ERROR ${error.statusCode}: `)); +``` + +## Contact +Developer Experience team: [devexp@sinch.com](mailto:devexp@sinch.com) diff --git a/packages/conversation/package.json b/packages/conversation/package.json new file mode 100644 index 00000000..87c18d11 --- /dev/null +++ b/packages/conversation/package.json @@ -0,0 +1,37 @@ +{ + "name": "@sinch/conversation", + "version": "0.0.1", + "description": "Sinch Conversation API", + "homepage": "", + "repository": { + "type": "git", + "url": "" + }, + "license": "Apache-2.0", + "author": "Sinch", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.js" + } + }, + "directories": { + "src": "dist", + "test": "tests" + }, + "files": ["/dist"], + "scripts": { + "build": "yarn run clean && yarn run compile", + "clean": "rimraf dist tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo", + "compile": "tsc -p tsconfig.build.json && tsc -p tsconfig.tests.json && rimraf dist/tests tsconfig.build.tsbuildinfo" + }, + "dependencies": { + "@sinch/sdk-client": "^0.0.1" + }, + "devDependencies": {}, + "publishConfig": { + "directory": "dist" + } +} diff --git a/packages/conversation/src/index.ts b/packages/conversation/src/index.ts new file mode 100644 index 00000000..20936a85 --- /dev/null +++ b/packages/conversation/src/index.ts @@ -0,0 +1,3 @@ +export * from './models'; +export * from './rest'; +export * from '@sinch/sdk-client'; diff --git a/packages/conversation/src/models/index.ts b/packages/conversation/src/models/index.ts new file mode 100644 index 00000000..5b98253d --- /dev/null +++ b/packages/conversation/src/models/index.ts @@ -0,0 +1 @@ +export * from './v1'; diff --git a/packages/conversation/src/models/v1/agent-joined-event/agent-joined-event.ts b/packages/conversation/src/models/v1/agent-joined-event/agent-joined-event.ts new file mode 100644 index 00000000..b6cc478f --- /dev/null +++ b/packages/conversation/src/models/v1/agent-joined-event/agent-joined-event.ts @@ -0,0 +1,12 @@ +import { Agent } from '../agent'; + +export interface AgentJoinedEvent { + + /** @see AgentJoinedEventType */ + agent_joined_event?: AgentJoinedEventType; +} + +export interface AgentJoinedEventType { + /** Represents an agent that is involved in a conversation. */ + agent: Agent; +} diff --git a/packages/conversation/src/models/v1/agent-joined-event/index.ts b/packages/conversation/src/models/v1/agent-joined-event/index.ts new file mode 100644 index 00000000..d785f388 --- /dev/null +++ b/packages/conversation/src/models/v1/agent-joined-event/index.ts @@ -0,0 +1 @@ +export type { AgentJoinedEvent, AgentJoinedEventType } from './agent-joined-event'; diff --git a/packages/conversation/src/models/v1/agent-left-event/agent-left-event.ts b/packages/conversation/src/models/v1/agent-left-event/agent-left-event.ts new file mode 100644 index 00000000..c900acc2 --- /dev/null +++ b/packages/conversation/src/models/v1/agent-left-event/agent-left-event.ts @@ -0,0 +1,12 @@ +import { Agent } from '../agent'; + +export interface AgentLeftEvent { + + /** @see AgentLeftEventType */ + agent_left_event?: AgentLeftEventType; +} + +export interface AgentLeftEventType { + /** Represents an agent that is involved in a conversation. */ + agent: Agent; +} diff --git a/packages/conversation/src/models/v1/agent-left-event/index.ts b/packages/conversation/src/models/v1/agent-left-event/index.ts new file mode 100644 index 00000000..4f333c51 --- /dev/null +++ b/packages/conversation/src/models/v1/agent-left-event/index.ts @@ -0,0 +1 @@ +export type { AgentLeftEvent, AgentLeftEventType } from './agent-left-event'; diff --git a/packages/conversation/src/models/v1/agent/agent.ts b/packages/conversation/src/models/v1/agent/agent.ts new file mode 100644 index 00000000..50e035d7 --- /dev/null +++ b/packages/conversation/src/models/v1/agent/agent.ts @@ -0,0 +1,12 @@ +/** + * Represents an agent that is involved in a conversation. + */ +export interface Agent { + + /** Agent\'s display name */ + display_name?: string; + /** Agent\'s classification. It can be UNKNOWN_AGENT_TYPE, HUMAN or BOT. */ + type?: 'UNKNOWN_AGENT_TYPE' | 'HUMAN' | 'BOT'; + /** The Agent\'s picture url. */ + picture_url?: string; +} diff --git a/packages/conversation/src/models/v1/agent/index.ts b/packages/conversation/src/models/v1/agent/index.ts new file mode 100644 index 00000000..f185dd2b --- /dev/null +++ b/packages/conversation/src/models/v1/agent/index.ts @@ -0,0 +1 @@ +export type { Agent } from './agent'; diff --git a/packages/conversation/src/models/v1/app-create-request/app-create-request.ts b/packages/conversation/src/models/v1/app-create-request/app-create-request.ts new file mode 100644 index 00000000..be17bc41 --- /dev/null +++ b/packages/conversation/src/models/v1/app-create-request/app-create-request.ts @@ -0,0 +1,30 @@ +import { CallbackSettings } from '../callback-settings'; +import { ConversationChannelCredential } from '../conversation-channel-credential'; +import { ConversationMetadataReportView } from '../conversation-metadata-report-view'; +import { DispatchRetentionPolicy } from '../dispatch-retention-policy'; +import { RetentionPolicy } from '../retention-policy'; +import { SmartConversation } from '../smart-conversation'; +import { ProcessingMode } from '../processing-mode'; + +/** + * The request sent to the API endpoint to create a new app. + */ +export interface AppCreateRequest { + + /** An array of channel credentials. The order of the credentials defines the app channel priority. */ + channel_credentials: ConversationChannelCredential[]; + /** @see ConversationMetadataReportView */ + conversation_metadata_report_view?: ConversationMetadataReportView; + /** The display name for the app. */ + display_name: string; + /** @see RetentionPolicy */ + retention_policy?: RetentionPolicy; + /** @see DispatchRetentionPolicy */ + dispatch_retention_policy?: DispatchRetentionPolicy; + /** Whether or not Conversation API should store contacts and conversations for the app. For more information, see [Processing Modes](../../../../../conversation/processing-modes/). */ + processing_mode?: ProcessingMode; + /** @see SmartConversation */ + smart_conversation?: SmartConversation; + /** @see CallbackSettings */ + callback_settings?: CallbackSettings; +} diff --git a/packages/conversation/src/models/v1/app-create-request/index.ts b/packages/conversation/src/models/v1/app-create-request/index.ts new file mode 100644 index 00000000..74505f38 --- /dev/null +++ b/packages/conversation/src/models/v1/app-create-request/index.ts @@ -0,0 +1 @@ +export type { AppCreateRequest } from './app-create-request'; diff --git a/packages/conversation/src/models/v1/app-event/app-event.ts b/packages/conversation/src/models/v1/app-event/app-event.ts new file mode 100644 index 00000000..7883c086 --- /dev/null +++ b/packages/conversation/src/models/v1/app-event/app-event.ts @@ -0,0 +1,17 @@ +import { ComposingEvent } from '../composing-event'; +import { ComposingEndEvent } from '../composing-end-event'; +import { CommentReplyEvent } from '../comment-reply-event'; +import { AgentJoinedEvent } from '../agent-joined-event'; +import { AgentLeftEvent } from '../agent-left-event'; +import { GenericEvent } from '../generic-event'; + +/** + * Event originating from an app + */ +export type AppEvent = + ComposingEvent + | ComposingEndEvent + | CommentReplyEvent + | AgentJoinedEvent + | AgentLeftEvent + | GenericEvent; diff --git a/packages/conversation/src/models/v1/app-event/index.ts b/packages/conversation/src/models/v1/app-event/index.ts new file mode 100644 index 00000000..5b321543 --- /dev/null +++ b/packages/conversation/src/models/v1/app-event/index.ts @@ -0,0 +1 @@ +export type { AppEvent } from './app-event'; diff --git a/packages/conversation/src/models/v1/app-message-additional-properties/app-message-additional-properties.ts b/packages/conversation/src/models/v1/app-message-additional-properties/app-message-additional-properties.ts new file mode 100644 index 00000000..6567852b --- /dev/null +++ b/packages/conversation/src/models/v1/app-message-additional-properties/app-message-additional-properties.ts @@ -0,0 +1,8 @@ +/** + * Additional properties of the message. + */ +export interface AppMessageAdditionalProperties { + + /** The `display_name` of the newly created contact in case it doesn't exist. */ + contact_name?: string; +} diff --git a/packages/conversation/src/models/v1/app-message-additional-properties/index.ts b/packages/conversation/src/models/v1/app-message-additional-properties/index.ts new file mode 100644 index 00000000..b6e4ef9c --- /dev/null +++ b/packages/conversation/src/models/v1/app-message-additional-properties/index.ts @@ -0,0 +1 @@ +export type { AppMessageAdditionalProperties } from './app-message-additional-properties'; diff --git a/packages/conversation/src/models/v1/app-message-message/app-message-message.ts b/packages/conversation/src/models/v1/app-message-message/app-message-message.ts new file mode 100644 index 00000000..fb7de8b5 --- /dev/null +++ b/packages/conversation/src/models/v1/app-message-message/app-message-message.ts @@ -0,0 +1,18 @@ +import { CardMessage } from '../card-message'; +import { CarouselMessage } from '../carousel-message'; +import { ChoiceMessage } from '../choice-message'; +import { LocationMessage } from '../location-message'; +import { MediaMessage } from '../media-message'; +import { TextMessage } from '../text-message'; +import { ListMessage } from '../list-message'; +import { TemplateMessage } from '../template-message'; + +export type AppMessageMessage = + CardMessage + | CarouselMessage + | ChoiceMessage + | LocationMessage + | MediaMessage + | TemplateMessage + | TextMessage + | ListMessage; diff --git a/packages/conversation/src/models/v1/app-message-message/index.ts b/packages/conversation/src/models/v1/app-message-message/index.ts new file mode 100644 index 00000000..e2b31f72 --- /dev/null +++ b/packages/conversation/src/models/v1/app-message-message/index.ts @@ -0,0 +1 @@ +export type { AppMessageMessage } from './app-message-message'; diff --git a/packages/conversation/src/models/v1/app-message/app-message.ts b/packages/conversation/src/models/v1/app-message/app-message.ts new file mode 100644 index 00000000..a76ccd47 --- /dev/null +++ b/packages/conversation/src/models/v1/app-message/app-message.ts @@ -0,0 +1,15 @@ +import { AppMessageAdditionalProperties } from '../app-message-additional-properties'; +import { AppMessageMessage } from '../app-message-message'; + +/** + * Message originating from an app + */ +export interface AppMessage { + + /** @see AppMessageMessage */ + message?: AppMessageMessage; + /** Optional. Channel specific messages, overriding any transcoding. The key in the map must point to a valid conversation channel as defined by the enum ConversationChannel. */ + explicit_channel_message?: object; + /** @see AppMessageAdditionalProperties */ + additionalProperties?: AppMessageAdditionalProperties; +} diff --git a/packages/conversation/src/models/v1/app-message/index.ts b/packages/conversation/src/models/v1/app-message/index.ts new file mode 100644 index 00000000..0e0e6c3e --- /dev/null +++ b/packages/conversation/src/models/v1/app-message/index.ts @@ -0,0 +1 @@ +export type { AppMessage } from './app-message'; diff --git a/packages/conversation/src/models/v1/app-response/app-response.ts b/packages/conversation/src/models/v1/app-response/app-response.ts new file mode 100644 index 00000000..dfa6d286 --- /dev/null +++ b/packages/conversation/src/models/v1/app-response/app-response.ts @@ -0,0 +1,56 @@ +import { ConversationChannelCredential } from '../conversation-channel-credential'; +import { ConversationMetadataReportView } from '../conversation-metadata-report-view'; +import { DispatchRetentionPolicy } from '../dispatch-retention-policy'; +import { QueueStats } from '../queue-stats'; +import { RateLimits } from '../rate-limits'; +import { RetentionPolicy } from '../retention-policy'; +import { SmartConversation } from '../smart-conversation'; +import { ProcessingMode } from '../processing-mode'; +import { CallbackSettings } from '../callback-settings'; + +/** + * The response showing information about the app. + */ +export interface AppResponse { + + /** An array of channel credentials. The order of the credentials defines the app channel priority. */ + channel_credentials?: ConversationChannelCredential[]; + /** @see ConversationMetadataReportView */ + conversation_metadata_report_view?: ConversationMetadataReportView; + /** The display name for the app. */ + display_name?: string; + /** The ID of the app. You can find this on the [Sinch Dashboard](https://dashboard.sinch.com/convapi/apps). */ + id?: string; + /** @see RateLimits */ + rate_limits?: RateLimits; + /** @see RetentionPolicy */ + retention_policy?: RetentionPolicy; + /** @see DispatchRetentionPolicy */ + dispatch_retention_policy?: DispatchRetentionPolicy; + /** Whether or not Conversation API should store contacts and conversations for the app. For more information, see [Processing Modes](../../../../../conversation/processing-modes/). */ + processing_mode?: ProcessingMode; + /** @see SmartConversation */ + smart_conversation?: SmartConversation; + /** @see QueueStats */ + queue_stats?: QueueStats; + + /** TBC: Not documented */ + persist_message_status?: Enabled; + /** TBC: Not documented */ + message_search?: Enabled; + /** TBC: Not documented @see CallbackSettings */ + callback_settings?: CallbackSettings; + /** TBC: Not documented */ + delivery_report_based_fallback?: DeliveryReportBasedFallback | null; + /** TBC: Not documented */ + message_retry_settings?: null; +} + +export interface Enabled { + enabled?: boolean; +} + +export interface DeliveryReportBasedFallback { + enabled?: boolean; + delivery_report_waiting_time?: number; +} diff --git a/packages/conversation/src/models/v1/app-response/index.ts b/packages/conversation/src/models/v1/app-response/index.ts new file mode 100644 index 00000000..2e74d6c9 --- /dev/null +++ b/packages/conversation/src/models/v1/app-response/index.ts @@ -0,0 +1 @@ +export type { AppResponse, DeliveryReportBasedFallback, Enabled } from './app-response'; diff --git a/packages/conversation/src/models/v1/app-update-request/app-update-request.ts b/packages/conversation/src/models/v1/app-update-request/app-update-request.ts new file mode 100644 index 00000000..2be890a1 --- /dev/null +++ b/packages/conversation/src/models/v1/app-update-request/app-update-request.ts @@ -0,0 +1,30 @@ +import { CallbackSettings } from '../callback-settings'; +import { ConversationChannelCredential } from '../conversation-channel-credential'; +import { ConversationMetadataReportView } from '../conversation-metadata-report-view'; +import { DispatchRetentionPolicy } from '../dispatch-retention-policy'; +import { RetentionPolicy } from '../retention-policy'; +import { SmartConversation } from '../smart-conversation'; +import { ProcessingMode } from '../processing-mode'; + +/** + * The request sent to the API endpoint to update the configuration of an app. + */ +export interface AppUpdateRequest { + + /** An array of channel credentials. The order of the credentials defines the app channel priority. */ + channel_credentials?: ConversationChannelCredential[]; + /** @see ConversationMetadataReportView */ + conversation_metadata_report_view?: ConversationMetadataReportView; + /** The display name for the app. */ + display_name: string; + /** @see RetentionPolicy */ + retention_policy?: RetentionPolicy; + /** @see DispatchRetentionPolicy */ + dispatch_retention_policy?: DispatchRetentionPolicy; + /** Whether or not Conversation API should store contacts and conversations for the app. For more information, see [Processing Modes](../../../../../conversation/processing-modes/). */ + processing_mode?: ProcessingMode; + /** @see SmartConversation */ + smart_conversation?: SmartConversation; + /** @see CallbackSettings */ + callback_settings?: CallbackSettings; +} diff --git a/packages/conversation/src/models/v1/app-update-request/index.ts b/packages/conversation/src/models/v1/app-update-request/index.ts new file mode 100644 index 00000000..70a7db14 --- /dev/null +++ b/packages/conversation/src/models/v1/app-update-request/index.ts @@ -0,0 +1 @@ +export type { AppUpdateRequest } from './app-update-request'; diff --git a/packages/conversation/src/models/v1/basic-auth-credential/basic-auth-credential.ts b/packages/conversation/src/models/v1/basic-auth-credential/basic-auth-credential.ts new file mode 100644 index 00000000..25348ff9 --- /dev/null +++ b/packages/conversation/src/models/v1/basic-auth-credential/basic-auth-credential.ts @@ -0,0 +1,10 @@ +/** + * It consists of a username and a password. + */ +export interface BasicAuthCredential { + + /** Basic auth password. */ + password: string; + /** Basic auth username. */ + username: string; +} diff --git a/packages/conversation/src/models/v1/basic-auth-credential/index.ts b/packages/conversation/src/models/v1/basic-auth-credential/index.ts new file mode 100644 index 00000000..4be43bf7 --- /dev/null +++ b/packages/conversation/src/models/v1/basic-auth-credential/index.ts @@ -0,0 +1 @@ +export type { BasicAuthCredential } from './basic-auth-credential'; diff --git a/packages/conversation/src/models/v1/call-message/call-message.ts b/packages/conversation/src/models/v1/call-message/call-message.ts new file mode 100644 index 00000000..f929320c --- /dev/null +++ b/packages/conversation/src/models/v1/call-message/call-message.ts @@ -0,0 +1,10 @@ +/** + * Message for triggering a call. + */ +export interface CallMessage { + + /** Phone number in E.164 with leading +. */ + phone_number: string; + /** Title shown close to the phone number. The title is clickable in some cases. */ + title: string; +} diff --git a/packages/conversation/src/models/v1/call-message/index.ts b/packages/conversation/src/models/v1/call-message/index.ts new file mode 100644 index 00000000..83faa2ca --- /dev/null +++ b/packages/conversation/src/models/v1/call-message/index.ts @@ -0,0 +1 @@ +export type { CallMessage } from './call-message'; diff --git a/packages/conversation/src/models/v1/callback-settings/callback-settings.ts b/packages/conversation/src/models/v1/callback-settings/callback-settings.ts new file mode 100644 index 00000000..f7fc13e1 --- /dev/null +++ b/packages/conversation/src/models/v1/callback-settings/callback-settings.ts @@ -0,0 +1,8 @@ +/** + * This object contains additional settings related to callback processing. + */ +export interface CallbackSettings { + + /** Optional. Secret can be used to sign contents of delivery receipts for a message that was sent with the default `callback_url` overridden. You can then use the secret to verify the signature. */ + secret_for_overridden_callback_urls?: string; +} diff --git a/packages/conversation/src/models/v1/callback-settings/index.ts b/packages/conversation/src/models/v1/callback-settings/index.ts new file mode 100644 index 00000000..281a396e --- /dev/null +++ b/packages/conversation/src/models/v1/callback-settings/index.ts @@ -0,0 +1 @@ +export type { CallbackSettings } from './callback-settings'; diff --git a/packages/conversation/src/models/v1/card-height/card-height.ts b/packages/conversation/src/models/v1/card-height/card-height.ts new file mode 100644 index 00000000..a5a79fa1 --- /dev/null +++ b/packages/conversation/src/models/v1/card-height/card-height.ts @@ -0,0 +1,4 @@ +/** + * You can set the desired size of the card in the message. + */ +export type CardHeight = 'UNSPECIFIED_HEIGHT' | 'SHORT' | 'MEDIUM' | 'TALL'; diff --git a/packages/conversation/src/models/v1/card-height/index.ts b/packages/conversation/src/models/v1/card-height/index.ts new file mode 100644 index 00000000..6cad63c1 --- /dev/null +++ b/packages/conversation/src/models/v1/card-height/index.ts @@ -0,0 +1 @@ +export type { CardHeight } from './card-height'; diff --git a/packages/conversation/src/models/v1/card-message/card-message.ts b/packages/conversation/src/models/v1/card-message/card-message.ts new file mode 100644 index 00000000..f8bb5253 --- /dev/null +++ b/packages/conversation/src/models/v1/card-message/card-message.ts @@ -0,0 +1,26 @@ +import { CardHeight } from '../card-height'; +import { MediaCarouselMessage } from '../media-carousel-message'; +import { Choice } from '../choice'; + +/** + * Message containing text, media and choices. + */ +export interface CardMessage { + + /** Message containing text, media and choices. */ + card_message: CardMessageItem; +} + +export interface CardMessageItem { + + /** You may include choices in your Card Message. The number of choices is limited to 10. */ + choices?: Choice[]; + /** This is an optional description field that is displayed below the title on the card. */ + description?: string; + /** @see CardHeight */ + height?: CardHeight; + /** @see MediaCarouselMessage */ + media_message?: MediaCarouselMessage; + /** The title of the card message. */ + title?: string; +} diff --git a/packages/conversation/src/models/v1/card-message/index.ts b/packages/conversation/src/models/v1/card-message/index.ts new file mode 100644 index 00000000..c7d93091 --- /dev/null +++ b/packages/conversation/src/models/v1/card-message/index.ts @@ -0,0 +1 @@ +export type { CardMessage, CardMessageItem } from './card-message'; diff --git a/packages/conversation/src/models/v1/carousel-message/carousel-message.ts b/packages/conversation/src/models/v1/carousel-message/carousel-message.ts new file mode 100644 index 00000000..664fa2ec --- /dev/null +++ b/packages/conversation/src/models/v1/carousel-message/carousel-message.ts @@ -0,0 +1,19 @@ +import { CardMessage } from '../card-message'; +import { Choice } from '../choice'; + +/** + * Message containing a list of cards often rendered horizontally on supported channels. Supported types for media are only images, such as .png, .jpg, .jpeg extensions. + */ +export interface CarouselMessage { + + /** Message containing a list of cards often rendered horizontally on supported channels. Supported types for media are only images, such as .png, .jpg, .jpeg extensions. */ + carousel_message: CarouselMessageItem; +} + +export interface CarouselMessageItem { + + /** A list of up to 10 cards. */ + cards: CardMessage[]; + /** Optional. Outer choices on the carousel level. The number of outer choices is limited to 3. */ + choices?: Choice[]; +} diff --git a/packages/conversation/src/models/v1/carousel-message/index.ts b/packages/conversation/src/models/v1/carousel-message/index.ts new file mode 100644 index 00000000..b569bf52 --- /dev/null +++ b/packages/conversation/src/models/v1/carousel-message/index.ts @@ -0,0 +1 @@ +export type { CarouselMessage, CarouselMessageItem } from './carousel-message'; diff --git a/packages/conversation/src/models/v1/channel-identities/channel-identities.ts b/packages/conversation/src/models/v1/channel-identities/channel-identities.ts new file mode 100644 index 00000000..d5acfb48 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-identities/channel-identities.ts @@ -0,0 +1,7 @@ +import { ChannelRecipientIdentity } from '../channel-recipient-identity'; + +export interface ChannelIdentities { + + /** A list of specific channel identities. The API will use these identities when sending to specific channels. */ + channel_identities: ChannelRecipientIdentity[]; +} diff --git a/packages/conversation/src/models/v1/channel-identities/index.ts b/packages/conversation/src/models/v1/channel-identities/index.ts new file mode 100644 index 00000000..ba4a5570 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-identities/index.ts @@ -0,0 +1 @@ +export type { ChannelIdentities } from './channel-identities'; diff --git a/packages/conversation/src/models/v1/channel-identity/channel-identity.ts b/packages/conversation/src/models/v1/channel-identity/channel-identity.ts new file mode 100644 index 00000000..ce7dac9a --- /dev/null +++ b/packages/conversation/src/models/v1/channel-identity/channel-identity.ts @@ -0,0 +1,14 @@ +import { ConversationChannel } from '../conversation-channel'; + +/** + * A unique identity of message recipient on a particular channel. For example, the channel identity on SMS, WHATSAPP or VIBERBM is a MSISDN phone number. + */ +export interface ChannelIdentity { + + /** Required if using a channel that uses app-scoped channel identities. Currently, FB Messenger, Viber Bot, Instagram, Apple Messages for Business, LINE, and WeChat use app-scoped channel identities, which means contacts will have different channel identities on different Conversation API apps. These can be thought of as virtual identities that are app-specific and, therefore, the app_id must be included in the API call. */ + app_id?: string; + /** @see ConversationChannel */ + channel: ConversationChannel; + /** The channel identity. This will differ from channel to channel. For example, a phone number for SMS, WhatsApp, and Viber Business. */ + identity: string; +} diff --git a/packages/conversation/src/models/v1/channel-identity/index.ts b/packages/conversation/src/models/v1/channel-identity/index.ts new file mode 100644 index 00000000..3dd1b593 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-identity/index.ts @@ -0,0 +1 @@ +export type { ChannelIdentity } from './channel-identity'; diff --git a/packages/conversation/src/models/v1/channel-recipient-identity/channel-recipient-identity.ts b/packages/conversation/src/models/v1/channel-recipient-identity/channel-recipient-identity.ts new file mode 100644 index 00000000..e0803ec5 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-recipient-identity/channel-recipient-identity.ts @@ -0,0 +1,9 @@ +import { ConversationChannel } from '../conversation-channel'; + +export interface ChannelRecipientIdentity { + + /** @see ConversationChannel */ + channel: ConversationChannel; + /** The channel recipient identity. */ + identity: string; +} diff --git a/packages/conversation/src/models/v1/channel-recipient-identity/index.ts b/packages/conversation/src/models/v1/channel-recipient-identity/index.ts new file mode 100644 index 00000000..7713a658 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-recipient-identity/index.ts @@ -0,0 +1 @@ +export type { ChannelRecipientIdentity } from './channel-recipient-identity'; diff --git a/packages/conversation/src/models/v1/choice-item/choice-item.ts b/packages/conversation/src/models/v1/choice-item/choice-item.ts new file mode 100644 index 00000000..c8ab5463 --- /dev/null +++ b/packages/conversation/src/models/v1/choice-item/choice-item.ts @@ -0,0 +1,13 @@ +import { MediaMessage } from '../media-message'; + +export interface ChoiceItem { + + /** Required parameter. Title for the choice item. */ + title: string; + /** Optional parameter. The description (or subtitle) of this choice item. */ + description?: string; + /** @see MediaMessage */ + media?: MediaMessage; + /** Optional parameter. Postback data that will be returned in the MO if the user selects this option. */ + postback_data?: string; +} diff --git a/packages/conversation/src/models/v1/choice-item/index.ts b/packages/conversation/src/models/v1/choice-item/index.ts new file mode 100644 index 00000000..91fab497 --- /dev/null +++ b/packages/conversation/src/models/v1/choice-item/index.ts @@ -0,0 +1 @@ +export type { ChoiceItem } from './choice-item'; diff --git a/packages/conversation/src/models/v1/choice-message/choice-message.ts b/packages/conversation/src/models/v1/choice-message/choice-message.ts new file mode 100644 index 00000000..2f4f83f6 --- /dev/null +++ b/packages/conversation/src/models/v1/choice-message/choice-message.ts @@ -0,0 +1,19 @@ +import { Choice } from '../choice'; +import { TextMessage } from '../text-message'; + +/** + * Message containing choices/actions. + */ +export interface ChoiceMessage { + + /** Message containing choices/actions. */ + choice_message: ChoiceMessageItem; +} + +export interface ChoiceMessageItem { + + /** The number of choices is limited to 10. */ + choices: Choice[]; + /** @see TextMessage */ + text_message?: TextMessage; +} diff --git a/packages/conversation/src/models/v1/choice-message/index.ts b/packages/conversation/src/models/v1/choice-message/index.ts new file mode 100644 index 00000000..36313eea --- /dev/null +++ b/packages/conversation/src/models/v1/choice-message/index.ts @@ -0,0 +1 @@ +export type { ChoiceMessage } from './choice-message'; diff --git a/packages/conversation/src/models/v1/choice-response-message/choice-response-message.ts b/packages/conversation/src/models/v1/choice-response-message/choice-response-message.ts new file mode 100644 index 00000000..2ab0a610 --- /dev/null +++ b/packages/conversation/src/models/v1/choice-response-message/choice-response-message.ts @@ -0,0 +1,10 @@ +/** + * Represents a response to a choice message. + */ +export interface ChoiceResponseMessage { + + /** The message id containing the choice. */ + message_id: string; + /** The postback_data defined in the selected choice. */ + postback_data: string; +} diff --git a/packages/conversation/src/models/v1/choice-response-message/index.ts b/packages/conversation/src/models/v1/choice-response-message/index.ts new file mode 100644 index 00000000..f465847a --- /dev/null +++ b/packages/conversation/src/models/v1/choice-response-message/index.ts @@ -0,0 +1 @@ +export type { ChoiceResponseMessage } from './choice-response-message'; diff --git a/packages/conversation/src/models/v1/choice/choice.ts b/packages/conversation/src/models/v1/choice/choice.ts new file mode 100644 index 00000000..6964b4b9 --- /dev/null +++ b/packages/conversation/src/models/v1/choice/choice.ts @@ -0,0 +1,23 @@ +import { CallMessage } from '../call-message'; +import { LocationMessageItem } from '../location-message'; +import { TextMessageItem } from '../text-message'; +import { UrlMessage } from '../url-message'; + +/** + * A choice is an action the user can take such as buttons for quick replies or other call to actions. + */ +export interface Choice { + + /** @see CallMessage */ + call_message: CallMessage; + /** @see LocationMessage */ + location_message: LocationMessageItem; + /** An optional field. This data will be returned in the ChoiceResponseMessage. The default is message_id_{text, title}. */ + postback_data :string; + /** @see TextMessageItem */ + text_message: TextMessageItem; + /** @see UrlMessage */ + url_message: UrlMessage; +} + + diff --git a/packages/conversation/src/models/v1/choice/index.ts b/packages/conversation/src/models/v1/choice/index.ts new file mode 100644 index 00000000..327cdc59 --- /dev/null +++ b/packages/conversation/src/models/v1/choice/index.ts @@ -0,0 +1 @@ +export type { Choice } from './choice'; diff --git a/packages/conversation/src/models/v1/client-credentials/client-credentials.ts b/packages/conversation/src/models/v1/client-credentials/client-credentials.ts new file mode 100644 index 00000000..cd062629 --- /dev/null +++ b/packages/conversation/src/models/v1/client-credentials/client-credentials.ts @@ -0,0 +1,12 @@ +/** + * Optional. Used for OAuth2 authentication. + */ +export interface ClientCredentials { + + /** The Client ID that will be used in the OAuth2 Client Credentials flow. */ + client_id: string; + /** The Client Secret that will be used in the OAuth2 Client Credentials flow. */ + client_secret: string; + /** The endpoint that will be used in the OAuth2 Client Credentials flow. Expected to return a JSON with an access token and `expires_in` value (in seconds). The `expires_in` value, which must be a minimum of 30 seconds and a maximum of 3600 seconds, is how long Sinch will save the access token before asking for a new one. */ + endpoint: string; +} diff --git a/packages/conversation/src/models/v1/client-credentials/index.ts b/packages/conversation/src/models/v1/client-credentials/index.ts new file mode 100644 index 00000000..c9b86d51 --- /dev/null +++ b/packages/conversation/src/models/v1/client-credentials/index.ts @@ -0,0 +1 @@ +export type { ClientCredentials } from './client-credentials'; diff --git a/packages/conversation/src/models/v1/comment-reply-event/comment-reply-event.ts b/packages/conversation/src/models/v1/comment-reply-event/comment-reply-event.ts new file mode 100644 index 00000000..a1f240e8 --- /dev/null +++ b/packages/conversation/src/models/v1/comment-reply-event/comment-reply-event.ts @@ -0,0 +1,11 @@ +export interface CommentReplyEvent { + + /** @see CommentReplyEvent */ + comment_reply_event?: CommentReplyEventItem; +} + +export interface CommentReplyEventItem { + + /** The text of the comment reply. */ + text: string; +} diff --git a/packages/conversation/src/models/v1/comment-reply-event/index.ts b/packages/conversation/src/models/v1/comment-reply-event/index.ts new file mode 100644 index 00000000..f7800137 --- /dev/null +++ b/packages/conversation/src/models/v1/comment-reply-event/index.ts @@ -0,0 +1 @@ +export type { CommentReplyEvent, CommentReplyEventItem } from './comment-reply-event'; diff --git a/packages/conversation/src/models/v1/composing-end-event/composing-end-event.ts b/packages/conversation/src/models/v1/composing-end-event/composing-end-event.ts new file mode 100644 index 00000000..9df7006b --- /dev/null +++ b/packages/conversation/src/models/v1/composing-end-event/composing-end-event.ts @@ -0,0 +1,5 @@ +export interface ComposingEndEvent { + + /** An empty object. Represents a typing end indicator. */ + composing_end_event?: Record; +} diff --git a/packages/conversation/src/models/v1/composing-end-event/index.ts b/packages/conversation/src/models/v1/composing-end-event/index.ts new file mode 100644 index 00000000..c398a9f5 --- /dev/null +++ b/packages/conversation/src/models/v1/composing-end-event/index.ts @@ -0,0 +1 @@ +export type { ComposingEndEvent } from './composing-end-event'; diff --git a/packages/conversation/src/models/v1/composing-event/composing-event.ts b/packages/conversation/src/models/v1/composing-event/composing-event.ts new file mode 100644 index 00000000..72974306 --- /dev/null +++ b/packages/conversation/src/models/v1/composing-event/composing-event.ts @@ -0,0 +1,5 @@ +export interface ComposingEvent { + + /** An empty object. Represents a typing indicator. */ + composing_event?: Record; +} diff --git a/packages/conversation/src/models/v1/composing-event/index.ts b/packages/conversation/src/models/v1/composing-event/index.ts new file mode 100644 index 00000000..0ebda1a7 --- /dev/null +++ b/packages/conversation/src/models/v1/composing-event/index.ts @@ -0,0 +1 @@ +export type { ComposingEvent } from './composing-event'; diff --git a/packages/conversation/src/models/v1/contact-create-request/contact-create-request.ts b/packages/conversation/src/models/v1/contact-create-request/contact-create-request.ts new file mode 100644 index 00000000..5c8268e3 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-create-request/contact-create-request.ts @@ -0,0 +1,24 @@ +import { ChannelIdentity } from '../channel-identity'; +import { ConversationChannel } from '../conversation-channel'; +import { ContactLanguage } from '../contact-language'; + +/** + * A participant in a conversation typically representing a person. It is associated with a collection of channel identities. + */ +export interface ContactCreateRequest { + + /** List of channel identities. Array must contain at least one item. */ + channel_identities: ChannelIdentity[]; + /** List of channels defining the channel priority. The channel at the top of the list is tried first. */ + channel_priority?: ConversationChannel[]; + /** The display name. A default \'Unknown\' will be assigned if left empty. */ + display_name?: string; + /** Email of the contact. */ + email?: string; + /** Contact identifier in an external system. */ + external_id?: string; + /** */ + language: ContactLanguage; + /** Metadata associated with the contact. Up to 1024 characters long. */ + metadata?: string; +} diff --git a/packages/conversation/src/models/v1/contact-create-request/index.ts b/packages/conversation/src/models/v1/contact-create-request/index.ts new file mode 100644 index 00000000..3c22240b --- /dev/null +++ b/packages/conversation/src/models/v1/contact-create-request/index.ts @@ -0,0 +1 @@ +export type { ContactCreateRequest } from './contact-create-request'; diff --git a/packages/conversation/src/models/v1/contact-id/contact-id.ts b/packages/conversation/src/models/v1/contact-id/contact-id.ts new file mode 100644 index 00000000..fb0c19c3 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-id/contact-id.ts @@ -0,0 +1,5 @@ +export interface ContactId { + + /** The ID of the contact. */ + contact_id?: string; +} diff --git a/packages/conversation/src/models/v1/contact-id/index.ts b/packages/conversation/src/models/v1/contact-id/index.ts new file mode 100644 index 00000000..e5949d45 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-id/index.ts @@ -0,0 +1 @@ +export type { ContactId } from './contact-id'; diff --git a/packages/conversation/src/models/v1/contact-language/contact-language.ts b/packages/conversation/src/models/v1/contact-language/contact-language.ts new file mode 100644 index 00000000..00e8cc16 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-language/contact-language.ts @@ -0,0 +1,71 @@ +export type ContactLanguage = + 'AF' + | 'SQ' + | 'AR' + | 'AZ' + | 'BN' + | 'BG' + | 'CA' + | 'ZH' + | 'ZH_CN' + | 'ZH_HK' + | 'ZH_TW' + | 'HR' + | 'CS' + | 'DA' + | 'NL' + | 'EN' + | 'EN_GB' + | 'EN_US' + | 'ET' + | 'FIL' + | 'FI' + | 'FR' + | 'DE' + | 'EL' + | 'GU' + | 'HA' + | 'HE' + | 'HI' + | 'HU' + | 'ID' + | 'GA' + | 'IT' + | 'JA' + | 'KN' + | 'KK' + | 'KO' + | 'LO' + | 'LV' + | 'LT' + | 'MK' + | 'MS' + | 'ML' + | 'MR' + | 'NB' + | 'FA' + | 'PL' + | 'PT' + | 'PT_BR' + | 'PT_PT' + | 'PA' + | 'RO' + | 'RU' + | 'SR' + | 'SK' + | 'SL' + | 'ES' + | 'ES_AR' + | 'ES_ES' + | 'ES_MX' + | 'SW' + | 'SV' + | 'TA' + | 'TE' + | 'TH' + | 'TR' + | 'UK' + | 'UR' + | 'UZ' + | 'VI' + | 'ZU'; diff --git a/packages/conversation/src/models/v1/contact-language/index.ts b/packages/conversation/src/models/v1/contact-language/index.ts new file mode 100644 index 00000000..b5a34c02 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-language/index.ts @@ -0,0 +1 @@ +export * from './contact-language'; diff --git a/packages/conversation/src/models/v1/contact-message/contact-message.ts b/packages/conversation/src/models/v1/contact-message/contact-message.ts new file mode 100644 index 00000000..3695b837 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-message/contact-message.ts @@ -0,0 +1,28 @@ +import { ChoiceResponseMessage } from '../choice-response-message'; +import { FallbackMessage } from '../fallback-message'; +import { LocationMessageItem } from '../location-message'; +import { MediaCardMessage } from '../media-card-message'; +import { MediaMessageItem } from '../media-message'; +import { ReplyTo } from '../reply-to'; +import { TextMessageItem } from '../text-message'; + +/** + * Message originating from a contact + */ +export interface ContactMessage { + + /** @see ChoiceResponseMessage */ + choice_response_message?: ChoiceResponseMessage; + /** @see FallbackMessage */ + fallback_message?: FallbackMessage; + /** @see LocationMessage */ + location_message?: LocationMessageItem; + /** @see MediaCardMessage */ + media_card_message?: MediaCardMessage; + /** @see MediaMessage */ + media_message?: MediaMessageItem; + /** @see ReplyTo */ + reply_to?: ReplyTo; + /** @see TextMessageItem */ + text_message?: TextMessageItem; +} diff --git a/packages/conversation/src/models/v1/contact-message/index.ts b/packages/conversation/src/models/v1/contact-message/index.ts new file mode 100644 index 00000000..18372c81 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-message/index.ts @@ -0,0 +1 @@ +export type { ContactMessage } from './contact-message'; diff --git a/packages/conversation/src/models/v1/contact/contact.ts b/packages/conversation/src/models/v1/contact/contact.ts new file mode 100644 index 00000000..c8f054db --- /dev/null +++ b/packages/conversation/src/models/v1/contact/contact.ts @@ -0,0 +1,26 @@ +import { ChannelIdentity } from '../channel-identity'; +import { ConversationChannel } from '../conversation-channel'; +import { ContactLanguage } from '../contact-language'; + +/** + * A participant in a conversation typically representing a person. It is associated with a collection of channel identities. + */ +export interface Contact { + + /** List of channel identities. */ + channel_identities?: ChannelIdentity[]; + /** List of channels defining the channel priority. */ + channel_priority?: ConversationChannel[]; + /** The display name. A default 'Unknown' will be assigned if left empty. */ + display_name?: string; + /** Email of the contact. */ + email?: string; + /** Contact identifier in an external system. */ + external_id?: string; + /** The ID of the contact. */ + id?: string; + /** */ + language?: ContactLanguage; + /** Metadata associated with the contact. Up to 1024 characters long. */ + metadata?: string; +} diff --git a/packages/conversation/src/models/v1/contact/index.ts b/packages/conversation/src/models/v1/contact/index.ts new file mode 100644 index 00000000..c229d70d --- /dev/null +++ b/packages/conversation/src/models/v1/contact/index.ts @@ -0,0 +1 @@ +export type { Contact } from './contact'; diff --git a/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts new file mode 100644 index 00000000..ead67350 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts @@ -0,0 +1,45 @@ +import { ConversationChannel } from '../conversation-channel'; +import { KakaoTalkCredentials } from '../kakao-talk-credentials'; +import { LineCredentials } from '../line-credentials'; +import { MMSCredentials } from '../mms-credentials'; +import { StaticBearerCredential } from '../static-bearer-credential'; +import { StaticTokenCredential } from '../static-token-credential'; +import { TelegramCredentials } from '../telegram-credentials'; +import { WeChatCredentials } from '../wechat-credentials'; + +/** + * Enables access to the underlying messaging channel. + */ +export interface ConversationChannelCredential { + + /** The secret used to verify the channel callbacks for channels which support callback verification. The callback verification is not needed for Sinch-managed channels because the callbacks are not leaving Sinch internal networks. Max length is 256 characters. Note: leaving channel_callback_secret empty for channels with callback verification will disable the verification. */ + callback_secret?: string; + /** @see ConversationChannel */ + channel: ConversationChannel; + /** @see MMSCredentials */ + mms_credentials?: MMSCredentials; + /** @see KakaoTalkCredentials */ + kakaotalk_credentials?: KakaoTalkCredentials; + /** @see StaticBearerCredential */ + static_bearer?: StaticBearerCredential; + /** @see StaticTokenCredential */ + static_token?: StaticTokenCredential; + /** @see TelegramCredentials */ + telegram_credentials?: TelegramCredentials; + /** @see LineCredentials */ + line_credentials?: LineCredentials; + /** @see WeChatCredentials */ + wechat_credentials?: WeChatCredentials; + + /** TBC: Not documented */ + state?: AppState; + /** TBC: Not documented */ + channel_known_id?: string +} + +export interface AppState { + /** TBC: Not documented - should be an enum 'PENDING' | 'FAILING' | 'ACTIVE' */ + status?: string + /** TBC: Not documented */ + description?: string; +} diff --git a/packages/conversation/src/models/v1/conversation-channel-credential/index.ts b/packages/conversation/src/models/v1/conversation-channel-credential/index.ts new file mode 100644 index 00000000..ff992ae1 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-channel-credential/index.ts @@ -0,0 +1 @@ +export type { ConversationChannelCredential, AppState } from './conversation-channel-credential'; diff --git a/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts new file mode 100644 index 00000000..6230360c --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts @@ -0,0 +1,17 @@ +/** + * The identifier of the channel you want to include. Must be one of the enum values. + */ +export type ConversationChannel = + 'WHATSAPP' + | 'RCS' + | 'SMS' + | 'MESSENGER' + | 'VIBER' + | 'VIBERBM' + | 'MMS' + | 'INSTAGRAM' + | 'TELEGRAM' + | 'KAKAOTALK' + | 'KAKAOTALKCHAT' + | 'LINE' + | 'WECHAT'; diff --git a/packages/conversation/src/models/v1/conversation-channel/index.ts b/packages/conversation/src/models/v1/conversation-channel/index.ts new file mode 100644 index 00000000..bad833a8 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-channel/index.ts @@ -0,0 +1 @@ +export type { ConversationChannel } from './conversation-channel'; diff --git a/packages/conversation/src/models/v1/conversation-direction/conversation-direction.ts b/packages/conversation/src/models/v1/conversation-direction/conversation-direction.ts new file mode 100644 index 00000000..7a7cfe6c --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-direction/conversation-direction.ts @@ -0,0 +1 @@ +export type ConversationDirection = 'UNDEFINED_DIRECTION' | 'TO_APP' | 'TO_CONTACT'; diff --git a/packages/conversation/src/models/v1/conversation-direction/index.ts b/packages/conversation/src/models/v1/conversation-direction/index.ts new file mode 100644 index 00000000..21f27f27 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-direction/index.ts @@ -0,0 +1 @@ +export type { ConversationDirection } from './conversation-direction'; diff --git a/packages/conversation/src/models/v1/conversation-merge-strategy/conversation-merge-strategy.ts b/packages/conversation/src/models/v1/conversation-merge-strategy/conversation-merge-strategy.ts new file mode 100644 index 00000000..c328128e --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-merge-strategy/conversation-merge-strategy.ts @@ -0,0 +1 @@ +export type ConversationMergeStrategy = 'MERGE'; diff --git a/packages/conversation/src/models/v1/conversation-merge-strategy/index.ts b/packages/conversation/src/models/v1/conversation-merge-strategy/index.ts new file mode 100644 index 00000000..0cc6315d --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-merge-strategy/index.ts @@ -0,0 +1 @@ +export type { ConversationMergeStrategy } from './conversation-merge-strategy'; diff --git a/packages/conversation/src/models/v1/conversation-message-injected/conversation-message-injected.ts b/packages/conversation/src/models/v1/conversation-message-injected/conversation-message-injected.ts new file mode 100644 index 00000000..bec6b788 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-message-injected/conversation-message-injected.ts @@ -0,0 +1,25 @@ +import { AppMessage } from '../app-message'; +import { ChannelIdentity } from '../channel-identity'; +import { ContactMessage } from '../contact-message'; +import { ConversationDirection } from '../conversation-direction'; + +/** + * A message on a particular channel. + */ +export interface ConversationMessageInjected { + + /** The processed time of the message in UTC timezone. Must be less than current_time and greater than (current_time - 30 days) */ + accept_time?: Date; + /** @see AppMessage */ + app_message?: AppMessage; + /** @see ChannelIdentity */ + channel_identity?: ChannelIdentity; + /** The ID of the contact registered in the conversation provided. */ + contact_id?: string; + /** @see ContactMessage */ + contact_message?: ContactMessage; + /** @see ConversationDirection */ + direction?: ConversationDirection; + /** Optional. Metadata associated with the contact. Up to 1024 characters long. */ + metadata?: string; +} diff --git a/packages/conversation/src/models/v1/conversation-message-injected/index.ts b/packages/conversation/src/models/v1/conversation-message-injected/index.ts new file mode 100644 index 00000000..d7b56ce0 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-message-injected/index.ts @@ -0,0 +1 @@ +export type { ConversationMessageInjected } from './conversation-message-injected'; diff --git a/packages/conversation/src/models/v1/conversation-message/conversation-message.ts b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts new file mode 100644 index 00000000..1d77e007 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts @@ -0,0 +1,31 @@ +import { AppMessage } from '../app-message'; +import { ChannelIdentity } from '../channel-identity'; +import { ContactMessage } from '../contact-message'; +import { ConversationDirection } from '../conversation-direction'; + +/** + * A message on a particular channel. + */ +export interface ConversationMessage { + + /** The time Conversation API processed the message. */ + accept_time?: Date; + /** @see AppMessage */ + app_message?: AppMessage; + /** @see ChannelIdentity */ + channel_identity?: ChannelIdentity; + /** The ID of the contact. */ + contact_id?: string; + /** @see ContactMessage */ + contact_message?: ContactMessage; + /** The ID of the conversation. */ + conversation_id?: string; + /** @see ConversationDirection */ + direction?: ConversationDirection; + /** The ID of the message. */ + id?: string; + /** Optional. Metadata associated with the contact. Up to 1024 characters long. */ + metadata?: string; + /** Flag for whether this message was injected. */ + injected?: boolean; +} diff --git a/packages/conversation/src/models/v1/conversation-message/index.ts b/packages/conversation/src/models/v1/conversation-message/index.ts new file mode 100644 index 00000000..99ecbf3b --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-message/index.ts @@ -0,0 +1 @@ +export type { ConversationMessage } from './conversation-message'; diff --git a/packages/conversation/src/models/v1/conversation-messages-view/conversation-messages-view.ts b/packages/conversation/src/models/v1/conversation-messages-view/conversation-messages-view.ts new file mode 100644 index 00000000..144fd50d --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-messages-view/conversation-messages-view.ts @@ -0,0 +1 @@ +export type ConversationMessagesView = 'WITH_METADATA' | 'WITHOUT_METADATA'; diff --git a/packages/conversation/src/models/v1/conversation-messages-view/index.ts b/packages/conversation/src/models/v1/conversation-messages-view/index.ts new file mode 100644 index 00000000..5e348951 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-messages-view/index.ts @@ -0,0 +1 @@ +export type { ConversationMessagesView } from './conversation-messages-view'; diff --git a/packages/conversation/src/models/v1/conversation-metadata-report-view/conversation-metadata-report-view.ts b/packages/conversation/src/models/v1/conversation-metadata-report-view/conversation-metadata-report-view.ts new file mode 100644 index 00000000..44b1e7ba --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-metadata-report-view/conversation-metadata-report-view.ts @@ -0,0 +1 @@ +export type ConversationMetadataReportView = 'NONE' | 'FULL'; diff --git a/packages/conversation/src/models/v1/conversation-metadata-report-view/index.ts b/packages/conversation/src/models/v1/conversation-metadata-report-view/index.ts new file mode 100644 index 00000000..3c5b784f --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-metadata-report-view/index.ts @@ -0,0 +1 @@ +export type { ConversationMetadataReportView } from './conversation-metadata-report-view'; diff --git a/packages/conversation/src/models/v1/conversation-metadata-update-strategy/conversation-metadata-update-strategy.ts b/packages/conversation/src/models/v1/conversation-metadata-update-strategy/conversation-metadata-update-strategy.ts new file mode 100644 index 00000000..71009e51 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-metadata-update-strategy/conversation-metadata-update-strategy.ts @@ -0,0 +1 @@ +export type ConversationMetadataUpdateStrategy = 'REPLACE' | 'MERGE_PATCH'; diff --git a/packages/conversation/src/models/v1/conversation-metadata-update-strategy/index.ts b/packages/conversation/src/models/v1/conversation-metadata-update-strategy/index.ts new file mode 100644 index 00000000..f964857c --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-metadata-update-strategy/index.ts @@ -0,0 +1 @@ +export type { ConversationMetadataUpdateStrategy } from './conversation-metadata-update-strategy'; diff --git a/packages/conversation/src/models/v1/conversation/conversation.ts b/packages/conversation/src/models/v1/conversation/conversation.ts new file mode 100644 index 00000000..3aadc9f5 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation/conversation.ts @@ -0,0 +1,24 @@ +import { ConversationChannel } from '../conversation-channel'; + +/** + * A collection of messages exchanged between a contact and an app. Conversations are normally created on the fly by Conversation API once a message is sent and there is no active conversation already. There can be only one active conversation at any given time between a particular contact and an app. + */ +export interface Conversation { + + /** Flag for whether this conversation is active. */ + active?: boolean; + /** @see ConversationChannel */ + active_channel?: ConversationChannel; + /** The ID of the participating app. */ + app_id?: string; + /** The ID of the participating contact. */ + contact_id?: string; + /** The ID of the conversation. */ + id?: string; + /** The timestamp of the latest message in the conversation. The timestamp will be Thursday January 01, 1970 00:00:00 UTC if the conversation contains no messages. */ + last_received?: Date; + /** Arbitrary data set by the Conversation API clients. Up to 1024 characters long. */ + metadata?: string; + /** Arbitrary data set by the Conversation API clients and/or provided in the `conversation_metadata` field of a SendMessageRequest. A valid JSON object. */ + metadata_json?: object; +} diff --git a/packages/conversation/src/models/v1/conversation/index.ts b/packages/conversation/src/models/v1/conversation/index.ts new file mode 100644 index 00000000..857922d4 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation/index.ts @@ -0,0 +1 @@ +export type { Conversation } from './conversation'; diff --git a/packages/conversation/src/models/v1/coordinates/coordinates.ts b/packages/conversation/src/models/v1/coordinates/coordinates.ts new file mode 100644 index 00000000..02939799 --- /dev/null +++ b/packages/conversation/src/models/v1/coordinates/coordinates.ts @@ -0,0 +1,7 @@ +export interface Coordinates { + + /** The latitude. */ + latitude: number; + /** The longitude. */ + longitude: number; +} diff --git a/packages/conversation/src/models/v1/coordinates/index.ts b/packages/conversation/src/models/v1/coordinates/index.ts new file mode 100644 index 00000000..7fcb323c --- /dev/null +++ b/packages/conversation/src/models/v1/coordinates/index.ts @@ -0,0 +1 @@ +export type { Coordinates } from './coordinates'; diff --git a/packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts b/packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts new file mode 100644 index 00000000..d3f8b499 --- /dev/null +++ b/packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts @@ -0,0 +1,22 @@ +import { ConversationChannel } from '../conversation-channel'; + +/** + * The conversation to create. + */ +export interface CreateConversationRequest { + + /** Flag for whether this conversation is active. */ + active?: boolean; + /** @see ConversationChannel */ + active_channel?: ConversationChannel; + /** The ID of the participating app. */ + app_id: string; + /** The ID of the participating contact. */ + contact_id: string; + /** The ID of the conversation. */ + id?: string; + /** Arbitrary data set by the Conversation API clients. Up to 1024 characters long. */ + metadata?: string; + /** Arbitrary data set by the Conversation API clients and/or provided in the `conversation_metadata` field of a SendMessageRequest. A valid JSON object. */ + metadata_json?: object; +} diff --git a/packages/conversation/src/models/v1/create-conversation-request/index.ts b/packages/conversation/src/models/v1/create-conversation-request/index.ts new file mode 100644 index 00000000..4527f5b1 --- /dev/null +++ b/packages/conversation/src/models/v1/create-conversation-request/index.ts @@ -0,0 +1 @@ +export type { CreateConversationRequest } from './create-conversation-request'; diff --git a/packages/conversation/src/models/v1/dispatch-retention-policy-type/dispatch-retention-policy-type.ts b/packages/conversation/src/models/v1/dispatch-retention-policy-type/dispatch-retention-policy-type.ts new file mode 100644 index 00000000..ad2b1afb --- /dev/null +++ b/packages/conversation/src/models/v1/dispatch-retention-policy-type/dispatch-retention-policy-type.ts @@ -0,0 +1 @@ +export type DispatchRetentionPolicyType = 'MESSAGE_EXPIRE_POLICY'; diff --git a/packages/conversation/src/models/v1/dispatch-retention-policy-type/index.ts b/packages/conversation/src/models/v1/dispatch-retention-policy-type/index.ts new file mode 100644 index 00000000..162a8247 --- /dev/null +++ b/packages/conversation/src/models/v1/dispatch-retention-policy-type/index.ts @@ -0,0 +1 @@ +export type { DispatchRetentionPolicyType } from './dispatch-retention-policy-type'; diff --git a/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts b/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts new file mode 100644 index 00000000..a5cc472b --- /dev/null +++ b/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts @@ -0,0 +1,12 @@ +import { DispatchRetentionPolicyType } from '../dispatch-retention-policy-type'; + +/** + * The retention policy configured for messages in [Dispatch Mode](../../../../../conversation/processing-modes/). Currently only `MESSAGE_EXPIRE_POLICY` is available. For more information about retention policies, see [Retention Policy](/docs/conversation/keyconcepts/#retention-policy). + */ +export interface DispatchRetentionPolicy { + + /** @see DispatchRetentionPolicyType */ + retention_type?: DispatchRetentionPolicyType; + /** Optional. The days before a message is eligible for deletion. The valid range is `[0 - 7]`. In the case of a `0` day TTL, messages aren\'t stored at all. Note the retention cleanup job runs once every twenty-four hours, so messages are not deleted on the minute they become eligible for deletion. */ + ttl_days?: number; +} diff --git a/packages/conversation/src/models/v1/dispatch-retention-policy/index.ts b/packages/conversation/src/models/v1/dispatch-retention-policy/index.ts new file mode 100644 index 00000000..e345a955 --- /dev/null +++ b/packages/conversation/src/models/v1/dispatch-retention-policy/index.ts @@ -0,0 +1 @@ +export type { DispatchRetentionPolicy } from './dispatch-retention-policy'; diff --git a/packages/conversation/src/models/v1/enums.ts b/packages/conversation/src/models/v1/enums.ts new file mode 100644 index 00000000..8cec2e9c --- /dev/null +++ b/packages/conversation/src/models/v1/enums.ts @@ -0,0 +1 @@ +export {}; \ No newline at end of file diff --git a/packages/conversation/src/models/v1/error-detail/error-detail.ts b/packages/conversation/src/models/v1/error-detail/error-detail.ts new file mode 100644 index 00000000..521b4eef --- /dev/null +++ b/packages/conversation/src/models/v1/error-detail/error-detail.ts @@ -0,0 +1,5 @@ +export interface ErrorDetail { + + type_url?: string; + value?: string; +} diff --git a/packages/conversation/src/models/v1/error-detail/index.ts b/packages/conversation/src/models/v1/error-detail/index.ts new file mode 100644 index 00000000..f8d11bbb --- /dev/null +++ b/packages/conversation/src/models/v1/error-detail/index.ts @@ -0,0 +1 @@ +export type { ErrorDetail } from './error-detail'; diff --git a/packages/conversation/src/models/v1/fallback-message/fallback-message.ts b/packages/conversation/src/models/v1/fallback-message/fallback-message.ts new file mode 100644 index 00000000..420203ca --- /dev/null +++ b/packages/conversation/src/models/v1/fallback-message/fallback-message.ts @@ -0,0 +1,12 @@ +import { Reason } from '../reason'; + +/** + * Fallback message. Used when original contact message can not be handled. + */ +export interface FallbackMessage { + + /** Optional. The raw fallback message if provided by the channel. */ + raw_message?: string; + /** @see Reason */ + reason?: Reason; +} diff --git a/packages/conversation/src/models/v1/fallback-message/index.ts b/packages/conversation/src/models/v1/fallback-message/index.ts new file mode 100644 index 00000000..1a34b689 --- /dev/null +++ b/packages/conversation/src/models/v1/fallback-message/index.ts @@ -0,0 +1 @@ +export type { FallbackMessage } from './fallback-message'; diff --git a/packages/conversation/src/models/v1/generic-event/generic-event.ts b/packages/conversation/src/models/v1/generic-event/generic-event.ts new file mode 100644 index 00000000..ba798d21 --- /dev/null +++ b/packages/conversation/src/models/v1/generic-event/generic-event.ts @@ -0,0 +1,9 @@ +export interface GenericEvent { + + /** @see GenericEvent */ + generic_event?: GenericEventItem; +} + +export interface GenericEventItem { + payload: object; +} diff --git a/packages/conversation/src/models/v1/generic-event/index.ts b/packages/conversation/src/models/v1/generic-event/index.ts new file mode 100644 index 00000000..c0d2f69a --- /dev/null +++ b/packages/conversation/src/models/v1/generic-event/index.ts @@ -0,0 +1 @@ +export type { GenericEvent, GenericEventItem } from './generic-event'; diff --git a/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/get-channel-profile-conversation-channel.ts b/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/get-channel-profile-conversation-channel.ts new file mode 100644 index 00000000..42d52e3c --- /dev/null +++ b/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/get-channel-profile-conversation-channel.ts @@ -0,0 +1,4 @@ +/** + * The channel. Must be one of the supported channels for this operation. + */ +export type GetChannelProfileConversationChannel = 'MESSENGER' | 'INSTAGRAM' | 'VIBER' | 'LINE'; diff --git a/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/index.ts b/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/index.ts new file mode 100644 index 00000000..6a84b96c --- /dev/null +++ b/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/index.ts @@ -0,0 +1 @@ +export type { GetChannelProfileConversationChannel } from './get-channel-profile-conversation-channel'; diff --git a/packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts b/packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts new file mode 100644 index 00000000..a01ba935 --- /dev/null +++ b/packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts @@ -0,0 +1,12 @@ +import { GetChannelProfileConversationChannel } from '../get-channel-profile-conversation-channel'; +import { Recipient } from '../recipient'; + +export interface GetChannelProfileRequest { + + /** The ID of the app. */ + app_id: string; + /** @see Recipient */ + recipient: Recipient; + /** @see GetChannelProfileConversationChannel */ + channel: GetChannelProfileConversationChannel; +} diff --git a/packages/conversation/src/models/v1/get-channel-profile-request/index.ts b/packages/conversation/src/models/v1/get-channel-profile-request/index.ts new file mode 100644 index 00000000..50f366c9 --- /dev/null +++ b/packages/conversation/src/models/v1/get-channel-profile-request/index.ts @@ -0,0 +1 @@ +export type { GetChannelProfileRequest } from './get-channel-profile-request'; diff --git a/packages/conversation/src/models/v1/get-channel-profile-response/get-channel-profile-response.ts b/packages/conversation/src/models/v1/get-channel-profile-response/get-channel-profile-response.ts new file mode 100644 index 00000000..ec7a8079 --- /dev/null +++ b/packages/conversation/src/models/v1/get-channel-profile-response/get-channel-profile-response.ts @@ -0,0 +1,5 @@ +export interface GetChannelProfileResponse { + + /** The profile name. */ + profile_name?: string; +} diff --git a/packages/conversation/src/models/v1/get-channel-profile-response/index.ts b/packages/conversation/src/models/v1/get-channel-profile-response/index.ts new file mode 100644 index 00000000..51d4cba0 --- /dev/null +++ b/packages/conversation/src/models/v1/get-channel-profile-response/index.ts @@ -0,0 +1 @@ +export type { GetChannelProfileResponse } from './get-channel-profile-response'; diff --git a/packages/conversation/src/models/v1/identified-by/identified-by.ts b/packages/conversation/src/models/v1/identified-by/identified-by.ts new file mode 100644 index 00000000..9246970d --- /dev/null +++ b/packages/conversation/src/models/v1/identified-by/identified-by.ts @@ -0,0 +1,13 @@ +import { ChannelRecipientIdentity } from '../channel-recipient-identity'; + +/** Identifies the recipient of the message. Requires either contact_id or identified_by. If Dispatch Mode is used, only identified_by is allowed. */ +export interface IdentifiedBy { + + /** The identity as specified by the channel. */ + identified_by: IdentifiedByItem; +} +export interface IdentifiedByItem { + + /** @see IdentifiedBy */ + channel_identities?: [ChannelRecipientIdentity]; +} diff --git a/packages/conversation/src/models/v1/identified-by/index.ts b/packages/conversation/src/models/v1/identified-by/index.ts new file mode 100644 index 00000000..5a50af4f --- /dev/null +++ b/packages/conversation/src/models/v1/identified-by/index.ts @@ -0,0 +1 @@ +export type { IdentifiedBy, IdentifiedByItem } from './identified-by'; diff --git a/packages/conversation/src/models/v1/index.ts b/packages/conversation/src/models/v1/index.ts new file mode 100644 index 00000000..27023640 --- /dev/null +++ b/packages/conversation/src/models/v1/index.ts @@ -0,0 +1,99 @@ +export * from './agent'; +export * from './agent-joined-event'; +export * from './agent-left-event'; +export * from './app-create-request'; +export * from './app-event'; +export * from './app-message'; +export * from './app-message-additional-properties'; +export * from './app-message-message'; +export * from './app-response'; +export * from './app-update-request'; +export * from './basic-auth-credential'; +export * from './call-message'; +export * from './callback-settings'; +export * from './card-height'; +export * from './card-message'; +export * from './carousel-message'; +export * from './channel-identities'; +export * from './channel-identity'; +export * from './channel-recipient-identity'; +export * from './choice'; +export * from './choice-message'; +export * from './choice-response-message'; +export * from './client-credentials'; +export * from './comment-reply-event'; +export * from './composing-end-event'; +export * from './composing-event'; +export * from './contact'; +export * from './contact-create-request'; +export * from './contact-id'; +export * from './contact-language'; +export * from './contact-message'; +export * from './conversation'; +export * from './conversation-channel'; +export * from './conversation-channel-credential'; +export * from './conversation-direction'; +export * from './conversation-merge-strategy'; +export * from './conversation-message'; +export * from './conversation-message-injected'; +export * from './conversation-messages-view'; +export * from './conversation-metadata-report-view'; +export * from './conversation-metadata-update-strategy'; +export * from './coordinates'; +export * from './create-conversation-request'; +export * from './dispatch-retention-policy'; +export * from './dispatch-retention-policy-type'; +export * from './fallback-message'; +export * from './generic-event'; +export * from './get-channel-profile-conversation-channel'; +export * from './get-channel-profile-request'; +export * from './get-channel-profile-response'; +export * from './identified-by'; +export * from './kakao-talk-credentials'; +export * from './line-credentials'; +export * from './list-apps-response'; +export * from './list-item'; +export * from './list-message'; +export * from './list-message-message-properties'; +export * from './list-messages-response'; +export * from './list-section'; +export * from './list-webhooks-response'; +export * from './location-message'; +export * from './mms-credentials'; +export * from './media-card-message'; +export * from './media-carousel-message'; +export * from './media-message'; +export * from './merge-contact-request'; +export * from './message-queue'; +export * from './processing-mode'; +export * from './processing-strategy'; +export * from './product'; +export * from './error-detail'; +export * from './query-capability'; +export * from './query-capability-response'; +export * from './queue-stats'; +export * from './rate-limits'; +export * from './reason'; +export * from './recipient'; +export * from './reply-to'; +export * from './retention-policy'; +export * from './runtime-error'; +export * from './send-event-request'; +export * from './send-event-response'; +export * from './send-message-request'; +export * from './send-message-response'; +export * from './smart-conversation'; +export * from './static-bearer-credential'; +export * from './static-token-credential'; +export * from './telegram-credentials'; +export * from './template-message'; +export * from './template-reference'; +export * from './text-message'; +export * from './transcode-message-request'; +export * from './transcode-message-response'; +export * from './url-message'; +export * from './wechat-credentials'; +export * from './webhook'; +export * from './webhook-target-type'; +export * from './webhook-trigger'; +export * from './enums'; diff --git a/packages/conversation/src/models/v1/kakao-talk-credentials/index.ts b/packages/conversation/src/models/v1/kakao-talk-credentials/index.ts new file mode 100644 index 00000000..e2a9c508 --- /dev/null +++ b/packages/conversation/src/models/v1/kakao-talk-credentials/index.ts @@ -0,0 +1 @@ +export type { KakaoTalkCredentials } from './kakao-talk-credentials'; diff --git a/packages/conversation/src/models/v1/kakao-talk-credentials/kakao-talk-credentials.ts b/packages/conversation/src/models/v1/kakao-talk-credentials/kakao-talk-credentials.ts new file mode 100644 index 00000000..3efcd51e --- /dev/null +++ b/packages/conversation/src/models/v1/kakao-talk-credentials/kakao-talk-credentials.ts @@ -0,0 +1,10 @@ +/** + * If you are including the KakaoTalk channel in the `channel_identifier` property, you must include this object. + */ +export interface KakaoTalkCredentials { + + /** KakaoTalk Business Channel ID. */ + kakaotalk_plus_friend_id: string; + /** KakaoTalk Sender Key. */ + kakaotalk_sender_key: string; +} diff --git a/packages/conversation/src/models/v1/line-credentials/index.ts b/packages/conversation/src/models/v1/line-credentials/index.ts new file mode 100644 index 00000000..f9456018 --- /dev/null +++ b/packages/conversation/src/models/v1/line-credentials/index.ts @@ -0,0 +1 @@ +export type { LineCredentials } from './line-credentials'; diff --git a/packages/conversation/src/models/v1/line-credentials/line-credentials.ts b/packages/conversation/src/models/v1/line-credentials/line-credentials.ts new file mode 100644 index 00000000..8b083c64 --- /dev/null +++ b/packages/conversation/src/models/v1/line-credentials/line-credentials.ts @@ -0,0 +1,10 @@ +/** + * If you are including the LINE channel in the `channel_identifier` property, you must include this object. + */ +export interface LineCredentials { + + /** The token for the LINE channel to which you are connecting. */ + token: string; + /** The secret for the LINE channel to which you are connecting. */ + secret: string; +} diff --git a/packages/conversation/src/models/v1/list-apps-response/index.ts b/packages/conversation/src/models/v1/list-apps-response/index.ts new file mode 100644 index 00000000..0b541095 --- /dev/null +++ b/packages/conversation/src/models/v1/list-apps-response/index.ts @@ -0,0 +1 @@ +export type { ListAppsResponse } from './list-apps-response'; diff --git a/packages/conversation/src/models/v1/list-apps-response/list-apps-response.ts b/packages/conversation/src/models/v1/list-apps-response/list-apps-response.ts new file mode 100644 index 00000000..66052179 --- /dev/null +++ b/packages/conversation/src/models/v1/list-apps-response/list-apps-response.ts @@ -0,0 +1,7 @@ +import { AppResponse } from '../app-response'; + +export interface ListAppsResponse { + + /** List of apps belonging to a specific project ID. */ + apps?: AppResponse[]; +} diff --git a/packages/conversation/src/models/v1/list-item/index.ts b/packages/conversation/src/models/v1/list-item/index.ts new file mode 100644 index 00000000..306dbbd8 --- /dev/null +++ b/packages/conversation/src/models/v1/list-item/index.ts @@ -0,0 +1 @@ +export type { ListItem } from './list-item'; diff --git a/packages/conversation/src/models/v1/list-item/list-item.ts b/packages/conversation/src/models/v1/list-item/list-item.ts new file mode 100644 index 00000000..9ce17ea9 --- /dev/null +++ b/packages/conversation/src/models/v1/list-item/list-item.ts @@ -0,0 +1,10 @@ +import { Product } from '../product'; +import { Choice } from '../choice'; + +/** + * Item containing either choiceItem or ProductItem + */ +export interface ListItem { + + item: Choice | Product; +} diff --git a/packages/conversation/src/models/v1/list-message-message-properties/index.ts b/packages/conversation/src/models/v1/list-message-message-properties/index.ts new file mode 100644 index 00000000..b51d58e5 --- /dev/null +++ b/packages/conversation/src/models/v1/list-message-message-properties/index.ts @@ -0,0 +1 @@ +export type { ListMessageMessageProperties } from './list-message-message-properties'; diff --git a/packages/conversation/src/models/v1/list-message-message-properties/list-message-message-properties.ts b/packages/conversation/src/models/v1/list-message-message-properties/list-message-message-properties.ts new file mode 100644 index 00000000..77669523 --- /dev/null +++ b/packages/conversation/src/models/v1/list-message-message-properties/list-message-message-properties.ts @@ -0,0 +1,10 @@ +/** + * Additional properties for the message. Required if sending a product list message. + */ +export interface ListMessageMessageProperties { + + /** Required if sending a product list message. The ID of the catalog to which the products belong. */ + catalog_id?: string; + /** Optional. Sets the text for the menu of a choice list message. */ + menu?: string; +} diff --git a/packages/conversation/src/models/v1/list-message/index.ts b/packages/conversation/src/models/v1/list-message/index.ts new file mode 100644 index 00000000..908b0db3 --- /dev/null +++ b/packages/conversation/src/models/v1/list-message/index.ts @@ -0,0 +1 @@ +export type { ListMessage, ListMessageItem } from './list-message'; diff --git a/packages/conversation/src/models/v1/list-message/list-message.ts b/packages/conversation/src/models/v1/list-message/list-message.ts new file mode 100644 index 00000000..da990167 --- /dev/null +++ b/packages/conversation/src/models/v1/list-message/list-message.ts @@ -0,0 +1,23 @@ +import { ListMessageMessageProperties } from '../list-message-message-properties'; +import { ListSection } from '../list-section'; + +/** + * A message containing a list of options to choose from + */ +export interface ListMessage { + + /** A message containing a list of options to choose from */ + list_message: ListMessageItem; +} + +export interface ListMessageItem { + + /** A title for the message that is displayed near the products or choices. */ + title: string; + /** This is an optional field, containing a description for the message. */ + description?: string; + /** List of ListSection objects containing choices to be presented in the list message. */ + sections: ListSection[]; + /** @see ListMessageMessageProperties */ + message_properties?: ListMessageMessageProperties; +} diff --git a/packages/conversation/src/models/v1/list-messages-response/index.ts b/packages/conversation/src/models/v1/list-messages-response/index.ts new file mode 100644 index 00000000..8d0a46a9 --- /dev/null +++ b/packages/conversation/src/models/v1/list-messages-response/index.ts @@ -0,0 +1 @@ +export type { ListMessagesResponse } from './list-messages-response'; diff --git a/packages/conversation/src/models/v1/list-messages-response/list-messages-response.ts b/packages/conversation/src/models/v1/list-messages-response/list-messages-response.ts new file mode 100644 index 00000000..5a192cb3 --- /dev/null +++ b/packages/conversation/src/models/v1/list-messages-response/list-messages-response.ts @@ -0,0 +1,10 @@ +import { ConversationMessage } from '../conversation-message'; + +export interface ListMessagesResponse { + + /** List of messages associated to the referenced conversation. */ + messages?: ConversationMessage[]; + /** Token that should be included in the next request to fetch the next page. */ + next_page_token?: string; + total_size?: number; +} diff --git a/packages/conversation/src/models/v1/list-section/index.ts b/packages/conversation/src/models/v1/list-section/index.ts new file mode 100644 index 00000000..a48683b8 --- /dev/null +++ b/packages/conversation/src/models/v1/list-section/index.ts @@ -0,0 +1 @@ +export type { ListSection } from './list-section'; diff --git a/packages/conversation/src/models/v1/list-section/list-section.ts b/packages/conversation/src/models/v1/list-section/list-section.ts new file mode 100644 index 00000000..6f6e4562 --- /dev/null +++ b/packages/conversation/src/models/v1/list-section/list-section.ts @@ -0,0 +1,12 @@ +import { ListItem } from '../list-item'; + +/** + * Section for interactive whatsapp messages containing ListItem + */ +export interface ListSection { + + /** Optional parameter. Title for list section. */ + title?: string; + /** List of ListItems */ + items?: ListItem[]; +} diff --git a/packages/conversation/src/models/v1/list-webhooks-response/index.ts b/packages/conversation/src/models/v1/list-webhooks-response/index.ts new file mode 100644 index 00000000..cef029a1 --- /dev/null +++ b/packages/conversation/src/models/v1/list-webhooks-response/index.ts @@ -0,0 +1 @@ +export type { ListWebhooksResponse } from './list-webhooks-response'; diff --git a/packages/conversation/src/models/v1/list-webhooks-response/list-webhooks-response.ts b/packages/conversation/src/models/v1/list-webhooks-response/list-webhooks-response.ts new file mode 100644 index 00000000..ec9151b4 --- /dev/null +++ b/packages/conversation/src/models/v1/list-webhooks-response/list-webhooks-response.ts @@ -0,0 +1,7 @@ +import { Webhook } from '../webhook'; + +export interface ListWebhooksResponse { + + /** List of webhooks belonging to a specific project ID and app ID */ + webhooks?: Webhook[]; +} diff --git a/packages/conversation/src/models/v1/location-message/index.ts b/packages/conversation/src/models/v1/location-message/index.ts new file mode 100644 index 00000000..371df423 --- /dev/null +++ b/packages/conversation/src/models/v1/location-message/index.ts @@ -0,0 +1 @@ +export type { LocationMessage, LocationMessageItem } from './location-message'; diff --git a/packages/conversation/src/models/v1/location-message/location-message.ts b/packages/conversation/src/models/v1/location-message/location-message.ts new file mode 100644 index 00000000..aba8b2a0 --- /dev/null +++ b/packages/conversation/src/models/v1/location-message/location-message.ts @@ -0,0 +1,19 @@ +import { Coordinates } from '../coordinates'; + +/** + * Message containing geographic location. + */ +export interface LocationMessage { + + /** Message containing geographic location. */ + location_message: LocationMessageItem; +} +export interface LocationMessageItem { + + /** @see Coordinates */ + coordinates: Coordinates; + /** Label or name for the position. */ + label?: string; + /** The title is shown close to the button or link that leads to a map showing the location. The title can be clickable in some cases. */ + title: string; +} diff --git a/packages/conversation/src/models/v1/media-card-message/index.ts b/packages/conversation/src/models/v1/media-card-message/index.ts new file mode 100644 index 00000000..d3477b83 --- /dev/null +++ b/packages/conversation/src/models/v1/media-card-message/index.ts @@ -0,0 +1 @@ +export type { MediaCardMessage } from './media-card-message'; diff --git a/packages/conversation/src/models/v1/media-card-message/media-card-message.ts b/packages/conversation/src/models/v1/media-card-message/media-card-message.ts new file mode 100644 index 00000000..4f16d3fd --- /dev/null +++ b/packages/conversation/src/models/v1/media-card-message/media-card-message.ts @@ -0,0 +1,10 @@ +/** + * A message containing a media component, such as an image or video. + */ +export interface MediaCardMessage { + + /** Caption for the media on supported channels. */ + caption?: string; + /** Url to the media file. */ + url: string; +} diff --git a/packages/conversation/src/models/v1/media-carousel-message/index.ts b/packages/conversation/src/models/v1/media-carousel-message/index.ts new file mode 100644 index 00000000..27dda8f4 --- /dev/null +++ b/packages/conversation/src/models/v1/media-carousel-message/index.ts @@ -0,0 +1 @@ +export type { MediaCarouselMessage } from './media-carousel-message'; diff --git a/packages/conversation/src/models/v1/media-carousel-message/media-carousel-message.ts b/packages/conversation/src/models/v1/media-carousel-message/media-carousel-message.ts new file mode 100644 index 00000000..e6c9a975 --- /dev/null +++ b/packages/conversation/src/models/v1/media-carousel-message/media-carousel-message.ts @@ -0,0 +1,8 @@ +/** + * A message containing an image media component. + */ +export interface MediaCarouselMessage { + + /** Url to the media file. */ + url: string; +} diff --git a/packages/conversation/src/models/v1/media-message/index.ts b/packages/conversation/src/models/v1/media-message/index.ts new file mode 100644 index 00000000..e17261bc --- /dev/null +++ b/packages/conversation/src/models/v1/media-message/index.ts @@ -0,0 +1 @@ +export type { MediaMessage, MediaMessageItem } from './media-message'; diff --git a/packages/conversation/src/models/v1/media-message/media-message.ts b/packages/conversation/src/models/v1/media-message/media-message.ts new file mode 100644 index 00000000..9884d92c --- /dev/null +++ b/packages/conversation/src/models/v1/media-message/media-message.ts @@ -0,0 +1,17 @@ +/** + * A message containing a media component, such as an image, document, or video. + */ +export interface MediaMessage { + + /** A message containing a media component, such as an image, document, or video. */ + media_message: MediaMessageItem; +} +export interface MediaMessageItem { + + /** An optional parameter. Will be used where it is natively supported. */ + thumbnail_url?: string; + /** Url to the media file. */ + url: string; + /** Overrides the media file name. */ + filename_override?: string; +} diff --git a/packages/conversation/src/models/v1/merge-contact-request/index.ts b/packages/conversation/src/models/v1/merge-contact-request/index.ts new file mode 100644 index 00000000..3feaab45 --- /dev/null +++ b/packages/conversation/src/models/v1/merge-contact-request/index.ts @@ -0,0 +1 @@ +export type { MergeContactRequest } from './merge-contact-request'; diff --git a/packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts b/packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts new file mode 100644 index 00000000..a374ff10 --- /dev/null +++ b/packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts @@ -0,0 +1,9 @@ +import { ConversationMergeStrategy } from '../conversation-merge-strategy'; + +export interface MergeContactRequest { + + /** Required. The ID of the contact that should be removed. */ + source_id: string; + /** @see ConversationMergeStrategy */ + strategy?: ConversationMergeStrategy; +} diff --git a/packages/conversation/src/models/v1/message-queue/index.ts b/packages/conversation/src/models/v1/message-queue/index.ts new file mode 100644 index 00000000..897648f7 --- /dev/null +++ b/packages/conversation/src/models/v1/message-queue/index.ts @@ -0,0 +1 @@ +export type { MessageQueue } from './message-queue'; diff --git a/packages/conversation/src/models/v1/message-queue/message-queue.ts b/packages/conversation/src/models/v1/message-queue/message-queue.ts new file mode 100644 index 00000000..8c95c9b4 --- /dev/null +++ b/packages/conversation/src/models/v1/message-queue/message-queue.ts @@ -0,0 +1,4 @@ +/** + * Select the priority type for the message + */ +export type MessageQueue = 'NORMAL_PRIORITY' | 'HIGH_PRIORITY'; diff --git a/packages/conversation/src/models/v1/mms-credentials/index.ts b/packages/conversation/src/models/v1/mms-credentials/index.ts new file mode 100644 index 00000000..52b425f6 --- /dev/null +++ b/packages/conversation/src/models/v1/mms-credentials/index.ts @@ -0,0 +1 @@ +export type { MMSCredentials } from './mms-credentials'; diff --git a/packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts b/packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts new file mode 100644 index 00000000..8a55436e --- /dev/null +++ b/packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts @@ -0,0 +1,14 @@ +import { BasicAuthCredential } from '../basic-auth-credential'; + +/** + * If you are including the MMS channel in the `channel_identifier` property, you must include this object. + */ +export interface MMSCredentials { + + /** MMS Account ID. */ + account_id: string; + /** MMS API Key. */ + api_key: string; + /** @see BasicAuthCredential */ + basic_auth?: BasicAuthCredential; +} diff --git a/packages/conversation/src/models/v1/processing-mode/index.ts b/packages/conversation/src/models/v1/processing-mode/index.ts new file mode 100644 index 00000000..723d6bbf --- /dev/null +++ b/packages/conversation/src/models/v1/processing-mode/index.ts @@ -0,0 +1 @@ +export type { ProcessingMode } from './processing-mode'; diff --git a/packages/conversation/src/models/v1/processing-mode/processing-mode.ts b/packages/conversation/src/models/v1/processing-mode/processing-mode.ts new file mode 100644 index 00000000..65f941b6 --- /dev/null +++ b/packages/conversation/src/models/v1/processing-mode/processing-mode.ts @@ -0,0 +1 @@ +export type ProcessingMode = 'CONVERSATION' | 'DISPATCH'; diff --git a/packages/conversation/src/models/v1/processing-strategy/index.ts b/packages/conversation/src/models/v1/processing-strategy/index.ts new file mode 100644 index 00000000..3d72e04f --- /dev/null +++ b/packages/conversation/src/models/v1/processing-strategy/index.ts @@ -0,0 +1 @@ +export type { ProcessingStrategy } from './processing-strategy'; diff --git a/packages/conversation/src/models/v1/processing-strategy/processing-strategy.ts b/packages/conversation/src/models/v1/processing-strategy/processing-strategy.ts new file mode 100644 index 00000000..7efe5c28 --- /dev/null +++ b/packages/conversation/src/models/v1/processing-strategy/processing-strategy.ts @@ -0,0 +1 @@ +export type ProcessingStrategy = 'DEFAULT' | 'DISPATCH_ONLY'; diff --git a/packages/conversation/src/models/v1/product/index.ts b/packages/conversation/src/models/v1/product/index.ts new file mode 100644 index 00000000..a4258086 --- /dev/null +++ b/packages/conversation/src/models/v1/product/index.ts @@ -0,0 +1 @@ +export type { Product } from './product'; diff --git a/packages/conversation/src/models/v1/product/product.ts b/packages/conversation/src/models/v1/product/product.ts new file mode 100644 index 00000000..b6882ccf --- /dev/null +++ b/packages/conversation/src/models/v1/product/product.ts @@ -0,0 +1,22 @@ +/** + * A message component for interactive messages, containing a product. + */ +export interface Product { + + /** A message component for interactive messages, containing a product. */ + product?: ProductItem; +} + +export interface ProductItem { + + /** Required parameter. The ID for the product. */ + id: string; + /** Required parameter. The marketplace to which the product belongs. */ + marketplace: string; + /** Output only. The quantity of the chosen product. */ + quantity?: number; + /** Output only. The price for one unit of the chosen product. */ + item_price?: number; + /** Output only. The currency of the item_price. */ + currency?: string; +} diff --git a/packages/conversation/src/models/v1/query-capability-response/index.ts b/packages/conversation/src/models/v1/query-capability-response/index.ts new file mode 100644 index 00000000..691d5884 --- /dev/null +++ b/packages/conversation/src/models/v1/query-capability-response/index.ts @@ -0,0 +1 @@ +export type { QueryCapabilityResponse } from './query-capability-response'; diff --git a/packages/conversation/src/models/v1/query-capability-response/query-capability-response.ts b/packages/conversation/src/models/v1/query-capability-response/query-capability-response.ts new file mode 100644 index 00000000..b36f7c5b --- /dev/null +++ b/packages/conversation/src/models/v1/query-capability-response/query-capability-response.ts @@ -0,0 +1,14 @@ +import { Recipient } from '../recipient'; + +/** + * An CapabilityResponse contains the identity of the recipient for which will be perform a capability lookup. + */ +export interface QueryCapabilityResponse { + + /** The ID of the app to use for capability lookup. */ + app_id?: string; + /** @see Recipient */ + recipient?: Recipient; + /** ID for the asynchronous response, will be generated if not set. */ + request_id?: string; +} diff --git a/packages/conversation/src/models/v1/query-capability/index.ts b/packages/conversation/src/models/v1/query-capability/index.ts new file mode 100644 index 00000000..71fb2622 --- /dev/null +++ b/packages/conversation/src/models/v1/query-capability/index.ts @@ -0,0 +1 @@ +export type { QueryCapability } from './query-capability'; diff --git a/packages/conversation/src/models/v1/query-capability/query-capability.ts b/packages/conversation/src/models/v1/query-capability/query-capability.ts new file mode 100644 index 00000000..d5f7f2fe --- /dev/null +++ b/packages/conversation/src/models/v1/query-capability/query-capability.ts @@ -0,0 +1,11 @@ +import { Recipient } from '../recipient'; + +export interface QueryCapability { + + /** The ID of the app to use for capability lookup. */ + app_id: string; + /** @see Recipient */ + recipient: Recipient; + /** ID for the asynchronous response, will be generated if not set. Currently this field is not used for idempotency. */ + request_id?: string; +} diff --git a/packages/conversation/src/models/v1/queue-stats/index.ts b/packages/conversation/src/models/v1/queue-stats/index.ts new file mode 100644 index 00000000..b8a2c979 --- /dev/null +++ b/packages/conversation/src/models/v1/queue-stats/index.ts @@ -0,0 +1 @@ +export type { QueueStats } from './queue-stats'; diff --git a/packages/conversation/src/models/v1/queue-stats/queue-stats.ts b/packages/conversation/src/models/v1/queue-stats/queue-stats.ts new file mode 100644 index 00000000..41a51275 --- /dev/null +++ b/packages/conversation/src/models/v1/queue-stats/queue-stats.ts @@ -0,0 +1,7 @@ +export interface QueueStats { + + /** The current size of the App\'s MT queue. */ + outbound_size?: number; + /** The limit of the App\'s MT queue. The default limit is 500000 messages. */ + outbound_limit?: number; +} diff --git a/packages/conversation/src/models/v1/rate-limits/index.ts b/packages/conversation/src/models/v1/rate-limits/index.ts new file mode 100644 index 00000000..8e20d4f8 --- /dev/null +++ b/packages/conversation/src/models/v1/rate-limits/index.ts @@ -0,0 +1 @@ +export type { RateLimits } from './rate-limits'; diff --git a/packages/conversation/src/models/v1/rate-limits/rate-limits.ts b/packages/conversation/src/models/v1/rate-limits/rate-limits.ts new file mode 100644 index 00000000..cd57189e --- /dev/null +++ b/packages/conversation/src/models/v1/rate-limits/rate-limits.ts @@ -0,0 +1,9 @@ +export interface RateLimits { + + /** The number of inbound messages/events we process per second, from underlying channels to the app. The default rate limit is 25. */ + inbound?: number; + /** The number of messages/events we process per second, from the app to the underlying channels. Note that underlying channels may have other rate limits. The default rate limit is 25. */ + outbound?: number; + /** The rate limit of callbacks sent to the webhooks registered for the app. Note that if you have multiple webhooks with shared triggers, multiple callbacks will be sent out for each triggering event. The default rate limit is 25. */ + webhooks?: number; +} diff --git a/packages/conversation/src/models/v1/reason/index.ts b/packages/conversation/src/models/v1/reason/index.ts new file mode 100644 index 00000000..a3017b6c --- /dev/null +++ b/packages/conversation/src/models/v1/reason/index.ts @@ -0,0 +1 @@ +export type { Reason, ReasonCode, ReasonSubCode } from './reason'; diff --git a/packages/conversation/src/models/v1/reason/reason.ts b/packages/conversation/src/models/v1/reason/reason.ts new file mode 100644 index 00000000..ea73407a --- /dev/null +++ b/packages/conversation/src/models/v1/reason/reason.ts @@ -0,0 +1,40 @@ +export interface Reason { + + code?: ReasonCode; + /** A textual description of the reason. */ + description?: string; + sub_code?: ReasonSubCode; +} + +export type ReasonCode = 'UNKNOWN' + | 'INTERNAL_ERROR' + | 'RATE_LIMITED' + | 'RECIPIENT_INVALID_CHANNEL_IDENTITY' + | 'RECIPIENT_NOT_REACHABLE' + | 'RECIPIENT_NOT_OPTED_IN' + | 'OUTSIDE_ALLOWED_SENDING_WINDOW' + | 'CHANNEL_FAILURE' + | 'CHANNEL_BAD_CONFIGURATION' + | 'CHANNEL_CONFIGURATION_MISSING' + | 'MEDIA_TYPE_UNSUPPORTED' + | 'MEDIA_TOO_LARGE' + | 'MEDIA_NOT_REACHABLE' + | 'NO_CHANNELS_LEFT' + | 'TEMPLATE_NOT_FOUND' + | 'TEMPLATE_INSUFFICIENT_PARAMETERS' + | 'TEMPLATE_NON_EXISTING_LANGUAGE_OR_VERSION' + | 'DELIVERY_TIMED_OUT' + | 'DELIVERY_REJECTED_DUE_TO_POLICY' + | 'CONTACT_NOT_FOUND' + | 'BAD_REQUEST' + | 'UNKNOWN_APP' + | 'NO_CHANNEL_IDENTITY_FOR_CONTACT' + | 'CHANNEL_REJECT' + | 'NO_PERMISSION' + | 'NO_PROFILE_AVAILABLE' + | 'UNSUPPORTED_OPERATION'; + +export type ReasonSubCode = 'UNSPECIFIED_SUB_CODE' + | 'ATTACHMENT_REJECTED' + | 'MEDIA_TYPE_UNDETERMINED' + | 'INACTIVE_SENDER'; diff --git a/packages/conversation/src/models/v1/recipient/index.ts b/packages/conversation/src/models/v1/recipient/index.ts new file mode 100644 index 00000000..ef3689f8 --- /dev/null +++ b/packages/conversation/src/models/v1/recipient/index.ts @@ -0,0 +1 @@ +export type { Recipient } from './recipient'; diff --git a/packages/conversation/src/models/v1/recipient/recipient.ts b/packages/conversation/src/models/v1/recipient/recipient.ts new file mode 100644 index 00000000..4dd33512 --- /dev/null +++ b/packages/conversation/src/models/v1/recipient/recipient.ts @@ -0,0 +1,7 @@ +import { ContactId } from '../contact-id'; +import { IdentifiedBy } from '../identified-by'; + +/** + * Identifies the recipient of the message. Requires either `contact_id` or `identified_by`. + */ +export type Recipient = ContactId | IdentifiedBy; diff --git a/packages/conversation/src/models/v1/reply-to/index.ts b/packages/conversation/src/models/v1/reply-to/index.ts new file mode 100644 index 00000000..7cf8a66c --- /dev/null +++ b/packages/conversation/src/models/v1/reply-to/index.ts @@ -0,0 +1 @@ +export type { ReplyTo } from './reply-to'; diff --git a/packages/conversation/src/models/v1/reply-to/reply-to.ts b/packages/conversation/src/models/v1/reply-to/reply-to.ts new file mode 100644 index 00000000..19151f9c --- /dev/null +++ b/packages/conversation/src/models/v1/reply-to/reply-to.ts @@ -0,0 +1,8 @@ +/** + * If the contact message was a response to a previous App message then this field contains information about that. + */ +export interface ReplyTo { + + /** Required. The Id of the message that this is a response to */ + message_id: string; +} diff --git a/packages/conversation/src/models/v1/retention-policy/index.ts b/packages/conversation/src/models/v1/retention-policy/index.ts new file mode 100644 index 00000000..9b7908c7 --- /dev/null +++ b/packages/conversation/src/models/v1/retention-policy/index.ts @@ -0,0 +1 @@ +export type { RetentionPolicy } from './retention-policy'; diff --git a/packages/conversation/src/models/v1/retention-policy/retention-policy.ts b/packages/conversation/src/models/v1/retention-policy/retention-policy.ts new file mode 100644 index 00000000..27efbec5 --- /dev/null +++ b/packages/conversation/src/models/v1/retention-policy/retention-policy.ts @@ -0,0 +1,9 @@ +/** + * The retention policy configured for the app. For more information about retention policies, see [Retention Policy](/docs/conversation/keyconcepts/#retention-policy). + */ +export interface RetentionPolicy { + + retention_type?: 'MESSAGE_EXPIRE_POLICY' | 'CONVERSATION_EXPIRE_POLICY' | 'PERSIST_RETENTION_POLICY'; + /** Optional. The days before a message or conversation is eligible for deletion. Default value is 180. The ttl_days value has no effect when retention_type is `PERSIST_RETENTION_POLICY`. The valid values for this field are [1 - 3650]. Note that retention cleanup job runs once every twenty-four hours which can lead to delay i.e., messages and conversations are not deleted on the minute they become eligible for deletion. */ + ttl_days?: number; +} diff --git a/packages/conversation/src/models/v1/runtime-error/index.ts b/packages/conversation/src/models/v1/runtime-error/index.ts new file mode 100644 index 00000000..207da3c0 --- /dev/null +++ b/packages/conversation/src/models/v1/runtime-error/index.ts @@ -0,0 +1 @@ +export type { RuntimeError } from './runtime-error'; diff --git a/packages/conversation/src/models/v1/runtime-error/runtime-error.ts b/packages/conversation/src/models/v1/runtime-error/runtime-error.ts new file mode 100644 index 00000000..8610cc27 --- /dev/null +++ b/packages/conversation/src/models/v1/runtime-error/runtime-error.ts @@ -0,0 +1,11 @@ +import { ErrorDetail } from '../error-detail'; + +export interface RuntimeError { + + code?: number; + /** List of error details */ + details?: ErrorDetail[]; + error?: string; + message?: string; + status?: string; +} diff --git a/packages/conversation/src/models/v1/send-event-request/index.ts b/packages/conversation/src/models/v1/send-event-request/index.ts new file mode 100644 index 00000000..9548df3c --- /dev/null +++ b/packages/conversation/src/models/v1/send-event-request/index.ts @@ -0,0 +1 @@ +export type { SendEventRequest } from './send-event-request'; diff --git a/packages/conversation/src/models/v1/send-event-request/send-event-request.ts b/packages/conversation/src/models/v1/send-event-request/send-event-request.ts new file mode 100644 index 00000000..b6bd6bf6 --- /dev/null +++ b/packages/conversation/src/models/v1/send-event-request/send-event-request.ts @@ -0,0 +1,22 @@ +import { AppEvent } from '../app-event'; +import { ConversationChannel } from '../conversation-channel'; +import { MessageQueue } from '../message-queue'; +import { Recipient } from '../recipient'; + +export interface SendEventRequest { + + /** The ID of the app sending the event. */ + app_id: string; + /** Overwrites the default callback url for delivery receipts for this message The REST URL should be of the form: `http://host[:port]/path` */ + callback_url?: string; + /** Optional. A single element array that dictates on what channel should the Conversation API try to send the event. It overrides any default set on the contact. Providing more than one option has no effect. */ + channel_priority_order?: ConversationChannel[]; + /** @see AppEvent */ + event: AppEvent; + /** Optional. Eventual metadata that should be associated to the event. */ + event_metadata?: string; + /** @see MessageQueue */ + queue?: MessageQueue; + /** @see Recipient */ + recipient: Recipient; +} diff --git a/packages/conversation/src/models/v1/send-event-response/index.ts b/packages/conversation/src/models/v1/send-event-response/index.ts new file mode 100644 index 00000000..c0b1dafd --- /dev/null +++ b/packages/conversation/src/models/v1/send-event-response/index.ts @@ -0,0 +1 @@ +export type { SendEventResponse } from './send-event-response'; diff --git a/packages/conversation/src/models/v1/send-event-response/send-event-response.ts b/packages/conversation/src/models/v1/send-event-response/send-event-response.ts new file mode 100644 index 00000000..66b7fc65 --- /dev/null +++ b/packages/conversation/src/models/v1/send-event-response/send-event-response.ts @@ -0,0 +1,7 @@ +export interface SendEventResponse { + + /** Accepted timestamp. */ + accepted_time?: Date; + /** Event id. */ + event_id?: string; +} diff --git a/packages/conversation/src/models/v1/send-message-request/index.ts b/packages/conversation/src/models/v1/send-message-request/index.ts new file mode 100644 index 00000000..2012d0b0 --- /dev/null +++ b/packages/conversation/src/models/v1/send-message-request/index.ts @@ -0,0 +1 @@ +export type { SendMessageRequest } from './send-message-request'; diff --git a/packages/conversation/src/models/v1/send-message-request/send-message-request.ts b/packages/conversation/src/models/v1/send-message-request/send-message-request.ts new file mode 100644 index 00000000..a1ebdcbc --- /dev/null +++ b/packages/conversation/src/models/v1/send-message-request/send-message-request.ts @@ -0,0 +1,39 @@ +import { AppMessage } from '../app-message'; +import { ConversationChannel } from '../conversation-channel'; +import { MessageQueue } from '../message-queue'; +import { Recipient } from '../recipient'; +import { ProcessingStrategy } from '../processing-strategy'; +import { ConversationMetadataUpdateStrategy } from '../conversation-metadata-update-strategy'; + +/** + * This is the request body for sending a message. `app_id`, `recipient`, and `message` are all required fields. + */ +export interface SendMessageRequest { + + /** The ID of the app sending the message. */ + app_id: string; + /** Overwrites the default callback url for delivery receipts for this message The REST URL should be of the form: `http://host[:port]/path` */ + callback_url?: string; + /** Explicitly define the channels and order in which they are tried when sending the message. All channels provided in this field must be configured in the corresponding Conversation API app, or the request will be rejected. Which channels the API will try and their priority is defined by: 1. `channel_priority_order` if available. 2. `recipient.identified_by.channel_identities` if available. 3. When recipient is a `contact_id`: - if a conversation with the contact exists: the active channel of the conversation is tried first. - the existing channels for the contact are ordered by contact channel preferences if given. - lastly the existing channels for the contact are ordered by the app priority. */ + channel_priority_order?: ConversationChannel[]; + /** Channel-specific properties. The key in the map must point to a valid channel property key as defined by the enum ChannelPropertyKeys. The maximum allowed property value length is 1024 characters. */ + channel_properties?: { [key: string]: string; }; + /** @see AppMessage */ + message: AppMessage; + /** Metadata that should be associated with the message. Returned in the `metadata` field of a [Message Delivery Receipt](https://developers.sinch.com/docs/conversation/callbacks/#message-delivery-receipt). Up to 1024 characters long. */ + message_metadata?: string; + /** Metadata that should be associated with the conversation. This metadata will be propagated on MO callbacks associated with this conversation. Up to 1024 characters long. Note that the MO callback will always use the last metadata available in the conversation. Important notes: - If you send a message with the `conversation_metadata` field populated, and then send another message without populating the `conversation_metadata` field, the original metadata will continue be propagated on the related MO callbacks. - If you send a message with the `conversation_metadata` field populated, and then send another message with a different value for `conversation_metadata` in the same conversation, the latest metadata value overwrites the existing one. So, future MO callbacks will include the new metadata. - The `conversation_metadata` only accepts json objects. Currently only returned in the `message_metadata` field of an [Inbound Message](/docs/conversation/callbacks/#inbound-message) callback. */ + conversation_metadata?: object; + /** @see MessageQueue */ + queue?: MessageQueue; + /** @see Recipient */ + recipient: Recipient; + /** The timeout allotted for sending the message, expressed in seconds. Passed to channels which support it and emulated by the Conversation API for channels without ttl support but with message retract/unsend functionality. Channel failover will not be performed for messages with an expired TTL. The format is an integer with the suffix `s` (for seconds). Valid integer range is 3 to 315,576,000,000 (inclusive). Example values include `10s` (10 seconds) and `86400s` (24 hours). */ + ttl?: string; + /** Overrides the app\'s [Processing Mode](../../../../../conversation/processing-modes/). Default value is `DEFAULT`. */ + processing_strategy?: ProcessingStrategy; + /** An arbitrary identifier that will be propagated to callbacks related to this message, including MO replies. Only applicable to messages sent with the `CONVERSATION` processing mode. Up to 128 characters long. */ + correlation_id?: string; + /** Update strategy for the `conversation_metadata` field. */ + conversation_metadata_update_strategy?: ConversationMetadataUpdateStrategy; +} diff --git a/packages/conversation/src/models/v1/send-message-response/index.ts b/packages/conversation/src/models/v1/send-message-response/index.ts new file mode 100644 index 00000000..ee6001f7 --- /dev/null +++ b/packages/conversation/src/models/v1/send-message-response/index.ts @@ -0,0 +1 @@ +export type { SendMessageResponse } from './send-message-response'; diff --git a/packages/conversation/src/models/v1/send-message-response/send-message-response.ts b/packages/conversation/src/models/v1/send-message-response/send-message-response.ts new file mode 100644 index 00000000..0c5230b3 --- /dev/null +++ b/packages/conversation/src/models/v1/send-message-response/send-message-response.ts @@ -0,0 +1,7 @@ +export interface SendMessageResponse { + + /** Timestamp when the Conversation API accepted the message for delivery to the referenced contact. */ + accepted_time?: Date; + /** The ID of the message. */ + message_id?: string; +} diff --git a/packages/conversation/src/models/v1/smart-conversation/index.ts b/packages/conversation/src/models/v1/smart-conversation/index.ts new file mode 100644 index 00000000..8e376d8e --- /dev/null +++ b/packages/conversation/src/models/v1/smart-conversation/index.ts @@ -0,0 +1 @@ +export type { SmartConversation } from './smart-conversation'; diff --git a/packages/conversation/src/models/v1/smart-conversation/smart-conversation.ts b/packages/conversation/src/models/v1/smart-conversation/smart-conversation.ts new file mode 100644 index 00000000..7d1b6903 --- /dev/null +++ b/packages/conversation/src/models/v1/smart-conversation/smart-conversation.ts @@ -0,0 +1,8 @@ +/** + * This object is required for apps that subscribe to Smart Conversations features. Note that this functionality is available for open beta testing. + */ +export interface SmartConversation { + + /** Set to true to allow messages processed by this app to be analyzed by Smart Conversations. */ + enabled?: boolean; +} diff --git a/packages/conversation/src/models/v1/static-bearer-credential/index.ts b/packages/conversation/src/models/v1/static-bearer-credential/index.ts new file mode 100644 index 00000000..a4ccb653 --- /dev/null +++ b/packages/conversation/src/models/v1/static-bearer-credential/index.ts @@ -0,0 +1 @@ +export type { StaticBearerCredential } from './static-bearer-credential'; diff --git a/packages/conversation/src/models/v1/static-bearer-credential/static-bearer-credential.ts b/packages/conversation/src/models/v1/static-bearer-credential/static-bearer-credential.ts new file mode 100644 index 00000000..d18037d9 --- /dev/null +++ b/packages/conversation/src/models/v1/static-bearer-credential/static-bearer-credential.ts @@ -0,0 +1,10 @@ +/** + * This object is required for channels which use a bearer-type of credential for authentication. + */ +export interface StaticBearerCredential { + + /** The claimed identity for the channel. */ + claimed_identity: string; + /** The static bearer token for the channel. */ + token: string; +} diff --git a/packages/conversation/src/models/v1/static-token-credential/index.ts b/packages/conversation/src/models/v1/static-token-credential/index.ts new file mode 100644 index 00000000..ae5231c4 --- /dev/null +++ b/packages/conversation/src/models/v1/static-token-credential/index.ts @@ -0,0 +1 @@ +export type { StaticTokenCredential } from './static-token-credential'; diff --git a/packages/conversation/src/models/v1/static-token-credential/static-token-credential.ts b/packages/conversation/src/models/v1/static-token-credential/static-token-credential.ts new file mode 100644 index 00000000..03b258ad --- /dev/null +++ b/packages/conversation/src/models/v1/static-token-credential/static-token-credential.ts @@ -0,0 +1,8 @@ +/** + * This object is required for channels which use a static token credential for authentication. + */ +export interface StaticTokenCredential { + + /** The static token for the channel. */ + token: string; +} diff --git a/packages/conversation/src/models/v1/telegram-credentials/index.ts b/packages/conversation/src/models/v1/telegram-credentials/index.ts new file mode 100644 index 00000000..beaafac8 --- /dev/null +++ b/packages/conversation/src/models/v1/telegram-credentials/index.ts @@ -0,0 +1 @@ +export type { TelegramCredentials } from './telegram-credentials'; diff --git a/packages/conversation/src/models/v1/telegram-credentials/telegram-credentials.ts b/packages/conversation/src/models/v1/telegram-credentials/telegram-credentials.ts new file mode 100644 index 00000000..916b3b27 --- /dev/null +++ b/packages/conversation/src/models/v1/telegram-credentials/telegram-credentials.ts @@ -0,0 +1,8 @@ +/** + * If you are including the Telegram Bot channel in the `channel_identifier` property, you must include this object. + */ +export interface TelegramCredentials { + + /** The token for the Telegram bot to which you are connecting. */ + token: string; +} diff --git a/packages/conversation/src/models/v1/template-message/index.ts b/packages/conversation/src/models/v1/template-message/index.ts new file mode 100644 index 00000000..4d515902 --- /dev/null +++ b/packages/conversation/src/models/v1/template-message/index.ts @@ -0,0 +1 @@ +export type { TemplateMessage, TemplateMessageItem } from './template-message'; diff --git a/packages/conversation/src/models/v1/template-message/template-message.ts b/packages/conversation/src/models/v1/template-message/template-message.ts new file mode 100644 index 00000000..1df48ba1 --- /dev/null +++ b/packages/conversation/src/models/v1/template-message/template-message.ts @@ -0,0 +1,15 @@ +import { TemplateReference } from '../template-reference'; + +export interface TemplateMessage { + + /** */ + template_message: TemplateMessageItem; +} + +export interface TemplateMessageItem { + + /** Optional. Channel specific template reference with parameters per channel. The channel template if exists overrides the omnichannel template. At least one of `channel_template` or `omni_template` needs to be present. The key in the map must point to a valid conversation channel as defined by the enum ConversationChannel. */ + channel_template?: { [key: string]: TemplateReference; }; + /** @see TemplateReference */ + omni_template?: TemplateReference; +} diff --git a/packages/conversation/src/models/v1/template-reference/index.ts b/packages/conversation/src/models/v1/template-reference/index.ts new file mode 100644 index 00000000..aa84882e --- /dev/null +++ b/packages/conversation/src/models/v1/template-reference/index.ts @@ -0,0 +1 @@ +export type { TemplateReference } from './template-reference'; diff --git a/packages/conversation/src/models/v1/template-reference/template-reference.ts b/packages/conversation/src/models/v1/template-reference/template-reference.ts new file mode 100644 index 00000000..b293b9d5 --- /dev/null +++ b/packages/conversation/src/models/v1/template-reference/template-reference.ts @@ -0,0 +1,14 @@ +/** + * The referenced template can be an omnichannel template stored in Conversation API Template Store as AppMessage or it can reference external channel-specific template such as WhatsApp Business Template. + */ +export interface TemplateReference { + + /** The BCP-47 language code, such as `en-US` or `sr-Latn`. For more information, see http://www.unicode.org/reports/tr35/#Unicode_locale_identifier. English is the default language_code. */ + language_code?: string; + /** Required if the template has parameters. Concrete values must be present for all defined parameters in the template. Parameters can be different for different versions and/or languages of the template. */ + parameters?: { [key: string]: string; }; + /** The ID of the template. */ + template_id: string; + /** Used to specify what version of a template to use. This will be used in conjunction with `language_code`. */ + version: string; +} diff --git a/packages/conversation/src/models/v1/text-message/index.ts b/packages/conversation/src/models/v1/text-message/index.ts new file mode 100644 index 00000000..cc92096a --- /dev/null +++ b/packages/conversation/src/models/v1/text-message/index.ts @@ -0,0 +1 @@ +export type { TextMessage, TextMessageItem } from './text-message'; diff --git a/packages/conversation/src/models/v1/text-message/text-message.ts b/packages/conversation/src/models/v1/text-message/text-message.ts new file mode 100644 index 00000000..e45984bd --- /dev/null +++ b/packages/conversation/src/models/v1/text-message/text-message.ts @@ -0,0 +1,14 @@ +/** + * A message containing only text. + */ +export interface TextMessage { + + /** A message containing only text. */ + text_message: TextMessageItem; +} + +export interface TextMessageItem { + + /** The text to be sent. */ + text: string; +} diff --git a/packages/conversation/src/models/v1/transcode-message-request/index.ts b/packages/conversation/src/models/v1/transcode-message-request/index.ts new file mode 100644 index 00000000..6fd815d7 --- /dev/null +++ b/packages/conversation/src/models/v1/transcode-message-request/index.ts @@ -0,0 +1 @@ +export type { TranscodeMessageRequest } from './transcode-message-request'; diff --git a/packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts b/packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts new file mode 100644 index 00000000..159b15a9 --- /dev/null +++ b/packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts @@ -0,0 +1,16 @@ +import { AppMessage } from '../app-message'; +import { ConversationChannel } from '../conversation-channel'; + +export interface TranscodeMessageRequest { + + /** The ID of the app used to transcode the message. */ + app_id: string; + /** @see AppMessage */ + app_message: AppMessage; + /** The list of channels for which the message shall be transcoded to. */ + channels: ConversationChannel[]; + /** Optional. */ + from?: string; + /** Optional. */ + to?: string; +} diff --git a/packages/conversation/src/models/v1/transcode-message-response/index.ts b/packages/conversation/src/models/v1/transcode-message-response/index.ts new file mode 100644 index 00000000..b09c2260 --- /dev/null +++ b/packages/conversation/src/models/v1/transcode-message-response/index.ts @@ -0,0 +1 @@ +export type { TranscodeMessageResponse } from './transcode-message-response'; diff --git a/packages/conversation/src/models/v1/transcode-message-response/transcode-message-response.ts b/packages/conversation/src/models/v1/transcode-message-response/transcode-message-response.ts new file mode 100644 index 00000000..fb8b679f --- /dev/null +++ b/packages/conversation/src/models/v1/transcode-message-response/transcode-message-response.ts @@ -0,0 +1,5 @@ +export interface TranscodeMessageResponse { + + /** The transcoded message for the different channels. The keys in the map correspond to channel names, as defined by the type ConversationChannel. */ + transcoded_message?: { [key: string]: string; }; +} diff --git a/packages/conversation/src/models/v1/url-message/index.ts b/packages/conversation/src/models/v1/url-message/index.ts new file mode 100644 index 00000000..bcca7df2 --- /dev/null +++ b/packages/conversation/src/models/v1/url-message/index.ts @@ -0,0 +1 @@ +export type { UrlMessage } from './url-message'; diff --git a/packages/conversation/src/models/v1/url-message/url-message.ts b/packages/conversation/src/models/v1/url-message/url-message.ts new file mode 100644 index 00000000..3fb79008 --- /dev/null +++ b/packages/conversation/src/models/v1/url-message/url-message.ts @@ -0,0 +1,10 @@ +/** + * A generic URL message. + */ +export interface UrlMessage { + + /** The title shown close to the URL. The title can be clickable in some cases. */ + title: string; + /** The url to show. */ + url: string; +} diff --git a/packages/conversation/src/models/v1/webhook-target-type/index.ts b/packages/conversation/src/models/v1/webhook-target-type/index.ts new file mode 100644 index 00000000..feb0b26d --- /dev/null +++ b/packages/conversation/src/models/v1/webhook-target-type/index.ts @@ -0,0 +1 @@ +export type { WebhookTargetType } from './webhook-target-type'; diff --git a/packages/conversation/src/models/v1/webhook-target-type/webhook-target-type.ts b/packages/conversation/src/models/v1/webhook-target-type/webhook-target-type.ts new file mode 100644 index 00000000..661eff6f --- /dev/null +++ b/packages/conversation/src/models/v1/webhook-target-type/webhook-target-type.ts @@ -0,0 +1 @@ +export type WebhookTargetType = 'DISMISS' | 'HTTP'; diff --git a/packages/conversation/src/models/v1/webhook-trigger/index.ts b/packages/conversation/src/models/v1/webhook-trigger/index.ts new file mode 100644 index 00000000..dee7d814 --- /dev/null +++ b/packages/conversation/src/models/v1/webhook-trigger/index.ts @@ -0,0 +1 @@ +export type { WebhookTrigger } from './webhook-trigger'; diff --git a/packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts b/packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts new file mode 100644 index 00000000..13252102 --- /dev/null +++ b/packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts @@ -0,0 +1,35 @@ +/** + * - `UNSPECIFIED_TRIGGER`: Using this value will cause errors. + * - `MESSAGE_DELIVERY`: Subscribe to delivery receipts for a message sent. + * - `EVENT_DELIVERY`: Subscribe to delivery receipts for a event sent. + * - `MESSAGE_INBOUND`: Subscribe to inbound messages from end users on the underlying channels. + * - `EVENT_INBOUND`: Subscribe to inbound events from end users on the underlying channels. + * - `CONVERSATION_START`: Subscribe to an event that is triggered when a new conversation has been started. + * - `CONVERSATION_STOP`: Subscribe to an event that is triggered when a active conversation has been stopped. + * - `CONTACT_CREATE`: Subscribe to an event that is triggered when a new contact has been created. + * - `CONTACT_DELETE`: Subscribe to an event that is triggered when a contact has been deleted. + * - `CONTACT_MERGE`: Subscribe to an event that is triggered when a two contacts are merged. + * - `CONTACT_UPDATE`: Subscribe to an event that is triggered when a contact is updated. + * - `UNSUPPORTED`: Subscribe to callbacks that are not natively supported by the Conversation API. + * - `OPT_IN`: Subscribe to opt_ins. - `OPT_OUT`: Subscribe to opt_outs. + * - `CAPABILITY`: Subscribe to see get capability results. + * - `CONVERSATION_DELETE`: Subscribe to get an event when a conversation is deleted. + * - `CONTACT_IDENTITIES_DUPLICATION`: Subscribe to get an event when contact identity duplications are found during message or event processing. + */ +export type WebhookTrigger = 'UNSPECIFIED_TRIGGER' + | 'MESSAGE_DELIVERY' + | 'EVENT_DELIVERY' + | 'MESSAGE_INBOUND' + | 'EVENT_INBOUND' + | 'CONVERSATION_START' + | 'CONVERSATION_STOP' + | 'CONTACT_CREATE' + | 'CONTACT_DELETE' + | 'CONTACT_MERGE' + | 'CONTACT_UPDATE' + | 'UNSUPPORTED' + | 'OPT_IN' + | 'OPT_OUT' + | 'CAPABILITY' + | 'CONVERSATION_DELETE' + | 'CONTACT_IDENTITIES_DUPLICATION'; diff --git a/packages/conversation/src/models/v1/webhook/index.ts b/packages/conversation/src/models/v1/webhook/index.ts new file mode 100644 index 00000000..54c42503 --- /dev/null +++ b/packages/conversation/src/models/v1/webhook/index.ts @@ -0,0 +1 @@ +export type { Webhook } from './webhook'; diff --git a/packages/conversation/src/models/v1/webhook/webhook.ts b/packages/conversation/src/models/v1/webhook/webhook.ts new file mode 100644 index 00000000..458b33c3 --- /dev/null +++ b/packages/conversation/src/models/v1/webhook/webhook.ts @@ -0,0 +1,24 @@ +import { ClientCredentials } from '../client-credentials'; +import { WebhookTargetType } from '../webhook-target-type'; +import { WebhookTrigger } from '../webhook-trigger'; + +/** + * Represents a destination for receiving callbacks from the Conversation API. + */ +export interface Webhook { + + /** The app that this webhook belongs to. */ + app_id: string; + /** @see ClientCredentials */ + client_credentials?: ClientCredentials; + /** The ID of the webhook. */ + id?: string; + /** Optional secret be used to sign contents of webhooks sent by the Conversation API. You can then use the secret to verify the signature. */ + secret?: string; + /** The target url where events should be sent to. Maximum URL length is 742. The conversation-api.*.sinch.com subdomains are forbidden. */ + target: string; + /** @see WebhookTargetType */ + target_type?: WebhookTargetType; + /** An array of triggers that should trigger the webhook and result in an event being sent to the target url. Refer to the list of [Webhook Triggers](/docs/conversation/callbacks#webhook-triggers) for a complete list. */ + triggers: WebhookTrigger[]; +} diff --git a/packages/conversation/src/models/v1/wechat-credentials/index.ts b/packages/conversation/src/models/v1/wechat-credentials/index.ts new file mode 100644 index 00000000..0bf66303 --- /dev/null +++ b/packages/conversation/src/models/v1/wechat-credentials/index.ts @@ -0,0 +1 @@ +export type { WeChatCredentials } from './wechat-credentials'; diff --git a/packages/conversation/src/models/v1/wechat-credentials/wechat-credentials.ts b/packages/conversation/src/models/v1/wechat-credentials/wechat-credentials.ts new file mode 100644 index 00000000..a2e19961 --- /dev/null +++ b/packages/conversation/src/models/v1/wechat-credentials/wechat-credentials.ts @@ -0,0 +1,14 @@ +/** + * If you are including the WeChat channel in the `channel_identifier` property, you must include this object. + */ +export interface WeChatCredentials { + + /** The AppID(Developer ID) for the WeChat channel to which you are connecting. */ + app_id: string; + /** The AppSecret(Developer Password) for the WeChat channel to which you are connecting. */ + app_secret: string; + /** The Token for the WeChat channel to which you are connecting. */ + token: string; + /** The Encoding AES Key for the WeChat channel to which you are connecting. */ + aes_key: string; +} diff --git a/packages/conversation/src/rest/index.ts b/packages/conversation/src/rest/index.ts new file mode 100644 index 00000000..5b98253d --- /dev/null +++ b/packages/conversation/src/rest/index.ts @@ -0,0 +1 @@ +export * from './v1'; diff --git a/packages/conversation/src/rest/v1/app/app-api.jest.fixture.ts b/packages/conversation/src/rest/v1/app/app-api.jest.fixture.ts new file mode 100644 index 00000000..f9d80dde --- /dev/null +++ b/packages/conversation/src/rest/v1/app/app-api.jest.fixture.ts @@ -0,0 +1,28 @@ +import { AppResponse } from '../../../models'; +import { ListAppsResponse } from '../../../models'; +import { AppApi, CreateAppRequestData, DeleteAppRequestData, GetAppRequestData, ListAppsRequestData, UpdateAppRequestData } from './app-api'; + +export class AppApiFixture implements Partial> { + + /** + * Fixture associated to function createApp + */ + public create: jest.Mock, [CreateAppRequestData]> = jest.fn(); + /** + * Fixture associated to function deleteApp + */ + public delete: jest.Mock, [DeleteAppRequestData]> = jest.fn(); + /** + * Fixture associated to function getApp + */ + public get: jest.Mock, [GetAppRequestData]> = jest.fn(); + /** + * Fixture associated to function listApps + */ + public list: jest.Mock, [ListAppsRequestData]> = jest.fn(); + /** + * Fixture associated to function updateApp + */ + public update: jest.Mock, [UpdateAppRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/app/app-api.ts b/packages/conversation/src/rest/v1/app/app-api.ts new file mode 100644 index 00000000..91464a59 --- /dev/null +++ b/packages/conversation/src/rest/v1/app/app-api.ts @@ -0,0 +1,189 @@ +import { + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + AppCreateRequest, + AppResponse, + AppUpdateRequest, + ListAppsResponse, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface CreateAppRequestData { + /** The app to create. */ + 'appCreateRequestBody': AppCreateRequest; +} +export interface DeleteAppRequestData { + /** The unique ID of the app. You can find this on the [Sinch Dashboard](https://dashboard.sinch.com/convapi/apps). */ + 'app_id': string; +} +export interface GetAppRequestData { + /** The unique ID of the app. You can find this on the [Sinch Dashboard](https://dashboard.sinch.com/convapi/apps). */ + 'app_id': string; +} +export interface ListAppsRequestData { +} +export interface UpdateAppRequestData { + /** The unique ID of the app. You can find this on the [Sinch Dashboard](https://dashboard.sinch.com/convapi/apps). */ + 'app_id': string; + /** The updated app. */ + 'appUpdateRequestBody': AppUpdateRequest; + /** The set of field mask paths. */ + 'update_mask'?: Array; +} + +export class AppApi extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'AppApi'); + } + + /** + * Create an app + * You can create a new Conversation API app using the API. You can create an app for one or more channels at once. The ID of the app is generated at creation and will be returned in the response. + * @param { CreateAppRequestData } data - The data to provide to the API call. + */ + public async create(data: CreateAppRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = data['appCreateRequestBody'] ? JSON.stringify(data['appCreateRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/apps`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'CreateApp', + }); + } + + /** + * Delete an app + * Deletes the app specified by the App ID. Note that this operation will not delete contacts (which are stored at the project level) nor any channel-specific resources (for example, WhatsApp Sender Identities will not be deleted). + * @param { DeleteAppRequestData } data - The data to provide to the API call. + */ + public async delete(data: DeleteAppRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/apps/${data['app_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'DeleteApp', + }); + } + + /** + * Get an app + * Returns a particular app as specified by the App ID. + * @param { GetAppRequestData } data - The data to provide to the API call. + */ + public async get(data: GetAppRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/apps/${data['app_id']}`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'GetApp', + }); + } + + /** + * List all apps for a given project + * Get a list of all apps in the specified project. + * @param { ListAppsRequestData } data - The data to provide to the API call. + */ + public async list(data: ListAppsRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/apps`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'ListApps', + }); + } + + /** + * Update an app + * Updates a particular app as specified by the App ID. Note that this is a `PATCH` operation, so any specified field values will replace existing values. Therefore, **if you\'d like to add additional configurations to an existing Conversation API app, ensure that you include existing values AND new values in the call**. For example, if you\'d like to add new `channel_credentials`, you can [get](/docs/conversation/api-reference/conversation/tag/App/#tag/App/operation/App_GetApp) your existing Conversation API app, extract the existing `channel_credentials` list, append your new configuration to that list, and include the updated `channel_credentials` list in this update call. + * @param { UpdateAppRequestData } data - The data to provide to the API call. + */ + public async update(data: UpdateAppRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, ['update_mask']); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = data['appUpdateRequestBody'] ? JSON.stringify(data['appUpdateRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/apps/${data['app_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'PATCH', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams, false, ','); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'UpdateApp', + }); + } + +} diff --git a/packages/conversation/src/rest/v1/app/index.ts b/packages/conversation/src/rest/v1/app/index.ts new file mode 100644 index 00000000..a5a85191 --- /dev/null +++ b/packages/conversation/src/rest/v1/app/index.ts @@ -0,0 +1,2 @@ +export * from './app-api'; +export * from './app-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts b/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts new file mode 100644 index 00000000..4ebaaad8 --- /dev/null +++ b/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts @@ -0,0 +1,11 @@ +import { QueryCapabilityResponse } from '../../../models'; +import { CapabilityApi, QueryCapabilityRequestData } from './capability-api'; + +export class CapabilityApiFixture implements Partial> { + + /** + * Fixture associated to function queryCapability + */ + public queryCapability: jest.Mock, [QueryCapabilityRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/capability/capability-api.ts b/packages/conversation/src/rest/v1/capability/capability-api.ts new file mode 100644 index 00000000..b8825c79 --- /dev/null +++ b/packages/conversation/src/rest/v1/capability/capability-api.ts @@ -0,0 +1,55 @@ +import { + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + QueryCapability, + QueryCapabilityResponse, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface QueryCapabilityRequestData { + /** The query capability request. */ + 'queryCapabilityBody': QueryCapability; +} + +export class CapabilityApi extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'CapabilityApi'); + } + + /** + * Capability lookup + * This method is asynchronous - it immediately returns the requested Capability registration. Capability check is then delivered as a callback to registered webhooks with trigger CAPABILITY for every reachable channel. + * @param { QueryCapabilityRequestData } data - The data to provide to the API call. + */ + public async queryCapability(data: QueryCapabilityRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = data['queryCapabilityBody'] ? JSON.stringify(data['queryCapabilityBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/capability:query`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'QueryCapability', + }); + } + +} diff --git a/packages/conversation/src/rest/v1/capability/index.ts b/packages/conversation/src/rest/v1/capability/index.ts new file mode 100644 index 00000000..094e9e90 --- /dev/null +++ b/packages/conversation/src/rest/v1/capability/index.ts @@ -0,0 +1,2 @@ +export * from './capability-api'; +export * from './capability-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/contact/contact-api.jest.fixture.ts b/packages/conversation/src/rest/v1/contact/contact-api.jest.fixture.ts new file mode 100644 index 00000000..b2880ae1 --- /dev/null +++ b/packages/conversation/src/rest/v1/contact/contact-api.jest.fixture.ts @@ -0,0 +1,37 @@ +import { Contact } from '../../../models'; +import { GetChannelProfileResponse } from '../../../models'; +import { ContactApi, CreateContactRequestData, DeleteContactRequestData, GetChannelProfileRequestData, GetContactRequestData, ListContactsRequestData, MergeContactRequestData, UpdateContactRequestData } from './contact-api'; +import { ApiListPromise } from '@sinch/sdk-client'; + +export class ContactApiFixture implements Partial> { + + /** + * Fixture associated to function createContact + */ + public createContact: jest.Mock, [CreateContactRequestData]> = jest.fn(); + /** + * Fixture associated to function deleteContact + */ + public deleteContact: jest.Mock, [DeleteContactRequestData]> = jest.fn(); + /** + * Fixture associated to function getChannelProfile + */ + public getChannelProfile: jest.Mock, [GetChannelProfileRequestData]> = jest.fn(); + /** + * Fixture associated to function getContact + */ + public getContact: jest.Mock, [GetContactRequestData]> = jest.fn(); + /** + * Fixture associated to function listContacts + */ + public listContacts: jest.Mock, [ListContactsRequestData]> = jest.fn(); + /** + * Fixture associated to function mergeContact + */ + public mergeContact: jest.Mock, [MergeContactRequestData]> = jest.fn(); + /** + * Fixture associated to function updateContact + */ + public updateContact: jest.Mock, [UpdateContactRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/contact/contact-api.ts b/packages/conversation/src/rest/v1/contact/contact-api.ts new file mode 100644 index 00000000..ac8b10ff --- /dev/null +++ b/packages/conversation/src/rest/v1/contact/contact-api.ts @@ -0,0 +1,284 @@ +import { + ApiListPromise, + buildPageResultPromise, + createIteratorMethodsForPagination, + PaginatedApiProperties, + PaginationEnum, + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + Contact, + ContactCreateRequest, + ConversationChannel, + GetChannelProfileRequest, + GetChannelProfileResponse, + MergeContactRequest, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface CreateContactRequestData { + /** The contact to create. */ + 'contactCreateRequestBody': ContactCreateRequest; +} +export interface DeleteContactRequestData { + /** The unique ID of the contact. */ + 'contact_id': string; +} +export interface GetChannelProfileRequestData { + /** */ + 'getChannelProfileRequestBody': GetChannelProfileRequest; +} +export interface GetContactRequestData { + /** The unique ID of the contact. */ + 'contact_id': string; +} +export interface ListContactsRequestData { + /** Optional. The maximum number of contacts to fetch. The default is 10 and the maximum is 20. */ + 'page_size'?: number; + /** Optional. Next page token previously returned if any. */ + 'page_token'?: string; + /** Optional. Contact identifier in an external system. If used, `channel` and `identity` query parameters can\'t be used. */ + 'external_id'?: string; + /** Optional. Specifies a channel, and must be set to one of the enum values. If set, the `identity` parameter must be set and `external_id` can\'t be used. Used in conjunction with `identity` to uniquely identify the specified channel identity. */ + 'channel'?: ConversationChannel; + /** Optional. If set, the `channel` parameter must be set and `external_id` can\'t be used. Used in conjunction with `channel` to uniquely identify the specified channel identity. This will differ from channel to channel. For example, a phone number for SMS, WhatsApp, and Viber Business. */ + 'identity'?: string; +} +export interface MergeContactRequestData { + /** The unique ID of the contact that should be kept when merging two contacts. */ + 'destination_id': string; + /** The contact to be removed. */ + 'mergeContactRequestBody': MergeContactRequest; +} +export interface UpdateContactRequestData { + /** The unique ID of the contact. */ + 'contact_id': string; + /** The updated contact. */ + 'contactBody': Contact; + /** The set of field mask paths. */ + 'update_mask.paths'?: Array; +} + +export class ContactApi extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'ContactApi'); + } + + /** + * Create a Contact + * Most Conversation API contacts are [created automatically](/docs/conversation/contact-management/) when a message is sent to a new recipient. You can also create a new contact manually using this API call. + * @param { CreateContactRequestData } data - The data to provide to the API call. + */ + public async createContact(data: CreateContactRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody + = data['contactCreateRequestBody'] ? JSON.stringify(data['contactCreateRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'CreateContact', + }); + } + + /** + * Delete a Contact + * Delete a contact as specified by the contact ID. + * @param { DeleteContactRequestData } data - The data to provide to the API call. + */ + public async deleteContact(data: DeleteContactRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts/${data['contact_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'DeleteContact', + }); + } + + /** + * Get Channel Profile + * Get user profile from a specific channel. Only supported on `MESSENGER`, `INSTAGRAM`, `VIBER` and `LINE` channels. Note that, in order to retrieve a WhatsApp display name, you can use the Get a Contact or List Contacts operations, which will populate the `display_name` field of each returned contact with the WhatsApp display name (if the name is already stored on the server and the `display_name` field has not been overwritten by the user). + * @param { GetChannelProfileRequestData } data - The data to provide to the API call. + */ + public async getChannelProfile(data: GetChannelProfileRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody + = data['getChannelProfileRequestBody'] ? JSON.stringify(data['getChannelProfileRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts:getChannelProfile`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'GetChannelProfile', + }); + } + + /** + * Get a Contact + * Returns a specific contact as specified by the contact ID. Note that, if a WhatsApp contact is returned, the `display_name` field of that contact may be populated with the WhatsApp display name (if the name is already stored on the server and the `display_name` field has not been overwritten by the user). + * @param { GetContactRequestData } data - The data to provide to the API call. + */ + public async getContact(data: GetContactRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts/${data['contact_id']}`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'GetContact', + }); + } + + /** + * List Contacts + * List all contacts in the project. Note that, if a WhatsApp contact is returned, the `display_name` field of that contact may be populated with the WhatsApp display name (if the name is already stored on the server and the `display_name` field has not been overwritten by the user). + * @param { ListContactsRequestData } data - The data to provide to the API call. + * @return {ApiListPromise} + */ + public listContacts(data: ListContactsRequestData): ApiListPromise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams( + data, + ['page_size', 'page_token', 'external_id', 'channel', 'identity']); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts`; + + const requestOptionsPromise = this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + + const operationProperties: PaginatedApiProperties = { + pagination: PaginationEnum.TOKEN, + apiName: this.apiName, + operationId: 'ListContacts', + dataKey: 'contacts', + }; + + // Create the promise containing the response wrapped as a PageResult + const listPromise = buildPageResultPromise( + this.client, + requestOptionsPromise, + operationProperties); + + // Add properties to the Promise to offer the possibility to use it as an iterator + Object.assign( + listPromise, + createIteratorMethodsForPagination( + this.client, requestOptionsPromise, listPromise, operationProperties), + ); + + return listPromise as ApiListPromise; + } + + /** + * Merge two Contacts + * The remaining contact will contain all conversations that the removed contact did. If both contacts had conversations within the same App, messages from the removed contact will be merged into corresponding active conversations in the destination contact. Channel identities will be moved from the source contact to the destination contact only for channels that weren\'t present there before. Moved channel identities will be placed at the bottom of the channel priority list. Optional fields from the source contact will be copied only if corresponding fields in the destination contact are empty The contact being removed cannot be referenced after this call. + * @param { MergeContactRequestData } data - The data to provide to the API call. + */ + public async mergeContact(data: MergeContactRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = data['mergeContactRequestBody'] ? JSON.stringify(data['mergeContactRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts/${data['destination_id']}:merge`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'MergeContact', + }); + } + + /** + * Update a Contact + * Updates a contact as specified by the contact ID. + * @param { UpdateContactRequestData } data - The data to provide to the API call. + */ + public async updateContact(data: UpdateContactRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, ['update_mask.paths']); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = data['contactBody'] ? JSON.stringify(data['contactBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts/${data['contact_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'PATCH', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'UpdateContact', + }); + } + +} diff --git a/packages/conversation/src/rest/v1/contact/index.ts b/packages/conversation/src/rest/v1/contact/index.ts new file mode 100644 index 00000000..48704c7f --- /dev/null +++ b/packages/conversation/src/rest/v1/contact/index.ts @@ -0,0 +1,2 @@ +export * from './contact-api'; +export * from './contact-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/conversation-domain-api.ts b/packages/conversation/src/rest/v1/conversation-domain-api.ts new file mode 100644 index 00000000..b88aac96 --- /dev/null +++ b/packages/conversation/src/rest/v1/conversation-domain-api.ts @@ -0,0 +1,81 @@ +import { + Api, + ApiClient, + ApiClientOptions, + ApiFetchClient, + SinchClientParameters, + Oauth2TokenRequest, + UnifiedCredentials, +} from '@sinch/sdk-client'; + +export class ConversationDomainApi implements Api { + public readonly apiName: string; + public client?: ApiClient; + private sinchClientParameters: SinchClientParameters; + + constructor(sinchClientParameters: SinchClientParameters, apiName: string) { + this.sinchClientParameters = sinchClientParameters; + this.apiName = apiName; + } + + /** + * Update the default basePath for the API + * @param {string} basePath - The new base path to use for the APIs. + */ + public setBasePath(basePath: string) { + this.client = this.getSinchClient(); + this.client.apiClientOptions.basePath = basePath; + } + + /** + * Updates the credentials used to authenticate API requests + * @param {UnifiedCredentials} credentials + */ + public setCredentials(credentials: UnifiedCredentials) { + const parametersBackup = { ...this.sinchClientParameters }; + this.sinchClientParameters = { + ...parametersBackup, + ...credentials, + }; + this.resetApiClient(); + try { + this.getSinchClient(); + } catch (error) { + console.error('Impossible to assign the new credentials to the Conversation API'); + this.sinchClientParameters = parametersBackup; + throw error; + } + } + + private resetApiClient() { + this.client = undefined; + } + + /** + * Checks the configuration parameters are ok and initialize the API client. Once initialized, the same instance will + * be returned for the subsequent API calls (singleton pattern) + * @return {ApiClient} the API Client or throws an error in case the configuration parameters are not ok + * @private + */ + public getSinchClient(): ApiClient { + if (!this.client) { + const apiClientOptions = this.buildApiClientOptions(this.sinchClientParameters); + this.client = new ApiFetchClient(apiClientOptions); + this.client.apiClientOptions.basePath = 'https://us.conversation.api.sinch.com'; + } + return this.client; + } + + private buildApiClientOptions(params: SinchClientParameters): ApiClientOptions { + if (!params.projectId || !params.keyId || !params.keySecret) { + throw new Error('Invalid configuration for the Conversation API: ' + + '"projectId", "keyId" and "keySecret" values must be provided'); + } + return { + projectId: params.projectId, + requestPlugins: [new Oauth2TokenRequest( params.keyId, params.keySecret)], + useServicePlanId: false, + }; + } + +} diff --git a/packages/conversation/src/rest/v1/conversation-domain.ts b/packages/conversation/src/rest/v1/conversation-domain.ts new file mode 100644 index 00000000..55914537 --- /dev/null +++ b/packages/conversation/src/rest/v1/conversation-domain.ts @@ -0,0 +1,47 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { ContactApi } from './contact'; +import { AppApi } from './app'; +import { EventsApi } from './events'; +import { MessagesApi } from './messages'; +import { TranscodingApi } from './transcoding'; +import { CapabilityApi } from './capability'; +import { ConversationApi } from './conversation'; +import { WebhooksApi } from './webhooks'; + +export class ConversationDomain { + public readonly contact: ContactApi; + public readonly app: AppApi; + public readonly events: EventsApi; + public readonly messages: MessagesApi; + public readonly transcoding: TranscodingApi; + public readonly capability: CapabilityApi; + public readonly conversation: ConversationApi; + public readonly webhooks: WebhooksApi; + + constructor(params: SinchClientParameters) { + this.contact = new ContactApi(params); + this.app = new AppApi(params); + this.events = new EventsApi(params); + this.messages = new MessagesApi(params); + this.transcoding = new TranscodingApi(params); + this.capability = new CapabilityApi(params); + this.conversation = new ConversationApi(params); + this.webhooks = new WebhooksApi(params); + } + + /** + * Update the default basePath for each API + * + * @param {string} basePath - The new base path to use for all the APIs. + */ + public setBasePath(basePath: string) { + this.contact.setBasePath(basePath); + this.app.setBasePath(basePath); + this.events.setBasePath(basePath); + this.messages.setBasePath(basePath); + this.transcoding.setBasePath(basePath); + this.capability.setBasePath(basePath); + this.conversation.setBasePath(basePath); + this.webhooks.setBasePath(basePath); + } +} diff --git a/packages/conversation/src/rest/v1/conversation/conversation-api.jest.fixture.ts b/packages/conversation/src/rest/v1/conversation/conversation-api.jest.fixture.ts new file mode 100644 index 00000000..9c17b433 --- /dev/null +++ b/packages/conversation/src/rest/v1/conversation/conversation-api.jest.fixture.ts @@ -0,0 +1,36 @@ +import { Conversation } from '../../../models'; +import { ConversationApi, CreateConversationRequestData, DeleteConversationRequestData, GetConversationRequestData, InjectMessageRequestData, ListConversationsRequestData, StopActiveConversationRequestData, UpdateConversationRequestData } from './conversation-api'; +import { ApiListPromise } from '@sinch/sdk-client'; + +export class ConversationApiFixture implements Partial> { + + /** + * Fixture associated to function createConversation + */ + public createConversation: jest.Mock, [CreateConversationRequestData]> = jest.fn(); + /** + * Fixture associated to function deleteConversation + */ + public deleteConversation: jest.Mock, [DeleteConversationRequestData]> = jest.fn(); + /** + * Fixture associated to function getConversation + */ + public getConversation: jest.Mock, [GetConversationRequestData]> = jest.fn(); + /** + * Fixture associated to function injectMessage + */ + public injectMessage: jest.Mock, [InjectMessageRequestData]> = jest.fn(); + /** + * Fixture associated to function listConversations + */ + public listConversations: jest.Mock, [ListConversationsRequestData]> = jest.fn(); + /** + * Fixture associated to function stopActiveConversation + */ + public stopActiveConversation: jest.Mock, [StopActiveConversationRequestData]> = jest.fn(); + /** + * Fixture associated to function updateConversation + */ + public updateConversation: jest.Mock, [UpdateConversationRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/conversation/conversation-api.ts b/packages/conversation/src/rest/v1/conversation/conversation-api.ts new file mode 100644 index 00000000..8064f899 --- /dev/null +++ b/packages/conversation/src/rest/v1/conversation/conversation-api.ts @@ -0,0 +1,304 @@ +import { + ApiListPromise, + buildPageResultPromise, + createIteratorMethodsForPagination, + PaginatedApiProperties, + PaginationEnum, + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + Conversation, + ConversationChannel, + ConversationMessageInjected, + ConversationMetadataUpdateStrategy, + CreateConversationRequest, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface CreateConversationRequestData { + /** The conversation to create. ID will be generated for the conversation and any ID in the given conversation will be ignored. */ + 'createConversationRequestBody': CreateConversationRequest; +} +export interface DeleteConversationRequestData { + /** The unique ID of the conversation. This is generated by the system. */ + 'conversation_id': string; +} +export interface GetConversationRequestData { + /** The unique ID of the conversation. This is generated by the system. */ + 'conversation_id': string; +} +export interface InjectMessageRequestData { + /** Required. The ID of the conversation. */ + 'message.conversation_id': string; + /** Message to be injected. */ + 'conversationMessageInjectedBody': ConversationMessageInjected; +} +export interface ListConversationsRequestData { + /** Required. True if only active conversations should be listed. */ + 'only_active': boolean; + /** The ID of the app involved in the conversations. */ + 'app_id'?: string; + /** Resource name (ID) of the contact. */ + 'contact_id'?: string; + /** The maximum number of conversations to fetch. Defaults to 10 and the maximum is 20. */ + 'page_size'?: number; + /** Next page token previously returned if any. */ + 'page_token'?: string; + /** Only fetch conversations from the `active_channel` */ + 'active_channel'?: ConversationChannel; +} +export interface StopActiveConversationRequestData { + /** The unique ID of the conversation. This is generated by the system. */ + 'conversation_id': string; +} +export interface UpdateConversationRequestData { + /** The unique ID of the conversation. This is generated by the system. */ + 'conversation_id': string; + /** The updated conversation. */ + 'conversationBody': Conversation; + /** The set of field mask paths. */ + 'update_mask.paths'?: Array; + /** Update strategy for the `conversation_metadata` field. */ + 'metadata_update_strategy'?: ConversationMetadataUpdateStrategy; +} + +export class ConversationApi extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'ConversationApi'); + } + + /** + * Create a conversation + * Creates a new empty conversation. It is generally not needed to create a conversation explicitly since sending or receiving a message automatically creates a new conversation if it does not already exist between the given app and contact. Creating empty conversation is useful if the metadata of the conversation should be populated when the first message in the conversation is a contact message or the first message in the conversation comes out-of-band and needs to be injected with InjectMessage endpoint. + * @param { CreateConversationRequestData } data - The data to provide to the API call. + */ + public async createConversation(data: CreateConversationRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody + = data['createConversationRequestBody'] ? JSON.stringify(data['createConversationRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'CreateConversation', + }); + } + + /** + * Delete a conversation + * Deletes a conversation together with all the messages sent as part of the conversation. + * @param { DeleteConversationRequestData } data - The data to provide to the API call. + */ + public async deleteConversation(data: DeleteConversationRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations/${data['conversation_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'DeleteConversation', + }); + } + + /** + * Get a conversation + * Retrieves a conversation by id. A conversation has two participating entities, an app and a contact. + * @param { GetConversationRequestData } data - The data to provide to the API call. + */ + public async getConversation(data: GetConversationRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations/${data['conversation_id']}`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'GetConversation', + }); + } + + /** + * Inject messages + * This operation injects a conversation message in to a specific conversation. + * @param { InjectMessageRequestData } data - The data to provide to the API call. + */ + public async injectMessage(data: InjectMessageRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody + = data['conversationMessageInjectedBody'] ? JSON.stringify(data['conversationMessageInjectedBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations/{message.conversation_id}:inject-message`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'InjectMessage', + }); + } + + /** + * List conversations + * This operation lists all conversations that are associated with an app and/or a contact. + * @param { ListConversationsRequestData } data - The data to provide to the API call. + * @return {ApiListPromise} + */ + public listConversations(data: ListConversationsRequestData): ApiListPromise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [ + 'app_id', + 'contact_id', + 'only_active', + 'page_size', + 'page_token', + 'active_channel', + ]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations`; + + const requestOptionsPromise = this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + + const operationProperties: PaginatedApiProperties = { + pagination: PaginationEnum.TOKEN, + apiName: this.apiName, + operationId: 'ListConversations', + dataKey: 'conversations', + }; + + // Create the promise containing the response wrapped as a PageResult + const listPromise = buildPageResultPromise( + this.client, + requestOptionsPromise, + operationProperties); + + // Add properties to the Promise to offer the possibility to use it as an iterator + Object.assign( + listPromise, + createIteratorMethodsForPagination( + this.client, requestOptionsPromise, listPromise, operationProperties), + ); + + return listPromise as ApiListPromise; + } + + /** + * Stop conversation + * This operation stops the referenced conversation, if the conversation is still active. A new conversation will be created if a new message is exchanged between the app or contact that was part of the stopped conversation. + * @param { StopActiveConversationRequestData } data - The data to provide to the API call. + */ + public async stopActiveConversation(data: StopActiveConversationRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations/${data['conversation_id']}:stop`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'StopActiveConversation', + }); + } + + /** + * Update a conversation + * This operation updates a conversation which can, for instance, be used to update the metadata associated with a conversation. + * @param { UpdateConversationRequestData } data - The data to provide to the API call. + */ + public async updateConversation(data: UpdateConversationRequestData): Promise { + this.client = this.getSinchClient(); + data['metadata_update_strategy'] = data['metadata_update_strategy'] !== undefined + ? data['metadata_update_strategy'] + : 'REPLACE'; + const getParams = this.client.extractQueryParams(data, [ + 'update_mask.paths', + 'metadata_update_strategy', + ]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = data['conversationBody'] ? JSON.stringify(data['conversationBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations/${data['conversation_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'PATCH', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'UpdateConversation', + }); + } + +} diff --git a/packages/conversation/src/rest/v1/conversation/index.ts b/packages/conversation/src/rest/v1/conversation/index.ts new file mode 100644 index 00000000..8a650d12 --- /dev/null +++ b/packages/conversation/src/rest/v1/conversation/index.ts @@ -0,0 +1,2 @@ +export * from './conversation-api'; +export * from './conversation-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/enums.ts b/packages/conversation/src/rest/v1/enums.ts new file mode 100644 index 00000000..a6a425ee --- /dev/null +++ b/packages/conversation/src/rest/v1/enums.ts @@ -0,0 +1 @@ +export type MessageSource = 'CONVERSATION_SOURCE' | 'DISPATCH_SOURCE'; diff --git a/packages/conversation/src/rest/v1/events/events-api.jest.fixture.ts b/packages/conversation/src/rest/v1/events/events-api.jest.fixture.ts new file mode 100644 index 00000000..20660a26 --- /dev/null +++ b/packages/conversation/src/rest/v1/events/events-api.jest.fixture.ts @@ -0,0 +1,11 @@ +import { SendEventResponse } from '../../../models'; +import { EventsApi, SendEventRequestData } from './events-api'; + +export class EventsApiFixture implements Partial> { + + /** + * Fixture associated to function sendEvent + */ + public sendEvent: jest.Mock, [SendEventRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/events/events-api.ts b/packages/conversation/src/rest/v1/events/events-api.ts new file mode 100644 index 00000000..7fe54ba7 --- /dev/null +++ b/packages/conversation/src/rest/v1/events/events-api.ts @@ -0,0 +1,55 @@ +import { + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + SendEventRequest, + SendEventResponse, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface SendEventRequestData { + /** The event to be sent. */ + 'sendEventRequestBody': SendEventRequest; +} + +export class EventsApi extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'EventsApi'); + } + + /** + * Send an event + * Sends an event to the referenced contact from the referenced app. Note that this operation enqueues the event in a queue so a successful response only indicates that the event has been queued. + * @param { SendEventRequestData } data - The data to provide to the API call. + */ + public async sendEvent(data: SendEventRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = data['sendEventRequestBody'] ? JSON.stringify(data['sendEventRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/events:send`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'SendEvent', + }); + } + +} diff --git a/packages/conversation/src/rest/v1/events/index.ts b/packages/conversation/src/rest/v1/events/index.ts new file mode 100644 index 00000000..21e737b1 --- /dev/null +++ b/packages/conversation/src/rest/v1/events/index.ts @@ -0,0 +1,2 @@ +export * from './events-api'; +export * from './events-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/index.ts b/packages/conversation/src/rest/v1/index.ts new file mode 100644 index 00000000..d6a2350f --- /dev/null +++ b/packages/conversation/src/rest/v1/index.ts @@ -0,0 +1,10 @@ +export * from './app'; +export * from './capability'; +export * from './contact'; +export * from './conversation'; +export * from './events'; +export * from './messages'; +export * from './transcoding'; +export * from './webhooks'; +export * from './enums'; +export * from './conversation-domain'; diff --git a/packages/conversation/src/rest/v1/messages/index.ts b/packages/conversation/src/rest/v1/messages/index.ts new file mode 100644 index 00000000..4267b55f --- /dev/null +++ b/packages/conversation/src/rest/v1/messages/index.ts @@ -0,0 +1,2 @@ +export * from './messages-api'; +export * from './messages-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts b/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts new file mode 100644 index 00000000..6d97af8d --- /dev/null +++ b/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts @@ -0,0 +1,25 @@ +import { ConversationMessage } from '../../../models'; +import { SendMessageResponse } from '../../../models'; +import { MessagesApi, DeleteMessageRequestData, GetMessageRequestData, ListMessagesRequestData, SendMessageRequestData } from './messages-api'; +import { ApiListPromise } from '@sinch/sdk-client'; + +export class MessagesApiFixture implements Partial> { + + /** + * Fixture associated to function deleteMessage + */ + public deleteMessage: jest.Mock, [DeleteMessageRequestData]> = jest.fn(); + /** + * Fixture associated to function getMessage + */ + public getMessage: jest.Mock, [GetMessageRequestData]> = jest.fn(); + /** + * Fixture associated to function listMessages + */ + public listMessages: jest.Mock, [ListMessagesRequestData]> = jest.fn(); + /** + * Fixture associated to function sendMessage + */ + public sendMessage: jest.Mock, [SendMessageRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/messages/messages-api.ts b/packages/conversation/src/rest/v1/messages/messages-api.ts new file mode 100644 index 00000000..27a89882 --- /dev/null +++ b/packages/conversation/src/rest/v1/messages/messages-api.ts @@ -0,0 +1,218 @@ +import { + ApiListPromise, + buildPageResultPromise, + createIteratorMethodsForPagination, + PaginatedApiProperties, + PaginationEnum, + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + ConversationChannel, + ConversationMessage, + ConversationMessagesView, + SendMessageRequest, + SendMessageResponse, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; +import { MessageSource } from '../enums'; + +export interface DeleteMessageRequestData { + /** The unique ID of the message. */ + 'message_id': string; + /** Specifies the message source for which the request will be processed. Used for operations on messages in Dispatch Mode. For more information, see [Processing Modes](../../../../../conversation/processing-modes/). */ + 'messages_source'?: MessageSource; +} +export interface GetMessageRequestData { + /** The unique ID of the message. */ + 'message_id': string; + /** Specifies the message source for which the request will be processed. Used for operations on messages in Dispatch Mode. For more information, see [Processing Modes](../../../../../conversation/processing-modes/). */ + 'messages_source'?: MessageSource; +} +export interface ListMessagesRequestData { + /** Resource name (ID) of the conversation. */ + 'conversation_id'?: string; + /** Resource name (ID) of the contact. */ + 'contact_id'?: string; + /** Id of the app. */ + 'app_id'?: string; + /** Channel identity of the contact. */ + 'channel_identity'?: string; + /** Filter messages with `accept_time` after this timestamp. Must be before `end_time` if that is specified. */ + 'start_time'?: Date; + /** Filter messages with `accept_time` before this timestamp. */ + 'end_time'?: Date; + /** Maximum number of messages to fetch. Defaults to 10 and the maximum is 1000. */ + 'page_size'?: number; + /** Next page token previously returned if any. When specifying this token, make sure to use the same values for the other parameters from the request that originated the token, otherwise the paged results may be inconsistent. */ + 'page_token'?: string; + /** */ + 'view'?: ConversationMessagesView; + /** Specifies the message source for which the request will be processed. Used for operations on messages in Dispatch Mode. For more information, see [Processing Modes](../../../../../conversation/processing-modes/). */ + 'messages_source'?: MessageSource; + /** If true, fetch only recipient originated messages. Available only when `messages_source` is `DISPATCH_SOURCE`. */ + 'only_recipient_originated'?: boolean; + /** Only fetch messages from the `channel`. */ + 'channel'?: ConversationChannel; +} +export interface SendMessageRequestData { + /** This is the request body for sending a message. `app_id`, `recipient`, and `message` are all required fields. */ + 'sendMessageRequestBody': SendMessageRequest; +} + +export class MessagesApi extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'MessagesApi'); + } + + /** + * Delete a message + * Delete a specific message by its ID. Note: Removing all messages of a conversation will not automatically delete the conversation. + * @param { DeleteMessageRequestData } data - The data to provide to the API call. + */ + public async deleteMessage(data: DeleteMessageRequestData): Promise { + this.client = this.getSinchClient(); + data['messages_source'] = data['messages_source'] !== undefined ? data['messages_source'] : 'CONVERSATION_SOURCE'; + const getParams = this.client.extractQueryParams(data, ['messages_source']); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/messages/${data['message_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'DeleteMessage', + }); + } + + /** + * Get a message + * Retrieves a specific message by its ID. + * @param { GetMessageRequestData } data - The data to provide to the API call. + */ + public async getMessage(data: GetMessageRequestData): Promise { + this.client = this.getSinchClient(); + data['messages_source'] = data['messages_source'] !== undefined ? data['messages_source'] : 'CONVERSATION_SOURCE'; + const getParams = this.client.extractQueryParams(data, ['messages_source']); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/messages/${data['message_id']}`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'GetMessage', + }); + } + + /** + * List messages + * This operation lists all messages sent or received via particular [Processing Modes](../../../../../conversation/processing-modes/). Setting the `messages_source` parameter to `CONVERSATION_SOURCE` allows for querying messages in `CONVERSATION` mode, and setting it to `DISPATCH_SOURCE` will allow for queries of messages in `DISPATCH` mode. Combining multiple parameters is supported for more detailed filtering of messages, but some of them are not supported depending on the value specified for `messages_source`. The description for each field will inform if that field may not be supported. The messages are ordered by their `accept_time` property in descending order, where `accept_time` is a timestamp of when the message was enqueued by the Conversation API. This means messages received most recently will be listed first. + * @param { ListMessagesRequestData } data - The data to provide to the API call. + * @return {ApiListPromise} + */ + public listMessages(data: ListMessagesRequestData): ApiListPromise { + this.client = this.getSinchClient(); + data['messages_source'] = data['messages_source'] !== undefined ? data['messages_source'] : 'CONVERSATION_SOURCE'; + const getParams = this.client.extractQueryParams(data, [ + 'conversation_id', + 'contact_id', + 'app_id', + 'channel_identity', + 'start_time', + 'end_time', + 'page_size', + 'page_token', + 'view', + 'messages_source', + 'only_recipient_originated', + 'channel', + ]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/messages`; + + const requestOptionsPromise = this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + + const operationProperties: PaginatedApiProperties = { + pagination: PaginationEnum.TOKEN, + apiName: this.apiName, + operationId: 'ListMessages', + dataKey: 'messages', + }; + + // Create the promise containing the response wrapped as a PageResult + const listPromise = buildPageResultPromise( + this.client, + requestOptionsPromise, + operationProperties); + + // Add properties to the Promise to offer the possibility to use it as an iterator + Object.assign( + listPromise, + createIteratorMethodsForPagination( + this.client, requestOptionsPromise, listPromise, operationProperties), + ); + + return listPromise as ApiListPromise; + } + + /** + * Send a message + * You can send a message from a Conversation app to a contact associated with that app. If the recipient is not associated with an existing contact, a new contact will be created. The message is added to the active conversation with the contact if a conversation already exists. If no active conversation exists a new one is started automatically. You can find all of your IDs and authentication credentials on the [Sinch Customer Dashboard](https://dashboard.sinch.com/convapi/overview). + * @param { SendMessageRequestData } data - The data to provide to the API call. + */ + public async sendMessage(data: SendMessageRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = data['sendMessageRequestBody'] ? JSON.stringify(data['sendMessageRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/messages:send`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'SendMessage', + }); + } + +} diff --git a/packages/conversation/src/rest/v1/transcoding/index.ts b/packages/conversation/src/rest/v1/transcoding/index.ts new file mode 100644 index 00000000..5e54df78 --- /dev/null +++ b/packages/conversation/src/rest/v1/transcoding/index.ts @@ -0,0 +1,2 @@ +export * from './transcoding-api'; +export * from './transcoding-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/transcoding/transcoding-api.jest.fixture.ts b/packages/conversation/src/rest/v1/transcoding/transcoding-api.jest.fixture.ts new file mode 100644 index 00000000..b401c559 --- /dev/null +++ b/packages/conversation/src/rest/v1/transcoding/transcoding-api.jest.fixture.ts @@ -0,0 +1,11 @@ +import { TranscodeMessageResponse } from '../../../models'; +import { TranscodingApi, TranscodeMessageRequestData } from './transcoding-api'; + +export class TranscodingApiFixture implements Partial> { + + /** + * Fixture associated to function transcodeMessage + */ + public transcodeMessage: jest.Mock, [TranscodeMessageRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/transcoding/transcoding-api.ts b/packages/conversation/src/rest/v1/transcoding/transcoding-api.ts new file mode 100644 index 00000000..bcdadb99 --- /dev/null +++ b/packages/conversation/src/rest/v1/transcoding/transcoding-api.ts @@ -0,0 +1,56 @@ +import { + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + TranscodeMessageRequest, + TranscodeMessageResponse, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface TranscodeMessageRequestData { + /** The message to be transcoded, and the app and channels for which the message is to be transcoded. */ + 'transcodeMessageRequestBody': TranscodeMessageRequest; +} + +export class TranscodingApi extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'TranscodingApi'); + } + + /** + * Transcode a message + * Transcodes the message from the Conversation API format to the channel-specific formats for the requested channels. No message is sent to the contact. + * @param { TranscodeMessageRequestData } data - The data to provide to the API call. + */ + public async transcodeMessage(data: TranscodeMessageRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody + = data['transcodeMessageRequestBody'] ? JSON.stringify(data['transcodeMessageRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/messages:transcode`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'TranscodeMessage', + }); + } + +} diff --git a/packages/conversation/src/rest/v1/webhooks/index.ts b/packages/conversation/src/rest/v1/webhooks/index.ts new file mode 100644 index 00000000..fa33f566 --- /dev/null +++ b/packages/conversation/src/rest/v1/webhooks/index.ts @@ -0,0 +1,2 @@ +export * from './webhooks-api'; +export * from './webhooks-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/webhooks/webhooks-api.jest.fixture.ts b/packages/conversation/src/rest/v1/webhooks/webhooks-api.jest.fixture.ts new file mode 100644 index 00000000..9599c194 --- /dev/null +++ b/packages/conversation/src/rest/v1/webhooks/webhooks-api.jest.fixture.ts @@ -0,0 +1,28 @@ +import { ListWebhooksResponse } from '../../../models'; +import { Webhook } from '../../../models'; +import { WebhooksApi, CreateWebhookRequestData, DeleteWebhookRequestData, GetWebhookRequestData, ListWebhooksRequestData, UpdateWebhookRequestData } from './webhooks-api'; + +export class WebhooksApiFixture implements Partial> { + + /** + * Fixture associated to function createWebhook + */ + public createWebhook: jest.Mock, [CreateWebhookRequestData]> = jest.fn(); + /** + * Fixture associated to function deleteWebhook + */ + public deleteWebhook: jest.Mock, [DeleteWebhookRequestData]> = jest.fn(); + /** + * Fixture associated to function getWebhook + */ + public getWebhook: jest.Mock, [GetWebhookRequestData]> = jest.fn(); + /** + * Fixture associated to function listWebhooks + */ + public listWebhooks: jest.Mock, [ListWebhooksRequestData]> = jest.fn(); + /** + * Fixture associated to function updateWebhook + */ + public updateWebhook: jest.Mock, [UpdateWebhookRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/webhooks/webhooks-api.ts b/packages/conversation/src/rest/v1/webhooks/webhooks-api.ts new file mode 100644 index 00000000..4f83769e --- /dev/null +++ b/packages/conversation/src/rest/v1/webhooks/webhooks-api.ts @@ -0,0 +1,189 @@ +import { + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + ListWebhooksResponse, + Webhook, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface CreateWebhookRequestData { + /** Required. The Webhook to create */ + 'webhookBody': Webhook; +} +export interface DeleteWebhookRequestData { + /** The unique ID of the webhook. */ + 'webhook_id': string; +} +export interface GetWebhookRequestData { + /** The unique ID of the webhook. */ + 'webhook_id': string; +} +export interface ListWebhooksRequestData { + /** The unique ID of the app. You can find this on the [Sinch Dashboard](https://dashboard.sinch.com/convapi/apps). */ + 'app_id': string; +} +export interface UpdateWebhookRequestData { + /** The unique ID of the webhook. */ + 'webhook_id': string; + /** Required. The Webhook to update */ + 'webhookBody': Webhook; + /** The set of field mask paths. */ + 'update_mask.paths'?: Array; +} + +export class WebhooksApi extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'WebhooksApi'); + } + + /** + * Create a new webhook + * Creates a webhook for receiving callbacks on specific triggers. You can create up to 5 webhooks per app. + * @param { CreateWebhookRequestData } data - The data to provide to the API call. + */ + public async createWebhook(data: CreateWebhookRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = data['webhookBody'] ? JSON.stringify(data['webhookBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/webhooks`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'CreateWebhook', + }); + } + + /** + * Delete an existing webhook + * Deletes a webhook as specified by the webhook ID. + * @param { DeleteWebhookRequestData } data - The data to provide to the API call. + */ + public async deleteWebhook(data: DeleteWebhookRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/webhooks/${data['webhook_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'DeleteWebhook', + }); + } + + /** + * Get a webhook + * Get a webhook as specified by the webhook ID. + * @param { GetWebhookRequestData } data - The data to provide to the API call. + */ + public async getWebhook(data: GetWebhookRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/webhooks/${data['webhook_id']}`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'GetWebhook', + }); + } + + /** + * List webhooks + * List all webhooks for a given app as specified by the App ID. + * @param { ListWebhooksRequestData } data - The data to provide to the API call. + */ + public async listWebhooks(data: ListWebhooksRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/apps/${data['app_id']}/webhooks`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'ListWebhooks', + }); + } + + /** + * Update an existing webhook + * Updates an existing webhook as specified by the webhook ID. + * @param { UpdateWebhookRequestData } data - The data to provide to the API call. + */ + public async updateWebhook(data: UpdateWebhookRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, ['update_mask.paths']); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + + }; + + const body: RequestBody = data['webhookBody'] ? JSON.stringify(data['webhookBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/webhooks/${data['webhook_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'PATCH', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'UpdateWebhook', + }); + } + +} diff --git a/packages/conversation/tsconfig.build.json b/packages/conversation/tsconfig.build.json new file mode 100644 index 00000000..73f1cf60 --- /dev/null +++ b/packages/conversation/tsconfig.build.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"], + + "references": [{ "path": "../sdk-client" }], + + "ts-node": { + "esm": true + } +} diff --git a/packages/conversation/tsconfig.json b/packages/conversation/tsconfig.json new file mode 100644 index 00000000..2684d3e0 --- /dev/null +++ b/packages/conversation/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "references": [ + { + "path": "tsconfig.build.json" + }, + { + "path": "tsconfig.tests.json" + } + ] +} diff --git a/packages/conversation/tsconfig.tests.json b/packages/conversation/tsconfig.tests.json new file mode 100644 index 00000000..2e454981 --- /dev/null +++ b/packages/conversation/tsconfig.tests.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + + "compilerOptions": { + "rootDir": ".", + "outDir": "dist/tests" + }, + + "include": ["src/**/*.ts", "tests/**/*.ts"], + "exclude": ["node_modules", "dist"], + + "references": [{ "path": "../sdk-client" }], + + "ts-node": { + "esm": true + } +} diff --git a/packages/sdk-client/src/client/api-client-pagination-helper.ts b/packages/sdk-client/src/client/api-client-pagination-helper.ts index d101523f..90aed091 100644 --- a/packages/sdk-client/src/client/api-client-pagination-helper.ts +++ b/packages/sdk-client/src/client/api-client-pagination-helper.ts @@ -159,7 +159,7 @@ export function hasMore( context: PaginationContext, ): boolean { if (context.pagination === PaginationEnum.TOKEN) { - return !!response.nextPageToken; + return !!response['nextPageToken'] || !!response['next_page_token']; } if (context.pagination === PaginationEnum.PAGE) { const requestedPageSize = context.requestOptions.queryParams?.page_size; @@ -174,7 +174,7 @@ export function calculateNextPage( context: PaginationContext, ): string { if (context.pagination === PaginationEnum.TOKEN) { - return response['nextPageToken']; + return response['nextPageToken'] || response['next_page_token']; } if (context.pagination === PaginationEnum.PAGE) { const currentPage: number = response.page || 0; diff --git a/packages/sdk-core/package.json b/packages/sdk-core/package.json index ff0038c9..ed8966e1 100644 --- a/packages/sdk-core/package.json +++ b/packages/sdk-core/package.json @@ -29,6 +29,7 @@ "compile": "tsc --build --verbose" }, "dependencies": { + "@sinch/conversation": "^0.0.1", "@sinch/numbers": "^0.0.1", "@sinch/sms": "^0.0.1", "@sinch/verification": "^0.0.1", diff --git a/packages/sdk-core/src/index.ts b/packages/sdk-core/src/index.ts index 616896ca..3f6bd3a3 100644 --- a/packages/sdk-core/src/index.ts +++ b/packages/sdk-core/src/index.ts @@ -1,4 +1,5 @@ export * from './sinch-client'; +export * from '@sinch/conversation'; export * from '@sinch/numbers'; export * from '@sinch/sms'; export * from '@sinch/verification'; diff --git a/packages/sdk-core/src/sinch-client.ts b/packages/sdk-core/src/sinch-client.ts index 4b0e97f1..4a5df9fb 100644 --- a/packages/sdk-core/src/sinch-client.ts +++ b/packages/sdk-core/src/sinch-client.ts @@ -3,10 +3,12 @@ import { Sms } from '@sinch/sms'; import { Verification } from '@sinch/verification'; import { SinchClientParameters } from '@sinch/sdk-client'; import { Voice } from '@sinch/voice'; +import { ConversationDomain } from '@sinch/conversation'; /** Sinch Client to declare and initialize the supported APIs */ export class SinchClient { + public readonly conversation: ConversationDomain; public readonly numbers: Numbers; public readonly sms: Sms; public readonly verification: Verification; @@ -18,6 +20,9 @@ export class SinchClient { * @param {SinchClientParameters} params - The object containing the Sinch credentials. */ constructor(params: SinchClientParameters) { + // Initialize the "Conversation" API + this.conversation = new ConversationDomain(params); + // Initialize the "Numbers" API this.numbers = new Numbers(params); From 50f2c8db84c46d3542a4c5a77dd5d4e768c578af Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Wed, 24 Jan 2024 20:41:57 +0100 Subject: [PATCH 03/19] Update contact method names --- .../v1/contact/contact-api.jest.fixture.ts | 20 +++++++++---------- .../src/rest/v1/contact/contact-api.ts | 16 +++++++-------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/conversation/src/rest/v1/contact/contact-api.jest.fixture.ts b/packages/conversation/src/rest/v1/contact/contact-api.jest.fixture.ts index b2880ae1..5cb3ca3c 100644 --- a/packages/conversation/src/rest/v1/contact/contact-api.jest.fixture.ts +++ b/packages/conversation/src/rest/v1/contact/contact-api.jest.fixture.ts @@ -6,32 +6,32 @@ import { ApiListPromise } from '@sinch/sdk-client'; export class ContactApiFixture implements Partial> { /** - * Fixture associated to function createContact + * Fixture associated to function create */ - public createContact: jest.Mock, [CreateContactRequestData]> = jest.fn(); + public create: jest.Mock, [CreateContactRequestData]> = jest.fn(); /** - * Fixture associated to function deleteContact + * Fixture associated to function delete */ - public deleteContact: jest.Mock, [DeleteContactRequestData]> = jest.fn(); + public delete: jest.Mock, [DeleteContactRequestData]> = jest.fn(); /** * Fixture associated to function getChannelProfile */ public getChannelProfile: jest.Mock, [GetChannelProfileRequestData]> = jest.fn(); /** - * Fixture associated to function getContact + * Fixture associated to function get */ - public getContact: jest.Mock, [GetContactRequestData]> = jest.fn(); + public get: jest.Mock, [GetContactRequestData]> = jest.fn(); /** - * Fixture associated to function listContacts + * Fixture associated to function list */ - public listContacts: jest.Mock, [ListContactsRequestData]> = jest.fn(); + public list: jest.Mock, [ListContactsRequestData]> = jest.fn(); /** * Fixture associated to function mergeContact */ public mergeContact: jest.Mock, [MergeContactRequestData]> = jest.fn(); /** - * Fixture associated to function updateContact + * Fixture associated to function update */ - public updateContact: jest.Mock, [UpdateContactRequestData]> = jest.fn(); + public update: jest.Mock, [UpdateContactRequestData]> = jest.fn(); } diff --git a/packages/conversation/src/rest/v1/contact/contact-api.ts b/packages/conversation/src/rest/v1/contact/contact-api.ts index ac8b10ff..67f84335 100644 --- a/packages/conversation/src/rest/v1/contact/contact-api.ts +++ b/packages/conversation/src/rest/v1/contact/contact-api.ts @@ -55,9 +55,9 @@ export interface UpdateContactRequestData { /** The unique ID of the contact. */ 'contact_id': string; /** The updated contact. */ - 'contactBody': Contact; + 'updateContactBody': Contact; /** The set of field mask paths. */ - 'update_mask.paths'?: Array; + 'update_mask'?: Array; } export class ContactApi extends ConversationDomainApi { @@ -76,7 +76,7 @@ export class ContactApi extends ConversationDomainApi { * Most Conversation API contacts are [created automatically](/docs/conversation/contact-management/) when a message is sent to a new recipient. You can also create a new contact manually using this API call. * @param { CreateContactRequestData } data - The data to provide to the API call. */ - public async createContact(data: CreateContactRequestData): Promise { + public async create(data: CreateContactRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { @@ -104,7 +104,7 @@ export class ContactApi extends ConversationDomainApi { * Delete a contact as specified by the contact ID. * @param { DeleteContactRequestData } data - The data to provide to the API call. */ - public async deleteContact(data: DeleteContactRequestData): Promise { + public async delete(data: DeleteContactRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { @@ -160,7 +160,7 @@ export class ContactApi extends ConversationDomainApi { * Returns a specific contact as specified by the contact ID. Note that, if a WhatsApp contact is returned, the `display_name` field of that contact may be populated with the WhatsApp display name (if the name is already stored on the server and the `display_name` field has not been overwritten by the user). * @param { GetContactRequestData } data - The data to provide to the API call. */ - public async getContact(data: GetContactRequestData): Promise { + public async get(data: GetContactRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { @@ -188,7 +188,7 @@ export class ContactApi extends ConversationDomainApi { * @param { ListContactsRequestData } data - The data to provide to the API call. * @return {ApiListPromise} */ - public listContacts(data: ListContactsRequestData): ApiListPromise { + public list(data: ListContactsRequestData): ApiListPromise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams( data, @@ -258,7 +258,7 @@ export class ContactApi extends ConversationDomainApi { * Updates a contact as specified by the contact ID. * @param { UpdateContactRequestData } data - The data to provide to the API call. */ - public async updateContact(data: UpdateContactRequestData): Promise { + public async update(data: UpdateContactRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, ['update_mask.paths']); const headers: { [key: string]: string | undefined } = { @@ -266,7 +266,7 @@ export class ContactApi extends ConversationDomainApi { 'Accept': 'application/json', }; - const body: RequestBody = data['contactBody'] ? JSON.stringify(data['contactBody']) : '{}'; + const body: RequestBody = data['updateContactBody'] ? JSON.stringify(data['updateContactBody']) : '{}'; const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts/${data['contact_id']}`; const requestOptions From 3a0f6fa613bafed48bb344e4fa9f5919fb32c6f6 Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Wed, 24 Jan 2024 20:51:40 +0100 Subject: [PATCH 04/19] Fix non updated parameter --- packages/conversation/src/rest/v1/contact/contact-api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/conversation/src/rest/v1/contact/contact-api.ts b/packages/conversation/src/rest/v1/contact/contact-api.ts index 67f84335..606d4be0 100644 --- a/packages/conversation/src/rest/v1/contact/contact-api.ts +++ b/packages/conversation/src/rest/v1/contact/contact-api.ts @@ -260,7 +260,7 @@ export class ContactApi extends ConversationDomainApi { */ public async update(data: UpdateContactRequestData): Promise { this.client = this.getSinchClient(); - const getParams = this.client.extractQueryParams(data, ['update_mask.paths']); + const getParams = this.client.extractQueryParams(data, ['update_mask']); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', From ddb3a4a8f77357de7821b1457d9097c6f5e8281d Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Thu, 25 Jan 2024 17:34:00 +0100 Subject: [PATCH 05/19] Update models and API methods and parameters --- .../src/models/v1/app-message/app-message.ts | 5 + .../conversation-message.ts | 8 ++ .../models/v1/conversation/conversation.ts | 2 + .../create-conversation-request.ts | 2 - packages/conversation/src/models/v1/index.ts | 2 +- .../src/models/v1/lookup-capability/index.ts | 1 + .../lookup-capability.ts} | 4 +- .../src/models/v1/query-capability/index.ts | 1 - .../send-message-request.ts | 4 +- .../transcode-message-request.ts | 6 +- .../conversation/src/rest/v1/app/app-api.ts | 5 - .../capability/capability-api.jest.fixture.ts | 6 +- .../src/rest/v1/capability/capability-api.ts | 19 ++-- .../src/rest/v1/contact/contact-api.ts | 4 +- .../conversation-api.jest.fixture.ts | 24 ++--- .../rest/v1/conversation/conversation-api.ts | 36 +++---- .../rest/v1/events/events-api.jest.fixture.ts | 4 +- .../src/rest/v1/events/events-api.ts | 3 +- .../v1/messages/messages-api.jest.fixture.ts | 16 +-- .../src/rest/v1/messages/messages-api.ts | 12 +-- .../rest/v1/transcoding/transcoding-api.ts | 1 - .../v1/webhooks/webhooks-api.jest.fixture.ts | 20 ++-- .../src/rest/v1/webhooks/webhooks-api.ts | 31 +++--- packages/sdk-client/src/api/api-errors.ts | 8 +- .../sdk-client/src/client/api-fetch-client.ts | 2 +- packages/voice/src/models/v1/enums.ts | 3 +- yarn.lock | 102 ++++++++++++++++-- 27 files changed, 208 insertions(+), 123 deletions(-) create mode 100644 packages/conversation/src/models/v1/lookup-capability/index.ts rename packages/conversation/src/models/v1/{query-capability/query-capability.ts => lookup-capability/lookup-capability.ts} (72%) delete mode 100644 packages/conversation/src/models/v1/query-capability/index.ts diff --git a/packages/conversation/src/models/v1/app-message/app-message.ts b/packages/conversation/src/models/v1/app-message/app-message.ts index a76ccd47..5fefb734 100644 --- a/packages/conversation/src/models/v1/app-message/app-message.ts +++ b/packages/conversation/src/models/v1/app-message/app-message.ts @@ -12,4 +12,9 @@ export interface AppMessage { explicit_channel_message?: object; /** @see AppMessageAdditionalProperties */ additionalProperties?: AppMessageAdditionalProperties; + + /** TBC: Not documented */ + agent?: any | null; + /** TBC: Not documented */ + explicit_channel_omni_message?: object; } diff --git a/packages/conversation/src/models/v1/conversation-message/conversation-message.ts b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts index 1d77e007..feaf1a4b 100644 --- a/packages/conversation/src/models/v1/conversation-message/conversation-message.ts +++ b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts @@ -2,6 +2,7 @@ import { AppMessage } from '../app-message'; import { ChannelIdentity } from '../channel-identity'; import { ContactMessage } from '../contact-message'; import { ConversationDirection } from '../conversation-direction'; +import { ProcessingMode } from '../processing-mode'; /** * A message on a particular channel. @@ -28,4 +29,11 @@ export interface ConversationMessage { metadata?: string; /** Flag for whether this message was injected. */ injected?: boolean; + + /** TBC: Not documented */ + sender_id?: string; + /** TBC: Not documented */ + processing_mode?: ProcessingMode; + /** TBC: Not documented */ + message_status?: any | null; } diff --git a/packages/conversation/src/models/v1/conversation/conversation.ts b/packages/conversation/src/models/v1/conversation/conversation.ts index 3aadc9f5..4bfde51d 100644 --- a/packages/conversation/src/models/v1/conversation/conversation.ts +++ b/packages/conversation/src/models/v1/conversation/conversation.ts @@ -21,4 +21,6 @@ export interface Conversation { metadata?: string; /** Arbitrary data set by the Conversation API clients and/or provided in the `conversation_metadata` field of a SendMessageRequest. A valid JSON object. */ metadata_json?: object; + /** Up to 128 characters long */ + correlation_id?: string; } diff --git a/packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts b/packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts index d3f8b499..401f7d1a 100644 --- a/packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts +++ b/packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts @@ -13,8 +13,6 @@ export interface CreateConversationRequest { app_id: string; /** The ID of the participating contact. */ contact_id: string; - /** The ID of the conversation. */ - id?: string; /** Arbitrary data set by the Conversation API clients. Up to 1024 characters long. */ metadata?: string; /** Arbitrary data set by the Conversation API clients and/or provided in the `conversation_metadata` field of a SendMessageRequest. A valid JSON object. */ diff --git a/packages/conversation/src/models/v1/index.ts b/packages/conversation/src/models/v1/index.ts index 27023640..746dda57 100644 --- a/packages/conversation/src/models/v1/index.ts +++ b/packages/conversation/src/models/v1/index.ts @@ -69,7 +69,7 @@ export * from './processing-mode'; export * from './processing-strategy'; export * from './product'; export * from './error-detail'; -export * from './query-capability'; +export * from './lookup-capability'; export * from './query-capability-response'; export * from './queue-stats'; export * from './rate-limits'; diff --git a/packages/conversation/src/models/v1/lookup-capability/index.ts b/packages/conversation/src/models/v1/lookup-capability/index.ts new file mode 100644 index 00000000..3c8b1e25 --- /dev/null +++ b/packages/conversation/src/models/v1/lookup-capability/index.ts @@ -0,0 +1 @@ +export type { LookupCapability } from './lookup-capability'; diff --git a/packages/conversation/src/models/v1/query-capability/query-capability.ts b/packages/conversation/src/models/v1/lookup-capability/lookup-capability.ts similarity index 72% rename from packages/conversation/src/models/v1/query-capability/query-capability.ts rename to packages/conversation/src/models/v1/lookup-capability/lookup-capability.ts index d5f7f2fe..14dce31d 100644 --- a/packages/conversation/src/models/v1/query-capability/query-capability.ts +++ b/packages/conversation/src/models/v1/lookup-capability/lookup-capability.ts @@ -1,11 +1,11 @@ import { Recipient } from '../recipient'; -export interface QueryCapability { +export interface LookupCapability { /** The ID of the app to use for capability lookup. */ app_id: string; /** @see Recipient */ recipient: Recipient; - /** ID for the asynchronous response, will be generated if not set. Currently this field is not used for idempotency. */ + /** ID for the asynchronous response, will be generated if not set. Currently, this field is not used for idempotency. */ request_id?: string; } diff --git a/packages/conversation/src/models/v1/query-capability/index.ts b/packages/conversation/src/models/v1/query-capability/index.ts deleted file mode 100644 index 71fb2622..00000000 --- a/packages/conversation/src/models/v1/query-capability/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { QueryCapability } from './query-capability'; diff --git a/packages/conversation/src/models/v1/send-message-request/send-message-request.ts b/packages/conversation/src/models/v1/send-message-request/send-message-request.ts index a1ebdcbc..d1e36398 100644 --- a/packages/conversation/src/models/v1/send-message-request/send-message-request.ts +++ b/packages/conversation/src/models/v1/send-message-request/send-message-request.ts @@ -1,9 +1,9 @@ -import { AppMessage } from '../app-message'; import { ConversationChannel } from '../conversation-channel'; import { MessageQueue } from '../message-queue'; import { Recipient } from '../recipient'; import { ProcessingStrategy } from '../processing-strategy'; import { ConversationMetadataUpdateStrategy } from '../conversation-metadata-update-strategy'; +import { AppMessageMessage } from '../app-message-message'; /** * This is the request body for sending a message. `app_id`, `recipient`, and `message` are all required fields. @@ -19,7 +19,7 @@ export interface SendMessageRequest { /** Channel-specific properties. The key in the map must point to a valid channel property key as defined by the enum ChannelPropertyKeys. The maximum allowed property value length is 1024 characters. */ channel_properties?: { [key: string]: string; }; /** @see AppMessage */ - message: AppMessage; + message: AppMessageMessage; /** Metadata that should be associated with the message. Returned in the `metadata` field of a [Message Delivery Receipt](https://developers.sinch.com/docs/conversation/callbacks/#message-delivery-receipt). Up to 1024 characters long. */ message_metadata?: string; /** Metadata that should be associated with the conversation. This metadata will be propagated on MO callbacks associated with this conversation. Up to 1024 characters long. Note that the MO callback will always use the last metadata available in the conversation. Important notes: - If you send a message with the `conversation_metadata` field populated, and then send another message without populating the `conversation_metadata` field, the original metadata will continue be propagated on the related MO callbacks. - If you send a message with the `conversation_metadata` field populated, and then send another message with a different value for `conversation_metadata` in the same conversation, the latest metadata value overwrites the existing one. So, future MO callbacks will include the new metadata. - The `conversation_metadata` only accepts json objects. Currently only returned in the `message_metadata` field of an [Inbound Message](/docs/conversation/callbacks/#inbound-message) callback. */ diff --git a/packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts b/packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts index 159b15a9..973955a7 100644 --- a/packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts +++ b/packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts @@ -1,12 +1,12 @@ -import { AppMessage } from '../app-message'; import { ConversationChannel } from '../conversation-channel'; +import { AppMessageMessage } from '../app-message-message'; export interface TranscodeMessageRequest { /** The ID of the app used to transcode the message. */ app_id: string; - /** @see AppMessage */ - app_message: AppMessage; + /** @see AppMessageMessage */ + app_message: AppMessageMessage; /** The list of channels for which the message shall be transcoded to. */ channels: ConversationChannel[]; /** Optional. */ diff --git a/packages/conversation/src/rest/v1/app/app-api.ts b/packages/conversation/src/rest/v1/app/app-api.ts index 91464a59..54cc80af 100644 --- a/packages/conversation/src/rest/v1/app/app-api.ts +++ b/packages/conversation/src/rest/v1/app/app-api.ts @@ -55,7 +55,6 @@ export class AppApi extends ConversationDomainApi { const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = data['appCreateRequestBody'] ? JSON.stringify(data['appCreateRequestBody']) : '{}'; @@ -83,7 +82,6 @@ export class AppApi extends ConversationDomainApi { const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -112,7 +110,6 @@ export class AppApi extends ConversationDomainApi { const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -140,7 +137,6 @@ export class AppApi extends ConversationDomainApi { const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -168,7 +164,6 @@ export class AppApi extends ConversationDomainApi { const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = data['appUpdateRequestBody'] ? JSON.stringify(data['appUpdateRequestBody']) : '{}'; diff --git a/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts b/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts index 4ebaaad8..d1277f14 100644 --- a/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts +++ b/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts @@ -1,11 +1,11 @@ import { QueryCapabilityResponse } from '../../../models'; -import { CapabilityApi, QueryCapabilityRequestData } from './capability-api'; +import { CapabilityApi, LookupCapabilityRequestData } from './capability-api'; export class CapabilityApiFixture implements Partial> { /** - * Fixture associated to function queryCapability + * Fixture associated to function lookup */ - public queryCapability: jest.Mock, [QueryCapabilityRequestData]> = jest.fn(); + public lookup: jest.Mock, [LookupCapabilityRequestData]> = jest.fn(); } diff --git a/packages/conversation/src/rest/v1/capability/capability-api.ts b/packages/conversation/src/rest/v1/capability/capability-api.ts index b8825c79..768d323a 100644 --- a/packages/conversation/src/rest/v1/capability/capability-api.ts +++ b/packages/conversation/src/rest/v1/capability/capability-api.ts @@ -3,14 +3,14 @@ import { SinchClientParameters, } from '@sinch/sdk-client'; import { - QueryCapability, + LookupCapability, QueryCapabilityResponse, } from '../../../models'; import { ConversationDomainApi } from '../conversation-domain-api'; -export interface QueryCapabilityRequestData { - /** The query capability request. */ - 'queryCapabilityBody': QueryCapability; +export interface LookupCapabilityRequestData { + /** The lookup capability request. */ + 'lookupCapabilityRequestBody': LookupCapability; } export class CapabilityApi extends ConversationDomainApi { @@ -27,18 +27,19 @@ export class CapabilityApi extends ConversationDomainApi { /** * Capability lookup * This method is asynchronous - it immediately returns the requested Capability registration. Capability check is then delivered as a callback to registered webhooks with trigger CAPABILITY for every reachable channel. - * @param { QueryCapabilityRequestData } data - The data to provide to the API call. + * @param { LookupCapabilityRequestData } data - The data to provide to the API call. */ - public async queryCapability(data: QueryCapabilityRequestData): Promise { + public async lookup(data: LookupCapabilityRequestData): Promise { this.client = this.getSinchClient(); - const getParams = this.client.extractQueryParams(data, [] as never[]); + const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; - const body: RequestBody = data['queryCapabilityBody'] ? JSON.stringify(data['queryCapabilityBody']) : '{}'; + const body: RequestBody = data['lookupCapabilityRequestBody'] + ? JSON.stringify(data['lookupCapabilityRequestBody']) + : '{}'; const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/capability:query`; const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); diff --git a/packages/conversation/src/rest/v1/contact/contact-api.ts b/packages/conversation/src/rest/v1/contact/contact-api.ts index 606d4be0..7999b71a 100644 --- a/packages/conversation/src/rest/v1/contact/contact-api.ts +++ b/packages/conversation/src/rest/v1/contact/contact-api.ts @@ -55,7 +55,7 @@ export interface UpdateContactRequestData { /** The unique ID of the contact. */ 'contact_id': string; /** The updated contact. */ - 'updateContactBody': Contact; + 'updateContactRequestBody': Contact; /** The set of field mask paths. */ 'update_mask'?: Array; } @@ -266,7 +266,7 @@ export class ContactApi extends ConversationDomainApi { 'Accept': 'application/json', }; - const body: RequestBody = data['updateContactBody'] ? JSON.stringify(data['updateContactBody']) : '{}'; + const body: RequestBody = data['updateContactRequestBody'] ? JSON.stringify(data['updateContactRequestBody']) : '{}'; const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts/${data['contact_id']}`; const requestOptions diff --git a/packages/conversation/src/rest/v1/conversation/conversation-api.jest.fixture.ts b/packages/conversation/src/rest/v1/conversation/conversation-api.jest.fixture.ts index 9c17b433..f202929a 100644 --- a/packages/conversation/src/rest/v1/conversation/conversation-api.jest.fixture.ts +++ b/packages/conversation/src/rest/v1/conversation/conversation-api.jest.fixture.ts @@ -5,32 +5,32 @@ import { ApiListPromise } from '@sinch/sdk-client'; export class ConversationApiFixture implements Partial> { /** - * Fixture associated to function createConversation + * Fixture associated to function create */ - public createConversation: jest.Mock, [CreateConversationRequestData]> = jest.fn(); + public create: jest.Mock, [CreateConversationRequestData]> = jest.fn(); /** - * Fixture associated to function deleteConversation + * Fixture associated to function delete */ - public deleteConversation: jest.Mock, [DeleteConversationRequestData]> = jest.fn(); + public delete: jest.Mock, [DeleteConversationRequestData]> = jest.fn(); /** - * Fixture associated to function getConversation + * Fixture associated to function get */ - public getConversation: jest.Mock, [GetConversationRequestData]> = jest.fn(); + public get: jest.Mock, [GetConversationRequestData]> = jest.fn(); /** * Fixture associated to function injectMessage */ public injectMessage: jest.Mock, [InjectMessageRequestData]> = jest.fn(); /** - * Fixture associated to function listConversations + * Fixture associated to function list */ - public listConversations: jest.Mock, [ListConversationsRequestData]> = jest.fn(); + public list: jest.Mock, [ListConversationsRequestData]> = jest.fn(); /** - * Fixture associated to function stopActiveConversation + * Fixture associated to function stopActive */ - public stopActiveConversation: jest.Mock, [StopActiveConversationRequestData]> = jest.fn(); + public stopActive: jest.Mock, [StopActiveConversationRequestData]> = jest.fn(); /** - * Fixture associated to function updateConversation + * Fixture associated to function update */ - public updateConversation: jest.Mock, [UpdateConversationRequestData]> = jest.fn(); + public update: jest.Mock, [UpdateConversationRequestData]> = jest.fn(); } diff --git a/packages/conversation/src/rest/v1/conversation/conversation-api.ts b/packages/conversation/src/rest/v1/conversation/conversation-api.ts index 8064f899..75a50ad4 100644 --- a/packages/conversation/src/rest/v1/conversation/conversation-api.ts +++ b/packages/conversation/src/rest/v1/conversation/conversation-api.ts @@ -30,9 +30,9 @@ export interface GetConversationRequestData { } export interface InjectMessageRequestData { /** Required. The ID of the conversation. */ - 'message.conversation_id': string; + 'conversation_id': string; /** Message to be injected. */ - 'conversationMessageInjectedBody': ConversationMessageInjected; + 'injectMessageRequestBody': ConversationMessageInjected; } export interface ListConversationsRequestData { /** Required. True if only active conversations should be listed. */ @@ -56,9 +56,9 @@ export interface UpdateConversationRequestData { /** The unique ID of the conversation. This is generated by the system. */ 'conversation_id': string; /** The updated conversation. */ - 'conversationBody': Conversation; + 'updateConversationRequestBody': Conversation; /** The set of field mask paths. */ - 'update_mask.paths'?: Array; + 'update_mask'?: Array; /** Update strategy for the `conversation_metadata` field. */ 'metadata_update_strategy'?: ConversationMetadataUpdateStrategy; } @@ -79,13 +79,12 @@ export class ConversationApi extends ConversationDomainApi { * Creates a new empty conversation. It is generally not needed to create a conversation explicitly since sending or receiving a message automatically creates a new conversation if it does not already exist between the given app and contact. Creating empty conversation is useful if the metadata of the conversation should be populated when the first message in the conversation is a contact message or the first message in the conversation comes out-of-band and needs to be injected with InjectMessage endpoint. * @param { CreateConversationRequestData } data - The data to provide to the API call. */ - public async createConversation(data: CreateConversationRequestData): Promise { + public async create(data: CreateConversationRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody @@ -108,13 +107,12 @@ export class ConversationApi extends ConversationDomainApi { * Deletes a conversation together with all the messages sent as part of the conversation. * @param { DeleteConversationRequestData } data - The data to provide to the API call. */ - public async deleteConversation(data: DeleteConversationRequestData): Promise { + public async delete(data: DeleteConversationRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -137,13 +135,12 @@ export class ConversationApi extends ConversationDomainApi { * Retrieves a conversation by id. A conversation has two participating entities, an app and a contact. * @param { GetConversationRequestData } data - The data to provide to the API call. */ - public async getConversation(data: GetConversationRequestData): Promise { + public async get(data: GetConversationRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -171,12 +168,11 @@ export class ConversationApi extends ConversationDomainApi { const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody - = data['conversationMessageInjectedBody'] ? JSON.stringify(data['conversationMessageInjectedBody']) : '{}'; - const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations/{message.conversation_id}:inject-message`; + = data['injectMessageRequestBody'] ? JSON.stringify(data['injectMessageRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations/${data['conversation_id']}:inject-message`; const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); @@ -195,7 +191,7 @@ export class ConversationApi extends ConversationDomainApi { * @param { ListConversationsRequestData } data - The data to provide to the API call. * @return {ApiListPromise} */ - public listConversations(data: ListConversationsRequestData): ApiListPromise { + public list(data: ListConversationsRequestData): ApiListPromise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [ 'app_id', @@ -243,13 +239,12 @@ export class ConversationApi extends ConversationDomainApi { * This operation stops the referenced conversation, if the conversation is still active. A new conversation will be created if a new message is exchanged between the app or contact that was part of the stopped conversation. * @param { StopActiveConversationRequestData } data - The data to provide to the API call. */ - public async stopActiveConversation(data: StopActiveConversationRequestData): Promise { + public async stopActive(data: StopActiveConversationRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -271,22 +266,23 @@ export class ConversationApi extends ConversationDomainApi { * This operation updates a conversation which can, for instance, be used to update the metadata associated with a conversation. * @param { UpdateConversationRequestData } data - The data to provide to the API call. */ - public async updateConversation(data: UpdateConversationRequestData): Promise { + public async update(data: UpdateConversationRequestData): Promise { this.client = this.getSinchClient(); data['metadata_update_strategy'] = data['metadata_update_strategy'] !== undefined ? data['metadata_update_strategy'] : 'REPLACE'; const getParams = this.client.extractQueryParams(data, [ - 'update_mask.paths', + 'update_mask', 'metadata_update_strategy', ]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; - const body: RequestBody = data['conversationBody'] ? JSON.stringify(data['conversationBody']) : '{}'; + const body: RequestBody = data['updateConversationRequestBody'] + ? JSON.stringify(data['updateConversationRequestBody']) + : '{}'; const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/conversations/${data['conversation_id']}`; const requestOptions diff --git a/packages/conversation/src/rest/v1/events/events-api.jest.fixture.ts b/packages/conversation/src/rest/v1/events/events-api.jest.fixture.ts index 20660a26..6a6294f6 100644 --- a/packages/conversation/src/rest/v1/events/events-api.jest.fixture.ts +++ b/packages/conversation/src/rest/v1/events/events-api.jest.fixture.ts @@ -4,8 +4,8 @@ import { EventsApi, SendEventRequestData } from './events-api'; export class EventsApiFixture implements Partial> { /** - * Fixture associated to function sendEvent + * Fixture associated to function send */ - public sendEvent: jest.Mock, [SendEventRequestData]> = jest.fn(); + public send: jest.Mock, [SendEventRequestData]> = jest.fn(); } diff --git a/packages/conversation/src/rest/v1/events/events-api.ts b/packages/conversation/src/rest/v1/events/events-api.ts index 7fe54ba7..fb49739e 100644 --- a/packages/conversation/src/rest/v1/events/events-api.ts +++ b/packages/conversation/src/rest/v1/events/events-api.ts @@ -29,13 +29,12 @@ export class EventsApi extends ConversationDomainApi { * Sends an event to the referenced contact from the referenced app. Note that this operation enqueues the event in a queue so a successful response only indicates that the event has been queued. * @param { SendEventRequestData } data - The data to provide to the API call. */ - public async sendEvent(data: SendEventRequestData): Promise { + public async send(data: SendEventRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = data['sendEventRequestBody'] ? JSON.stringify(data['sendEventRequestBody']) : '{}'; diff --git a/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts b/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts index 6d97af8d..f60793e7 100644 --- a/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts +++ b/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts @@ -6,20 +6,20 @@ import { ApiListPromise } from '@sinch/sdk-client'; export class MessagesApiFixture implements Partial> { /** - * Fixture associated to function deleteMessage + * Fixture associated to function delete */ - public deleteMessage: jest.Mock, [DeleteMessageRequestData]> = jest.fn(); + public delete: jest.Mock, [DeleteMessageRequestData]> = jest.fn(); /** - * Fixture associated to function getMessage + * Fixture associated to function get */ - public getMessage: jest.Mock, [GetMessageRequestData]> = jest.fn(); + public get: jest.Mock, [GetMessageRequestData]> = jest.fn(); /** - * Fixture associated to function listMessages + * Fixture associated to function list */ - public listMessages: jest.Mock, [ListMessagesRequestData]> = jest.fn(); + public list: jest.Mock, [ListMessagesRequestData]> = jest.fn(); /** - * Fixture associated to function sendMessage + * Fixture associated to function send */ - public sendMessage: jest.Mock, [SendMessageRequestData]> = jest.fn(); + public send: jest.Mock, [SendMessageRequestData]> = jest.fn(); } diff --git a/packages/conversation/src/rest/v1/messages/messages-api.ts b/packages/conversation/src/rest/v1/messages/messages-api.ts index 27a89882..3ab17e90 100644 --- a/packages/conversation/src/rest/v1/messages/messages-api.ts +++ b/packages/conversation/src/rest/v1/messages/messages-api.ts @@ -76,14 +76,13 @@ export class MessagesApi extends ConversationDomainApi { * Delete a specific message by its ID. Note: Removing all messages of a conversation will not automatically delete the conversation. * @param { DeleteMessageRequestData } data - The data to provide to the API call. */ - public async deleteMessage(data: DeleteMessageRequestData): Promise { + public async delete(data: DeleteMessageRequestData): Promise { this.client = this.getSinchClient(); data['messages_source'] = data['messages_source'] !== undefined ? data['messages_source'] : 'CONVERSATION_SOURCE'; const getParams = this.client.extractQueryParams(data, ['messages_source']); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -106,14 +105,13 @@ export class MessagesApi extends ConversationDomainApi { * Retrieves a specific message by its ID. * @param { GetMessageRequestData } data - The data to provide to the API call. */ - public async getMessage(data: GetMessageRequestData): Promise { + public async get(data: GetMessageRequestData): Promise { this.client = this.getSinchClient(); data['messages_source'] = data['messages_source'] !== undefined ? data['messages_source'] : 'CONVERSATION_SOURCE'; const getParams = this.client.extractQueryParams(data, ['messages_source']); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -136,7 +134,7 @@ export class MessagesApi extends ConversationDomainApi { * @param { ListMessagesRequestData } data - The data to provide to the API call. * @return {ApiListPromise} */ - public listMessages(data: ListMessagesRequestData): ApiListPromise { + public list(data: ListMessagesRequestData): ApiListPromise { this.client = this.getSinchClient(); data['messages_source'] = data['messages_source'] !== undefined ? data['messages_source'] : 'CONVERSATION_SOURCE'; const getParams = this.client.extractQueryParams(data, [ @@ -156,7 +154,6 @@ export class MessagesApi extends ConversationDomainApi { const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -192,13 +189,12 @@ export class MessagesApi extends ConversationDomainApi { * You can send a message from a Conversation app to a contact associated with that app. If the recipient is not associated with an existing contact, a new contact will be created. The message is added to the active conversation with the contact if a conversation already exists. If no active conversation exists a new one is started automatically. You can find all of your IDs and authentication credentials on the [Sinch Customer Dashboard](https://dashboard.sinch.com/convapi/overview). * @param { SendMessageRequestData } data - The data to provide to the API call. */ - public async sendMessage(data: SendMessageRequestData): Promise { + public async send(data: SendMessageRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = data['sendMessageRequestBody'] ? JSON.stringify(data['sendMessageRequestBody']) : '{}'; diff --git a/packages/conversation/src/rest/v1/transcoding/transcoding-api.ts b/packages/conversation/src/rest/v1/transcoding/transcoding-api.ts index bcdadb99..48dd1951 100644 --- a/packages/conversation/src/rest/v1/transcoding/transcoding-api.ts +++ b/packages/conversation/src/rest/v1/transcoding/transcoding-api.ts @@ -35,7 +35,6 @@ export class TranscodingApi extends ConversationDomainApi { const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody diff --git a/packages/conversation/src/rest/v1/webhooks/webhooks-api.jest.fixture.ts b/packages/conversation/src/rest/v1/webhooks/webhooks-api.jest.fixture.ts index 9599c194..39131f5f 100644 --- a/packages/conversation/src/rest/v1/webhooks/webhooks-api.jest.fixture.ts +++ b/packages/conversation/src/rest/v1/webhooks/webhooks-api.jest.fixture.ts @@ -5,24 +5,24 @@ import { WebhooksApi, CreateWebhookRequestData, DeleteWebhookRequestData, GetWeb export class WebhooksApiFixture implements Partial> { /** - * Fixture associated to function createWebhook + * Fixture associated to function create */ - public createWebhook: jest.Mock, [CreateWebhookRequestData]> = jest.fn(); + public create: jest.Mock, [CreateWebhookRequestData]> = jest.fn(); /** - * Fixture associated to function deleteWebhook + * Fixture associated to function delete */ - public deleteWebhook: jest.Mock, [DeleteWebhookRequestData]> = jest.fn(); + public delete: jest.Mock, [DeleteWebhookRequestData]> = jest.fn(); /** - * Fixture associated to function getWebhook + * Fixture associated to function get */ - public getWebhook: jest.Mock, [GetWebhookRequestData]> = jest.fn(); + public get: jest.Mock, [GetWebhookRequestData]> = jest.fn(); /** - * Fixture associated to function listWebhooks + * Fixture associated to function list */ - public listWebhooks: jest.Mock, [ListWebhooksRequestData]> = jest.fn(); + public list: jest.Mock, [ListWebhooksRequestData]> = jest.fn(); /** - * Fixture associated to function updateWebhook + * Fixture associated to function update */ - public updateWebhook: jest.Mock, [UpdateWebhookRequestData]> = jest.fn(); + public update: jest.Mock, [UpdateWebhookRequestData]> = jest.fn(); } diff --git a/packages/conversation/src/rest/v1/webhooks/webhooks-api.ts b/packages/conversation/src/rest/v1/webhooks/webhooks-api.ts index 4f83769e..f5726608 100644 --- a/packages/conversation/src/rest/v1/webhooks/webhooks-api.ts +++ b/packages/conversation/src/rest/v1/webhooks/webhooks-api.ts @@ -10,7 +10,7 @@ import { ConversationDomainApi } from '../conversation-domain-api'; export interface CreateWebhookRequestData { /** Required. The Webhook to create */ - 'webhookBody': Webhook; + 'webhookCreateRequestBody': Webhook; } export interface DeleteWebhookRequestData { /** The unique ID of the webhook. */ @@ -28,9 +28,9 @@ export interface UpdateWebhookRequestData { /** The unique ID of the webhook. */ 'webhook_id': string; /** Required. The Webhook to update */ - 'webhookBody': Webhook; + 'webhookUpdateRequestBody': Webhook; /** The set of field mask paths. */ - 'update_mask.paths'?: Array; + 'update_mask'?: Array; } export class WebhooksApi extends ConversationDomainApi { @@ -49,16 +49,17 @@ export class WebhooksApi extends ConversationDomainApi { * Creates a webhook for receiving callbacks on specific triggers. You can create up to 5 webhooks per app. * @param { CreateWebhookRequestData } data - The data to provide to the API call. */ - public async createWebhook(data: CreateWebhookRequestData): Promise { + public async create(data: CreateWebhookRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; - const body: RequestBody = data['webhookBody'] ? JSON.stringify(data['webhookBody']) : '{}'; + const body: RequestBody = data['webhookCreateRequestBody'] + ? JSON.stringify(data['webhookCreateRequestBody']) + : '{}'; const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/webhooks`; const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); @@ -77,13 +78,12 @@ export class WebhooksApi extends ConversationDomainApi { * Deletes a webhook as specified by the webhook ID. * @param { DeleteWebhookRequestData } data - The data to provide to the API call. */ - public async deleteWebhook(data: DeleteWebhookRequestData): Promise { + public async delete(data: DeleteWebhookRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -106,13 +106,12 @@ export class WebhooksApi extends ConversationDomainApi { * Get a webhook as specified by the webhook ID. * @param { GetWebhookRequestData } data - The data to provide to the API call. */ - public async getWebhook(data: GetWebhookRequestData): Promise { + public async get(data: GetWebhookRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -134,13 +133,12 @@ export class WebhooksApi extends ConversationDomainApi { * List all webhooks for a given app as specified by the App ID. * @param { ListWebhooksRequestData } data - The data to provide to the API call. */ - public async listWebhooks(data: ListWebhooksRequestData): Promise { + public async list(data: ListWebhooksRequestData): Promise { this.client = this.getSinchClient(); const getParams = this.client.extractQueryParams(data, [] as never[]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; const body: RequestBody = ''; @@ -162,16 +160,17 @@ export class WebhooksApi extends ConversationDomainApi { * Updates an existing webhook as specified by the webhook ID. * @param { UpdateWebhookRequestData } data - The data to provide to the API call. */ - public async updateWebhook(data: UpdateWebhookRequestData): Promise { + public async update(data: UpdateWebhookRequestData): Promise { this.client = this.getSinchClient(); - const getParams = this.client.extractQueryParams(data, ['update_mask.paths']); + const getParams = this.client.extractQueryParams(data, ['update_mask']); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', 'Accept': 'application/json', - }; - const body: RequestBody = data['webhookBody'] ? JSON.stringify(data['webhookBody']) : '{}'; + const body: RequestBody = data['webhookUpdateRequestBody'] + ? JSON.stringify(data['webhookUpdateRequestBody']) + : '{}'; const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/webhooks/${data['webhook_id']}`; const requestOptions diff --git a/packages/sdk-client/src/api/api-errors.ts b/packages/sdk-client/src/api/api-errors.ts index 3512eb6a..1b5b7e09 100644 --- a/packages/sdk-client/src/api/api-errors.ts +++ b/packages/sdk-client/src/api/api-errors.ts @@ -45,7 +45,7 @@ export class RequestFailedError extends GenericError { /** * Data decoded from the response body */ - public data?: T; + public data?: string; constructor( message: string, @@ -55,7 +55,7 @@ export class RequestFailedError extends GenericError { ) { super(`[status: ${statusCode}] ${message}`, errorContext); this.statusCode = statusCode; - this.data = data; + this.data = JSON.stringify(data, null, 2); } } @@ -66,11 +66,11 @@ export class EmptyResponseError extends GenericError { /** * Data decoded from the response body */ - public data?: T; + public data?: string; constructor(message: string, errorContext: ErrorContext, data?: T) { super(`[Empty response] ${message}`, errorContext); - this.data = data; + this.data = JSON.stringify(data, null, 2); } } diff --git a/packages/sdk-client/src/client/api-fetch-client.ts b/packages/sdk-client/src/client/api-fetch-client.ts index 4d479177..6a03eb7b 100644 --- a/packages/sdk-client/src/client/api-fetch-client.ts +++ b/packages/sdk-client/src/client/api-fetch-client.ts @@ -152,7 +152,7 @@ export class ApiFetchClient extends ApiClient { // Build the PageResult object const nextPage = calculateNextPage(result, buildPaginationContext(apiCallParameters)); return { - data: responseData, + data: responseData || [], hasNextPage: hasMore(result, buildPaginationContext(apiCallParameters)), nextPageValue: nextPage, nextPage: () => createNextPageMethod( diff --git a/packages/voice/src/models/v1/enums.ts b/packages/voice/src/models/v1/enums.ts index 3d847155..c3dd6a3a 100644 --- a/packages/voice/src/models/v1/enums.ts +++ b/packages/voice/src/models/v1/enums.ts @@ -38,4 +38,5 @@ export type ReasonEnum = 'N/A' | 'NOCREDITPARTNER' | 'MANAGERHANGUP' | 'CANCEL' - | 'GENERALERROR'; + | 'GENERALERROR' + | 'INVALIDSVAMLACTION'; diff --git a/yarn.lock b/yarn.lock index b1e91495..6a9b73a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2177,6 +2177,23 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@^6.0.0": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz#bb0676af940bc23bf299ca58dbdc6589c2548c2e" + integrity sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.19.1" + "@typescript-eslint/type-utils" "6.19.1" + "@typescript-eslint/utils" "6.19.1" + "@typescript-eslint/visitor-keys" "6.19.1" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/eslint-plugin@^6.9.0": version "6.15.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.15.0.tgz#b0b3e15fa8c3e67ed4386b765cc0ba98ad3a303b" @@ -2194,6 +2211,17 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/parser@^6.0.0": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.19.1.tgz#68a87bb21afaf0b1689e9cdce0e6e75bc91ada78" + integrity sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ== + dependencies: + "@typescript-eslint/scope-manager" "6.19.1" + "@typescript-eslint/types" "6.19.1" + "@typescript-eslint/typescript-estree" "6.19.1" + "@typescript-eslint/visitor-keys" "6.19.1" + debug "^4.3.4" + "@typescript-eslint/parser@^6.9.0": version "6.15.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.15.0.tgz#1af69741cfa314a13c1434d0bdd5a0c3096699d7" @@ -2221,6 +2249,14 @@ "@typescript-eslint/types" "6.15.0" "@typescript-eslint/visitor-keys" "6.15.0" +"@typescript-eslint/scope-manager@6.19.1": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz#2f527ee30703a6169a52b31d42a1103d80acd51b" + integrity sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w== + dependencies: + "@typescript-eslint/types" "6.19.1" + "@typescript-eslint/visitor-keys" "6.19.1" + "@typescript-eslint/type-utils@6.15.0": version "6.15.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.15.0.tgz#c22261bd00566821a300d08f4632533a8f9bed01" @@ -2231,6 +2267,16 @@ debug "^4.3.4" ts-api-utils "^1.0.1" +"@typescript-eslint/type-utils@6.19.1": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz#6a130e3afe605a4898e043fa9f72e96309b54935" + integrity sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg== + dependencies: + "@typescript-eslint/typescript-estree" "6.19.1" + "@typescript-eslint/utils" "6.19.1" + debug "^4.3.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/types@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" @@ -2241,6 +2287,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.15.0.tgz#a9f7b006aee52b0948be6e03f521814bf435ddd5" integrity sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ== +"@typescript-eslint/types@6.19.1": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.19.1.tgz#2d4c9d492a63ede15e7ba7d129bdf7714b77f771" + integrity sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg== + "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" @@ -2267,6 +2318,20 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/typescript-estree@6.19.1": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz#796d88d88882f12e85bb33d6d82d39e1aea54ed1" + integrity sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA== + dependencies: + "@typescript-eslint/types" "6.19.1" + "@typescript-eslint/visitor-keys" "6.19.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/utils@6.15.0", "@typescript-eslint/utils@^6.0.0": version "6.15.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.15.0.tgz#f80dbb79f3b0f569077a8711dd44186a8933fa4c" @@ -2280,6 +2345,19 @@ "@typescript-eslint/typescript-estree" "6.15.0" semver "^7.5.4" +"@typescript-eslint/utils@6.19.1": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.19.1.tgz#df93497f9cfddde2bcc2a591da80536e68acd151" + integrity sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.19.1" + "@typescript-eslint/types" "6.19.1" + "@typescript-eslint/typescript-estree" "6.19.1" + semver "^7.5.4" + "@typescript-eslint/utils@^5.10.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" @@ -2310,6 +2388,14 @@ "@typescript-eslint/types" "6.15.0" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@6.19.1": + version "6.19.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz#2164073ed4fc34a5ff3b5e25bb5a442100454c4c" + integrity sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ== + dependencies: + "@typescript-eslint/types" "6.19.1" + eslint-visitor-keys "^3.4.1" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -6019,6 +6105,13 @@ minimatch@3.0.5: dependencies: brace-expansion "^1.1.7" +minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -6040,13 +6133,6 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.0, minimatch@^9.0.1: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -7008,7 +7094,7 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@2.5.2: +raw-body@2.5.2, raw-body@^2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== From 921bc7156e6264ca9b551101c43aa7bbeeb1f04a Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Thu, 25 Jan 2024 17:36:01 +0100 Subject: [PATCH 06/19] Fix linter --- packages/conversation/src/rest/v1/contact/contact-api.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/conversation/src/rest/v1/contact/contact-api.ts b/packages/conversation/src/rest/v1/contact/contact-api.ts index 7999b71a..45a65e2e 100644 --- a/packages/conversation/src/rest/v1/contact/contact-api.ts +++ b/packages/conversation/src/rest/v1/contact/contact-api.ts @@ -266,7 +266,9 @@ export class ContactApi extends ConversationDomainApi { 'Accept': 'application/json', }; - const body: RequestBody = data['updateContactRequestBody'] ? JSON.stringify(data['updateContactRequestBody']) : '{}'; + const body: RequestBody = data['updateContactRequestBody'] + ? JSON.stringify(data['updateContactRequestBody']) + : '{}'; const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/contacts/${data['contact_id']}`; const requestOptions From cd247d91d5d8565842e875fcd2c825e0c0e4982d Mon Sep 17 00:00:00 2001 From: Antoine SEIN <142824551+asein-sinch@users.noreply.github.com> Date: Tue, 30 Jan 2024 18:45:06 +0100 Subject: [PATCH 07/19] DEVEXP-274: Conversation API - Write tests (#14) * DEVEXP-274: Conversation API - Write tests * DEVEXP-276: Conversation API - Add example files (#15) --- examples/simple-examples/.env.template | 8 + examples/simple-examples/package.json | 31 +++ examples/simple-examples/src/config.ts | 32 +++ .../src/conversation/app/create.ts | 41 +++ .../src/conversation/app/delete.ts | 20 ++ .../src/conversation/app/get.ts | 26 ++ .../src/conversation/app/list.ts | 24 ++ .../src/conversation/app/update.ts | 47 ++++ .../src/conversation/capability/lookup.ts | 27 ++ .../src/conversation/contact/create.ts | 50 ++++ .../src/conversation/contact/delete.ts | 20 ++ .../src/conversation/contact/get.ts | 26 ++ .../conversation/contact/getChannelProfile.ts | 39 +++ .../src/conversation/contact/list.ts | 66 +++++ .../src/conversation/contact/merge.ts | 74 ++++++ .../src/conversation/contact/update.ts | 33 +++ .../src/conversation/conversation/create.ts | 45 ++++ .../src/conversation/conversation/delete.ts | 21 ++ .../src/conversation/conversation/get.ts | 31 +++ .../conversation/injectMessage.ts | 47 ++++ .../src/conversation/conversation/list.ts | 69 +++++ .../src/conversation/conversation/stop.ts | 21 ++ .../src/conversation/conversation/update.ts | 37 +++ .../src/conversation/events/send.ts | 33 +++ .../src/conversation/messages/delete.ts | 21 ++ .../src/conversation/messages/get.ts | 20 ++ .../src/conversation/messages/list.ts | 79 ++++++ .../src/conversation/messages/send.ts | 35 +++ .../src/conversation/transcoding/transcode.ts | 50 ++++ .../src/conversation/webhooks/create.ts | 46 ++++ .../src/conversation/webhooks/delete.ts | 21 ++ .../src/conversation/webhooks/get.ts | 31 +++ .../src/conversation/webhooks/list.ts | 30 +++ .../src/conversation/webhooks/update.ts | 45 ++++ examples/webhooks/src/app.module.ts | 2 + .../webhooks/src/controller/app.controller.ts | 8 + .../src/services/conversation.service.ts | 9 + jest.config.ts | 5 + .../tests/rest/v1/app/app-api.test.ts | 150 +++++++++++ .../rest/v1/capability/capability-api.test.ts | 53 ++++ .../tests/rest/v1/contact/contact-api.test.ts | 215 +++++++++++++++ .../v1/conversation/conversation-api.test.ts | 204 +++++++++++++++ .../tests/rest/v1/events/events-api.test.ts | 54 ++++ .../rest/v1/messages/messages-api.test.ts | 245 ++++++++++++++++++ .../v1/transcoding/transcoding-api.test.ts | 54 ++++ .../rest/v1/webhooks/webhooks-api.test.ts | 194 ++++++++++++++ 46 files changed, 2439 insertions(+) create mode 100644 examples/simple-examples/src/conversation/app/create.ts create mode 100644 examples/simple-examples/src/conversation/app/delete.ts create mode 100644 examples/simple-examples/src/conversation/app/get.ts create mode 100644 examples/simple-examples/src/conversation/app/list.ts create mode 100644 examples/simple-examples/src/conversation/app/update.ts create mode 100644 examples/simple-examples/src/conversation/capability/lookup.ts create mode 100644 examples/simple-examples/src/conversation/contact/create.ts create mode 100644 examples/simple-examples/src/conversation/contact/delete.ts create mode 100644 examples/simple-examples/src/conversation/contact/get.ts create mode 100644 examples/simple-examples/src/conversation/contact/getChannelProfile.ts create mode 100644 examples/simple-examples/src/conversation/contact/list.ts create mode 100644 examples/simple-examples/src/conversation/contact/merge.ts create mode 100644 examples/simple-examples/src/conversation/contact/update.ts create mode 100644 examples/simple-examples/src/conversation/conversation/create.ts create mode 100644 examples/simple-examples/src/conversation/conversation/delete.ts create mode 100644 examples/simple-examples/src/conversation/conversation/get.ts create mode 100644 examples/simple-examples/src/conversation/conversation/injectMessage.ts create mode 100644 examples/simple-examples/src/conversation/conversation/list.ts create mode 100644 examples/simple-examples/src/conversation/conversation/stop.ts create mode 100644 examples/simple-examples/src/conversation/conversation/update.ts create mode 100644 examples/simple-examples/src/conversation/events/send.ts create mode 100644 examples/simple-examples/src/conversation/messages/delete.ts create mode 100644 examples/simple-examples/src/conversation/messages/get.ts create mode 100644 examples/simple-examples/src/conversation/messages/list.ts create mode 100644 examples/simple-examples/src/conversation/messages/send.ts create mode 100644 examples/simple-examples/src/conversation/transcoding/transcode.ts create mode 100644 examples/simple-examples/src/conversation/webhooks/create.ts create mode 100644 examples/simple-examples/src/conversation/webhooks/delete.ts create mode 100644 examples/simple-examples/src/conversation/webhooks/get.ts create mode 100644 examples/simple-examples/src/conversation/webhooks/list.ts create mode 100644 examples/simple-examples/src/conversation/webhooks/update.ts create mode 100644 examples/webhooks/src/services/conversation.service.ts create mode 100644 packages/conversation/tests/rest/v1/app/app-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/capability/capability-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/contact/contact-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/events/events-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/messages/messages-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/transcoding/transcoding-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/webhooks/webhooks-api.test.ts diff --git a/examples/simple-examples/.env.template b/examples/simple-examples/.env.template index c523358e..8c769e24 100644 --- a/examples/simple-examples/.env.template +++ b/examples/simple-examples/.env.template @@ -19,3 +19,11 @@ VERIFICATION_ID=verification-id to fill with the verification started with the V VERIFICATION_IDENTITY=verification-identity to fill with the identity of the user VERIFICATION_REFERENCE=verification-reference to add when starting a verification or getting its status VOICE_CALLBACK_URL=URL found in the Voice dashboard to handle webhooks +CONVERSATION_APP_ID=app_id to fill with one of the conversation app created with the Conversation API or in the Dashboard +CONVERSATION_CONTACT_ID=contact_id to fill with one off the contacts +MESSENGER_TOKEN=static token to define credentials for a Messenger application +MESSENGER_USER_ID=Id of a user using messenger (can be found on a desktop by selecting a user: the user id will be in the URL) +CONVERSATION_ID=conversation_id to fill with one of the conversation create with the Conversation API +MESSAGE_ID=message_id to fill from a sent or injected message +WEBHOOK_ID=webhook_id to fill from a webhook creation with the Conversation API or the Dashboard +WEBHOOK_TARGET=URL of the webhook diff --git a/examples/simple-examples/package.json b/examples/simple-examples/package.json index 20736d8d..1cd6283a 100644 --- a/examples/simple-examples/package.json +++ b/examples/simple-examples/package.json @@ -8,6 +8,37 @@ "build": "yarn run clean && yarn run compile", "clean": "rimraf dist tsconfig.tsbuildinfo", "compile": "tsc --build --verbose", + "conversation:app:create": "ts-node src/conversation/app/create.ts", + "conversation:app:get": "ts-node src/conversation/app/get.ts", + "conversation:app:list": "ts-node src/conversation/app/list.ts", + "conversation:app:update": "ts-node src/conversation/app/update.ts pretty", + "conversation:app:delete": "ts-node src/conversation/app/delete.ts", + "conversation:contact:create": "ts-node src/conversation/contact/create.ts", + "conversation:contact:get": "ts-node src/conversation/contact/get.ts", + "conversation:contact:list": "ts-node src/conversation/contact/list.ts", + "conversation:contact:update": "ts-node src/conversation/contact/update.ts", + "conversation:contact:merge": "ts-node src/conversation/contact/merge.ts", + "conversation:contact:getChannelProfile": "ts-node src/conversation/contact/getChannelProfile.ts", + "conversation:contact:delete": "ts-node src/conversation/contact/delete.ts", + "conversation:messages:send": "ts-node src/conversation/messages/send.ts", + "conversation:messages:get": "ts-node src/conversation/messages/get.ts", + "conversation:messages:list": "ts-node src/conversation/messages/list.ts", + "conversation:messages:delete": "ts-node src/conversation/messages/delete.ts", + "conversation:conversation:create": "ts-node src/conversation/conversation/create.ts", + "conversation:conversation:get": "ts-node src/conversation/conversation/get.ts", + "conversation:conversation:list": "ts-node src/conversation/conversation/list.ts", + "conversation:conversation:injectMessage": "ts-node src/conversation/conversation/injectMessage.ts", + "conversation:conversation:update": "ts-node src/conversation/conversation/update.ts", + "conversation:conversation:stop": "ts-node src/conversation/conversation/stop.ts", + "conversation:conversation:delete": "ts-node src/conversation/conversation/delete.ts", + "conversation:events:send": "ts-node src/conversation/events/send.ts", + "conversation:transcoding:transcode": "ts-node src/conversation/transcoding/transcode.ts", + "conversation:capability:lookup": "ts-node src/conversation/capability/lookup.ts", + "conversation:webhooks:create": "ts-node src/conversation/webhooks/create.ts", + "conversation:webhooks:get": "ts-node src/conversation/webhooks/get.ts", + "conversation:webhooks:list": "ts-node src/conversation/webhooks/list.ts", + "conversation:webhooks:update": "ts-node src/conversation/webhooks/update.ts", + "conversation:webhooks:delete": "ts-node src/conversation/webhooks/delete.ts", "numbers:regions:list": "ts-node src/numbers/regions/list.ts", "numbers:available:list": "ts-node src/numbers/available/list.ts", "numbers:available:checkAvailability": "ts-node src/numbers/available/checkAvailability.ts", diff --git a/examples/simple-examples/src/config.ts b/examples/simple-examples/src/config.ts index 49e57d4a..012b697d 100644 --- a/examples/simple-examples/src/config.ts +++ b/examples/simple-examples/src/config.ts @@ -101,6 +101,38 @@ export const getVoiceCallBackUrl = (): string => { return readVariable('VOICE_CALLBACK_URL'); }; +export const getAppIdFromConfig = () => { + return readVariable('CONVERSATION_APP_ID'); +}; + +export const getContactIdFromConfig = () => { + return readVariable('CONVERSATION_CONTACT_ID'); +}; + +export const getMessengerTokenFormConfig = () => { + return readVariable('MESSENGER_TOKEN'); +}; + +export const getMessengerUserIdFromConfig = () => { + return readVariable('MESSENGER_USER_ID'); +}; + +export const getConversationIdFromConfig = () => { + return readVariable('CONVERSATION_ID'); +}; + +export const getMessageIdFromConfig = () => { + return readVariable('MESSAGE_ID'); +}; + +export const getWebhookIdFromConfig = () => { + return readVariable('WEBHOOK_ID'); +}; + +export const getWebhookTargetFromConfig = () => { + return readVariable('WEBHOOK_TARGET'); +}; + const readVariable = ( name: string): string => { const value = process.env[name]; if (!value) { diff --git a/examples/simple-examples/src/conversation/app/create.ts b/examples/simple-examples/src/conversation/app/create.ts new file mode 100644 index 00000000..fbf487b8 --- /dev/null +++ b/examples/simple-examples/src/conversation/app/create.ts @@ -0,0 +1,41 @@ +import { CreateAppRequestData } from '@sinch/sdk-core'; +import { getMessengerTokenFormConfig, getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*****************'); + console.log('* App_CreateApp *'); + console.log('*****************'); + + const messengerToken = getMessengerTokenFormConfig(); + + const requestData: CreateAppRequestData = { + appCreateRequestBody: { + display_name: 'New app created with the Node.js SDK', + channel_credentials: [ + { + channel: 'MESSENGER', + static_token: { + token: messengerToken, + }, + }, + ], + conversation_metadata_report_view: 'FULL', + retention_policy: { + retention_type: 'CONVERSATION_EXPIRE_POLICY', + ttl_days: 60, + }, + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.app.create(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`New app created with the id '${response.id}'`); + } else { + printFullResponse(response); + } + console.log(`You may want to update your .env file with the following value: CONVERSATION_APP_ID=${response.id}`); +})(); diff --git a/examples/simple-examples/src/conversation/app/delete.ts b/examples/simple-examples/src/conversation/app/delete.ts new file mode 100644 index 00000000..15414354 --- /dev/null +++ b/examples/simple-examples/src/conversation/app/delete.ts @@ -0,0 +1,20 @@ +import { DeleteAppRequestData } from '@sinch/sdk-core'; +import { getAppIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*****************'); + console.log('* App_DeleteApp *'); + console.log('*****************'); + + const appId = getAppIdFromConfig(); + + const requestData: DeleteAppRequestData = { + app_id: appId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.app.delete(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/app/get.ts b/examples/simple-examples/src/conversation/app/get.ts new file mode 100644 index 00000000..8667fe0a --- /dev/null +++ b/examples/simple-examples/src/conversation/app/get.ts @@ -0,0 +1,26 @@ +import { GetAppRequestData } from '@sinch/sdk-core'; +import { getAppIdFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('**************'); + console.log('* App_GetApp *'); + console.log('**************'); + + const appId = getAppIdFromConfig(); + + const requestData: GetAppRequestData = { + app_id: appId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.app.get(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`The app with the id '${response.id}' is named '${response.display_name}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/app/list.ts b/examples/simple-examples/src/conversation/app/list.ts new file mode 100644 index 00000000..c51d83a9 --- /dev/null +++ b/examples/simple-examples/src/conversation/app/list.ts @@ -0,0 +1,24 @@ +import { ListAppsRequestData } from '@sinch/sdk-core'; +import { getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('****************'); + console.log('* App_ListApps *'); + console.log('****************'); + + const requestData: ListAppsRequestData= {}; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.app.list(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(response.apps + ? response.apps.map((app) => `'${app.id}': ${app.display_name}`).join('\n') + : 'No Conversation Applications were found'); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/app/update.ts b/examples/simple-examples/src/conversation/app/update.ts new file mode 100644 index 00000000..49a1d27d --- /dev/null +++ b/examples/simple-examples/src/conversation/app/update.ts @@ -0,0 +1,47 @@ +import { UpdateAppRequestData } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, getMessengerTokenFormConfig, + getPrintFormat, + initClient, + printFullResponse, +} from '../../config'; + +(async () => { + console.log('*****************'); + console.log('* App_UpdateApp *'); + console.log('*****************'); + + const appId = getAppIdFromConfig(); + + const requestData: UpdateAppRequestData = { + app_id: appId, + update_mask: ['display_name', 'conversation_metadata_report_view'], + appUpdateRequestBody: { + display_name: 'Updated name by the Node.js SDK', + conversation_metadata_report_view: 'NONE', + channel_credentials: [ + { + channel: 'MESSENGER', + static_token: { + token: 'new token (invalid) - should not be updated thanks to the mask', + }, + }, + ], + + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.app.update(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`App updated! New name: '${response.display_name}'.`); + const token = getMessengerTokenFormConfig(); + console.log(`Verifying the token (it should be unchanged):\nOLD: '${token}'\nNEW: '${response.channel_credentials?.[0].static_token?.token}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/capability/lookup.ts b/examples/simple-examples/src/conversation/capability/lookup.ts new file mode 100644 index 00000000..ee1b5145 --- /dev/null +++ b/examples/simple-examples/src/conversation/capability/lookup.ts @@ -0,0 +1,27 @@ +import { LookupCapabilityRequestData } from '@sinch/sdk-core'; +import { getAppIdFromConfig, getContactIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('******************************'); + console.log('* Capability_QueryCapability *'); + console.log('******************************'); + + const appId = getAppIdFromConfig(); + const contactId = getContactIdFromConfig(); + + const requestData: LookupCapabilityRequestData = { + lookupCapabilityRequestBody: { + app_id: appId, + recipient: { + contact_id: contactId, + }, + request_id: 'myPersonalId_' + new Date().getTime(), + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.capability.lookup(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/contact/create.ts b/examples/simple-examples/src/conversation/contact/create.ts new file mode 100644 index 00000000..c54566bf --- /dev/null +++ b/examples/simple-examples/src/conversation/contact/create.ts @@ -0,0 +1,50 @@ +import { CreateContactRequestData } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, + getMessengerUserIdFromConfig, + getPhoneNumberFromConfig, + getPrintFormat, + initClient, + printFullResponse, +} from '../../config'; + +(async () => { + console.log('*************************'); + console.log('* Contact_CreateContact *'); + console.log('*************************'); + + const phoneNumber = getPhoneNumberFromConfig(); + const messengerUserId = getMessengerUserIdFromConfig(); + const appId = getAppIdFromConfig(); + + const requestData: CreateContactRequestData = { + contactCreateRequestBody: { + display_name: 'New contact created with the Node.js SDK', + channel_identities: [ + { + identity: messengerUserId, + channel: 'MESSENGER', + app_id:appId, + }, + { + identity: phoneNumber, + channel: 'WHATSAPP', + }, + ], + channel_priority: ['WHATSAPP'], + language: 'EN_US', + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.contact.create(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`New contact created with the id '${response.id}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/contact/delete.ts b/examples/simple-examples/src/conversation/contact/delete.ts new file mode 100644 index 00000000..6fbad08a --- /dev/null +++ b/examples/simple-examples/src/conversation/contact/delete.ts @@ -0,0 +1,20 @@ +import { DeleteContactRequestData } from '@sinch/sdk-core'; +import { getContactIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*************************'); + console.log('* Contact_DeleteContact *'); + console.log('*************************'); + + const contactId = getContactIdFromConfig(); + + const requestData: DeleteContactRequestData = { + contact_id: contactId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.contact.delete(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/contact/get.ts b/examples/simple-examples/src/conversation/contact/get.ts new file mode 100644 index 00000000..4978c478 --- /dev/null +++ b/examples/simple-examples/src/conversation/contact/get.ts @@ -0,0 +1,26 @@ +import { GetContactRequestData } from '@sinch/sdk-core'; +import { getContactIdFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('**********************'); + console.log('* Contact_GetContact *'); + console.log('**********************'); + + const contactId = getContactIdFromConfig(); + + const requestData: GetContactRequestData = { + contact_id: contactId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.contact.get(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`The contact with the id '${response.id}' is named '${response.display_name}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/contact/getChannelProfile.ts b/examples/simple-examples/src/conversation/contact/getChannelProfile.ts new file mode 100644 index 00000000..4febbca6 --- /dev/null +++ b/examples/simple-examples/src/conversation/contact/getChannelProfile.ts @@ -0,0 +1,39 @@ +import { GetChannelProfileRequestData } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, + getMessengerUserIdFromConfig, + initClient, + printFullResponse, +} from '../../config'; + +(async () => { + console.log('*****************************'); + console.log('* Contact_GetChannelProfile *'); + console.log('*****************************'); + + const appId = getAppIdFromConfig(); + const messengerUserId = getMessengerUserIdFromConfig(); + + const requestData: GetChannelProfileRequestData = { + getChannelProfileRequestBody: { + app_id: appId, + channel: 'MESSENGER', + recipient: { + identified_by: { + channel_identities: [ + { + identity: messengerUserId, + channel: 'MESSENGER', + }, + ], + }, + }, + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.contact.getChannelProfile(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/contact/list.ts b/examples/simple-examples/src/conversation/contact/list.ts new file mode 100644 index 00000000..3e83a3e4 --- /dev/null +++ b/examples/simple-examples/src/conversation/contact/list.ts @@ -0,0 +1,66 @@ +import { Contact, ListContactsRequestData, PageResult } from '@sinch/sdk-core'; +import { getPrintFormat, initClient, printFullResponse } from '../../config'; + +const populateContactsList = ( + contactPage: PageResult, + contactList: Contact[], + contactDetailsList: string[], +) => { + contactPage.data?.map((contact: Contact) => { + contactList.push(contact); + contactDetailsList.push(`${contact.id} - ${contact.display_name}`); + }); +}; + +(async () => { + console.log('************************'); + console.log('* Contact_ListContacts *'); + console.log('************************'); + + const requestData: ListContactsRequestData = { + page_size: 2, + }; + + const sinchClient = initClient(); + + // ---------------------------------------------- + // Method 1: Fetch the data page by page manually + // ---------------------------------------------- + let response = await sinchClient.conversation.contact.list(requestData); + + const contactList: Contact[] = []; + const contactDetailsList: string[] = []; + + // Loop on all the pages to get all the active numbers + let reachedEndOfPages = false; + while (!reachedEndOfPages) { + populateContactsList(response, contactList, contactDetailsList); + if (response.hasNextPage) { + response = await response.nextPage(); + } else { + reachedEndOfPages = true; + } + } + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(contactDetailsList.length > 0 + ? 'List of contacts:\n' + contactDetailsList.join('\n') + : 'Sorry, no contacts were found.'); + } else { + printFullResponse(contactList); + } + + // --------------------------------------------------------------------- + // Method 2: Use the iterator and fetch data on more pages automatically + // --------------------------------------------------------------------- + for await (const contact of sinchClient.conversation.contact.list(requestData)) { + if (printFormat === 'pretty') { + console.log(`${contact.id} - ${contact.display_name}`); + } else { + console.log(contact); + } + } + +})(); diff --git a/examples/simple-examples/src/conversation/contact/merge.ts b/examples/simple-examples/src/conversation/contact/merge.ts new file mode 100644 index 00000000..9035853c --- /dev/null +++ b/examples/simple-examples/src/conversation/contact/merge.ts @@ -0,0 +1,74 @@ +import { CreateContactRequestData, MergeContactRequestData } from '@sinch/sdk-core'; +import { + getPhoneNumberFromConfig, + getPrintFormat, + initClient, + printFullResponse, +} from '../../config'; + + +(async () => { + console.log('************************'); + console.log('* Contact_MergeContact *'); + console.log('************************'); + + const phoneNumber = getPhoneNumberFromConfig(); + + const sourceContactRequestData: CreateContactRequestData = { + contactCreateRequestBody: { + channel_identities: [ + { + channel: 'SMS', + identity: phoneNumber, + }, + ], + language: 'FR', + email: 'source@mail.com', + display_name: 'Source Contact', + metadata: 'Some metadata belonging to the source contact', + }, + }; + + const destinationContactRequestData: CreateContactRequestData = { + contactCreateRequestBody: { + channel_identities: [ + { + channel: 'MMS', + identity: phoneNumber, + }, + ], + language: 'EN_US', + channel_priority: ['MMS'], + display_name: 'Destination Contact', + }, + }; + + const sinchClient = initClient(); + const sourceContact = await sinchClient.conversation.contact.create(sourceContactRequestData); + const destinationContact = await sinchClient.conversation.contact.create(destinationContactRequestData); + + if (sourceContact.id && destinationContact.id) { + const requestData: MergeContactRequestData = { + destination_id: destinationContact.id, + mergeContactRequestBody: { + source_id: sourceContact.id, + strategy: 'MERGE', + }, + }; + + const response = await sinchClient.conversation.contact.mergeContact(requestData); + + const printFormat = getPrintFormat(process.argv); + if (printFormat === 'pretty') { + console.log(`The merged contact has the Id '${response.id}' (should be the same as the destination contact: '${destinationContact.id}')`); + console.log(`The merged contact should still have the same '${destinationContact.language}' language from the destination contact: ${response.language}`); + console.log(`The merged contact has now the email: ${response.email}`); + console.log(`The merged contact has ${response.channel_identities?.length} channel identities: ${response.channel_identities?.map((channelIdentity) => channelIdentity.channel).join(', ')}`); + }else { + printFullResponse(response); + } + } else { + console.log(`An error occurred when creating the contacts`); + } + +})(); diff --git a/examples/simple-examples/src/conversation/contact/update.ts b/examples/simple-examples/src/conversation/contact/update.ts new file mode 100644 index 00000000..f5c763ed --- /dev/null +++ b/examples/simple-examples/src/conversation/contact/update.ts @@ -0,0 +1,33 @@ +import { getContactIdFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config'; +import { UpdateContactRequestData } from '@sinch/sdk-core'; + +(async () => { + console.log('*************************'); + console.log('* Contact_UpdateContact *'); + console.log('*************************'); + + const contactId = getContactIdFromConfig(); + + const requestData: UpdateContactRequestData = { + contact_id: contactId, + update_mask:['channel_priority'], + updateContactRequestBody: { + display_name: 'Updated name with the Node.js SDK', + language: 'FR', + channel_priority: ['MESSENGER'], + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.contact.update(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Contact updated! New name: '${response.display_name}`); + console.log(`Verifying the language (it should be unchanged):\nOLD: 'EN-US'\nNEW: '${response.language}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/conversation/create.ts b/examples/simple-examples/src/conversation/conversation/create.ts new file mode 100644 index 00000000..4e1c993c --- /dev/null +++ b/examples/simple-examples/src/conversation/conversation/create.ts @@ -0,0 +1,45 @@ +import { CreateConversationRequestData } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, + getContactIdFromConfig, + getPrintFormat, + initClient, + printFullResponse, +} from '../../config'; + +(async () => { + console.log('***********************************'); + console.log('* Conversation_CreateConversation *'); + console.log('***********************************'); + + const appId = getAppIdFromConfig(); + const contactId = getContactIdFromConfig(); + + const requestData: CreateConversationRequestData = { + createConversationRequestBody: { + app_id: appId, + contact_id: contactId, + active: true, + active_channel: 'MESSENGER', + metadata: 'somme metadata', + metadata_json: { + date: new Date(), + string: 'metadata', + number: 0, + boolean: true, + }, + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.conversation.create(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`New contact created with the id '${response.id}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/conversation/delete.ts b/examples/simple-examples/src/conversation/conversation/delete.ts new file mode 100644 index 00000000..bea76e55 --- /dev/null +++ b/examples/simple-examples/src/conversation/conversation/delete.ts @@ -0,0 +1,21 @@ +import { DeleteConversationRequestData } from '@sinch/sdk-core'; +import { getConversationIdFromConfig, initClient, printFullResponse } from '../../config'; + + +(async () => { + console.log('***********************************'); + console.log('* Conversation_DeleteConversation *'); + console.log('***********************************'); + + const conversationId = getConversationIdFromConfig(); + + const requestData: DeleteConversationRequestData = { + conversation_id: conversationId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.conversation.delete(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/conversation/get.ts b/examples/simple-examples/src/conversation/conversation/get.ts new file mode 100644 index 00000000..7bcd5eec --- /dev/null +++ b/examples/simple-examples/src/conversation/conversation/get.ts @@ -0,0 +1,31 @@ +import { GetConversationRequestData } from '@sinch/sdk-core'; +import { + getConversationIdFromConfig, + getPrintFormat, + initClient, + printFullResponse, +} from '../../config'; + +(async () => { + console.log('********************************'); + console.log('* Conversation_GetConversation *'); + console.log('********************************'); + + const conversationId = getConversationIdFromConfig(); + + const requestData: GetConversationRequestData = { + conversation_id: conversationId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.conversation.get(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`The conversation with the id '${response.id}' has the last message received at '${response.last_received}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/conversation/injectMessage.ts b/examples/simple-examples/src/conversation/conversation/injectMessage.ts new file mode 100644 index 00000000..6f71aea3 --- /dev/null +++ b/examples/simple-examples/src/conversation/conversation/injectMessage.ts @@ -0,0 +1,47 @@ +import { InjectMessageRequestData } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, getContactIdFromConfig, + getConversationIdFromConfig, + getMessengerUserIdFromConfig, + initClient, + printFullResponse, +} from '../../config'; + + +(async () => { + console.log('***********************************'); + console.log('* Conversation_InjectMessage *'); + console.log('***********************************'); + + const conversationId = getConversationIdFromConfig(); + const messengerUserId = getMessengerUserIdFromConfig(); + const appId = getAppIdFromConfig(); + const contactId = getContactIdFromConfig(); + + const requestData: InjectMessageRequestData= { + conversation_id: conversationId, + injectMessageRequestBody: { + app_message: { + message: { + text_message: { + text: 'test', + }, + }, + }, + direction: 'TO_CONTACT', + channel_identity: { + channel: 'MESSENGER', + identity: messengerUserId, + app_id: appId, + }, + accept_time: new Date(), + contact_id: contactId, + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.conversation.injectMessage(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/conversation/list.ts b/examples/simple-examples/src/conversation/conversation/list.ts new file mode 100644 index 00000000..5aefa536 --- /dev/null +++ b/examples/simple-examples/src/conversation/conversation/list.ts @@ -0,0 +1,69 @@ +import { Conversation, ListConversationsRequestData, PageResult } from '@sinch/sdk-core'; +import { getAppIdFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config'; + +const populateConversationsList = ( + conversationPage: PageResult, + conversationList: Conversation[], + conversationDetailsList: string[], +) => { + conversationPage.data.map((conversation: Conversation) => { + conversationList.push(conversation); + conversationDetailsList.push(`${conversation.id} - ${conversation.active_channel}`); + }); +}; + +(async () => { + console.log('**********************************'); + console.log('* Conversation_ListConversations *'); + console.log('**********************************'); + + const appId = getAppIdFromConfig(); + + const requestData: ListConversationsRequestData = { + only_active: false, + app_id: appId, + }; + + const sinchClient = initClient(); + + // ---------------------------------------------- + // Method 1: Fetch the data page by page manually + // ---------------------------------------------- + let response = await sinchClient.conversation.conversation.list(requestData); + + const conversationList: Conversation[] = []; + const conversationDetailsList: string[] = []; + + // Loop on all the pages to get all the active numbers + let reachedEndOfPages = false; + while (!reachedEndOfPages) { + populateConversationsList(response, conversationList, conversationDetailsList); + if (response.hasNextPage) { + response = await response.nextPage(); + } else { + reachedEndOfPages = true; + } + } + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(conversationDetailsList.length > 0 + ? 'List of conversations:\n' + conversationDetailsList.join('\n') + : 'Sorry, no conversations were found.'); + } else { + printFullResponse(conversationList); + } + + // --------------------------------------------------------------------- + // Method 2: Use the iterator and fetch data on more pages automatically + // --------------------------------------------------------------------- + for await (const conversation of sinchClient.conversation.conversation.list(requestData)) { + if (printFormat === 'pretty') { + console.log(`${conversation.id} - ${conversation.active_channel}`); + } else { + console.log(conversation); + } + } + +})(); diff --git a/examples/simple-examples/src/conversation/conversation/stop.ts b/examples/simple-examples/src/conversation/conversation/stop.ts new file mode 100644 index 00000000..606c56c1 --- /dev/null +++ b/examples/simple-examples/src/conversation/conversation/stop.ts @@ -0,0 +1,21 @@ +import { StopActiveConversationRequestData } from '@sinch/sdk-core'; +import { getConversationIdFromConfig, initClient, printFullResponse } from '../../config'; + + +(async () => { + console.log('***************************************'); + console.log('* Conversation_StopActiveConversation *'); + console.log('***************************************'); + + const conversationId = getConversationIdFromConfig(); + + const requestData: StopActiveConversationRequestData = { + conversation_id: conversationId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.conversation.stopActive(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/conversation/update.ts b/examples/simple-examples/src/conversation/conversation/update.ts new file mode 100644 index 00000000..81d12b51 --- /dev/null +++ b/examples/simple-examples/src/conversation/conversation/update.ts @@ -0,0 +1,37 @@ +import { + getConversationIdFromConfig, + getPrintFormat, + initClient, + printFullResponse, +} from '../../config'; +import { UpdateConversationRequestData } from '@sinch/sdk-core'; + +(async () => { + console.log('***********************************'); + console.log('* Conversation_UpdateConversation *'); + console.log('***********************************'); + + const conversationId = getConversationIdFromConfig(); + + const requestData: UpdateConversationRequestData = { + conversation_id: conversationId, + update_mask: ['metadata'], + updateConversationRequestBody: { + metadata: 'Updates metadata', + active_channel: 'KAKAOTALK', + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.conversation.update(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Conversation updated! New metadata: '${response.metadata}`); + console.log(`Verifying the active channel (it should be unchanged):\nOLD: 'MESSENGER'\nNEW: '${response.active_channel}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/events/send.ts b/examples/simple-examples/src/conversation/events/send.ts new file mode 100644 index 00000000..6aed9db1 --- /dev/null +++ b/examples/simple-examples/src/conversation/events/send.ts @@ -0,0 +1,33 @@ +import { SendEventRequestData } from '@sinch/sdk-core'; +import { getAppIdFromConfig, getContactIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('********************'); + console.log('* Events_SendEvent *'); + console.log('********************'); + + const appId = getAppIdFromConfig(); + const contactId = getContactIdFromConfig(); + + const requestData: SendEventRequestData = { + sendEventRequestBody: { + app_id: appId, + recipient: { + contact_id: contactId, + }, + event: { + generic_event: { + payload: { + key: 'value for the generic event', + }, + }, + }, + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.events.send(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/messages/delete.ts b/examples/simple-examples/src/conversation/messages/delete.ts new file mode 100644 index 00000000..e2f0fb8d --- /dev/null +++ b/examples/simple-examples/src/conversation/messages/delete.ts @@ -0,0 +1,21 @@ +import { DeleteMessageRequestData } from '@sinch/sdk-core'; +import { getMessageIdFromConfig, initClient, printFullResponse } from '../../config'; + + +(async () => { + console.log('**************************'); + console.log('* Messages_DeleteMessage *'); + console.log('**************************'); + + const messageId = getMessageIdFromConfig(); + + const requestData: DeleteMessageRequestData = { + message_id: messageId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.messages.delete(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/messages/get.ts b/examples/simple-examples/src/conversation/messages/get.ts new file mode 100644 index 00000000..ddbbad18 --- /dev/null +++ b/examples/simple-examples/src/conversation/messages/get.ts @@ -0,0 +1,20 @@ +import { GetMessageRequestData } from '@sinch/sdk-core'; +import { getMessageIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('***********************'); + console.log('* Messages_GetMessage *'); + console.log('***********************'); + + const messageId = getMessageIdFromConfig(); + + const requestData: GetMessageRequestData = { + message_id: messageId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.messages.get(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/messages/list.ts b/examples/simple-examples/src/conversation/messages/list.ts new file mode 100644 index 00000000..b6faf157 --- /dev/null +++ b/examples/simple-examples/src/conversation/messages/list.ts @@ -0,0 +1,79 @@ +import { ConversationMessage, ListMessagesRequestData, PageResult } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, + getContactIdFromConfig, getConversationIdFromConfig, + getPrintFormat, + initClient, + printFullResponse, +} from '../../config'; + +const populateMessagesList = ( + conversationPage: PageResult, + conversationList: ConversationMessage[], + conversationDetailsList: string[], +) => { + conversationPage.data.map((message: ConversationMessage) => { + conversationList.push(message); + conversationDetailsList.push(`${message.id} - ${message.accept_time}`); + }); +}; + +(async () => { + console.log('*************************'); + console.log('* Messages_ListMessages *'); + console.log('*************************'); + + const appId = getAppIdFromConfig(); + const contactId = getContactIdFromConfig(); + const conversationId = getConversationIdFromConfig(); + + const requestData: ListMessagesRequestData = { + app_id: appId, + contact_id: contactId, + conversation_id: conversationId, + channel: 'MESSENGER', + }; + + const sinchClient = initClient(); + + // ---------------------------------------------- + // Method 1: Fetch the data page by page manually + // ---------------------------------------------- + let response = await sinchClient.conversation.messages.list(requestData); + + const messageList: ConversationMessage[] = []; + const messagesDetailsList: string[] = []; + + // Loop on all the pages to get all the active numbers + let reachedEndOfPages = false; + while (!reachedEndOfPages) { + populateMessagesList(response, messageList, messagesDetailsList); + if (response.hasNextPage) { + response = await response.nextPage(); + } else { + reachedEndOfPages = true; + } + } + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(messagesDetailsList.length > 0 + ? 'List of messages:\n' + messagesDetailsList.join('\n') + : 'Sorry, no messages were found.'); + } else { + printFullResponse(messageList); + } + + // --------------------------------------------------------------------- + // Method 2: Use the iterator and fetch data on more pages automatically + // --------------------------------------------------------------------- + for await (const message of sinchClient.conversation.messages.list(requestData)) { + if (printFormat === 'pretty') { + console.log(`${message.id} - ${message.accept_time}`); + } else { + console.log(message); + } + } + +})(); diff --git a/examples/simple-examples/src/conversation/messages/send.ts b/examples/simple-examples/src/conversation/messages/send.ts new file mode 100644 index 00000000..6f4468c9 --- /dev/null +++ b/examples/simple-examples/src/conversation/messages/send.ts @@ -0,0 +1,35 @@ +import { SendMessageRequestData } from '@sinch/sdk-core'; +import { getAppIdFromConfig, getContactIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('************************'); + console.log('* Messages_SendMessage *'); + console.log('************************'); + + const appId = getAppIdFromConfig(); + const contactId = getContactIdFromConfig(); + + const requestData: SendMessageRequestData = { + sendMessageRequestBody: { + app_id: appId, + message: { + text_message: { + text: 'Text message from Sinch', + }, + }, + recipient: { + contact_id: contactId, + }, + correlation_id: 'correlator', + queue: 'HIGH_PRIORITY', + processing_strategy: 'DEFAULT', + channel_priority_order: ['MESSENGER'], + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.messages.send(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/transcoding/transcode.ts b/examples/simple-examples/src/conversation/transcoding/transcode.ts new file mode 100644 index 00000000..b2f3b477 --- /dev/null +++ b/examples/simple-examples/src/conversation/transcoding/transcode.ts @@ -0,0 +1,50 @@ +import { TranscodeMessageRequestData } from '@sinch/sdk-core'; +import { getAppIdFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('********************************'); + console.log('* Transcoding_TranscodeMessage *'); + console.log('********************************'); + + const appId = getAppIdFromConfig(); + + const requestData: TranscodeMessageRequestData = { + transcodeMessageRequestBody: { + app_id: appId, + app_message: { + location_message: { + title: 'Phare d\'Eckmühl', + label: 'Pointe de Penmarch', + coordinates: { + latitude: 47.7981899, + longitude: -4.3727685, + }, + }, + }, + channels: [ + 'MESSENGER', + ], + from: 'from', + to: 'to', + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.transcoding.transcodeMessage(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + if (response.transcoded_message) { + console.log(`Transcoded messages:\n - ${Object.keys(response.transcoded_message) + .map((key: string) => { + const transcodedMessage = JSON.parse(response.transcoded_message![key]); + return key + ': ' + JSON.stringify(transcodedMessage.message); + })}`); + } else { + console.log('No transcoded messages returned.'); + } + } else { + printFullResponse(response); + } +})(); diff --git a/examples/simple-examples/src/conversation/webhooks/create.ts b/examples/simple-examples/src/conversation/webhooks/create.ts new file mode 100644 index 00000000..b5789d10 --- /dev/null +++ b/examples/simple-examples/src/conversation/webhooks/create.ts @@ -0,0 +1,46 @@ +import { CreateWebhookRequestData } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, + getPrintFormat, getWebhookTargetFromConfig, + initClient, + printFullResponse, +} from '../../config'; + +(async () => { + console.log('**************************'); + console.log('* Webhooks_CreateWebhook *'); + console.log('**************************'); + + const appId = getAppIdFromConfig(); + const webhookTarget = getWebhookTargetFromConfig(); + + const requestData: CreateWebhookRequestData = { + webhookCreateRequestBody: { + app_id: appId, + target: webhookTarget, + target_type: 'HTTP', + triggers: [ + 'MESSAGE_DELIVERY', + 'MESSAGE_INBOUND', + 'CAPABILITY', + 'CONTACT_CREATE', + 'CONTACT_UPDATE', + 'CONTACT_DELETE', + 'CONTACT_MERGE', + ], + secret: 'A secret', + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.webhooks.create(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`New webhook created with the id '${response.id}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/webhooks/delete.ts b/examples/simple-examples/src/conversation/webhooks/delete.ts new file mode 100644 index 00000000..66b692cf --- /dev/null +++ b/examples/simple-examples/src/conversation/webhooks/delete.ts @@ -0,0 +1,21 @@ +import { DeleteWebhookRequestData } from '@sinch/sdk-core'; +import { getWebhookIdFromConfig, initClient, printFullResponse } from '../../config'; + + +(async () => { + console.log('**************************'); + console.log('* Webhooks_DeleteWebhook *'); + console.log('**************************'); + + const webhookId = getWebhookIdFromConfig(); + + const requestData: DeleteWebhookRequestData = { + webhook_id: webhookId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.webhooks.delete(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/webhooks/get.ts b/examples/simple-examples/src/conversation/webhooks/get.ts new file mode 100644 index 00000000..2ce54894 --- /dev/null +++ b/examples/simple-examples/src/conversation/webhooks/get.ts @@ -0,0 +1,31 @@ +import { GetWebhookRequestData } from '@sinch/sdk-core'; +import { + getPrintFormat, + getWebhookIdFromConfig, + initClient, + printFullResponse, +} from '../../config'; + +(async () => { + console.log('***********************'); + console.log('* Webhooks_GetWebhook *'); + console.log('***********************'); + + const webhookId = getWebhookIdFromConfig(); + + const requestData: GetWebhookRequestData = { + webhook_id: webhookId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.webhooks.get(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Webhook id: ${response.id} - Triggers: ${response.triggers.join(', ')}`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/webhooks/list.ts b/examples/simple-examples/src/conversation/webhooks/list.ts new file mode 100644 index 00000000..3df1d1ae --- /dev/null +++ b/examples/simple-examples/src/conversation/webhooks/list.ts @@ -0,0 +1,30 @@ +import { ListWebhooksRequestData } from '@sinch/sdk-core'; +import { getAppIdFromConfig, getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*************************'); + console.log('* Webhooks_ListWebhooks *'); + console.log('*************************'); + + const appId = getAppIdFromConfig(); + + const requestData: ListWebhooksRequestData = { + app_id: appId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.webhooks.list(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + if (response.webhooks && response.webhooks.length > 0) { + console.log(`${response.webhooks.map((webhook) => `Webhook id: ${webhook.id} - Triggers: ${webhook.triggers.join(', ')}`).join('\n')}`); + } else { + console.log('Sorry, no webhooks were found.'); + } + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/webhooks/update.ts b/examples/simple-examples/src/conversation/webhooks/update.ts new file mode 100644 index 00000000..be113477 --- /dev/null +++ b/examples/simple-examples/src/conversation/webhooks/update.ts @@ -0,0 +1,45 @@ +import { UpdateWebhookRequestData } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, + getPrintFormat, getWebhookIdFromConfig, + initClient, + printFullResponse, +} from '../../config'; + + +(async () => { + console.log('**************************'); + console.log('* Webhooks_UpdateWebhook *'); + console.log('**************************'); + + const webhookId = getWebhookIdFromConfig(); + const appId = getAppIdFromConfig(); + + const requestData: UpdateWebhookRequestData = { + webhook_id: webhookId, + update_mask: ['triggers', 'secret'], + webhookUpdateRequestBody: { + app_id: appId, + triggers: [ + 'CONVERSATION_START', + 'CONVERSATION_STOP', + 'CONVERSATION_DELETE', + ], + target: 'http://no-update.url', + secret: 'New secret', + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.webhooks.update(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Webhook updated! New triggers: '${response.triggers.join(', ')}`); + console.log(`Verifying the target (it should the original URL): '${response.target}'`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/webhooks/src/app.module.ts b/examples/webhooks/src/app.module.ts index 21df1f8b..5d6a66e4 100644 --- a/examples/webhooks/src/app.module.ts +++ b/examples/webhooks/src/app.module.ts @@ -4,11 +4,13 @@ import { NumbersService } from './services/numbers.service'; import { SmsService } from './services/sms.service'; import { VerificationService } from './services/verification.service'; import { VoiceService } from './services/voice.service'; +import { ConversationService } from './services/conversation.service'; @Module({ imports: [], controllers: [AppController], providers: [ + ConversationService, NumbersService, SmsService, VerificationService, diff --git a/examples/webhooks/src/controller/app.controller.ts b/examples/webhooks/src/controller/app.controller.ts index b7873867..17b24dc2 100644 --- a/examples/webhooks/src/controller/app.controller.ts +++ b/examples/webhooks/src/controller/app.controller.ts @@ -11,6 +11,7 @@ import { import { SmsService } from '../services/sms.service'; import { VerificationService } from '../services/verification.service'; import { VoiceService } from '../services/voice.service'; +import { ConversationService } from '../services/conversation.service'; require('dotenv').config(); const SINCH_APPLICATION_KEY = process.env.SINCH_APPLICATION_KEY || ''; @@ -20,6 +21,7 @@ const SINCH_APPLICATION_SECRET = process.env.SINCH_APPLICATION_SECRET || ''; export class AppController { constructor( + private readonly conversationService: ConversationService, private readonly numbersService: NumbersService, private readonly smsService: SmsService, private readonly verificationService: VerificationService, @@ -91,4 +93,10 @@ export class AppController { res.status(500).send(); } } + + @Post('/conversation') + public conversation(@Body() requestBody: any, @Res() res: Response) { + this.conversationService.handleEvent(JSON.stringify(requestBody)); + res.status(200).send(); + } } diff --git a/examples/webhooks/src/services/conversation.service.ts b/examples/webhooks/src/services/conversation.service.ts new file mode 100644 index 00000000..d92300ab --- /dev/null +++ b/examples/webhooks/src/services/conversation.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class ConversationService { + + handleEvent(event: string): void { + console.log(event); + } +} diff --git a/jest.config.ts b/jest.config.ts index 21e88f3e..865fface 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -9,6 +9,11 @@ const config: Config.InitialOptions = { testMatch: ['/packages/sdk-client/tests/**/*.test.ts'], coveragePathIgnorePatterns: ['node_modules', 'tests'], }, + { + displayName: 'Conversation', + testMatch: ['/packages/conversation/tests/**/*.test.ts'], + coveragePathIgnorePatterns: ['node_modules', 'tests'], + }, { displayName: 'Numbers', testMatch: ['/packages/numbers/tests/**/*.test.ts'], diff --git a/packages/conversation/tests/rest/v1/app/app-api.test.ts b/packages/conversation/tests/rest/v1/app/app-api.test.ts new file mode 100644 index 00000000..b623f4ec --- /dev/null +++ b/packages/conversation/tests/rest/v1/app/app-api.test.ts @@ -0,0 +1,150 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { + AppResponse, + CreateAppRequestData, + DeleteAppRequestData, + GetAppRequestData, + ListAppsRequestData, UpdateAppRequestData, +} from '../../../../src'; +import { ListAppsResponse } from '../../../../src'; +import { AppApi, AppApiFixture } from '../../../../src'; + +describe('AppApi', () => { + let appApi: AppApi; + let fixture: AppApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new AppApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + appApi = new AppApi(credentials); + }); + + + describe ('createApp', () => { + it('should make a POST request to create a new Conversation App', async () => { + // Given + const requestData: CreateAppRequestData = { + appCreateRequestBody: { + display_name: 'Test App', + channel_credentials: [ + { + channel: 'WHATSAPP', + static_bearer: { + claimed_identity: 'identity', + token: 'token', + }, + }, + ], + }, + }; + const expectedResponse: AppResponse = { + id: 'app_id', + display_name: 'Test App', + }; + + // When + fixture.create.mockResolvedValue(expectedResponse); + appApi.create = fixture.create; + const response = await appApi.create(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.create).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('deleteApp', () => { + it('should make a DELETE request to delete the specified App ID', async () => { + // Given + const requestData: DeleteAppRequestData = { + app_id: 'app_id', + }; + const expectedResponse: any = {}; + + // When + fixture.delete.mockResolvedValue(expectedResponse); + appApi.delete = fixture.delete; + const response = await appApi.delete(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.delete).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('getApp', () => { + it('should make a GET request to retrieve the particular app as specified by the App ID', async () => { + // Given + const requestData: GetAppRequestData = { + app_id: 'app_id', + }; + const expectedResponse: AppResponse = { + id: 'app_id', + display_name: 'Test App', + }; + + // When + fixture.get.mockResolvedValue(expectedResponse); + appApi.get = fixture.get; + const response = await appApi.get(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.get).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('listApps', () => { + it('should make a GET request to get the list of all apps', async () => { + // Given + const requestData: ListAppsRequestData = {}; + const expectedResponse: ListAppsResponse = { + apps: [ + { + id: 'app_id', + display_name: 'Test App', + }, + ], + }; + + // When + fixture.list.mockResolvedValue(expectedResponse); + appApi.list = fixture.list; + const response = await appApi.list(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.list).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('updateApp', () => { + it('should make a PATCH request to update a particular app as specified by the App ID', async () => { + // Given + const requestData: UpdateAppRequestData = { + app_id: 'app_id', + appUpdateRequestBody: { + display_name: 'New display name', + }, + }; + const expectedResponse: AppResponse = { + id: 'app_id', + display_name: 'New display name', + }; + + // When + fixture.update.mockResolvedValue(expectedResponse); + appApi.update = fixture.update; + const response = await appApi.update(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.update).toHaveBeenCalledWith(requestData); + }); + }); +}); diff --git a/packages/conversation/tests/rest/v1/capability/capability-api.test.ts b/packages/conversation/tests/rest/v1/capability/capability-api.test.ts new file mode 100644 index 00000000..e94f2d4c --- /dev/null +++ b/packages/conversation/tests/rest/v1/capability/capability-api.test.ts @@ -0,0 +1,53 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { LookupCapabilityRequestData, QueryCapabilityResponse } from '../../../../src'; +import { CapabilityApi, CapabilityApiFixture } from '../../../../src'; + +describe('CapabilityApi', () => { + let capabilityApi: CapabilityApi; + let fixture: CapabilityApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new CapabilityApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + capabilityApi = new CapabilityApi(credentials); + }); + + + describe ('queryCapability', () => { + it('should make a POST request to ...', async () => { + // Given + const requestData: LookupCapabilityRequestData = { + lookupCapabilityRequestBody: { + app_id: 'app_id', + recipient: { + identified_by: { + channel_identities: [ + { + identity: 'Whatsapp identity', + channel: 'WHATSAPP', + }, + ], + }, + }, + }, + }; + const expectedResponse: QueryCapabilityResponse = { + app_id: 'app_id', + }; + + // When + fixture.lookup.mockResolvedValue(expectedResponse); + capabilityApi.lookup = fixture.lookup; + const response = await capabilityApi.lookup(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.lookup).toHaveBeenCalledWith(requestData); + }); + }); +}); diff --git a/packages/conversation/tests/rest/v1/contact/contact-api.test.ts b/packages/conversation/tests/rest/v1/contact/contact-api.test.ts new file mode 100644 index 00000000..d235f626 --- /dev/null +++ b/packages/conversation/tests/rest/v1/contact/contact-api.test.ts @@ -0,0 +1,215 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { + Contact, + CreateContactRequestData, + DeleteContactRequestData, + GetChannelProfileRequestData, + GetContactRequestData, + ListContactsRequestData, + MergeContactRequestData, + UpdateContactRequestData, + GetChannelProfileResponse, + ContactApi, ContactApiFixture, +} from '../../../../src'; + +describe('ContactApi', () => { + let contactApi: ContactApi; + let fixture: ContactApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new ContactApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + contactApi = new ContactApi(credentials); + }); + + + describe ('createContact', () => { + it('should make a POST request to create a contact manually', async () => { + // Given + const requestData: CreateContactRequestData = { + contactCreateRequestBody: { + channel_identities: [ + { + identity: 'Whatsapp identity', + channel: 'WHATSAPP', + }, + ], + language: 'EN_US', + display_name: 'A contact', + }, + }; + const expectedResponse: Contact = { + id: 'contact_id', + language: 'EN_US', + }; + + // When + fixture.create.mockResolvedValue(expectedResponse); + contactApi.create = fixture.create; + const response = await contactApi.create(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.create).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('deleteContact', () => { + it('should make a DELETE request to delete a contact as specified by the contact ID', async () => { + // Given + const requestData: DeleteContactRequestData = { + contact_id: 'contact_id', + }; + const expectedResponse: any = {}; + + // When + fixture.delete.mockResolvedValue(expectedResponse); + contactApi.delete = fixture.delete; + const response = await contactApi.delete(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.delete).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('getChannelProfile', () => { + it('should make a POST request to get a user profile from a specific channel', async () => { + // Given + const requestData: GetChannelProfileRequestData = { + getChannelProfileRequestBody: { + app_id: 'app_id', + channel: 'MESSENGER', + recipient: { + identified_by: { + channel_identities: [ + { + identity: '', + channel: 'WHATSAPP', + }, + ], + }, + }, + }, + }; + const expectedResponse: GetChannelProfileResponse = { + profile_name: 'Profile Name', + }; + + // When + fixture.getChannelProfile.mockResolvedValue(expectedResponse); + contactApi.getChannelProfile = fixture.getChannelProfile; + const response = await contactApi.getChannelProfile(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.getChannelProfile).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('getContact', () => { + it('should make a GET request to retrieve a specific contact as specified by the contact ID', async () => { + // Given + const requestData: GetContactRequestData = { + contact_id: 'contact_id', + }; + const expectedResponse: Contact = { + id: 'contact_id', + language: 'EN_US', + channel_priority: ['WHATSAPP'], + email: 'mail@mail.com', + }; + + // When + fixture.get.mockResolvedValue(expectedResponse); + contactApi.get = fixture.get; + const response = await contactApi.get(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.get).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('listContacts', () => { + it('should make a GET request to list all contacts in the project', async () => { + // Given + const requestData: ListContactsRequestData = {}; + const mockData: Contact[] = [ + { + id: 'contact_id', + }, + ]; + const expectedResponse = { + data: mockData, + hasNextPage: false, + nextPageValue: '', + nextPage: jest.fn(), + }; + + // When + fixture.list.mockResolvedValue(expectedResponse); + contactApi.list = fixture.list; + const response = await contactApi.list(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(response.data).toBeDefined(); + expect(fixture.list).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('mergeContact', () => { + it('should make a POST request to merge two contacts', async () => { + // Given + const requestData: MergeContactRequestData = { + destination_id: 'contact_id', + mergeContactRequestBody: { + source_id: 'to_be_removed_contact_id', + strategy: 'MERGE', + }, + }; + const expectedResponse: Contact = { + id: 'contact_id', + }; + + // When + fixture.mergeContact.mockResolvedValue(expectedResponse); + contactApi.mergeContact = fixture.mergeContact; + const response = await contactApi.mergeContact(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.mergeContact).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('updateContact', () => { + it('should make a PATCH request to update a contact as specified by the contact ID', async () => { + // Given + const requestData: UpdateContactRequestData = { + contact_id: 'contact_id', + updateContactRequestBody: { + language: 'EN_GB', + }, + }; + const expectedResponse: Contact = { + id: 'contact_id', + }; + + // When + fixture.update.mockResolvedValue(expectedResponse); + contactApi.update = fixture.update; + const response = await contactApi.update(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.update).toHaveBeenCalledWith(requestData); + }); + }); +}); diff --git a/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts b/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts new file mode 100644 index 00000000..2159c578 --- /dev/null +++ b/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts @@ -0,0 +1,204 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { + Conversation, + CreateConversationRequestData, + ConversationApi, + ConversationApiFixture, + DeleteConversationRequestData, + GetConversationRequestData, + InjectMessageRequestData, + ListConversationsRequestData, + StopActiveConversationRequestData, + UpdateConversationRequestData, +} from '../../../../src'; + +describe('ConversationApi', () => { + let conversationApi: ConversationApi; + let fixture: ConversationApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new ConversationApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + conversationApi = new ConversationApi(credentials); + }); + + + describe ('createConversation', () => { + it('should make a POST request to create a new empty conversation', async () => { + // Given + const requestData: CreateConversationRequestData = { + createConversationRequestBody: { + app_id: 'app_id', + contact_id: 'contact_id', + }, + }; + const expectedResponse: Conversation = { + id: 'conversation_id', + }; + + // When + fixture.create.mockResolvedValue(expectedResponse); + conversationApi.create = fixture.create; + const response = await conversationApi.create(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.create).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('deleteConversation', () => { + it('should make a DELETE request to delete a conversation and all messages related', async () => { + // Given + const requestData: DeleteConversationRequestData = { + conversation_id: 'conversation_id', + }; + const expectedResponse: any = {}; + + // When + fixture.delete.mockResolvedValue(expectedResponse); + conversationApi.delete = fixture.delete; + const response = await conversationApi.delete(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.delete).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('getConversation', () => { + it('should make a GET request to retrieve a conversation by id', async () => { + // Given + const requestData: GetConversationRequestData = { + conversation_id: 'conversation_id', + }; + const expectedResponse: Conversation = { + id: 'conversation_id', + }; + + // When + fixture.get.mockResolvedValue(expectedResponse); + conversationApi.get = fixture.get; + const response = await conversationApi.get(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.get).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('injectMessage', () => { + it('should make a POST request to inject a conversation message in to a specific conversation', async () => { + // Given + const requestData: InjectMessageRequestData = { + conversation_id: 'conversation_id', + injectMessageRequestBody: { + app_message: { + message: { + card_message: { + choices: [], + title: 'title', + description: 'description', + }, + }, + }, + }, + }; + const expectedResponse: any = {}; + + // When + fixture.injectMessage.mockResolvedValue(expectedResponse); + conversationApi.injectMessage = fixture.injectMessage; + const response = await conversationApi.injectMessage(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.injectMessage).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('listConversations', () => { + it('should make a GET request to ...', async () => { + // Given + const requestData: ListConversationsRequestData = { + only_active: false, + }; + const mockData: Conversation[] = [ + { + id: 'conversation_id', + active: true, + }, + ]; + const expectedResponse= { + data: mockData, + hasNextPage: false, + nextPageValue: '', + nextPage: jest.fn(), + }; + + // When + fixture.list.mockResolvedValue(expectedResponse); + conversationApi.list = fixture.list; + const response = await conversationApi.list(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(response.data).toBeDefined(); + expect(fixture.list).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('stopActiveConversation', () => { + it('should make a POST request to stop the referenced conversation', async () => { + // Given + const requestData: StopActiveConversationRequestData = { + conversation_id: 'conversation_id', + }; + const expectedResponse: any = {}; + + // When + fixture.stopActive.mockResolvedValue(expectedResponse); + conversationApi.stopActive = fixture.stopActive; + const response = await conversationApi.stopActive(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.stopActive).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('updateConversation', () => { + it('should make a PATCH request to update a conversation', async () => { + // Given + const requestData: UpdateConversationRequestData = { + conversation_id: 'conversation_id', + metadata_update_strategy: 'REPLACE', + updateConversationRequestBody: { + app_id: 'app_id', + metadata: 'Some metadata', + metadata_json: { + whatever: 'whatever', + number: 0, + }, + }, + }; + const expectedResponse: Conversation = { + id: 'conversation_id', + }; + + // When + fixture.update.mockResolvedValue(expectedResponse); + conversationApi.update = fixture.update; + const response = await conversationApi.update(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.update).toHaveBeenCalledWith(requestData); + }); + }); +}); diff --git a/packages/conversation/tests/rest/v1/events/events-api.test.ts b/packages/conversation/tests/rest/v1/events/events-api.test.ts new file mode 100644 index 00000000..79530ccc --- /dev/null +++ b/packages/conversation/tests/rest/v1/events/events-api.test.ts @@ -0,0 +1,54 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { GenericEvent, SendEventRequestData, SendEventResponse } from '../../../../src'; +import { EventsApi, EventsApiFixture } from '../../../../src'; + +describe('EventsApi', () => { + let eventsApi: EventsApi; + let fixture: EventsApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new EventsApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + eventsApi = new EventsApi(credentials); + }); + + + describe ('sendEvent', () => { + it('should make a POST request to send an event to the referenced contact from the referenced app', async () => { + // Given + const requestData: SendEventRequestData = { + sendEventRequestBody: { + app_id: 'app_id', + recipient: { + contact_id: 'contact_id', + }, + event: { + generic_event: { + payload: { + some: 'data', + }, + }, + } as GenericEvent, + }, + }; + const expectedResponse: SendEventResponse = { + accepted_time: new Date('2019-08-24T14:15:22Z'), + event_id: 'event_id', + }; + + // When + fixture.send.mockResolvedValue(expectedResponse); + eventsApi.send = fixture.send; + const response = await eventsApi.send(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.send).toHaveBeenCalledWith(requestData); + }); + }); +}); diff --git a/packages/conversation/tests/rest/v1/messages/messages-api.test.ts b/packages/conversation/tests/rest/v1/messages/messages-api.test.ts new file mode 100644 index 00000000..d332efb3 --- /dev/null +++ b/packages/conversation/tests/rest/v1/messages/messages-api.test.ts @@ -0,0 +1,245 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { + ConversationMessage, + DeleteMessageRequestData, + GetMessageRequestData, + ListMessagesRequestData, SendMessageRequestData, +} from '../../../../src'; +import { SendMessageResponse } from '../../../../src'; +import { MessagesApi, MessagesApiFixture } from '../../../../src'; + +describe('MessagesApi', () => { + let messagesApi: MessagesApi; + let fixture: MessagesApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new MessagesApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + messagesApi = new MessagesApi(credentials); + }); + + + describe ('deleteMessage', () => { + it('should make a DELETE request to delete a specific message by its ID', async () => { + // Given + const requestData: DeleteMessageRequestData = { + message_id: 'message_id', + }; + const expectedResponse: any = {}; + + // When + fixture.delete.mockResolvedValue(expectedResponse); + messagesApi.delete = fixture.delete; + const response = await messagesApi.delete(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.delete).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('getMessage', () => { + it('should make a GET request to retrieve a specific message by its ID', async () => { + // Given + const requestData: GetMessageRequestData = { + message_id: 'message_id', + }; + const expectedResponse: ConversationMessage = { + accept_time: new Date('2019-08-24T14:15:22Z'), + app_message: { + message: { + card_message: { + choices: [], + description: 'description', + height: 'UNSPECIFIED_HEIGHT', + media_message: { + url: 'url', + }, + title: 'title', + }, + }, + explicit_channel_message: {}, + additionalProperties: { + contact_name: 'contactName', + }, + }, + channel_identity: { + app_id: 'app_id', + channel: 'WHATSAPP', + identity: 'identity', + }, + contact_id: 'contact_id', + contact_message: { + choice_response_message: { + message_id: 'message_id', + postback_data: 'postback-data', + }, + fallback_message: { + raw_message: 'raw', + reason: { + code: 'UNKNOWN', + description: 'description', + sub_code: 'UNSPECIFIED_SUB_CODE', + }, + }, + location_message: { + title: 'title', + label: 'label', + coordinates: { + latitude: 0, + longitude: 0, + }, + }, + media_card_message: { + url: 'url', + caption: 'caption', + }, + media_message: { + url: 'url', + filename_override: 'filename', + thumbnail_url: 'thumbnail', + }, + reply_to: { + message_id: 'message_id', + }, + text_message: { + text: 'text', + }, + }, + conversation_id: 'conversation_id', + direction: 'UNDEFINED_DIRECTION', + id: 'id', + metadata: 'metadata', + injected: true, + }; + + // When + fixture.get.mockResolvedValue(expectedResponse); + messagesApi.get = fixture.get; + const response = await messagesApi.get(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.get).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('listMessages', () => { + it('should make a GET request to list all the messages sent or received', async () => { + // Given + const requestData: ListMessagesRequestData = {}; + const mockData: ConversationMessage[] = [ + { + accept_time: new Date('2019-08-24T14:15:22Z'), + app_message: { + message: { + card_message: { + choices: [ + { + call_message: { + title: 'title', + phone_number: 'number', + }, + location_message: { + coordinates: { + latitude: 0, + longitude: 0, + }, + title: 'title', + label: 'label', + }, + postback_data: 'data', + text_message: { + text: 'text', + }, + url_message: { + url: 'url', + title: 'title', + }, + }, + ], + description: 'description', + height: 'UNSPECIFIED_HEIGHT', + media_message: { + url: 'url', + }, + title: 'title', + }, + }, + explicit_channel_message: {}, + additionalProperties: { + contact_name: 'contact_name', + }, + }, + channel_identity: { + identity: 'identity', + app_id: 'app_id', + channel: 'WHATSAPP', + }, + contact_id: 'contact_id', + contact_message: { + + }, + conversation_id: 'conversation_id', + direction: 'UNDEFINED_DIRECTION', + id: 'id', + metadata: 'metadata', + injected: true, + }, + ]; + const expectedResponse = { + data: mockData, + hasNextPage: false, + nextPageValue: '', + nextPage: jest.fn(), + }; + + // When + fixture.list.mockResolvedValue(expectedResponse); + messagesApi.list = fixture.list; + const response = await messagesApi.list(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(response.data).toBeDefined(); + expect(fixture.list).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('sendMessage', () => { + it('should make a POST request to send a request from a conversation app to a contact', async () => { + // Given + const requestData: SendMessageRequestData = { + sendMessageRequestBody: { + app_id: 'app_id', + recipient: { + contact_id: 'contact_id', + }, + message: { + text_message: { + text: 'text', + }, + }, + }, + }; + const expectedResponse: SendMessageResponse = { + accepted_time: new Date('2019-08-24T14:15:22Z'), + message_id: 'message_id', + }; + + // When + fixture.send.mockResolvedValue(expectedResponse); + messagesApi.send = fixture.send; + const response = await messagesApi.send(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.send).toHaveBeenCalledWith(requestData); + }); + }); +}); diff --git a/packages/conversation/tests/rest/v1/transcoding/transcoding-api.test.ts b/packages/conversation/tests/rest/v1/transcoding/transcoding-api.test.ts new file mode 100644 index 00000000..f5853f8b --- /dev/null +++ b/packages/conversation/tests/rest/v1/transcoding/transcoding-api.test.ts @@ -0,0 +1,54 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { TranscodeMessageRequestData, TranscodeMessageResponse } from '../../../../src'; +import { TranscodingApi, TranscodingApiFixture } from '../../../../src'; + +describe('TranscodingApi', () => { + let transcodingApi: TranscodingApi; + let fixture: TranscodingApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new TranscodingApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + transcodingApi = new TranscodingApi(credentials); + }); + + + describe ('transcodeMessage', () => { + it('should make a POST request to transcode a generic message to a channel-specific one', async () => { + // Given + const requestData: TranscodeMessageRequestData = { + transcodeMessageRequestBody: { + app_id: 'app_id', + app_message: { + text_message: { + text: 'Text message to be transcoded', + }, + }, + channels: [ + 'WHATSAPP', + ], + }, + }; + const expectedResponse: TranscodeMessageResponse = { + transcoded_message: { + property1: 'string', + property2: 'string', + }, + }; + + // When + fixture.transcodeMessage.mockResolvedValue(expectedResponse); + transcodingApi.transcodeMessage = fixture.transcodeMessage; + const response = await transcodingApi.transcodeMessage(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.transcodeMessage).toHaveBeenCalledWith(requestData); + }); + }); +}); diff --git a/packages/conversation/tests/rest/v1/webhooks/webhooks-api.test.ts b/packages/conversation/tests/rest/v1/webhooks/webhooks-api.test.ts new file mode 100644 index 00000000..06824169 --- /dev/null +++ b/packages/conversation/tests/rest/v1/webhooks/webhooks-api.test.ts @@ -0,0 +1,194 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { + CreateWebhookRequestData, + DeleteWebhookRequestData, + GetWebhookRequestData, ListWebhooksRequestData, + ListWebhooksResponse, UpdateWebhookRequestData, +} from '../../../../src'; +import { Webhook } from '../../../../src'; +import { WebhooksApi, WebhooksApiFixture } from '../../../../src'; + +describe('WebhooksApi', () => { + let webhooksApi: WebhooksApi; + let fixture: WebhooksApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new WebhooksApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + webhooksApi = new WebhooksApi(credentials); + }); + + + describe ('createWebhook', () => { + it('should make a POST request to create a webhook for receiving callbacks on specific triggers', async () => { + // Given + const requestData: CreateWebhookRequestData = { + webhookCreateRequestBody: { + app_id: 'app_id', + target: 'target', + triggers: [ + 'MESSAGE_DELIVERY', + ], + }, + }; + const expectedResponse: Webhook = { + app_id: 'app_id', + client_credentials: { + client_id: 'client_id', + client_secret: 'client_secret', + endpoint: 'endpoint', + }, + id: 'id', + secret: 'secret', + target: 'target', + target_type: 'DISMISS', + triggers: [ + 'MESSAGE_DELIVERY', + ], + }; + + // When + fixture.create.mockResolvedValue(expectedResponse); + webhooksApi.create = fixture.create; + const response = await webhooksApi.create(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.create).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('deleteWebhook', () => { + it('should make a DELETE request to delete a webhook as specified by the webhook ID.', async () => { + // Given + const requestData: DeleteWebhookRequestData = { + webhook_id: 'webhook_id', + }; + const expectedResponse: any = {}; + + // When + fixture.delete.mockResolvedValue(expectedResponse); + webhooksApi.delete = fixture.delete; + const response = await webhooksApi.delete(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.delete).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('getWebhook', () => { + it('should make a GET request to get a webhook as specified by the webhook ID.', async () => { + // Given + const requestData: GetWebhookRequestData = { + webhook_id: 'webhook_id', + }; + const expectedResponse: Webhook = { + app_id: 'app_id', + client_credentials: { + client_id: 'client_id', + client_secret: 'client_secret', + endpoint: 'endpoint', + }, + id: 'id', + secret: 'secret', + target: 'target', + target_type: 'DISMISS', + triggers: [ + 'MESSAGE_DELIVERY', + ], + }; + + // When + fixture.get.mockResolvedValue(expectedResponse); + webhooksApi.get = fixture.get; + const response = await webhooksApi.get(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.get).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('listWebhooks', () => { + it('should make a GET request to list all webhooks for a given app as specified by the App ID.', async () => { + // Given + const requestData: ListWebhooksRequestData = { + app_id: 'app_id', + }; + const expectedResponse: ListWebhooksResponse = { + webhooks: [ + { + app_id: 'app_id', + client_credentials: { + client_id: 'client_id', + client_secret: 'client_secret', + endpoint: 'endpoint', + }, + id: 'id', + secret: 'secret', + target: 'target', + target_type: 'DISMISS', + triggers: [ + 'MESSAGE_DELIVERY', + ], + }, + ], + }; + + // When + fixture.list.mockResolvedValue(expectedResponse); + webhooksApi.list = fixture.list; + const response = await webhooksApi.list(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.list).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('updateWebhook', () => { + it('should make a PATCH request to update an existing webhook as specified by the webhook ID.', async () => { + // Given + const requestData: UpdateWebhookRequestData = { + webhook_id: 'webhook_id', + webhookUpdateRequestBody: { + app_id: 'app_id', + target: 'target', + triggers: [ + 'MESSAGE_DELIVERY', + ], + }, + }; + const expectedResponse: Webhook = { + app_id: 'app_id', + client_credentials: { + client_id: 'client_id', + client_secret: 'client_secret', + endpoint: 'endpoint', + }, + id: 'id', + secret: 'secret', + target: 'target', + target_type: 'DISMISS', + triggers: [ + 'MESSAGE_DELIVERY', + ], + }; + + // When + fixture.update.mockResolvedValue(expectedResponse); + webhooksApi.update = fixture.update; + const response = await webhooksApi.update(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.update).toHaveBeenCalledWith(requestData); + }); + }); +}); From b6891024fd6ec88df6d3b69a6469f8e0b3cdebe1 Mon Sep 17 00:00:00 2001 From: Antoine SEIN <142824551+asein-sinch@users.noreply.github.com> Date: Thu, 1 Feb 2024 18:50:04 +0100 Subject: [PATCH 08/19] DEVEXP-288: Support Callback Events in Conversation API (#16) * Support multiple regions for the conversation API (#17) --- .../src/conversation/contact/create.ts | 2 +- .../webhooks/src/controller/app.controller.ts | 35 ++- .../src/services/conversation.service.ts | 207 +++++++++++++++++- .../v1/capability-event/capability-event.ts | 45 ++++ .../src/models/v1/capability-event/index.ts | 1 + .../models/v1/channel-event/channel-event.ts | 35 +++ .../src/models/v1/channel-event/index.ts | 1 + .../contact-create-event.ts | 25 +++ .../models/v1/contact-create-event/index.ts | 1 + .../contact-delete-event.ts | 25 +++ .../models/v1/contact-delete-event/index.ts | 1 + .../contact-identities-duplication-event.ts | 36 +++ .../index.ts | 1 + .../v1/contact-language/contact-language.ts | 3 +- .../contact-merge-event.ts | 33 +++ .../models/v1/contact-merge-event/index.ts | 1 + .../contact-notification.ts | 7 + .../models/v1/contact-notification/index.ts | 1 + .../contact-update-event.ts | 25 +++ .../models/v1/contact-update-event/index.ts | 1 + .../conversation-channel.ts | 5 +- .../conversation-delete-event.ts | 34 +++ .../v1/conversation-delete-event/index.ts | 1 + .../conversation-event/conversation-event.ts | 5 + .../src/models/v1/conversation-event/index.ts | 1 + .../conversation-start-event.ts | 34 +++ .../v1/conversation-start-event/index.ts | 1 + .../conversation-stop-event.ts | 34 +++ .../v1/conversation-stop-event/index.ts | 1 + .../conversation-webhook-event.ts | 42 ++++ .../v1/conversation-webhook-event/index.ts | 1 + .../v1/delivery-status/delivery-status.ts | 1 + .../src/models/v1/delivery-status/index.ts | 1 + packages/conversation/src/models/v1/enums.ts | 23 +- .../v1/event-delivery/event-delivery.ts | 43 ++++ .../src/models/v1/event-delivery/index.ts | 1 + .../models/v1/event-inbound/event-inbound.ts | 110 ++++++++++ .../src/models/v1/event-inbound/index.ts | 8 + .../models/v1/identified-by/identified-by.ts | 2 +- packages/conversation/src/models/v1/index.ts | 24 ++ .../message-delivery-receipt-event/index.ts | 4 + .../message-delivery-receipt-event.ts | 48 ++++ .../v1/message-inbound-event-item/index.ts | 1 + .../message-inbound-event-item.ts | 30 +++ .../models/v1/message-inbound-event/index.ts | 1 + .../message-inbound-event.ts | 25 +++ .../index.ts | 3 + ...ound-smart-conversation-redaction-event.ts | 25 +++ .../models/v1/message-submit-event/index.ts | 1 + .../message-submit-event.ts | 45 ++++ .../src/models/v1/opt-in-event/index.ts | 1 + .../models/v1/opt-in-event/opt-in-event.ts | 54 +++++ .../src/models/v1/opt-out-event/index.ts | 1 + .../models/v1/opt-out-event/opt-out-event.ts | 54 +++++ .../v1/smart-conversations-event/index.ts | 17 ++ .../smart-conversations-event.ts | 176 +++++++++++++++ .../v1/unsupported-callback-event/index.ts | 1 + .../unsupported-callback-event.ts | 45 ++++ .../v1/webhook-trigger/webhook-trigger.ts | 19 +- .../rest/v1/callbacks/callbacks-webhook.ts | 159 ++++++++++++++ .../src/rest/v1/callbacks/index.ts | 1 + .../src/rest/v1/conversation-domain-api.ts | 10 +- packages/conversation/src/rest/v1/index.ts | 1 + .../rest/v1/conversation-domain-api.test.ts | 48 ++++ .../sdk-client/src/domain/domain-interface.ts | 6 + .../src/utils/authorization.helper.ts | 57 ++++- .../tests/utils/authorization.helper.test.ts | 26 +++ 67 files changed, 1688 insertions(+), 29 deletions(-) create mode 100644 packages/conversation/src/models/v1/capability-event/capability-event.ts create mode 100644 packages/conversation/src/models/v1/capability-event/index.ts create mode 100644 packages/conversation/src/models/v1/channel-event/channel-event.ts create mode 100644 packages/conversation/src/models/v1/channel-event/index.ts create mode 100644 packages/conversation/src/models/v1/contact-create-event/contact-create-event.ts create mode 100644 packages/conversation/src/models/v1/contact-create-event/index.ts create mode 100644 packages/conversation/src/models/v1/contact-delete-event/contact-delete-event.ts create mode 100644 packages/conversation/src/models/v1/contact-delete-event/index.ts create mode 100644 packages/conversation/src/models/v1/contact-identities-duplication-event/contact-identities-duplication-event.ts create mode 100644 packages/conversation/src/models/v1/contact-identities-duplication-event/index.ts create mode 100644 packages/conversation/src/models/v1/contact-merge-event/contact-merge-event.ts create mode 100644 packages/conversation/src/models/v1/contact-merge-event/index.ts create mode 100644 packages/conversation/src/models/v1/contact-notification/contact-notification.ts create mode 100644 packages/conversation/src/models/v1/contact-notification/index.ts create mode 100644 packages/conversation/src/models/v1/contact-update-event/contact-update-event.ts create mode 100644 packages/conversation/src/models/v1/contact-update-event/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-delete-event/conversation-delete-event.ts create mode 100644 packages/conversation/src/models/v1/conversation-delete-event/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-event/conversation-event.ts create mode 100644 packages/conversation/src/models/v1/conversation-event/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-start-event/conversation-start-event.ts create mode 100644 packages/conversation/src/models/v1/conversation-start-event/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-stop-event/conversation-stop-event.ts create mode 100644 packages/conversation/src/models/v1/conversation-stop-event/index.ts create mode 100644 packages/conversation/src/models/v1/conversation-webhook-event/conversation-webhook-event.ts create mode 100644 packages/conversation/src/models/v1/conversation-webhook-event/index.ts create mode 100644 packages/conversation/src/models/v1/delivery-status/delivery-status.ts create mode 100644 packages/conversation/src/models/v1/delivery-status/index.ts create mode 100644 packages/conversation/src/models/v1/event-delivery/event-delivery.ts create mode 100644 packages/conversation/src/models/v1/event-delivery/index.ts create mode 100644 packages/conversation/src/models/v1/event-inbound/event-inbound.ts create mode 100644 packages/conversation/src/models/v1/event-inbound/index.ts create mode 100644 packages/conversation/src/models/v1/message-delivery-receipt-event/index.ts create mode 100644 packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts create mode 100644 packages/conversation/src/models/v1/message-inbound-event-item/index.ts create mode 100644 packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts create mode 100644 packages/conversation/src/models/v1/message-inbound-event/index.ts create mode 100644 packages/conversation/src/models/v1/message-inbound-event/message-inbound-event.ts create mode 100644 packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/index.ts create mode 100644 packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts create mode 100644 packages/conversation/src/models/v1/message-submit-event/index.ts create mode 100644 packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts create mode 100644 packages/conversation/src/models/v1/opt-in-event/index.ts create mode 100644 packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts create mode 100644 packages/conversation/src/models/v1/opt-out-event/index.ts create mode 100644 packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts create mode 100644 packages/conversation/src/models/v1/smart-conversations-event/index.ts create mode 100644 packages/conversation/src/models/v1/smart-conversations-event/smart-conversations-event.ts create mode 100644 packages/conversation/src/models/v1/unsupported-callback-event/index.ts create mode 100644 packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts create mode 100644 packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts create mode 100644 packages/conversation/src/rest/v1/callbacks/index.ts create mode 100644 packages/conversation/tests/rest/v1/conversation-domain-api.test.ts diff --git a/examples/simple-examples/src/conversation/contact/create.ts b/examples/simple-examples/src/conversation/contact/create.ts index c54566bf..0b81d29a 100644 --- a/examples/simple-examples/src/conversation/contact/create.ts +++ b/examples/simple-examples/src/conversation/contact/create.ts @@ -31,7 +31,7 @@ import { channel: 'WHATSAPP', }, ], - channel_priority: ['WHATSAPP'], + channel_priority: ['MESSENGER'], language: 'EN_US', }, }; diff --git a/examples/webhooks/src/controller/app.controller.ts b/examples/webhooks/src/controller/app.controller.ts index 17b24dc2..968c6acc 100644 --- a/examples/webhooks/src/controller/app.controller.ts +++ b/examples/webhooks/src/controller/app.controller.ts @@ -1,19 +1,25 @@ import { Body, Controller, Post, Req, Res } from '@nestjs/common'; import { Request, Response } from 'express'; -import { NumbersService } from '../services/numbers.service'; import { + parseConversationEventNotification, parseNumbersEventNotification, parseSmsEventNotification, parseVerificationEventNotification, parseVoiceEventNotification, validateAuthenticationHeader, + validateWebhookSignature, } from '@sinch/sdk-core'; +import { NumbersService } from '../services/numbers.service'; import { SmsService } from '../services/sms.service'; import { VerificationService } from '../services/verification.service'; import { VoiceService } from '../services/voice.service'; import { ConversationService } from '../services/conversation.service'; require('dotenv').config(); +// Const for Conversation API +const SINCH_CONVERSATION_APP_SECRET = process.env.SINCH_CONVERSATION_APP_SECRET || ''; + +// Const for Voice and Verification APIs const SINCH_APPLICATION_KEY = process.env.SINCH_APPLICATION_KEY || ''; const SINCH_APPLICATION_SECRET = process.env.SINCH_APPLICATION_SECRET || ''; @@ -27,6 +33,26 @@ export class AppController { private readonly verificationService: VerificationService, private readonly voiceService: VoiceService) {} + @Post('/conversation') + public conversation(@Req() request: Request, @Res() res: Response) { + // console.log(request.headers); + // console.log(JSON.stringify(request.body, null, 2)); + // console.log(request['rawBody']); + const validated = validateWebhookSignature(SINCH_CONVERSATION_APP_SECRET, request.headers, request['rawBody']); + if (!validated) { + res.status(401).send('Invalid webhook signature'); + return; + } + try { + const event = parseConversationEventNotification(request.body); + this.conversationService.handleEvent(event); + res.status(200).send(); + } catch (error) { + console.error(error); + res.status(500).send(); + } + } + @Post('/numbers') public numbers(@Body() eventBody: any, @Res() res: Response) { // console.log(eventBody); @@ -76,7 +102,7 @@ export class AppController { @Post('/voice') public voice (@Req() request: Request, @Res() res: Response) { // console.log(request.headers); - // console.log(request.body); + // console.log(JSON.stringify(request.body, null, 2)); // console.log(request['rawBody']); const validated = validateAuthenticationHeader(SINCH_APPLICATION_KEY, SINCH_APPLICATION_SECRET, request.headers, request.path, request['rawBody'], request.method); @@ -94,9 +120,4 @@ export class AppController { } } - @Post('/conversation') - public conversation(@Body() requestBody: any, @Res() res: Response) { - this.conversationService.handleEvent(JSON.stringify(requestBody)); - res.status(200).send(); - } } diff --git a/examples/webhooks/src/services/conversation.service.ts b/examples/webhooks/src/services/conversation.service.ts index d92300ab..6d510b44 100644 --- a/examples/webhooks/src/services/conversation.service.ts +++ b/examples/webhooks/src/services/conversation.service.ts @@ -1,9 +1,212 @@ import { Injectable } from '@nestjs/common'; +import { + SinchClient, + ConversationWebhookEventParsed, + ContactMessage, + MediaMessage, + FallbackMessage, + TextMessage, + SendMessageRequestData, +} from '@sinch/sdk-core'; @Injectable() export class ConversationService { - handleEvent(event: string): void { - console.log(event); + private sinchClient: SinchClient; + + constructor() { + this.sinchClient = this.initClient(); + } + + private initClient = () => { + const keyId = process.env.SINCH_KEY_ID || ''; + const keySecret = process.env.SINCH_KEY_SECRET || ''; + const projectId = process.env.SINCH_PROJECT_ID || ''; + return new SinchClient({ projectId, keyId, keySecret }); + }; + + private buildTextMessage(contactMessage: ContactMessage) { + if ('text_message' in contactMessage) { + return { + text_message: { + text: `Parrot mode 🦜: ${contactMessage.text_message.text}`, + } + } as TextMessage; + } + if ('media_message' in contactMessage) { + return { + media_message: { + url: contactMessage.media_message.url, + } + } as MediaMessage; + } + if ('fallback_message' in contactMessage) { + return { + text_message: { + text: `Error: ${contactMessage.fallback_message.reason.code} (${contactMessage.fallback_message.reason.sub_code})\n${contactMessage.fallback_message.reason.description}` + } + } as TextMessage + } + } + + handleEvent(event: ConversationWebhookEventParsed): void { + switch (event.trigger) { + case 'MESSAGE_INBOUND': + console.log('\n## MESSAGE_INBOUND'); + const contactMessage = event.message.contact_message; + const channelIdentityTo = event.message.channel_identity; + console.log(`A new message has been received on the channel '${channelIdentityTo.channel}' (identity: ${channelIdentityTo.identity}) from the contact ID '${event.message.contact_id}':\n${JSON.stringify(contactMessage, null, 2)}`); + const requestData: SendMessageRequestData = { + sendMessageRequestBody: { + app_id: event.app_id, + recipient: { + contact_id: event.message.contact_id, + }, + message: this.buildTextMessage(contactMessage), + }, + }; + this.sinchClient.conversation.messages.send(requestData) + .then(response=> console.log(`Response successfully sent at '${response.accepted_time}': Message ID = ${response.message_id}`)) + .catch(error => console.error(`Impossible to send back a message to the user: ${error}`)); + break; + case 'MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION': + console.log('\n## MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION'); + console.log(`A.I. analyzed and redacted message:\n${event.message_redaction.contact_message.text_message.text}`); + break; + case 'MESSAGE_SUBMIT': + console.log('\n## MESSAGE_SUBMIT'); + const submittedMessage = event.message_submit_notification.submitted_message; + const channelIdentityFrom = event.message_submit_notification.channel_identity; + console.log(`The following message has been submitted on the channel '${channelIdentityFrom.channel}' (identity: ${channelIdentityFrom.identity}) to the contact ID '${event.message_submit_notification.contact_id}':\n${JSON.stringify(submittedMessage, null, 2)}`); + break; + case 'SMART_CONVERSATIONS': + console.log('\n## SMART_CONVERSATIONS'); + const analysisResult = event.smart_conversation_notification.analysis_results; + if (analysisResult.ml_sentiment_result) { + console.log(`The sentiment of the message is '${analysisResult.ml_sentiment_result[0].sentiment}' with a score of ${analysisResult.ml_sentiment_result[0].score}`); + } + if (analysisResult.ml_nlu_result) { + console.log(`The intent of the message is '${analysisResult.ml_nlu_result[0].intent}' with a score of ${analysisResult.ml_nlu_result[0].score}. Other intents are\n:${analysisResult.ml_nlu_result[0].results.map((result) => '- ' + result.intent + ': ' + result.score).join('\n')}`); + } + if (analysisResult.ml_pii_result) { + console.log(`Message with masked PII:\n${analysisResult.ml_pii_result[0].masked}`); + } + if (analysisResult.ml_offensive_analysis_result) { + console.log(`Message offensiveness evaluation: '${analysisResult.ml_offensive_analysis_result[0].evaluation}' with a score of ${analysisResult.ml_offensive_analysis_result[0].score}`); + } + if (analysisResult.ml_image_recognition_result) { + console.log(`Image recognition results:\n${JSON.stringify(analysisResult.ml_image_recognition_result[0])}`); + } + break; + case 'MESSAGE_DELIVERY': + console.log('\n## MESSAGE_DELIVERY'); + const messageDeliveryStatus = event.message_delivery_report.status; + console.log(`Message delivery status: '${messageDeliveryStatus}'`); + if ('FAILED' === messageDeliveryStatus) { + const failedDeliveryReason = event.message_delivery_report.reason; + console.log(`Reason: ${failedDeliveryReason.code} (${failedDeliveryReason.sub_code})`); + console.log(`Description: ${failedDeliveryReason.description}`); + } + break; + case 'EVENT_INBOUND': + console.log('\n## EVENT_INBOUND'); + if ('contact_event' in event.event) { + console.log(`A new contact event has been received on the channel '${event.event.channel_identity.channel}' (${event.event.channel_identity.identity}) from the contact ID '${event.event.contact_id}'`); + } + if ('contact_message_event' in event.event) { + const contactMessageEvent = event.event.contact_message_event; + console.log(`A new contact message event has been received on the channel '${event.event.channel_identity.channel}' (${event.event.channel_identity.identity}) from the contact ID '${event.event.contact_id}'`); + console.log(`Payment status: ${contactMessageEvent.payment_status_update_event.payment_status}`); + } + break; + case 'EVENT_DELIVERY': + console.log('\n## EVENT_DELIVERY'); + const eventDeliveryStatus = event.event_delivery_report.status; + console.log(`Event delivery status: '${eventDeliveryStatus}'`); + if ('FAILED' === eventDeliveryStatus) { + const failedDeliveryReason = event.event_delivery_report.reason; + console.log(`Reason: ${failedDeliveryReason.code} (${failedDeliveryReason.sub_code})`); + console.log(`Description: ${failedDeliveryReason.description}`); + } + break; + case 'CONVERSATION_START': + console.log('\n## CONVERSATION_START'); + const conversationStart = event.conversation_start_notification.conversation; + console.log(`The conversation '${conversationStart.id}' has started on the channel ${conversationStart.active_channel}`); + break; + case 'CONVERSATION_STOP': + console.log('\n## CONVERSATION_STOP'); + const conversationStop = event.conversation_stop_notification.conversation; + console.log(`The conversation '${conversationStop.id}' has been stopped.\nThe last message was sent at '${conversationStop.last_received}' on the channel '${conversationStop.active_channel}'`); + break; + case 'CONVERSATION_DELETE': + console.log('\n## CONVERSATION_DELETE'); + const conversationDelete = event.conversation_delete_notification.conversation; + console.log(`The conversation '${conversationDelete.id}' has been deleted.\nThe last message was sent at '${conversationDelete.last_received}' on the channel '${conversationDelete.active_channel}'`); + break; + case 'CONTACT_CREATE': + console.log('\n## CONTACT_CREATE'); + console.log(`A new contact has been created: '${event.contact_create_notification.contact.display_name}'`); + console.log(`List of channels:\n${event.contact_create_notification.contact.channel_identities.map((channelIdentity) => channelIdentity.channel).join('\n')}`); + break; + case 'CONTACT_DELETE': + console.log('\n## CONTACT_DELETE'); + console.log(`A contact has been deleted: '${event.contact_delete_notification.contact.display_name}'`); + break; + case 'CONTACT_MERGE': + console.log('\n## CONTACT_MERGE'); + const deletedContact = event.contact_merge_notification.deleted_contact; + const preservedContact = event.contact_merge_notification.preserved_contact; + console.log(`The contact ID '${deletedContact.id}' (${deletedContact.display_name}) has been merged into the contact ID '${preservedContact.id}' (${preservedContact.display_name})`); + break; + case 'CONTACT_UPDATE': + console.log('\n## CONTACT_UPDATE'); + console.log(`A contact has been updated: '${event.contact_update_notification.contact.display_name}'`); + break; + case 'CONTACT_IDENTITIES_DUPLICATION': + console.log('\n## CONTACT_IDENTITIES_DUPLICATION'); + const duplicatedEntities = event.duplicated_contact_identities_notification.duplicated_identities; + for(const duplication of duplicatedEntities) { + console.log(`The channel ${duplication.channel} contains the following duplicated contact IDs: ${duplication.contact_ids.join(', ')}`); + } + break; + case 'CAPABILITY': + console.log('\n## CAPABILITY'); + const capabilityNotification = event.capability_notification; + console.log(`Capability for the contact ID '${capabilityNotification.contact_id}':`) + console.log(`Channel: '${capabilityNotification.channel}' - Identity: ${capabilityNotification.identity}`); + if ('reason' in event.capability_notification) { + const capabilityUnknownReason = event.capability_notification.reason; + console.log(`Reason: ${capabilityUnknownReason.code} (${capabilityUnknownReason.sub_code})`); + console.log(`Description: ${capabilityUnknownReason.description}`); + } + break; + case 'OPT_IN': + console.log('\n## OPT_IN') + const optIn = event.opt_in_notification; + console.log(`Status of the opt-in registration for the identity '${optIn.identity}' on the channel '${optIn.channel}': '${optIn.status}'`); + break; + case 'OPT_OUT': + console.log('\n## OPT_OUT') + const optOut = event.opt_out_notification; + console.log(`Status of the opt-out registration for the identity '${optOut.identity}' on the channel '${optOut.channel}': '${optOut.status}'`); + break; + case 'CHANNEL_EVENT': + console.log('\n## CHANNEL_EVENT') + const channelEvent = event.channel_event_notification; + console.log(`The event '${channelEvent.event_type}' occurred on the channel '${channelEvent.channel}'.`); + if ('additional_data' in channelEvent) { + console.log(`Additional data:\n${JSON.stringify(channelEvent.additional_data, null, 2)}`); + } + break; + case 'UNSUPPORTED': + console.log('\n## UNSUPPORTED') + const unsupportedCallback = event.unsupported_callback; + console.log(`The channel ${unsupportedCallback.channel} has received an unsupported payload:\n${unsupportedCallback.payload}`); + break; + default: + console.log('\n## Unknown event: the following event is unknown or not handled'); + console.log(JSON.stringify(event, null, 2)); + } } } diff --git a/packages/conversation/src/models/v1/capability-event/capability-event.ts b/packages/conversation/src/models/v1/capability-event/capability-event.ts new file mode 100644 index 00000000..2aaee558 --- /dev/null +++ b/packages/conversation/src/models/v1/capability-event/capability-event.ts @@ -0,0 +1,45 @@ +import { ConversationChannel } from '../conversation-channel'; +import { Reason } from '../reason'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is used to deliver the results of the asynchronous capability checks. + */ +export interface CapabilityEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see CapabilityEventCapabilityNotification */ + capability_notification?: CapabilityNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CAPABILITY'; +} + +export interface CapabilityNotification { + + /** ID generated when submitting the capability request. Can be used to detect duplicates. */ + request_id?: string; + /** The ID of the contact. */ + contact_id?: string; + /** @see ConversationChannel */ + channel?: ConversationChannel; + /** The channel identity. For example, a phone number for SMS, WhatsApp, and Viber Business. */ + identity?: string; + /** Status indicating the recipient\'s capability on the channel. */ + capability_status?: CapabilityStatusEnum; + /** When capability_status is set to CAPABILITY_PARTIAL, this field includes a list of the supported channel-specific capabilities reported by the channel. */ + channel_capabilities?: string[]; + /** @see Reason */ + reason?: Reason; +} +export type CapabilityStatusEnum = 'CAPABILITY_UNKNOWN' | 'CAPABILITY_FULL' | 'CAPABILITY_PARTIAL' | 'NO_CAPABILITY'; diff --git a/packages/conversation/src/models/v1/capability-event/index.ts b/packages/conversation/src/models/v1/capability-event/index.ts new file mode 100644 index 00000000..8a673538 --- /dev/null +++ b/packages/conversation/src/models/v1/capability-event/index.ts @@ -0,0 +1 @@ +export type { CapabilityEvent, CapabilityNotification } from './capability-event'; diff --git a/packages/conversation/src/models/v1/channel-event/channel-event.ts b/packages/conversation/src/models/v1/channel-event/channel-event.ts new file mode 100644 index 00000000..fd4c879e --- /dev/null +++ b/packages/conversation/src/models/v1/channel-event/channel-event.ts @@ -0,0 +1,35 @@ +import { ConversationChannel } from '../conversation-channel'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is used to deliver notifications regarding channel-specific information and updates. For example, if your are using the WhatsApp channel of the Conversation API, and your quality rating has been changed to GREEN, a POST would be made to the CHANNEL_EVENT webhook. + */ +export interface ChannelEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see ChannelEventNotification */ + channel_event_notification?: ChannelEventNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CHANNEL_EVENT'; +} + +export interface ChannelEventNotification { + + /** @see ConversationChannel */ + channel?: ConversationChannel; + /** The type of event being reported. */ + event_type?: string; + /** An object containing additional information regarding the event. The contents of the object depend on the channel and the event_type. */ + additional_data?: object; +} diff --git a/packages/conversation/src/models/v1/channel-event/index.ts b/packages/conversation/src/models/v1/channel-event/index.ts new file mode 100644 index 00000000..7dd22303 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-event/index.ts @@ -0,0 +1 @@ +export type { ChannelEvent, ChannelEventNotification } from './channel-event'; diff --git a/packages/conversation/src/models/v1/contact-create-event/contact-create-event.ts b/packages/conversation/src/models/v1/contact-create-event/contact-create-event.ts new file mode 100644 index 00000000..e3d12a75 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-create-event/contact-create-event.ts @@ -0,0 +1,25 @@ +import { ContactNotification } from '../contact-notification'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is sent when a new contact is created. + */ +export interface ContactCreateEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see ContactNotification */ + contact_create_notification?: ContactNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CONTACT_CREATE'; +} diff --git a/packages/conversation/src/models/v1/contact-create-event/index.ts b/packages/conversation/src/models/v1/contact-create-event/index.ts new file mode 100644 index 00000000..799d65aa --- /dev/null +++ b/packages/conversation/src/models/v1/contact-create-event/index.ts @@ -0,0 +1 @@ +export type { ContactCreateEvent } from './contact-create-event'; diff --git a/packages/conversation/src/models/v1/contact-delete-event/contact-delete-event.ts b/packages/conversation/src/models/v1/contact-delete-event/contact-delete-event.ts new file mode 100644 index 00000000..ef4f9263 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-delete-event/contact-delete-event.ts @@ -0,0 +1,25 @@ +import { ContactNotification } from '../contact-notification'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is sent when a new contact is deleted. + */ +export interface ContactDeleteEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see ContactNotification */ + contact_delete_notification?: ContactNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CONTACT_DELETE'; +} diff --git a/packages/conversation/src/models/v1/contact-delete-event/index.ts b/packages/conversation/src/models/v1/contact-delete-event/index.ts new file mode 100644 index 00000000..967b2119 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-delete-event/index.ts @@ -0,0 +1 @@ +export type { ContactDeleteEvent } from './contact-delete-event'; diff --git a/packages/conversation/src/models/v1/contact-identities-duplication-event/contact-identities-duplication-event.ts b/packages/conversation/src/models/v1/contact-identities-duplication-event/contact-identities-duplication-event.ts new file mode 100644 index 00000000..9e541831 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-identities-duplication-event/contact-identities-duplication-event.ts @@ -0,0 +1,36 @@ +import { ConversationChannel } from '../conversation-channel'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is sent when duplicates of channel identities are found between multiple contacts in the contact database during message and event processing. + */ +export interface ContactIdentitiesDuplicationEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see DuplicatedIdentitiesEvent */ + duplicated_contact_identities_notification: DuplicatedIdentitiesEvent; + /** Name of the trigger responsible for this event. */ + trigger: 'CONTACT_IDENTITIES_DUPLICATION'; +} + +export interface DuplicatedIdentitiesEvent { + /** List of DuplicatedIdentities */ + duplicated_identities?: DuplicatedIdentities[]; +} +export interface DuplicatedIdentities { + /** @see ConversationChannel */ + channel?: ConversationChannel; + /** List of duplicated ids in the specified channel. */ + contact_ids?: string[]; +} diff --git a/packages/conversation/src/models/v1/contact-identities-duplication-event/index.ts b/packages/conversation/src/models/v1/contact-identities-duplication-event/index.ts new file mode 100644 index 00000000..abbc9eb7 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-identities-duplication-event/index.ts @@ -0,0 +1 @@ +export type { ContactIdentitiesDuplicationEvent, DuplicatedIdentities } from './contact-identities-duplication-event'; diff --git a/packages/conversation/src/models/v1/contact-language/contact-language.ts b/packages/conversation/src/models/v1/contact-language/contact-language.ts index 00e8cc16..c51375aa 100644 --- a/packages/conversation/src/models/v1/contact-language/contact-language.ts +++ b/packages/conversation/src/models/v1/contact-language/contact-language.ts @@ -68,4 +68,5 @@ export type ContactLanguage = | 'UR' | 'UZ' | 'VI' - | 'ZU'; + | 'ZU' + | 'UNSPECIFIED'; diff --git a/packages/conversation/src/models/v1/contact-merge-event/contact-merge-event.ts b/packages/conversation/src/models/v1/contact-merge-event/contact-merge-event.ts new file mode 100644 index 00000000..442ec1f5 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-merge-event/contact-merge-event.ts @@ -0,0 +1,33 @@ +import { Contact } from '../contact'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is sent when two contacts are merged. + */ +export interface ContactMergeEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see ContactMergeEventContactMergeNotification */ + contact_merge_notification?: ContactMergeNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CONTACT_MERGE'; +} + +export interface ContactMergeNotification { + + /** @see Contact */ + preserved_contact?: Contact; + /** @see Contact */ + deleted_contact?: Contact; +} diff --git a/packages/conversation/src/models/v1/contact-merge-event/index.ts b/packages/conversation/src/models/v1/contact-merge-event/index.ts new file mode 100644 index 00000000..d1d8a4b8 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-merge-event/index.ts @@ -0,0 +1 @@ +export type { ContactMergeEvent, ContactMergeNotification } from './contact-merge-event'; diff --git a/packages/conversation/src/models/v1/contact-notification/contact-notification.ts b/packages/conversation/src/models/v1/contact-notification/contact-notification.ts new file mode 100644 index 00000000..c116ae09 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-notification/contact-notification.ts @@ -0,0 +1,7 @@ +import { Contact } from '../contact'; + +export interface ContactNotification { + + /** @see Contact */ + contact?: Contact; +} diff --git a/packages/conversation/src/models/v1/contact-notification/index.ts b/packages/conversation/src/models/v1/contact-notification/index.ts new file mode 100644 index 00000000..bf81b51e --- /dev/null +++ b/packages/conversation/src/models/v1/contact-notification/index.ts @@ -0,0 +1 @@ +export type { ContactNotification } from './contact-notification'; diff --git a/packages/conversation/src/models/v1/contact-update-event/contact-update-event.ts b/packages/conversation/src/models/v1/contact-update-event/contact-update-event.ts new file mode 100644 index 00000000..719f0169 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-update-event/contact-update-event.ts @@ -0,0 +1,25 @@ +import { ContactNotification } from '../contact-notification'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is sent when a new contact is updated. + */ +export interface ContactUpdateEvent extends ConversationEvent{ + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see ContactNotification */ + contact_update_notification?: ContactNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CONTACT_UPDATE'; +} diff --git a/packages/conversation/src/models/v1/contact-update-event/index.ts b/packages/conversation/src/models/v1/contact-update-event/index.ts new file mode 100644 index 00000000..e2d683b4 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-update-event/index.ts @@ -0,0 +1 @@ +export type { ContactUpdateEvent } from './contact-update-event'; diff --git a/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts index 6230360c..f0bc1184 100644 --- a/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts +++ b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts @@ -1,5 +1,5 @@ /** - * The identifier of the channel you want to include. Must be one of the enum values. + * The identifier of the channel you want to include. Must be one of the enum values except 'CHANNEL_UNSPECIFIED'. */ export type ConversationChannel = 'WHATSAPP' @@ -14,4 +14,5 @@ export type ConversationChannel = | 'KAKAOTALK' | 'KAKAOTALKCHAT' | 'LINE' - | 'WECHAT'; + | 'WECHAT' + | 'CHANNEL_UNSPECIFIED'; diff --git a/packages/conversation/src/models/v1/conversation-delete-event/conversation-delete-event.ts b/packages/conversation/src/models/v1/conversation-delete-event/conversation-delete-event.ts new file mode 100644 index 00000000..d136e44c --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-delete-event/conversation-delete-event.ts @@ -0,0 +1,34 @@ +import { Conversation } from '../conversation'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is sent when a conversation between the subscribed app and a contact is deleted. + */ +export interface ConversationDeleteEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: string; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: string; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback\'s documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see ConversationNotification */ + conversation_delete_notification?: ConversationNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CONVERSATION_DELETE'; +} + +/** + * Object containing the details of the deleted conversation + */ +export interface ConversationNotification { + + /** @see Conversation */ + conversation?: Conversation; +} diff --git a/packages/conversation/src/models/v1/conversation-delete-event/index.ts b/packages/conversation/src/models/v1/conversation-delete-event/index.ts new file mode 100644 index 00000000..e0e7ac2d --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-delete-event/index.ts @@ -0,0 +1 @@ +export type { ConversationDeleteEvent } from './conversation-delete-event'; diff --git a/packages/conversation/src/models/v1/conversation-event/conversation-event.ts b/packages/conversation/src/models/v1/conversation-event/conversation-event.ts new file mode 100644 index 00000000..f52df4d6 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-event/conversation-event.ts @@ -0,0 +1,5 @@ +import { WebhookTrigger } from '../webhook-trigger'; + +export interface ConversationEvent { + trigger: WebhookTrigger; +} diff --git a/packages/conversation/src/models/v1/conversation-event/index.ts b/packages/conversation/src/models/v1/conversation-event/index.ts new file mode 100644 index 00000000..782519a5 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-event/index.ts @@ -0,0 +1 @@ +export { ConversationEvent } from './conversation-event'; diff --git a/packages/conversation/src/models/v1/conversation-start-event/conversation-start-event.ts b/packages/conversation/src/models/v1/conversation-start-event/conversation-start-event.ts new file mode 100644 index 00000000..c5a6d51e --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-start-event/conversation-start-event.ts @@ -0,0 +1,34 @@ +import { Conversation } from '../conversation'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is sent when a new conversation between the subscribed app and a contact is started. + */ +export interface ConversationStartEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see Conversation */ + conversation_start_notification?: ConversationNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CONVERSATION_START'; +} + +/** + * Object containing the details of the started conversation + */ +export interface ConversationNotification { + + /** @see Conversation */ + conversation?: Conversation; +} diff --git a/packages/conversation/src/models/v1/conversation-start-event/index.ts b/packages/conversation/src/models/v1/conversation-start-event/index.ts new file mode 100644 index 00000000..fecb24c8 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-start-event/index.ts @@ -0,0 +1 @@ +export type { ConversationStartEvent } from './conversation-start-event'; diff --git a/packages/conversation/src/models/v1/conversation-stop-event/conversation-stop-event.ts b/packages/conversation/src/models/v1/conversation-stop-event/conversation-stop-event.ts new file mode 100644 index 00000000..4946d7a9 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-stop-event/conversation-stop-event.ts @@ -0,0 +1,34 @@ +import { Conversation } from '../conversation'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is sent when a conversation between the subscribed app and a contact is stopped. + */ +export interface ConversationStopEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: string; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: string; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback\'s documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see Conversation */ + conversation_stop_notification?: ConversationNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'CONVERSATION_STOP'; +} + +/** + * Object containing the details of the stopped conversation + */ +export interface ConversationNotification { + + /** @see Conversation */ + conversation?: Conversation; +} diff --git a/packages/conversation/src/models/v1/conversation-stop-event/index.ts b/packages/conversation/src/models/v1/conversation-stop-event/index.ts new file mode 100644 index 00000000..ec0f786c --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-stop-event/index.ts @@ -0,0 +1 @@ +export type { ConversationStopEvent } from './conversation-stop-event'; diff --git a/packages/conversation/src/models/v1/conversation-webhook-event/conversation-webhook-event.ts b/packages/conversation/src/models/v1/conversation-webhook-event/conversation-webhook-event.ts new file mode 100644 index 00000000..15dea601 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-webhook-event/conversation-webhook-event.ts @@ -0,0 +1,42 @@ +import { MessageInboundEvent } from '../message-inbound-event'; +import { MessageInboundSmartConversationRedactionEvent } from '../message-inbound-smart-conversation-redaction-event'; +import { MessageSubmitEvent } from '../message-submit-event'; +import { MessageDeliveryReceiptEvent } from '../message-delivery-receipt-event'; +import { EventInbound } from '../event-inbound'; +import { EventDelivery } from '../event-delivery'; +import { ConversationStartEvent } from '../conversation-start-event'; +import { ConversationStopEvent } from '../conversation-stop-event'; +import { ConversationDeleteEvent } from '../conversation-delete-event'; +import { ContactCreateEvent } from '../contact-create-event'; +import { ContactDeleteEvent } from '../contact-delete-event'; +import { ContactMergeEvent } from '../contact-merge-event'; +import { ContactUpdateEvent } from '../contact-update-event'; +import { ContactIdentitiesDuplicationEvent } from '../contact-identities-duplication-event'; +import { CapabilityEvent } from '../capability-event'; +import { OptInEvent } from '../opt-in-event'; +import { OptOutEvent } from '../opt-out-event'; +import { ChannelEvent } from '../channel-event'; +import { UnsupportedCallbackEvent } from '../unsupported-callback-event'; +import { SmartConversationsEvent } from '../smart-conversations-event'; + +export type ConversationWebhookEvent = + MessageInboundEvent + | MessageInboundSmartConversationRedactionEvent + | MessageSubmitEvent + | MessageDeliveryReceiptEvent + | EventInbound + | EventDelivery + | ConversationStartEvent + | ConversationStopEvent + | ConversationDeleteEvent + | ContactCreateEvent + | ContactDeleteEvent + | ContactMergeEvent + | ContactUpdateEvent + | ContactIdentitiesDuplicationEvent + | CapabilityEvent + | OptInEvent + | OptOutEvent + | ChannelEvent + | SmartConversationsEvent + | UnsupportedCallbackEvent; diff --git a/packages/conversation/src/models/v1/conversation-webhook-event/index.ts b/packages/conversation/src/models/v1/conversation-webhook-event/index.ts new file mode 100644 index 00000000..ee93ce03 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-webhook-event/index.ts @@ -0,0 +1 @@ +export type { ConversationWebhookEvent } from './conversation-webhook-event'; diff --git a/packages/conversation/src/models/v1/delivery-status/delivery-status.ts b/packages/conversation/src/models/v1/delivery-status/delivery-status.ts new file mode 100644 index 00000000..91802a4f --- /dev/null +++ b/packages/conversation/src/models/v1/delivery-status/delivery-status.ts @@ -0,0 +1 @@ +export type DeliveryStatus = 'QUEUED_ON_CHANNEL' | 'DELIVERED' | 'READ' | 'FAILED' | 'SWITCHING_CHANNEL'; diff --git a/packages/conversation/src/models/v1/delivery-status/index.ts b/packages/conversation/src/models/v1/delivery-status/index.ts new file mode 100644 index 00000000..ead5f089 --- /dev/null +++ b/packages/conversation/src/models/v1/delivery-status/index.ts @@ -0,0 +1 @@ +export type { DeliveryStatus } from './delivery-status'; diff --git a/packages/conversation/src/models/v1/enums.ts b/packages/conversation/src/models/v1/enums.ts index 8cec2e9c..8f0fdc70 100644 --- a/packages/conversation/src/models/v1/enums.ts +++ b/packages/conversation/src/models/v1/enums.ts @@ -1 +1,22 @@ -export {}; \ No newline at end of file +export type { + CapabilityStatusEnum as CapabilityNotificationCapabilityStatusEnum, +} from './capability-event/capability-event'; +export type { + DirectionEnum as EventInboundDirectionEnum, + CommentTypeEnum as CommentEventCommentTypeEnum, + PaymentStatusEnum as PaymentStatusUpdateEventPaymentStatusEnum, + PaymentTransactionStatusEnum as PaymentStatusUpdateEventPaymentTransactionStatusEnum, +} from './event-inbound/event-inbound'; +export type { + SentimentResult as MachineLearningSentimentEnum, + EvaluationEnum as OffensiveAnalysisEvaluationEnum, +} from './smart-conversations-event/smart-conversations-event'; +export type { + DirectionEnum as MessageInboundEventItemDirectionEnum, +} from './message-inbound-event-item/message-inbound-event-item'; +export type { + StatusEnum as OptInNotificationStatusEnum, +} from './opt-in-event/opt-in-event'; +export type { + StatusEnum as OptOutEventOptOutNotificationStatusEnum, +} from './opt-out-event/opt-out-event'; diff --git a/packages/conversation/src/models/v1/event-delivery/event-delivery.ts b/packages/conversation/src/models/v1/event-delivery/event-delivery.ts new file mode 100644 index 00000000..edc19c73 --- /dev/null +++ b/packages/conversation/src/models/v1/event-delivery/event-delivery.ts @@ -0,0 +1,43 @@ +import { ChannelIdentity } from '../channel-identity'; +import { Reason } from '../reason'; +import { ProcessingMode } from '../processing-mode'; +import { DeliveryStatus } from '../delivery-status'; +import { ConversationEvent } from '../conversation-event'; + +export interface EventDelivery extends ConversationEvent{ + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see EventDeliveryEventDeliveryReport */ + event_delivery_report?: EventDeliveryReport; + /** Name of the trigger responsible for this event. */ + trigger: 'EVENT_DELIVERY'; +} + +export interface EventDeliveryReport { + + /** The ID of the app event. */ + event_id?: string; + /** Shows the status of the message or event delivery */ + status?: DeliveryStatus; + /** @see ChannelIdentity */ + channel_identity?: ChannelIdentity; + /** The ID of the contact. Will be empty if processing_mode is DISPATCH. */ + contact_id?: string; + /** @see Reason */ + reason?: Reason; + /** Metadata specified when sending the event if any. */ + metadata?: string; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; +} diff --git a/packages/conversation/src/models/v1/event-delivery/index.ts b/packages/conversation/src/models/v1/event-delivery/index.ts new file mode 100644 index 00000000..6845a076 --- /dev/null +++ b/packages/conversation/src/models/v1/event-delivery/index.ts @@ -0,0 +1 @@ +export type { EventDelivery, EventDeliveryReport } from './event-delivery'; diff --git a/packages/conversation/src/models/v1/event-inbound/event-inbound.ts b/packages/conversation/src/models/v1/event-inbound/event-inbound.ts new file mode 100644 index 00000000..8d417738 --- /dev/null +++ b/packages/conversation/src/models/v1/event-inbound/event-inbound.ts @@ -0,0 +1,110 @@ +import { ProcessingMode } from '../processing-mode'; +import { ChannelIdentity } from '../channel-identity'; +import { ConversationEvent } from '../conversation-event'; + +export interface EventInbound extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback\'s documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see EventInboundEvent */ + event?: EventInboundEvent; + /** Name of the trigger responsible for this event. */ + trigger: 'EVENT_INBOUND'; +} + +export interface EventInboundEvent { + + /** The event ID. */ + id?: string; + /** The direction of the event. It\'s always TO_APP for contact events. */ + direction?: DirectionEnum; + /** @see ContactEvent */ + contact_event?: ContactEvent; + /** @see ContactMessageEvent */ + contact_message_event?: ContactMessageEvent; + /** @see ChannelIdentity */ + channel_identity?: ChannelIdentity; + /** The ID of the contact. Will be empty if processing_mode is DISPATCH. */ + contact_id?: string; + /** The ID of the conversation this event is part of. Will be empty if processing_mode is DISPATCH. */ + conversation_id?: string; + /** Timestamp marking when the channel callback was received by the Conversation API. */ + accept_time?: Date; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; +} + +export type DirectionEnum = 'TO_APP'; + +export interface ContactEvent { + + /** Empty object denoting the contact is composing a message. */ + composing_event?: object; + /** @see CommentEvent */ + comment_event?: CommentEvent; +} + +/** + * Object which contains information of a comment made by a user outside the main conversation context. Currently only supported on Instagram channel, see Instagram Private Replies for more details + */ +export interface CommentEvent { + /** Event\'s ID */ + id?: string; + /** Comment\'s text */ + text?: string; + /** Either LIVE or FEED. Indicates the type of media on which the comment was made. */ + comment_type?: CommentTypeEnum; + /** Instagram\'s URL of the live broadcast or the post on which the comment was made (permalink). */ + commented_on?: string; + /** Username of the account that commented in the live broadcast or post. */ + user?: string; +} +export type CommentTypeEnum = 'FEED' | 'LIVE'; + +/** + * The content of the event when contact_event is not populated. Note that this object is currently only available to select customers for beta testing. Mutually exclusive with contact_event. + */ +export interface ContactMessageEvent { + + /** @see ContactMessageEventPaymentStatusUpdateEvent */ + payment_status_update_event?: PaymentStatusUpdateEvent; +} + +/** + * Object reflecting the current state of a particular payment flow. + */ +export interface PaymentStatusUpdateEvent { + + /** Unique identifier for the corresponding payment of a particular order. */ + reference_id?: string; + /** The stage the payment has reached within the payment flow. */ + payment_status?: PaymentStatusEnum; + /** The status of the stage detailed in payment_status. */ + payment_transaction_status?: PaymentTransactionStatusEnum; + /** Unique identifier of the payment_transaction_status. */ + payment_transaction_id?: string; +} +export type PaymentStatusEnum = + 'PAYMENT_STATUS_UNKNOWN' + | 'PAYMENT_STATUS_NEW' + | 'PAYMENT_STATUS_PENDING' + | 'PAYMENT_STATUS_CAPTURED' + | 'PAYMENT_STATUS_CANCELED' + | 'PAYMENT_STATUS_FAILED'; + +export type PaymentTransactionStatusEnum = + 'PAYMENT_STATUS_TRANSACTION_UNKNOWN' + | 'PAYMENT_STATUS_TRANSACTION_PENDING' + | 'PAYMENT_STATUS_TRANSACTION_FAILED' + | 'PAYMENT_STATUS_TRANSACTION_SUCCESS' + | 'PAYMENT_STATUS_TRANSACTION_CANCELED'; diff --git a/packages/conversation/src/models/v1/event-inbound/index.ts b/packages/conversation/src/models/v1/event-inbound/index.ts new file mode 100644 index 00000000..5f7f4f04 --- /dev/null +++ b/packages/conversation/src/models/v1/event-inbound/index.ts @@ -0,0 +1,8 @@ +export type { + EventInbound, + EventInboundEvent, + ContactEvent, + CommentEvent, + ContactMessageEvent, + PaymentStatusUpdateEvent, +} from './event-inbound'; diff --git a/packages/conversation/src/models/v1/identified-by/identified-by.ts b/packages/conversation/src/models/v1/identified-by/identified-by.ts index 9246970d..c9505826 100644 --- a/packages/conversation/src/models/v1/identified-by/identified-by.ts +++ b/packages/conversation/src/models/v1/identified-by/identified-by.ts @@ -9,5 +9,5 @@ export interface IdentifiedBy { export interface IdentifiedByItem { /** @see IdentifiedBy */ - channel_identities?: [ChannelRecipientIdentity]; + channel_identities: ChannelRecipientIdentity[]; } diff --git a/packages/conversation/src/models/v1/index.ts b/packages/conversation/src/models/v1/index.ts index 746dda57..af2d70d1 100644 --- a/packages/conversation/src/models/v1/index.ts +++ b/packages/conversation/src/models/v1/index.ts @@ -11,9 +11,11 @@ export * from './app-update-request'; export * from './basic-auth-credential'; export * from './call-message'; export * from './callback-settings'; +export * from './capability-event'; export * from './card-height'; export * from './card-message'; export * from './carousel-message'; +export * from './channel-event'; export * from './channel-identities'; export * from './channel-identity'; export * from './channel-recipient-identity'; @@ -25,13 +27,20 @@ export * from './comment-reply-event'; export * from './composing-end-event'; export * from './composing-event'; export * from './contact'; +export * from './contact-create-event'; export * from './contact-create-request'; +export * from './contact-delete-event'; export * from './contact-id'; +export * from './contact-identities-duplication-event'; +export * from './contact-merge-event'; export * from './contact-language'; export * from './contact-message'; +export * from './contact-notification'; +export * from './contact-update-event'; export * from './conversation'; export * from './conversation-channel'; export * from './conversation-channel-credential'; +export * from './conversation-delete-event'; export * from './conversation-direction'; export * from './conversation-merge-strategy'; export * from './conversation-message'; @@ -39,10 +48,16 @@ export * from './conversation-message-injected'; export * from './conversation-messages-view'; export * from './conversation-metadata-report-view'; export * from './conversation-metadata-update-strategy'; +export * from './conversation-start-event'; +export * from './conversation-stop-event'; +export * from './conversation-webhook-event'; export * from './coordinates'; export * from './create-conversation-request'; +export * from './delivery-status'; export * from './dispatch-retention-policy'; export * from './dispatch-retention-policy-type'; +export * from './event-delivery'; +export * from './event-inbound'; export * from './fallback-message'; export * from './generic-event'; export * from './get-channel-profile-conversation-channel'; @@ -59,12 +74,19 @@ export * from './list-messages-response'; export * from './list-section'; export * from './list-webhooks-response'; export * from './location-message'; +export * from './message-inbound-event'; +export * from './message-inbound-event-item'; +export * from './message-inbound-smart-conversation-redaction-event'; export * from './mms-credentials'; +export * from './opt-in-event'; +export * from './opt-out-event'; export * from './media-card-message'; export * from './media-carousel-message'; export * from './media-message'; export * from './merge-contact-request'; +export * from './message-delivery-receipt-event'; export * from './message-queue'; +export * from './message-submit-event'; export * from './processing-mode'; export * from './processing-strategy'; export * from './product'; @@ -83,6 +105,7 @@ export * from './send-event-response'; export * from './send-message-request'; export * from './send-message-response'; export * from './smart-conversation'; +export * from './smart-conversations-event'; export * from './static-bearer-credential'; export * from './static-token-credential'; export * from './telegram-credentials'; @@ -91,6 +114,7 @@ export * from './template-reference'; export * from './text-message'; export * from './transcode-message-request'; export * from './transcode-message-response'; +export * from './unsupported-callback-event'; export * from './url-message'; export * from './wechat-credentials'; export * from './webhook'; diff --git a/packages/conversation/src/models/v1/message-delivery-receipt-event/index.ts b/packages/conversation/src/models/v1/message-delivery-receipt-event/index.ts new file mode 100644 index 00000000..2f535d06 --- /dev/null +++ b/packages/conversation/src/models/v1/message-delivery-receipt-event/index.ts @@ -0,0 +1,4 @@ +export type { + MessageDeliveryReceiptEvent, + MessageDeliveryReport, +} from './message-delivery-receipt-event'; diff --git a/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts b/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts new file mode 100644 index 00000000..84959189 --- /dev/null +++ b/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts @@ -0,0 +1,48 @@ +import { ChannelIdentity } from '../channel-identity'; +import { Reason } from '../reason'; +import { ProcessingMode } from '../processing-mode'; +import { DeliveryStatus } from '../delivery-status'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback notifies the API clients about status changes of already sent app message. + */ +export interface MessageDeliveryReceiptEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see MessageDeliveryReceiptEventMessageDeliveryReport */ + message_delivery_report?: MessageDeliveryReport; + /** Name of the trigger responsible for this event. */ + trigger: 'MESSAGE_DELIVERY'; +} + +export interface MessageDeliveryReport { + + /** The ID of the app message. */ + message_id?: string; + /** The ID of the conversation the app message is part of. Will be empty if processing_mode is DISPATCH. */ + conversation_id?: string; + /** The delivery status */ + status?: DeliveryStatus; + /** @see ChannelIdentity */ + channel_identity?: ChannelIdentity; + /** The ID of the contact. Will be empty if processing_mode is DISPATCH. */ + contact_id?: string; + /** @see Reason */ + reason?: Reason; + /** Metadata specified in the message_metadata field of a Send Message request, if any. */ + metadata?: string; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; +} diff --git a/packages/conversation/src/models/v1/message-inbound-event-item/index.ts b/packages/conversation/src/models/v1/message-inbound-event-item/index.ts new file mode 100644 index 00000000..a436afa0 --- /dev/null +++ b/packages/conversation/src/models/v1/message-inbound-event-item/index.ts @@ -0,0 +1 @@ +export type { MessageInboundEventItem } from './message-inbound-event-item'; diff --git a/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts b/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts new file mode 100644 index 00000000..7baee0be --- /dev/null +++ b/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts @@ -0,0 +1,30 @@ +import { ChannelIdentity } from '../channel-identity'; +import { ContactMessage } from '../contact-message'; +import { ProcessingMode } from '../processing-mode'; + +export interface MessageInboundEventItem { + + /** The message ID. */ + id?: string; + /** The direction of the message, it\'s always TO_APP for contact messages. */ + direction?: DirectionEnum; + /** @see ContactMessage */ + contact_message?: ContactMessage; + /** @see ChannelIdentity */ + channel_identity?: ChannelIdentity; + /** The ID of the conversation this message is part of. Will be empty if processing_mode is DISPATCH. */ + conversation_id?: string; + /** The ID of the contact. Will be empty if processing_mode is DISPATCH. */ + contact_id?: string; + /** Usually, metadata specific to the underlying channel is provided in this field. Refer to the individual channels\' documentation for more information (for example, SMS delivery receipts). Note that, for Choice message responses, this field is populated with the value of the message_metadata field of the corresponding Send message request. */ + metadata?: string; + /** Timestamp marking when the channel callback was received by the Conversation API. */ + accept_time?: string; + /** The sender ID to which the contact sent the message, if applicable. For example, originator msisdn/short code for SMS and MMS. */ + sender_id?: string; + /** Whether or not Conversation API should store contacts and conversations for the app. For more information, see [Processing Modes](../../../../../conversation/processing-modes/). */ + processing_mode?: ProcessingMode; + /** Flag for whether this message was injected. */ + injected?: boolean; +} +export type DirectionEnum = 'TO_APP'; diff --git a/packages/conversation/src/models/v1/message-inbound-event/index.ts b/packages/conversation/src/models/v1/message-inbound-event/index.ts new file mode 100644 index 00000000..7f7a277d --- /dev/null +++ b/packages/conversation/src/models/v1/message-inbound-event/index.ts @@ -0,0 +1 @@ +export type { MessageInboundEvent } from './message-inbound-event'; diff --git a/packages/conversation/src/models/v1/message-inbound-event/message-inbound-event.ts b/packages/conversation/src/models/v1/message-inbound-event/message-inbound-event.ts new file mode 100644 index 00000000..fc3b7342 --- /dev/null +++ b/packages/conversation/src/models/v1/message-inbound-event/message-inbound-event.ts @@ -0,0 +1,25 @@ +import { MessageInboundEventItem } from '../message-inbound-event-item'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback delivers contact (end-user) messages to the API clients. + */ +export interface MessageInboundEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see MessageInboundEventItem */ + message?: MessageInboundEventItem; + /** Name of the trigger responsible for this event. */ + trigger: 'MESSAGE_INBOUND'; +} diff --git a/packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/index.ts b/packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/index.ts new file mode 100644 index 00000000..f125b096 --- /dev/null +++ b/packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/index.ts @@ -0,0 +1,3 @@ +export type { + MessageInboundSmartConversationRedactionEvent, +} from './message-inbound-smart-conversation-redaction-event'; diff --git a/packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts b/packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts new file mode 100644 index 00000000..c54b9149 --- /dev/null +++ b/packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts @@ -0,0 +1,25 @@ +import { MessageInboundEventItem } from '../message-inbound-event-item'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback delivers contact (end-user) messages to the API clients. The content of the message goes through an A.I. analysis and is redacted if required. + */ +export interface MessageInboundSmartConversationRedactionEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see MessageInboundEventItem */ + message_redaction?: MessageInboundEventItem; + /** Name of the trigger responsible for this event. */ + trigger: 'MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION'; +} diff --git a/packages/conversation/src/models/v1/message-submit-event/index.ts b/packages/conversation/src/models/v1/message-submit-event/index.ts new file mode 100644 index 00000000..c03ff64c --- /dev/null +++ b/packages/conversation/src/models/v1/message-submit-event/index.ts @@ -0,0 +1 @@ +export type { MessageSubmitEvent, MessageSubmitNotification } from './message-submit-event'; diff --git a/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts b/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts new file mode 100644 index 00000000..1bfba31c --- /dev/null +++ b/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts @@ -0,0 +1,45 @@ +import { ChannelIdentity } from '../channel-identity'; +import { ContactMessage } from '../contact-message'; +import { ProcessingMode } from '../processing-mode'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback provides a notification to the API clients that the corresponding app message was submitted to a channel. This notification is created before any confirmation from Delivery Receipts. + */ +export interface MessageSubmitEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see MessageSubmitEventMessageSubmitNotification */ + message_submit_notification?: MessageSubmitNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'MESSAGE_SUBMIT'; +} + +export interface MessageSubmitNotification { + + /** The ID of the app message. */ + message_id?: string; + /** The ID of the conversation the app message is part of. Will be empty if processing_mode is DISPATCH. */ + conversation_id?: string; + /** @see ChannelIdentity */ + channel_identity?: ChannelIdentity; + /** The ID of the contact. Will be empty if processing_mode is DISPATCH. */ + contact_id?: string; + /** @see ContactMessage */ + submitted_message?: ContactMessage; + /** Metadata specified in the message_metadata field of a Send Message request, if any. */ + metadata?: string; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; +} diff --git a/packages/conversation/src/models/v1/opt-in-event/index.ts b/packages/conversation/src/models/v1/opt-in-event/index.ts new file mode 100644 index 00000000..f908d1a0 --- /dev/null +++ b/packages/conversation/src/models/v1/opt-in-event/index.ts @@ -0,0 +1 @@ +export type { OptInEvent, OptInNotification, OptInNotificationErrorDetails } from './opt-in-event'; diff --git a/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts b/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts new file mode 100644 index 00000000..154a01e0 --- /dev/null +++ b/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts @@ -0,0 +1,54 @@ +import { ConversationChannel } from '../conversation-channel'; +import { ProcessingMode } from '../processing-mode'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is used to deliver opt-in notifications from the channels. + */ +export interface OptInEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback\'s documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see OptInNotification */ + opt_in_notification?: OptInNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'OPT_IN'; +} + +export interface OptInNotification { + + /** ID generated when making an opt-in registration request. Can be used to detect duplicates. */ + request_id?: string; + /** The ID of the contact which is the subject of the opt-in. Will be empty if processing_mode is DISPATCH. */ + contact_id?: string; + /** @see ConversationChannel */ + channel?: ConversationChannel; + /** The channel identity. For example, a phone number for SMS, WhatsApp and Viber Business. */ + identity?: string; + /** Status of the opt-in registration. */ + status?: StatusEnum; + /** @see OptInNotificationErrorDetails */ + error_details?:OptInNotificationErrorDetails; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; +} +export type StatusEnum = 'OPT_IN_SUCCEEDED' | 'OPT_IN_FAILED' | 'OPT_IN_STATUS_UNSPECIFIED'; + +/** + * This field is populated if the opt-in failed. + */ +export interface OptInNotificationErrorDetails { + + /** Human-readable error description. */ + description?: string; +} diff --git a/packages/conversation/src/models/v1/opt-out-event/index.ts b/packages/conversation/src/models/v1/opt-out-event/index.ts new file mode 100644 index 00000000..b2b54504 --- /dev/null +++ b/packages/conversation/src/models/v1/opt-out-event/index.ts @@ -0,0 +1 @@ +export type { OptOutEvent } from './opt-out-event'; diff --git a/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts b/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts new file mode 100644 index 00000000..0a287f04 --- /dev/null +++ b/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts @@ -0,0 +1,54 @@ +import { ConversationChannel } from '../conversation-channel'; +import { ProcessingMode } from '../processing-mode'; +import { ConversationEvent } from '../conversation-event'; + +/** + * This callback is used to deliver opt-out notifications from the channels. + */ +export interface OptOutEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see OptOutNotification */ + opt_out_notification?: OptOutNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'OPT_OUT'; +} + +export interface OptOutNotification { + + /** ID generated when making an opt-out registration request. Can be used to detect duplicates. */ + request_id?: string; + /** The ID of the contact which is the subject of the opt-out. Will be empty if processing_mode is DISPATCH. */ + contact_id?: string; + /** @see ConversationChannel */ + channel?: ConversationChannel; + /** The channel identity. For example, a phone number for SMS, WhatsApp and Viber Business. */ + identity?: string; + /** Status of the opt-out registration. */ + status?: StatusEnum; + /** @see OptOutNotificationErrorDetails */ + error_details?: OptOutNotificationErrorDetails; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; +} +export type StatusEnum = 'OPT_OUT_SUCCEEDED' | 'OPT_OUT_FAILED' | 'OPT_OUT_STATUS_UNSPECIFIED'; + +/** + * This field is populated if the opt-out failed. + */ +export interface OptOutNotificationErrorDetails { + + /** Human-readable error description. */ + description?: string; +} diff --git a/packages/conversation/src/models/v1/smart-conversations-event/index.ts b/packages/conversation/src/models/v1/smart-conversations-event/index.ts new file mode 100644 index 00000000..a1475c8f --- /dev/null +++ b/packages/conversation/src/models/v1/smart-conversations-event/index.ts @@ -0,0 +1,17 @@ +export type { + SmartConversationsEvent, + SmartConversationNotification, + AnalysisResult, + MachineLearningSentimentResult, + SentimentResult, + MachineLearningNLUResult, + IntentResult, + MachineLearningImageRecognitionResult, + DocumentImageClassification, + OpticalCharacterRecognition, + OpticalCharacterRecognitionData, + DocumentFieldClassification, + DocumentFieldClassificationData, + MachineLearningPIIResult, + OffensiveAnalysis, +} from './smart-conversations-event'; diff --git a/packages/conversation/src/models/v1/smart-conversations-event/smart-conversations-event.ts b/packages/conversation/src/models/v1/smart-conversations-event/smart-conversations-event.ts new file mode 100644 index 00000000..1e61e02b --- /dev/null +++ b/packages/conversation/src/models/v1/smart-conversations-event/smart-conversations-event.ts @@ -0,0 +1,176 @@ +import { ConversationChannel } from '../conversation-channel'; +import { ConversationEvent } from '../conversation-event'; + +/** + * When using the Smart Conversations functionality, Machine Learning and Artificial Intelligence analyses are delivered through specific callbacks on the Conversation API. + */ +export interface SmartConversationsEvent extends ConversationEvent{ + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see SmartConversationNotification */ + smart_conversation_notification?: SmartConversationNotification; + /** Name of the trigger responsible for this event. */ + trigger: 'SMART_CONVERSATIONS'; +} + +export interface SmartConversationNotification { + + /** The unique ID of the contact that sent the message. */ + contact_id?: string; + /** The channel-specific identifier for the contact. */ + channel_identity?: string; + /** @see ConversationChannel */ + channel?: ConversationChannel; + /** The unique ID of the corresponding message. */ + message_id?: string; + /** The ID of the conversation the app message is part of. */ + conversation_id?: string; + /** @see AnalysisResult */ + analysis_results?: AnalysisResult; +} + +/** + * The analysis provided by the Smart Conversations machine learning engine(s). The contents of the object are determined by the functionalities that are enabled for your solution. + */ +export interface AnalysisResult { + + /** An array that contains the analyses of the sentiments of the corresponding messages. */ + ml_sentiment_result?: MachineLearningSentimentResult[]; + /** An array that contains the analyses of the intentions of, and entities within, the corresponding messages. */ + ml_nlu_result?: MachineLearningNLUResult[]; + /** An array that contains the image recognition analyses of the images identified in the corresponding messages. */ + ml_image_recognition_result?: MachineLearningImageRecognitionResult[]; + /** An array that contains the PII analysis of the corresponding messages. */ + ml_pii_result?: MachineLearningPIIResult[]; + /** An array that contains the analyses of the offenses of the corresponding messages. */ + ml_offensive_analysis_result?: OffensiveAnalysis[]; +} + +export interface MachineLearningSentimentResult { + + /** The message text that was analyzed. */ + message?: string; + /** An array of JSON objects made up of sentiment and score pairs, where the score represents the likelihood that the message communicates the corresponding sentiment. */ + results?: SentimentResult[]; + /** The most probable sentiment of the analyzed text. */ + sentiment?: SentimentEnum; + /** The likelihood that the assigned sentiment represents the emotional context of the analyzed text. 1 is the maximum value, representing the highest likelihood that the message text matches the sentiment, and 0 is the minimum value, representing the lowest likelihood that the message text matches the sentiment. */ + score?: number; +} +export type SentimentEnum = 'positive' | 'negative' | 'neutral'; + +export interface SentimentResult { + + /** The most probable sentiment of the analyzed text. */ + sentiment?: SentimentEnum; + /** The likelihood that the assigned sentiment represents the emotional context of the analyzed text. 1 is the maximum value, representing the highest likelihood that the message text matches the sentiment, and 0 is the minimum value, representing the lowest likelihood that the message text matches the sentiment. */ + score?: number; +} + +export interface MachineLearningNLUResult { + + /** The message text that was analyzed. */ + message?: string; + /** An array of JSON objects made up of intent and score pairs, where the score represents the likelihood that the message has the corresponding intent. */ + results?: IntentResult[]; + /** The most probable intent of the analyzed text. For example, chitchat.greeting, chitchat.bye, chitchat.compliment, chitchat.how_are_you, or general.yes_or_agreed. */ + intent?: string; + /** The likelihood that the assigned intent represents the purpose of the analyzed text. 1 is the maximum value, representing the highest likelihood that the message text matches the intent, and 0 is the minimum value, representing the lowest likelihood that the message text matches the intent. */ + score?: number; +} + +export interface IntentResult { + + /** The most probable intent of the analyzed text. For example, chitchat.greeting, chitchat.bye, chitchat.compliment, chitchat.how_are_you, or general.yes_or_agreed. */ + intent?: string; + /** The likelihood that the assigned intent represents the purpose of the analyzed text. 1 is the maximum value, representing the highest likelihood that the message text matches the intent, and 0 is the minimum value, representing the lowest likelihood that the message text matches the intent. */ + score?: number; +} + +export interface MachineLearningImageRecognitionResult { + + /** The URL of the image that was processed. */ + url?: string; + /** @see DocumentImageClassification */ + document_image_classification?: DocumentImageClassification; + /** @see OpticalCharacterRecognition */ + optical_character_recognition?: OpticalCharacterRecognition; + /** @see DocumentFieldClassification */ + document_field_classification?: DocumentFieldClassification; +} + +/** + * An object that identifies a document type within the image, along with a confidence level for that document type. + */ +export interface DocumentImageClassification { + + /** The document type that the analyzed image most likely contains. */ + doc_type?: string; + /** The likelihood that the analyzed image contains the assigned document type. 1 is the maximum value, representing the highest likelihood that the analyzed image contains the assigned document type, and 0 is the minimum value, representing the lowest likelihood that the analyzed image contains the assigned document type. */ + confidence?: number; +} + +/** + * An object containing a result array that reports the machine learning engine\'s character extraction results. + */ +export interface OpticalCharacterRecognition { + + /** The result of the OCR process. */ + result?: OpticalCharacterRecognitionData[]; +} + +export interface OpticalCharacterRecognitionData { + + /** The data array contains the string(s) identified in one section of an analyzed image. */ + data?: string[]; +} + +/** + * An object containing a result object that reports on all identified fields, as well as the values assigned to those fields. + */ +export interface DocumentFieldClassification { + + /** The result of the Document Field Classification process */ + result?: { [key: string]: DocumentFieldClassificationData; }[]; +} + +export interface DocumentFieldClassificationData { + + /** The data array contains the string(s) assigned to the corresponding document field. */ + data?: string[]; +} + +/** + * An object that contains the PII analysis of the corresponding messages. + */ +export interface MachineLearningPIIResult { + + /** The message text that was analyzed. */ + message?: string; + /** The redacted message text in which sensitive information was replaced with appropriate masks. A MISC mask is applied to a term that has been identified as PII, but with low confidence regarding which type of mask to assign. */ + masked?: string; +} + +export interface OffensiveAnalysis { + + /** Either the message text or the URL of the image that was analyzed. */ + message?: string; + /** */ + url?: string; + /** A label, either SAFE or UNSAFE, that classifies the analyzed content. */ + evaluation?: EvaluationEnum; + /** The likelihood that the assigned evaluation represents the analyzed message correctly. 1 is the maximum value, representing the highest likelihood that the content of the message matches the evaluation. 0 is the minimum value, representing the lowest likelihood that the content of the message matches the evaluation. */ + score?: number; +} +export type EvaluationEnum = 'SAFE' | 'UNSAFE'; diff --git a/packages/conversation/src/models/v1/unsupported-callback-event/index.ts b/packages/conversation/src/models/v1/unsupported-callback-event/index.ts new file mode 100644 index 00000000..ebdb1d02 --- /dev/null +++ b/packages/conversation/src/models/v1/unsupported-callback-event/index.ts @@ -0,0 +1 @@ +export type { UnsupportedCallbackEvent, UnsupportedCallback } from './unsupported-callback-event'; diff --git a/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts b/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts new file mode 100644 index 00000000..c8459270 --- /dev/null +++ b/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts @@ -0,0 +1,45 @@ +import { ConversationChannel } from '../conversation-channel'; +import { ProcessingMode } from '../processing-mode'; +import { ChannelIdentity } from '../channel-identity'; +import { ConversationEvent } from '../conversation-event'; + +/** + * Some of the callbacks received from the underlying channels might be specific to a single channel or may not have a proper mapping in Conversation API yet. + */ +export interface UnsupportedCallbackEvent extends ConversationEvent { + + /** Id of the subscribed app. */ + app_id?: string; + /** Timestamp marking when the channel callback was accepted/received by the Conversation API. */ + accepted_time?: Date; + /** Timestamp of the event as provided by the underlying channels. */ + event_time?: Date; + /** The project ID of the app which has subscribed for the callback. */ + project_id?: string; + /** Context-dependent metadata. Refer to specific callback's documentation for exact information provided. */ + message_metadata?: string; + /** The value provided in field correlation_id of a send message request. */ + correlation_id?: string; + /** @see UnsupportedCallback */ + unsupported_callback?: UnsupportedCallback; + /** Name of the trigger responsible for this event. */ + trigger: 'UNSUPPORTED'; +} + +export interface UnsupportedCallback { + + /** @see ConversationChannel */ + channel?: ConversationChannel; + /** Normally a JSON payload as sent by the channel. */ + payload?: string; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; + /** The message ID. */ + id?: string; + /** The ID of the contact. This field is blank if not supported. */ + contact_id?: string; + /** The ID of the conversation this message is part of. This field is blank if not supported. */ + conversation_id?: string; + /** @see ChannelIdentity */ + channel_identity?: ChannelIdentity; +} diff --git a/packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts b/packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts index 13252102..44aa0792 100644 --- a/packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts +++ b/packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts @@ -8,28 +8,35 @@ * - `CONVERSATION_STOP`: Subscribe to an event that is triggered when a active conversation has been stopped. * - `CONTACT_CREATE`: Subscribe to an event that is triggered when a new contact has been created. * - `CONTACT_DELETE`: Subscribe to an event that is triggered when a contact has been deleted. - * - `CONTACT_MERGE`: Subscribe to an event that is triggered when a two contacts are merged. + * - `CONTACT_MERGE`: Subscribe to an event that is triggered when two contacts are merged. * - `CONTACT_UPDATE`: Subscribe to an event that is triggered when a contact is updated. * - `UNSUPPORTED`: Subscribe to callbacks that are not natively supported by the Conversation API. - * - `OPT_IN`: Subscribe to opt_ins. - `OPT_OUT`: Subscribe to opt_outs. + * - `OPT_IN`: Subscribe to opt_ins. + * - `OPT_OUT`: Subscribe to opt_outs. * - `CAPABILITY`: Subscribe to see get capability results. + * - `CHANNEL_EVENT`: Subscribe to channel event notifications. * - `CONVERSATION_DELETE`: Subscribe to get an event when a conversation is deleted. * - `CONTACT_IDENTITIES_DUPLICATION`: Subscribe to get an event when contact identity duplications are found during message or event processing. + * - `SMART_CONVERSATIONS`: Subscribe to smart conversations callback */ export type WebhookTrigger = 'UNSPECIFIED_TRIGGER' | 'MESSAGE_DELIVERY' - | 'EVENT_DELIVERY' + | 'MESSAGE_SUBMIT' | 'MESSAGE_INBOUND' + | 'EVENT_DELIVERY' | 'EVENT_INBOUND' + | 'SMART_CONVERSATIONS' + | 'MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION' | 'CONVERSATION_START' | 'CONVERSATION_STOP' + | 'CONVERSATION_DELETE' | 'CONTACT_CREATE' | 'CONTACT_DELETE' | 'CONTACT_MERGE' | 'CONTACT_UPDATE' + | 'CONTACT_IDENTITIES_DUPLICATION' | 'UNSUPPORTED' | 'OPT_IN' | 'OPT_OUT' - | 'CAPABILITY' - | 'CONVERSATION_DELETE' - | 'CONTACT_IDENTITIES_DUPLICATION'; + | 'CHANNEL_EVENT' + | 'CAPABILITY'; diff --git a/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts b/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts new file mode 100644 index 00000000..f905f135 --- /dev/null +++ b/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts @@ -0,0 +1,159 @@ +import { + CapabilityEvent, ChannelEvent, + ContactCreateEvent, + ContactDeleteEvent, + ContactIdentitiesDuplicationEvent, + ContactMergeEvent, + ContactUpdateEvent, + ConversationDeleteEvent, + ConversationStartEvent, + ConversationStopEvent, + ConversationWebhookEvent, + EventDelivery, + EventInbound, + MessageDeliveryReceiptEvent, + MessageInboundEvent, + MessageInboundSmartConversationRedactionEvent, + MessageSubmitEvent, + OptInEvent, + OptOutEvent, SmartConversationsEvent, UnsupportedCallbackEvent, + WebhookTrigger, +} from '../../../models'; + +interface WebhookTriggerEvent { + trigger: WebhookTrigger; +} +export type ConversationWebhookEventParsed = ConversationWebhookEvent & WebhookTriggerEvent; + +/** + * Add the trigger corresponding to the trigger + * 'message' <==> MESSAGE_INBOUND + * 'message_redaction' <==> MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION + * 'message_submit_notification' <==> MESSAGE_SUBMIT + * 'message_delivery_report' <==> MESSAGE_DELIVERY + * 'event' <==> EVENT_INBOUND + * 'event_delivery_report' <==> EVENT_DELIVERY + * 'conversation_start_notification' <==> CONVERSATION_START + * 'conversation_stop_notification' <==> CONVERSATION_STOP + * 'conversation_delete_notification' <==> CONVERSATION_DELETE + * 'contact_create_notification' <==> CONTACT_CREATE + * 'contact_delete_notification' <==> CONTACT_DELETE + * 'contact_merge_notification' <==> CONTACT_MERGE + * 'contact_update_notification' <==> CONTACT_UPDATE + * 'duplicated_identities' <==> CONTACT_IDENTITIES_DUPLICATION + * 'capability_notification' <==> CAPABILITY + * 'opt_in_notification' <==> OPT_IN + * 'opt_out_notification' <==> OPT_OUT + * 'channel_event_notification' <==> CHANNEL_EVENT + * 'unsupported_callback' <==> UNSUPPORTED + * 'smart_conversation_notification' <==> SMART_CONVERSATIONS + * + * @param {any} eventBody - The conversation event to parse + * @return {ConversationWebhookEventParsed} - Parsed conversation event. + * @throws {Error} If the eventBody is not valid or cannot be parsed. + */ +export const parseConversationEventNotification = (eventBody: any): ConversationWebhookEventParsed => { + if('message' in eventBody) { + return { + ...eventBody, + trigger: 'MESSAGE_INBOUND', + } as MessageInboundEvent; + } else if('message_redaction' in eventBody) { + return { + ...eventBody, + trigger: 'MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION', + } as MessageInboundSmartConversationRedactionEvent; + } else if('message_submit_notification' in eventBody) { + return { + ...eventBody, + trigger: 'MESSAGE_SUBMIT', + } as MessageSubmitEvent; + } else if('message_delivery_report' in eventBody) { + return { + ...eventBody, + trigger: 'MESSAGE_DELIVERY', + } as MessageDeliveryReceiptEvent; + } else if('event' in eventBody) { + return { + ...eventBody, + trigger: 'EVENT_INBOUND', + } as EventInbound; + } else if('event_delivery_report' in eventBody) { + return { + ...eventBody, + trigger: 'EVENT_DELIVERY', + } as EventDelivery; + } else if('conversation_start_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONVERSATION_START', + } as ConversationStartEvent; + } else if('conversation_stop_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONVERSATION_STOP', + } as ConversationStopEvent; + } else if('conversation_delete_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONVERSATION_DELETE', + } as ConversationDeleteEvent; + } else if('contact_create_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_CREATE', + } as ContactCreateEvent; + } else if('contact_delete_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_DELETE', + } as ContactDeleteEvent; + } else if('contact_merge_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_MERGE', + } as ContactMergeEvent; + } else if('contact_update_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_UPDATE', + } as ContactUpdateEvent; + } else if('duplicated_identities' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_IDENTITIES_DUPLICATION', + } as ContactIdentitiesDuplicationEvent; + } else if('capability_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CAPABILITY', + } as CapabilityEvent; + } else if('opt_in_notification' in eventBody) { + return { + ...eventBody, + trigger: 'OPT_IN', + } as OptInEvent; + } else if('opt_out_notification' in eventBody) { + return { + ...eventBody, + trigger: 'OPT_OUT', + } as OptOutEvent; + } else if('channel_event_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CHANNEL_EVENT', + } as ChannelEvent; + } else if('unsupported_callback' in eventBody) { + return { + ...eventBody, + trigger: 'UNSUPPORTED', + } as UnsupportedCallbackEvent; + } else if('smart_conversation_notification' in eventBody) { + return { + ...eventBody, + trigger: 'SMART_CONVERSATIONS', + } as SmartConversationsEvent; + } else { + throw new Error('Unknown Conversation event to parse'); + } +}; diff --git a/packages/conversation/src/rest/v1/callbacks/index.ts b/packages/conversation/src/rest/v1/callbacks/index.ts new file mode 100644 index 00000000..f04a2490 --- /dev/null +++ b/packages/conversation/src/rest/v1/callbacks/index.ts @@ -0,0 +1 @@ +export * from './callbacks-webhook'; diff --git a/packages/conversation/src/rest/v1/conversation-domain-api.ts b/packages/conversation/src/rest/v1/conversation-domain-api.ts index b88aac96..772aa109 100644 --- a/packages/conversation/src/rest/v1/conversation-domain-api.ts +++ b/packages/conversation/src/rest/v1/conversation-domain-api.ts @@ -3,8 +3,10 @@ import { ApiClient, ApiClientOptions, ApiFetchClient, - SinchClientParameters, + ConversationRegion, Oauth2TokenRequest, + Region, + SinchClientParameters, UnifiedCredentials, } from '@sinch/sdk-client'; @@ -59,9 +61,13 @@ export class ConversationDomainApi implements Api { */ public getSinchClient(): ApiClient { if (!this.client) { + const region = this.sinchClientParameters.region || Region.UNITED_STATES; + if(!Object.values(ConversationRegion).includes((region as unknown) as ConversationRegion)) { + console.warn(`The region '${region}' is not supported for the Conversation API`); + } const apiClientOptions = this.buildApiClientOptions(this.sinchClientParameters); this.client = new ApiFetchClient(apiClientOptions); - this.client.apiClientOptions.basePath = 'https://us.conversation.api.sinch.com'; + this.client.apiClientOptions.basePath = `https://${region}.conversation.api.sinch.com`; } return this.client; } diff --git a/packages/conversation/src/rest/v1/index.ts b/packages/conversation/src/rest/v1/index.ts index d6a2350f..04d972d9 100644 --- a/packages/conversation/src/rest/v1/index.ts +++ b/packages/conversation/src/rest/v1/index.ts @@ -1,4 +1,5 @@ export * from './app'; +export * from './callbacks'; export * from './capability'; export * from './contact'; export * from './conversation'; diff --git a/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts b/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts new file mode 100644 index 00000000..6a0252e0 --- /dev/null +++ b/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts @@ -0,0 +1,48 @@ +import { ConversationApi, Region, UnifiedCredentials } from '../../../src'; + +describe('Conversation API', () => { + let conversationApi: ConversationApi; + let params: UnifiedCredentials; + + beforeEach(() => { + params = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + }); + + it('should initialize the client with the default "us" region', () => { + conversationApi = new ConversationApi(params); + conversationApi.getSinchClient(); + expect(conversationApi.client).toBeDefined(); + expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://us.conversation.api.sinch.com'); + }); + + it('should change the URL when specifying a different region', () => { + params.region = Region.EUROPE; + conversationApi = new ConversationApi(params); + conversationApi.getSinchClient(); + expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://eu.conversation.api.sinch.com'); + }); + + it('should log a warning when using an unsupported region', async () => { + params.region = Region.CANADA; + conversationApi = new ConversationApi(params); + const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation(() => {}); + await conversationApi.getSinchClient(); + // Add a small delay to allow jest to capture the warning + setTimeout(() => { + expect(consoleWarnSpy).toHaveBeenCalledWith('The region \'ca\' is not supported for the Conversation API'); + consoleWarnSpy.mockRestore(); + }, 20); + }); + + it('should set a custom URL', () => { + conversationApi = new ConversationApi(params); + conversationApi.setBasePath('https:/foo.com'); + expect(conversationApi.client).toBeDefined(); + expect(conversationApi.client?.apiClientOptions.basePath).toBe('https:/foo.com'); + }); + +}); diff --git a/packages/sdk-client/src/domain/domain-interface.ts b/packages/sdk-client/src/domain/domain-interface.ts index 98115734..8802b000 100644 --- a/packages/sdk-client/src/domain/domain-interface.ts +++ b/packages/sdk-client/src/domain/domain-interface.ts @@ -78,6 +78,12 @@ export enum VoiceRegion { SOUTHEAST_ASIA_2 = '-apse2' } +export enum ConversationRegion { + UNITED_STATES = 'us', + EUROPE = 'eu', + BRAZIL = 'br' +} + export const getVoiceRegion = (value: string | undefined): VoiceRegion | undefined => { if (!value) { return undefined; diff --git a/packages/sdk-client/src/utils/authorization.helper.ts b/packages/sdk-client/src/utils/authorization.helper.ts index dfa5d550..88d40d96 100644 --- a/packages/sdk-client/src/utils/authorization.helper.ts +++ b/packages/sdk-client/src/utils/authorization.helper.ts @@ -1,6 +1,7 @@ import crypto from 'crypto'; import { IncomingHttpHeaders } from 'http'; import { RequestBody } from '../plugins'; +import * as console from 'console'; export const calculateMD5 = (body: string): string => { // Content-MD5 = Base64 ( MD5 ( UTF8 ( [BODY] ) ) ) @@ -46,6 +47,43 @@ export const generateAuthorizationHeader = ( return `Application ${applicationKey}:${signature}`; }; +export const validateWebhookSignature = ( + secret: string, + headers: IncomingHttpHeaders, + body: string, +): boolean => { + const normalizedHeaders = normalizeHeaders(headers); + const nonce = getHeader(normalizedHeaders['x-sinch-webhook-signature-nonce']); + const timestamp = getHeader(normalizedHeaders['x-sinch-webhook-signature-timestamp']); + + let bodyAsString = body; + if (typeof body === 'object' && body !== null) { + bodyAsString = JSON.stringify(body); + } + + const signedData = computeSignedData(bodyAsString, nonce, timestamp); + const signature = calculateWebhookSignature(signedData, secret); + + const headerSignature = normalizedHeaders['x-sinch-webhook-signature']; + + return headerSignature === signature; +}; + +export const computeSignedData = ( + body: string, + nonce: string, + timestamp: string, +): string => { + return `${body}.${nonce}.${timestamp}`; +}; + +export const calculateWebhookSignature = ( + signedData: string, + secret: string, +): string => { + return crypto.createHmac('sha256', secret).update(signedData).digest('base64'); +}; + export const validateAuthenticationHeader = ( applicationKey: string, applicationSecret: string, @@ -54,12 +92,7 @@ export const validateAuthenticationHeader = ( body: any, method: string, ): boolean => { - const normalizedHeaders = Object.fromEntries( - Object.entries(headers) - .map(([key, value]) => [key.toLowerCase(), value]) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - .filter(([_, value]) => value !== undefined), - ) as { [p: string]: string | string[] }; + const normalizedHeaders = normalizeHeaders(headers); const authorization = getHeader(normalizedHeaders.authorization); const authParts = checkAuthorizationHeaderFormat(authorization); @@ -88,6 +121,18 @@ export const validateAuthenticationHeader = ( return false; }; +const normalizeHeaders = ( + headers: IncomingHttpHeaders, +): { [p: string]: string | string[] } => { + return Object.fromEntries( + Object.entries(headers) + .map(([key, value]) => [key.toLowerCase(), value]) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + .filter(([_, value]) => value !== undefined), + ); +}; + + const validateApplicationAuth = ( authorizationValue: string, normalizedHeaders: {[p: string]: string | string[]}, diff --git a/packages/sdk-client/tests/utils/authorization.helper.test.ts b/packages/sdk-client/tests/utils/authorization.helper.test.ts index 32afb99a..bf54f917 100644 --- a/packages/sdk-client/tests/utils/authorization.helper.test.ts +++ b/packages/sdk-client/tests/utils/authorization.helper.test.ts @@ -1,6 +1,8 @@ import { calculateMD5, calculateSignature, + calculateWebhookSignature, + computeSignedData, generateAuthorizationHeader, validateAuthenticationHeader, } from '../../src'; @@ -174,3 +176,27 @@ describe('Authorization validation', () => { }); }); + +describe('Webhook signature (Conversation API)', () => { + + it('should compute the signed data', () => { + const body = 'body'; + const nonce = 'nonce'; + const timestamp = 'timestamp'; + const signedData = computeSignedData(body, nonce, timestamp); + expect(signedData).toEqual('body.nonce.timestamp'); + }); + + it('should calculate the right signature', () => { + // eslint-disable-next-line max-len + const body = '{"app_id":"","accepted_time":"2021-10-18T17:49:13.813615Z","project_id":"e2df3a34-a71b-4448-9db5-a8d2baad28e4","contact_create_notification":{"contact":{"id":"01FJA8B466Y0R2GNXD78MD9SM1","channel_identities":[{"channel":"SMS","identity":"48123456789","app_id":""}],"display_name":"New Test Contact","email":"new.contact@email.com","external_id":"","metadata":"","language":"EN_US"}},"message_metadata":""}'; + const nonce = '01FJA8B4A7BM43YGWSG9GBV067'; + const timestamp= '1634579353'; + const signedData = computeSignedData(body, nonce, timestamp); + const secret = 'foo_secret1234'; + const signature = calculateWebhookSignature(signedData, secret); + + expect(signature).toEqual('6bpJoRmFoXVjfJIVglMoJzYXxnoxRujzR4k2GOXewOE='); + }); + +}); From 3b7fd879671af73567e7a04a530e4112e8634c75 Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Mon, 5 Feb 2024 10:13:11 +0100 Subject: [PATCH 09/19] Update credentials for SMS, Instagram, AppleBC and KakaoTalkChat --- .../conversation/injectMessage.ts | 10 +-- .../conversation/src/models/v1/agent/agent.ts | 4 +- .../app-message-message.ts | 1 + .../src/models/v1/app-message/app-message.ts | 73 ++++++++++++++++--- .../models/v1/app-response/app-response.ts | 36 ++++++--- .../src/models/v1/app-response/index.ts | 8 +- .../applebc-credentials.ts | 14 ++++ .../models/v1/applebc-credentials/index.ts | 1 + .../v1/contact-message/contact-message.ts | 35 +++++++-- .../conversation-channel-credential.ts | 36 ++++++--- .../conversation-channel-credential/index.ts | 2 +- .../conversation-channel.ts | 1 + .../conversation-message.ts | 32 ++++++-- .../v1/delivery-status/delivery-status.ts | 7 +- packages/conversation/src/models/v1/index.ts | 7 +- .../models/v1/instagram-credentials/index.ts | 1 + .../instagram-credentials.ts | 10 +++ .../models/v1/kakao-talk-credentials/index.ts | 1 - .../models/v1/kakaotalk-credentials/index.ts | 1 + .../kakaotalk-credentials.ts} | 0 .../v1/kakaotalkchat-credentials/index.ts | 1 + .../kakaotalkchat-credentials.ts | 10 +++ .../models/v1/list-messages-response/index.ts | 1 - .../list-messages-response.ts | 10 --- .../v1/mms-credentials/mms-credentials.ts | 4 +- .../src/models/v1/sms-credentials/index.ts | 1 + .../v1/sms-credentials/sms-credentials.ts | 8 ++ .../v1/conversation/conversation-api.test.ts | 10 +-- .../rest/v1/messages/messages-api.test.ts | 72 +++++++++--------- 29 files changed, 288 insertions(+), 109 deletions(-) create mode 100644 packages/conversation/src/models/v1/applebc-credentials/applebc-credentials.ts create mode 100644 packages/conversation/src/models/v1/applebc-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/instagram-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/instagram-credentials/instagram-credentials.ts delete mode 100644 packages/conversation/src/models/v1/kakao-talk-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/kakaotalk-credentials/index.ts rename packages/conversation/src/models/v1/{kakao-talk-credentials/kakao-talk-credentials.ts => kakaotalk-credentials/kakaotalk-credentials.ts} (100%) create mode 100644 packages/conversation/src/models/v1/kakaotalkchat-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/kakaotalkchat-credentials/kakaotalkchat-credentials.ts delete mode 100644 packages/conversation/src/models/v1/list-messages-response/index.ts delete mode 100644 packages/conversation/src/models/v1/list-messages-response/list-messages-response.ts create mode 100644 packages/conversation/src/models/v1/sms-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/sms-credentials/sms-credentials.ts diff --git a/examples/simple-examples/src/conversation/conversation/injectMessage.ts b/examples/simple-examples/src/conversation/conversation/injectMessage.ts index 6f71aea3..5a34d5f8 100644 --- a/examples/simple-examples/src/conversation/conversation/injectMessage.ts +++ b/examples/simple-examples/src/conversation/conversation/injectMessage.ts @@ -9,9 +9,9 @@ import { (async () => { - console.log('***********************************'); + console.log('******************************'); console.log('* Conversation_InjectMessage *'); - console.log('***********************************'); + console.log('******************************'); const conversationId = getConversationIdFromConfig(); const messengerUserId = getMessengerUserIdFromConfig(); @@ -22,10 +22,8 @@ import { conversation_id: conversationId, injectMessageRequestBody: { app_message: { - message: { - text_message: { - text: 'test', - }, + text_message: { + text: 'test', }, }, direction: 'TO_CONTACT', diff --git a/packages/conversation/src/models/v1/agent/agent.ts b/packages/conversation/src/models/v1/agent/agent.ts index 50e035d7..813b16c4 100644 --- a/packages/conversation/src/models/v1/agent/agent.ts +++ b/packages/conversation/src/models/v1/agent/agent.ts @@ -4,9 +4,9 @@ export interface Agent { /** Agent\'s display name */ - display_name?: string; + display_name: string; /** Agent\'s classification. It can be UNKNOWN_AGENT_TYPE, HUMAN or BOT. */ - type?: 'UNKNOWN_AGENT_TYPE' | 'HUMAN' | 'BOT'; + type: 'UNKNOWN_AGENT_TYPE' | 'HUMAN' | 'BOT'; /** The Agent\'s picture url. */ picture_url?: string; } diff --git a/packages/conversation/src/models/v1/app-message-message/app-message-message.ts b/packages/conversation/src/models/v1/app-message-message/app-message-message.ts index fb7de8b5..880d2575 100644 --- a/packages/conversation/src/models/v1/app-message-message/app-message-message.ts +++ b/packages/conversation/src/models/v1/app-message-message/app-message-message.ts @@ -7,6 +7,7 @@ import { TextMessage } from '../text-message'; import { ListMessage } from '../list-message'; import { TemplateMessage } from '../template-message'; +/** The content of the message */ export type AppMessageMessage = CardMessage | CarouselMessage diff --git a/packages/conversation/src/models/v1/app-message/app-message.ts b/packages/conversation/src/models/v1/app-message/app-message.ts index 5fefb734..fc7a74cb 100644 --- a/packages/conversation/src/models/v1/app-message/app-message.ts +++ b/packages/conversation/src/models/v1/app-message/app-message.ts @@ -1,20 +1,75 @@ import { AppMessageAdditionalProperties } from '../app-message-additional-properties'; import { AppMessageMessage } from '../app-message-message'; +import { Agent } from '../agent'; +import { LocationMessageItem } from '../location-message'; +import { MediaMessageItem } from '../media-message'; +import { TextMessageItem } from '../text-message'; +import { TemplateMessage } from '../template-message'; +import { CardMessageItem } from '../card-message'; +import { ChoiceMessage } from '../choice-message'; +import { CarouselMessage } from '../carousel-message'; +import { ListMessage } from '../list-message'; /** * Message originating from an app */ -export interface AppMessage { +export type AppMessage = + AppMessageCardMessage + | AppMessageChoiceMessage + | AppMessageLocationMessage + | AppMessageCarouselMessage + | AppMessageMediaMessage + | AppMessageTemplateMessage + | AppMessageTextMessage + | AppMessageListMessage; - /** @see AppMessageMessage */ - message?: AppMessageMessage; +interface AppMessageCardMessage extends AppMessageBase { + /** @see CardMessageItem */ + card_message?: CardMessageItem; +} + +interface AppMessageChoiceMessage extends AppMessageBase { + /** @see ChoiceResponseMessage */ + choice_message?: ChoiceMessage; +} + +interface AppMessageLocationMessage extends AppMessageBase { + /** @see LocationMessageItem */ + location_message?: LocationMessageItem; +} + +interface AppMessageCarouselMessage extends AppMessageBase { + /** @see CarouselMessage */ + carousel_message?: CarouselMessage; +} + +interface AppMessageMediaMessage extends AppMessageBase { + /** @see MediaMessageItem */ + media_message?: MediaMessageItem; +} + +interface AppMessageTemplateMessage extends AppMessageBase { + /** @see TemplateMessage */ + template_message?: TemplateMessage; +} + +interface AppMessageTextMessage extends AppMessageBase { + /** @see TextMessageItem */ + text_message?: TextMessageItem; +} + +interface AppMessageListMessage extends AppMessageBase { + /** @see ListMessage */ + list_message?: ListMessage; +} + +interface AppMessageBase { /** Optional. Channel specific messages, overriding any transcoding. The key in the map must point to a valid conversation channel as defined by the enum ConversationChannel. */ - explicit_channel_message?: object; + explicit_channel_message?: { [key: string]: string; }; /** @see AppMessageAdditionalProperties */ additionalProperties?: AppMessageAdditionalProperties; - - /** TBC: Not documented */ - agent?: any | null; - /** TBC: Not documented */ - explicit_channel_omni_message?: object; + /** Identity of a sender */ + agent?: Agent | null; + /** */ + explicit_channel_omni_message?: { [key: string]: AppMessageMessage; }; } diff --git a/packages/conversation/src/models/v1/app-response/app-response.ts b/packages/conversation/src/models/v1/app-response/app-response.ts index dfa6d286..ea989bfb 100644 --- a/packages/conversation/src/models/v1/app-response/app-response.ts +++ b/packages/conversation/src/models/v1/app-response/app-response.ts @@ -34,23 +34,41 @@ export interface AppResponse { /** @see QueueStats */ queue_stats?: QueueStats; - /** TBC: Not documented */ - persist_message_status?: Enabled; - /** TBC: Not documented */ - message_search?: Enabled; - /** TBC: Not documented @see CallbackSettings */ + /** Message status persistence configuration. */ + persist_message_status?: PersistMessageStatus; + /** Message search configuration */ + message_search?: MessageSearch; + /** Additional callback configuration. */ callback_settings?: CallbackSettings; - /** TBC: Not documented */ + /** Fallback upon no positive delivery report configuration. */ delivery_report_based_fallback?: DeliveryReportBasedFallback | null; - /** TBC: Not documented */ - message_retry_settings?: null; + /** TBC: Message retry time configuration. */ + message_retry_settings?: MessageRetrySettings | null; } -export interface Enabled { +export interface PersistMessageStatus { + /** A flag specifying whether message status for this app should be persisted. */ + enabled?: boolean; +} + +export interface MessageSearch { + /** A flag specifying whether this app has enabled Message Search services. */ enabled?: boolean; } export interface DeliveryReportBasedFallback { + /** A flag specifying whether this app has enabled fallback upon no positive delivery report feature. Disabled by default */ enabled?: boolean; + /** The time, in seconds, after which a message without a positive delivery report will fallback to the next channel. The valid values for this field are [60 - 259200]. */ delivery_report_waiting_time?: number; } + +export interface MessageRetrySettings { + /** + * The maximum duration, in seconds, for which to retry sending a message in case of a temporary processing failure. Time is counted after the first message processing failure. At least one retry is guaranteed. + * Subsequent retry times are randomized with exponential backoff. If the next retry timestamp exceeds the configured time, one last retry will be performed on the cut-off time. + * If the message has a configured fallback channel, a switch_on_channel will be triggered. + * The valid values for this field are [30 - 3600]. Default value is 3600 (seconds - 1 hour). + */ + retry_duration?: number; +} diff --git a/packages/conversation/src/models/v1/app-response/index.ts b/packages/conversation/src/models/v1/app-response/index.ts index 2e74d6c9..bdc7716f 100644 --- a/packages/conversation/src/models/v1/app-response/index.ts +++ b/packages/conversation/src/models/v1/app-response/index.ts @@ -1 +1,7 @@ -export type { AppResponse, DeliveryReportBasedFallback, Enabled } from './app-response'; +export type { + AppResponse, + DeliveryReportBasedFallback, + MessageRetrySettings, + MessageSearch, + PersistMessageStatus, +} from './app-response'; diff --git a/packages/conversation/src/models/v1/applebc-credentials/applebc-credentials.ts b/packages/conversation/src/models/v1/applebc-credentials/applebc-credentials.ts new file mode 100644 index 00000000..18efe1e1 --- /dev/null +++ b/packages/conversation/src/models/v1/applebc-credentials/applebc-credentials.ts @@ -0,0 +1,14 @@ +/** + * If you are including the Apple Business Chat channel in the `channel_identifier` property, you must include this object. + */ +export interface AppleBcCredentials { + + /** The ID that identifies a Business Chat Account (BCA). */ + business_chat_account_id: string; + /** Required if our client wants to use Apple Pay. */ + merchant_id?: string; + /** Required if our client wants to use Apple Pay. */ + apple_pay_certificate_reference?: string; + /** Required if our client wants to use Apple Pay. */ + apple_pay_certificate_password?: string; +} diff --git a/packages/conversation/src/models/v1/applebc-credentials/index.ts b/packages/conversation/src/models/v1/applebc-credentials/index.ts new file mode 100644 index 00000000..8e41cd71 --- /dev/null +++ b/packages/conversation/src/models/v1/applebc-credentials/index.ts @@ -0,0 +1 @@ +export type { AppleBcCredentials } from './applebc-credentials'; diff --git a/packages/conversation/src/models/v1/contact-message/contact-message.ts b/packages/conversation/src/models/v1/contact-message/contact-message.ts index 3695b837..5712ea93 100644 --- a/packages/conversation/src/models/v1/contact-message/contact-message.ts +++ b/packages/conversation/src/models/v1/contact-message/contact-message.ts @@ -9,20 +9,45 @@ import { TextMessageItem } from '../text-message'; /** * Message originating from a contact */ -export interface ContactMessage { +export type ContactMessage = + ContactMessageChoiceResponseMessage + | ContactMessageFallbackMessage + | ContactMessageLocationMessage + | ContactMessageMediaCardMessage + | ContactMessageMediaMessage + | ContactMessageTextMessage; +interface ContactMessageChoiceResponseMessage extends ContactMessageBase { /** @see ChoiceResponseMessage */ choice_response_message?: ChoiceResponseMessage; +} + +interface ContactMessageFallbackMessage extends ContactMessageBase { /** @see FallbackMessage */ fallback_message?: FallbackMessage; - /** @see LocationMessage */ +} + +interface ContactMessageLocationMessage extends ContactMessageBase { + /** @see LocationMessageItem */ location_message?: LocationMessageItem; +} + +interface ContactMessageMediaCardMessage extends ContactMessageBase { /** @see MediaCardMessage */ media_card_message?: MediaCardMessage; - /** @see MediaMessage */ +} + +interface ContactMessageMediaMessage extends ContactMessageBase { + /** @see MediaMessageItem */ media_message?: MediaMessageItem; - /** @see ReplyTo */ - reply_to?: ReplyTo; +} + +interface ContactMessageTextMessage extends ContactMessageBase { /** @see TextMessageItem */ text_message?: TextMessageItem; } + +interface ContactMessageBase { + /** @see ReplyTo */ + reply_to?: ReplyTo; +} diff --git a/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts index ead67350..5d06998e 100644 --- a/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts +++ b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts @@ -1,11 +1,15 @@ import { ConversationChannel } from '../conversation-channel'; -import { KakaoTalkCredentials } from '../kakao-talk-credentials'; +import { KakaoTalkCredentials } from '../kakaotalk-credentials'; +import { KakaoTalkChatCredentials } from '../kakaotalkchat-credentials'; import { LineCredentials } from '../line-credentials'; import { MMSCredentials } from '../mms-credentials'; +import { SMSCredentials } from '../sms-credentials'; import { StaticBearerCredential } from '../static-bearer-credential'; import { StaticTokenCredential } from '../static-token-credential'; import { TelegramCredentials } from '../telegram-credentials'; import { WeChatCredentials } from '../wechat-credentials'; +import { InstagramCredentials } from '../instagram-credentials'; +import { AppleBcCredentials } from '../applebc-credentials'; /** * Enables access to the underlying messaging channel. @@ -18,8 +22,12 @@ export interface ConversationChannelCredential { channel: ConversationChannel; /** @see MMSCredentials */ mms_credentials?: MMSCredentials; + /** @see SMSCredentials */ + sms_credentials?: SMSCredentials; /** @see KakaoTalkCredentials */ kakaotalk_credentials?: KakaoTalkCredentials; + /** @see KakaoTalkCredentials */ + kakaotalkchat_credentials?: KakaoTalkChatCredentials; /** @see StaticBearerCredential */ static_bearer?: StaticBearerCredential; /** @see StaticTokenCredential */ @@ -30,16 +38,26 @@ export interface ConversationChannelCredential { line_credentials?: LineCredentials; /** @see WeChatCredentials */ wechat_credentials?: WeChatCredentials; - - /** TBC: Not documented */ - state?: AppState; - /** TBC: Not documented */ + /** @see InstagramCredentials */ + instagram_credentials?: InstagramCredentials; + /** @see AppleBcCredentials */ + applebc_credentials?: AppleBcCredentials; + /** + * Output only. The state of the channel credentials integration. + * When a channel is activated, the user is prompted for credentials that must be validated and in some cases exchanged by a long-lived token (Instagram). + */ + state?: ChannelIntegrationState; + /** Output only. Additional identifier set by the channel that represents a specific id used by the channel. */ channel_known_id?: string } -export interface AppState { - /** TBC: Not documented - should be an enum 'PENDING' | 'FAILING' | 'ACTIVE' */ - status?: string - /** TBC: Not documented */ +export interface ChannelIntegrationState { + /** + * Pending - initial status when the channel has been activated in the front-end. + * Active - credentials have been successfully validated and exchanged for a long-lived token. This status is used by default for channels in which the credential can't be validated. + * Failed - failed to validate credentials and acquire a long-lived token. + */ + status: 'PENDING' | 'ACTIVE' | 'FAILING'; + /** Description in case the integration fails. */ description?: string; } diff --git a/packages/conversation/src/models/v1/conversation-channel-credential/index.ts b/packages/conversation/src/models/v1/conversation-channel-credential/index.ts index ff992ae1..249291c8 100644 --- a/packages/conversation/src/models/v1/conversation-channel-credential/index.ts +++ b/packages/conversation/src/models/v1/conversation-channel-credential/index.ts @@ -1 +1 @@ -export type { ConversationChannelCredential, AppState } from './conversation-channel-credential'; +export type { ConversationChannelCredential, ChannelIntegrationState } from './conversation-channel-credential'; diff --git a/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts index f0bc1184..509db586 100644 --- a/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts +++ b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts @@ -15,4 +15,5 @@ export type ConversationChannel = | 'KAKAOTALKCHAT' | 'LINE' | 'WECHAT' + | 'APPLEBC' | 'CHANNEL_UNSPECIFIED'; diff --git a/packages/conversation/src/models/v1/conversation-message/conversation-message.ts b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts index feaf1a4b..e77e504e 100644 --- a/packages/conversation/src/models/v1/conversation-message/conversation-message.ts +++ b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts @@ -9,7 +9,7 @@ import { ProcessingMode } from '../processing-mode'; */ export interface ConversationMessage { - /** The time Conversation API processed the message. */ + /** Output only. The time Conversation API processed the message. */ accept_time?: Date; /** @see AppMessage */ app_message?: AppMessage; @@ -27,13 +27,31 @@ export interface ConversationMessage { id?: string; /** Optional. Metadata associated with the contact. Up to 1024 characters long. */ metadata?: string; - /** Flag for whether this message was injected. */ + /** Output only. Flag for whether this message was injected. */ injected?: boolean; - - /** TBC: Not documented */ + /** For Contact Messages the sender ID that the contact sent the message to. For App Messages the sender that was used to send the message, if applicable. */ sender_id?: string; - /** TBC: Not documented */ + /** Output only. The processing mode. */ processing_mode?: ProcessingMode; - /** TBC: Not documented */ - message_status?: any | null; + /** The status of the message, eventTime of the status and reason if status is failed */ + message_status?: MessageStatus | null; +} + +export interface MessageStatus { + /** Status of the message */ + status: Status; + /** Timestamp at which the current status occurred */ + event_time: Date; + /** If status is FAILED, reason of failure */ + reason?: string } + +export type Status = + 'STATUS_UNSPECIFIED' + | 'QUEUED' + | 'QUEUED_ON_CHANNEL' + | 'DELIVERED' + | 'READ' + | 'FAILED' + | 'SWITCHING_CHANNEL' + | 'RECEIVED'; diff --git a/packages/conversation/src/models/v1/delivery-status/delivery-status.ts b/packages/conversation/src/models/v1/delivery-status/delivery-status.ts index 91802a4f..431830a7 100644 --- a/packages/conversation/src/models/v1/delivery-status/delivery-status.ts +++ b/packages/conversation/src/models/v1/delivery-status/delivery-status.ts @@ -1 +1,6 @@ -export type DeliveryStatus = 'QUEUED_ON_CHANNEL' | 'DELIVERED' | 'READ' | 'FAILED' | 'SWITCHING_CHANNEL'; +export type DeliveryStatus = + 'QUEUED_ON_CHANNEL' + | 'DELIVERED' + | 'READ' + | 'FAILED' + | 'SWITCHING_CHANNEL'; diff --git a/packages/conversation/src/models/v1/index.ts b/packages/conversation/src/models/v1/index.ts index af2d70d1..16eed50b 100644 --- a/packages/conversation/src/models/v1/index.ts +++ b/packages/conversation/src/models/v1/index.ts @@ -8,6 +8,7 @@ export * from './app-message-additional-properties'; export * from './app-message-message'; export * from './app-response'; export * from './app-update-request'; +export * from './applebc-credentials'; export * from './basic-auth-credential'; export * from './call-message'; export * from './callback-settings'; @@ -64,13 +65,14 @@ export * from './get-channel-profile-conversation-channel'; export * from './get-channel-profile-request'; export * from './get-channel-profile-response'; export * from './identified-by'; -export * from './kakao-talk-credentials'; +export * from './instagram-credentials'; +export * from './kakaotalk-credentials'; +export * from './kakaotalkchat-credentials'; export * from './line-credentials'; export * from './list-apps-response'; export * from './list-item'; export * from './list-message'; export * from './list-message-message-properties'; -export * from './list-messages-response'; export * from './list-section'; export * from './list-webhooks-response'; export * from './location-message'; @@ -106,6 +108,7 @@ export * from './send-message-request'; export * from './send-message-response'; export * from './smart-conversation'; export * from './smart-conversations-event'; +export * from './sms-credentials'; export * from './static-bearer-credential'; export * from './static-token-credential'; export * from './telegram-credentials'; diff --git a/packages/conversation/src/models/v1/instagram-credentials/index.ts b/packages/conversation/src/models/v1/instagram-credentials/index.ts new file mode 100644 index 00000000..f1016965 --- /dev/null +++ b/packages/conversation/src/models/v1/instagram-credentials/index.ts @@ -0,0 +1 @@ +export type { InstagramCredentials } from './instagram-credentials'; diff --git a/packages/conversation/src/models/v1/instagram-credentials/instagram-credentials.ts b/packages/conversation/src/models/v1/instagram-credentials/instagram-credentials.ts new file mode 100644 index 00000000..545393f7 --- /dev/null +++ b/packages/conversation/src/models/v1/instagram-credentials/instagram-credentials.ts @@ -0,0 +1,10 @@ +/** + * If you are including the Instagram channel in the `channel_identifier` property, you must include this object. + */ +export interface InstagramCredentials { + + /** The Token for the Instagram channel to which you are connecting. */ + token: string; + /** Required if using the Sinch Facebook App. */ + business_account_id?: string; +} diff --git a/packages/conversation/src/models/v1/kakao-talk-credentials/index.ts b/packages/conversation/src/models/v1/kakao-talk-credentials/index.ts deleted file mode 100644 index e2a9c508..00000000 --- a/packages/conversation/src/models/v1/kakao-talk-credentials/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { KakaoTalkCredentials } from './kakao-talk-credentials'; diff --git a/packages/conversation/src/models/v1/kakaotalk-credentials/index.ts b/packages/conversation/src/models/v1/kakaotalk-credentials/index.ts new file mode 100644 index 00000000..488353e3 --- /dev/null +++ b/packages/conversation/src/models/v1/kakaotalk-credentials/index.ts @@ -0,0 +1 @@ +export type { KakaoTalkCredentials } from './kakaotalk-credentials'; diff --git a/packages/conversation/src/models/v1/kakao-talk-credentials/kakao-talk-credentials.ts b/packages/conversation/src/models/v1/kakaotalk-credentials/kakaotalk-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/kakao-talk-credentials/kakao-talk-credentials.ts rename to packages/conversation/src/models/v1/kakaotalk-credentials/kakaotalk-credentials.ts diff --git a/packages/conversation/src/models/v1/kakaotalkchat-credentials/index.ts b/packages/conversation/src/models/v1/kakaotalkchat-credentials/index.ts new file mode 100644 index 00000000..e39631c0 --- /dev/null +++ b/packages/conversation/src/models/v1/kakaotalkchat-credentials/index.ts @@ -0,0 +1 @@ +export type { KakaoTalkChatCredentials } from './kakaotalkchat-credentials'; diff --git a/packages/conversation/src/models/v1/kakaotalkchat-credentials/kakaotalkchat-credentials.ts b/packages/conversation/src/models/v1/kakaotalkchat-credentials/kakaotalkchat-credentials.ts new file mode 100644 index 00000000..3b5b32eb --- /dev/null +++ b/packages/conversation/src/models/v1/kakaotalkchat-credentials/kakaotalkchat-credentials.ts @@ -0,0 +1,10 @@ +/** + * If you are including the KakaoTalkChat channel in the `channel_identifier` property, you must include this object. + */ +export interface KakaoTalkChatCredentials { + + /** KakaoTalk Business Channel ID. */ + kakaotalk_plus_friend_id: string; + /** InfoBank API KEY. */ + api_key?: string +} diff --git a/packages/conversation/src/models/v1/list-messages-response/index.ts b/packages/conversation/src/models/v1/list-messages-response/index.ts deleted file mode 100644 index 8d0a46a9..00000000 --- a/packages/conversation/src/models/v1/list-messages-response/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ListMessagesResponse } from './list-messages-response'; diff --git a/packages/conversation/src/models/v1/list-messages-response/list-messages-response.ts b/packages/conversation/src/models/v1/list-messages-response/list-messages-response.ts deleted file mode 100644 index 5a192cb3..00000000 --- a/packages/conversation/src/models/v1/list-messages-response/list-messages-response.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ConversationMessage } from '../conversation-message'; - -export interface ListMessagesResponse { - - /** List of messages associated to the referenced conversation. */ - messages?: ConversationMessage[]; - /** Token that should be included in the next request to fetch the next page. */ - next_page_token?: string; - total_size?: number; -} diff --git a/packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts b/packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts index 8a55436e..1cd34b37 100644 --- a/packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts +++ b/packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts @@ -10,5 +10,7 @@ export interface MMSCredentials { /** MMS API Key. */ api_key: string; /** @see BasicAuthCredential */ - basic_auth?: BasicAuthCredential; + basic_auth: BasicAuthCredential; + /** Default Sender (shortcode or longnumber), will be used when {{YOUR_MMS_SENDER}} in a message is empty */ + default_sender?: string; } diff --git a/packages/conversation/src/models/v1/sms-credentials/index.ts b/packages/conversation/src/models/v1/sms-credentials/index.ts new file mode 100644 index 00000000..b57e808c --- /dev/null +++ b/packages/conversation/src/models/v1/sms-credentials/index.ts @@ -0,0 +1 @@ +export type { SMSCredentials } from './sms-credentials'; diff --git a/packages/conversation/src/models/v1/sms-credentials/sms-credentials.ts b/packages/conversation/src/models/v1/sms-credentials/sms-credentials.ts new file mode 100644 index 00000000..5de7cff8 --- /dev/null +++ b/packages/conversation/src/models/v1/sms-credentials/sms-credentials.ts @@ -0,0 +1,8 @@ +/** + * If you are including the SMS channel in the `channel_identifier` property, you must include this object or a 'static_bearer' object. + */ +export interface SMSCredentials { + + /** Indicates particular Sms App Id inside SMPP Service */ + sms_app_id: string; +} diff --git a/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts b/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts index 2159c578..1ab7976b 100644 --- a/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts +++ b/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts @@ -99,12 +99,10 @@ describe('ConversationApi', () => { conversation_id: 'conversation_id', injectMessageRequestBody: { app_message: { - message: { - card_message: { - choices: [], - title: 'title', - description: 'description', - }, + card_message: { + choices: [], + title: 'title', + description: 'description', }, }, }, diff --git a/packages/conversation/tests/rest/v1/messages/messages-api.test.ts b/packages/conversation/tests/rest/v1/messages/messages-api.test.ts index d332efb3..8d1ae6d7 100644 --- a/packages/conversation/tests/rest/v1/messages/messages-api.test.ts +++ b/packages/conversation/tests/rest/v1/messages/messages-api.test.ts @@ -52,16 +52,14 @@ describe('MessagesApi', () => { const expectedResponse: ConversationMessage = { accept_time: new Date('2019-08-24T14:15:22Z'), app_message: { - message: { - card_message: { - choices: [], - description: 'description', - height: 'UNSPECIFIED_HEIGHT', - media_message: { - url: 'url', - }, - title: 'title', + card_message: { + choices: [], + description: 'description', + height: 'UNSPECIFIED_HEIGHT', + media_message: { + url: 'url', }, + title: 'title', }, explicit_channel_message: {}, additionalProperties: { @@ -137,39 +135,37 @@ describe('MessagesApi', () => { { accept_time: new Date('2019-08-24T14:15:22Z'), app_message: { - message: { - card_message: { - choices: [ - { - call_message: { - title: 'title', - phone_number: 'number', - }, - location_message: { - coordinates: { - latitude: 0, - longitude: 0, - }, - title: 'title', - label: 'label', - }, - postback_data: 'data', - text_message: { - text: 'text', - }, - url_message: { - url: 'url', - title: 'title', + card_message: { + choices: [ + { + call_message: { + title: 'title', + phone_number: 'number', + }, + location_message: { + coordinates: { + latitude: 0, + longitude: 0, }, + title: 'title', + label: 'label', + }, + postback_data: 'data', + text_message: { + text: 'text', + }, + url_message: { + url: 'url', + title: 'title', }, - ], - description: 'description', - height: 'UNSPECIFIED_HEIGHT', - media_message: { - url: 'url', }, - title: 'title', + ], + description: 'description', + height: 'UNSPECIFIED_HEIGHT', + media_message: { + url: 'url', }, + title: 'title', }, explicit_channel_message: {}, additionalProperties: { From 40e970dca954599c3c86e2de774fab1b64839ebf Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Mon, 5 Feb 2024 10:22:04 +0100 Subject: [PATCH 10/19] Fix compilation error in nest.js app --- examples/webhooks/src/services/conversation.service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/webhooks/src/services/conversation.service.ts b/examples/webhooks/src/services/conversation.service.ts index 6d510b44..5fae5a9a 100644 --- a/examples/webhooks/src/services/conversation.service.ts +++ b/examples/webhooks/src/services/conversation.service.ts @@ -4,7 +4,6 @@ import { ConversationWebhookEventParsed, ContactMessage, MediaMessage, - FallbackMessage, TextMessage, SendMessageRequestData, } from '@sinch/sdk-core'; @@ -71,7 +70,9 @@ export class ConversationService { break; case 'MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION': console.log('\n## MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION'); - console.log(`A.I. analyzed and redacted message:\n${event.message_redaction.contact_message.text_message.text}`); + if ('text_message' in event.message_redaction.contact_message) { + console.log(`A.I. analyzed and redacted message:\n${event.message_redaction.contact_message.text_message.text}`); + } break; case 'MESSAGE_SUBMIT': console.log('\n## MESSAGE_SUBMIT'); From b4481853e1f15538a05081f27a78c760e0f0e5f2 Mon Sep 17 00:00:00 2001 From: Antoine SEIN <142824551+asein-sinch@users.noreply.github.com> Date: Tue, 6 Feb 2024 17:02:15 +0100 Subject: [PATCH 11/19] DEVEXP-295: Refactor channel credentials interface (#18) --- .../src/conversation/app/update.ts | 5 +- .../models/v1/app-response/app-response.ts | 2 +- .../conversation-channel-credential.ts | 127 ++++++++++++--- .../conversation-channel-credential/index.ts | 21 ++- .../tests/rest/v1/app/app-api.test.ts | 152 ++++++++++++++++-- 5 files changed, 273 insertions(+), 34 deletions(-) diff --git a/examples/simple-examples/src/conversation/app/update.ts b/examples/simple-examples/src/conversation/app/update.ts index 49a1d27d..b121ad58 100644 --- a/examples/simple-examples/src/conversation/app/update.ts +++ b/examples/simple-examples/src/conversation/app/update.ts @@ -39,7 +39,10 @@ import { if (printFormat === 'pretty') { console.log(`App updated! New name: '${response.display_name}'.`); const token = getMessengerTokenFormConfig(); - console.log(`Verifying the token (it should be unchanged):\nOLD: '${token}'\nNEW: '${response.channel_credentials?.[0].static_token?.token}'`); + const channelCredentials = response.channel_credentials?.[0]; + if(channelCredentials?.channel === 'MESSENGER') { + console.log(`Verifying the token (it should be unchanged):\nOLD: '${token}'\nNEW: '${channelCredentials.static_token?.token}'`); + } } else { printFullResponse(response); } diff --git a/packages/conversation/src/models/v1/app-response/app-response.ts b/packages/conversation/src/models/v1/app-response/app-response.ts index ea989bfb..2a32bad7 100644 --- a/packages/conversation/src/models/v1/app-response/app-response.ts +++ b/packages/conversation/src/models/v1/app-response/app-response.ts @@ -42,7 +42,7 @@ export interface AppResponse { callback_settings?: CallbackSettings; /** Fallback upon no positive delivery report configuration. */ delivery_report_based_fallback?: DeliveryReportBasedFallback | null; - /** TBC: Message retry time configuration. */ + /** Message retry time configuration. */ message_retry_settings?: MessageRetrySettings | null; } diff --git a/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts index 5d06998e..a0fd4cf8 100644 --- a/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts +++ b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts @@ -14,34 +14,119 @@ import { AppleBcCredentials } from '../applebc-credentials'; /** * Enables access to the underlying messaging channel. */ -export interface ConversationChannelCredential { +export type ConversationChannelCredential = + ChannelCredentialsAppleBC + | ChannelCredentialsInstagram + | ChannelCredentialsKakaoTalk + | ChannelCredentialsKakaoTalkChat + | ChannelCredentialsLine + | ChannelCredentialsMessenger + | ChannelCredentialsMms + | ChannelCredentialsRcs + | ChannelCredentialsSms + | ChannelCredentialsTelegram + | ChannelCredentialsViber + | ChannelCredentialsViberBM + | ChannelCredentialsWeChat + | ChannelCredentialsWhatsApp; - /** The secret used to verify the channel callbacks for channels which support callback verification. The callback verification is not needed for Sinch-managed channels because the callbacks are not leaving Sinch internal networks. Max length is 256 characters. Note: leaving channel_callback_secret empty for channels with callback verification will disable the verification. */ - callback_secret?: string; - /** @see ConversationChannel */ - channel: ConversationChannel; - /** @see MMSCredentials */ - mms_credentials?: MMSCredentials; - /** @see SMSCredentials */ - sms_credentials?: SMSCredentials; - /** @see KakaoTalkCredentials */ - kakaotalk_credentials?: KakaoTalkCredentials; - /** @see KakaoTalkCredentials */ - kakaotalkchat_credentials?: KakaoTalkChatCredentials; +export interface ChannelCredentialsWhatsApp extends ConversationChannelCredentialBase { + channel: 'WHATSAPP'; + /** @see StaticBearerCredential */ + static_bearer: StaticBearerCredential; +} + +export interface ChannelCredentialsRcs extends ConversationChannelCredentialBase { + channel: 'RCS'; /** @see StaticBearerCredential */ - static_bearer?: StaticBearerCredential; + static_bearer: StaticBearerCredential; +} + +export type ChannelCredentialsSms = ChannelCredentialsSmsWithBearer | ChannelCredentialsSmsWithAppId; + +export interface ChannelCredentialsSmsWithBearer extends ConversationChannelCredentialBase { + channel: 'SMS'; + /** @see StaticBearerCredential */ + static_bearer: StaticBearerCredential; +} + +export interface ChannelCredentialsSmsWithAppId extends ConversationChannelCredentialBase { + channel: 'SMS'; + /** @see SMSCredentials */ + sms_credentials: SMSCredentials; +} + +export interface ChannelCredentialsMessenger extends ConversationChannelCredentialBase { + channel: 'MESSENGER'; /** @see StaticTokenCredential */ - static_token?: StaticTokenCredential; + static_token: StaticTokenCredential; +} + +export interface ChannelCredentialsViber extends ConversationChannelCredentialBase { + channel: 'VIBER'; + /** @see StaticTokenCredential */ + static_token: StaticTokenCredential; +} + +export interface ChannelCredentialsViberBM extends ConversationChannelCredentialBase { + channel: 'VIBERBM'; + /** @see StaticBearerCredential */ + static_bearer: StaticBearerCredential; +} + +export interface ChannelCredentialsMms extends ConversationChannelCredentialBase { + channel: 'MMS'; + /** @see MMSCredentials */ + mms_credentials: MMSCredentials; +} + +export interface ChannelCredentialsInstagram extends ConversationChannelCredentialBase { + channel: 'INSTAGRAM'; + /** @see InstagramCredentials */ + instagram_credentials: InstagramCredentials; +} + +export interface ChannelCredentialsTelegram extends ConversationChannelCredentialBase { + channel: 'TELEGRAM'; /** @see TelegramCredentials */ - telegram_credentials?: TelegramCredentials; + telegram_credentials: TelegramCredentials; +} + +export interface ChannelCredentialsKakaoTalk extends ConversationChannelCredentialBase { + channel: 'KAKAOTALK'; + /** @see KakaoTalkCredentials */ + kakaotalk_credentials: KakaoTalkCredentials; +} + +export interface ChannelCredentialsKakaoTalkChat extends ConversationChannelCredentialBase { + channel: 'KAKAOTALKCHAT'; + /** @see KakaoTalkCredentials */ + kakaotalkchat_credentials: KakaoTalkChatCredentials; +} + +export interface ChannelCredentialsLine extends ConversationChannelCredentialBase { + channel: 'LINE'; /** @see LineCredentials */ - line_credentials?: LineCredentials; + line_credentials: LineCredentials; +} + +export interface ChannelCredentialsWeChat extends ConversationChannelCredentialBase { + channel: 'WECHAT'; /** @see WeChatCredentials */ - wechat_credentials?: WeChatCredentials; - /** @see InstagramCredentials */ - instagram_credentials?: InstagramCredentials; + wechat_credentials: WeChatCredentials; +} + +export interface ChannelCredentialsAppleBC extends ConversationChannelCredentialBase { + channel: 'APPLEBC'; /** @see AppleBcCredentials */ - applebc_credentials?: AppleBcCredentials; + applebc_credentials: AppleBcCredentials; +} + +interface ConversationChannelCredentialBase { + /** @see ConversationChannel */ + channel: ConversationChannel; + /** The secret used to verify the channel callbacks for channels which support callback verification. The callback verification is not needed for Sinch-managed channels because the callbacks are not leaving Sinch internal networks. Max length is 256 characters. Note: leaving channel_callback_secret empty for channels with callback verification will disable the verification. */ + callback_secret?: string; /** * Output only. The state of the channel credentials integration. * When a channel is activated, the user is prompted for credentials that must be validated and in some cases exchanged by a long-lived token (Instagram). diff --git a/packages/conversation/src/models/v1/conversation-channel-credential/index.ts b/packages/conversation/src/models/v1/conversation-channel-credential/index.ts index 249291c8..3a9afc37 100644 --- a/packages/conversation/src/models/v1/conversation-channel-credential/index.ts +++ b/packages/conversation/src/models/v1/conversation-channel-credential/index.ts @@ -1 +1,20 @@ -export type { ConversationChannelCredential, ChannelIntegrationState } from './conversation-channel-credential'; +export type { + ConversationChannelCredential, + ChannelIntegrationState, + ChannelCredentialsAppleBC, + ChannelCredentialsInstagram, + ChannelCredentialsKakaoTalk, + ChannelCredentialsKakaoTalkChat, + ChannelCredentialsLine, + ChannelCredentialsMessenger, + ChannelCredentialsMms, + ChannelCredentialsRcs, + ChannelCredentialsSms, + ChannelCredentialsTelegram, + ChannelCredentialsViber, + ChannelCredentialsViberBM, + ChannelCredentialsWeChat, + ChannelCredentialsWhatsApp, + ChannelCredentialsSmsWithBearer, + ChannelCredentialsSmsWithAppId, +} from './conversation-channel-credential'; diff --git a/packages/conversation/tests/rest/v1/app/app-api.test.ts b/packages/conversation/tests/rest/v1/app/app-api.test.ts index b623f4ec..0c98c15d 100644 --- a/packages/conversation/tests/rest/v1/app/app-api.test.ts +++ b/packages/conversation/tests/rest/v1/app/app-api.test.ts @@ -4,10 +4,24 @@ import { CreateAppRequestData, DeleteAppRequestData, GetAppRequestData, - ListAppsRequestData, UpdateAppRequestData, + ListAppsRequestData, + UpdateAppRequestData, + ChannelCredentialsAppleBC, + ChannelCredentialsInstagram, + ChannelCredentialsKakaoTalk, + ChannelCredentialsKakaoTalkChat, + ChannelCredentialsLine, + ChannelCredentialsMessenger, + ChannelCredentialsMms, + ChannelCredentialsRcs, + ChannelCredentialsSms, + ListAppsResponse, + AppApi, + AppApiFixture, + ChannelCredentialsTelegram, + ChannelCredentialsViber, + ChannelCredentialsViberBM, ChannelCredentialsWeChat, ChannelCredentialsWhatsApp, } from '../../../../src'; -import { ListAppsResponse } from '../../../../src'; -import { AppApi, AppApiFixture } from '../../../../src'; describe('AppApi', () => { let appApi: AppApi; @@ -28,17 +42,135 @@ describe('AppApi', () => { describe ('createApp', () => { it('should make a POST request to create a new Conversation App', async () => { // Given + const channelCredentialsAppleBC: ChannelCredentialsAppleBC = { + channel: 'APPLEBC', + applebc_credentials: { + business_chat_account_id: 'apple_business_chat_account_id', + merchant_id: 'merchant_id', + apple_pay_certificate_reference: 'apple_pay_certificate_reference', + apple_pay_certificate_password: 'apple_pay_certificate_password', + }, + }; + const channelCredentialsInstagram: ChannelCredentialsInstagram = { + channel: 'INSTAGRAM', + instagram_credentials: { + token: 'instagram_channel_token', + business_account_id: 'instagram_business_account_id', + }, + }; + const channelCredentialsKakaoTalk: ChannelCredentialsKakaoTalk = { + channel: 'KAKAOTALK', + kakaotalk_credentials: { + kakaotalk_plus_friend_id: 'kakaotalk_friend_id', + kakaotalk_sender_key: 'kakaotalk_sender_key', + }, + }; + const channelCredentialsKakaoTalkChat: ChannelCredentialsKakaoTalkChat = { + channel: 'KAKAOTALKCHAT', + kakaotalkchat_credentials: { + kakaotalk_plus_friend_id: 'kakaotalk_friend_id', + api_key: 'info_bank_api_key', + }, + }; + const channelCredentialsLine: ChannelCredentialsLine = { + channel: 'LINE', + line_credentials: { + token: 'line_token', + secret: 'line_secret', + }, + }; + const channelCredentialsMms: ChannelCredentialsMms = { + channel: 'MMS', + mms_credentials: { + account_id: 'mms_account_id', + api_key: 'mms_api_key', + basic_auth: { + username: 'username', + password: 'password', + }, + default_sender: 'default_sender', + }, + }; + const channelCredentialsMessenger: ChannelCredentialsMessenger = { + channel: 'MESSENGER', + static_token: { + token: 'messenger_static_token', + }, + }; + const channelCredentialsRcs: ChannelCredentialsRcs = { + channel: 'RCS', + static_bearer: { + claimed_identity: 'rcs_claimed_identity', + token: 'rcs_token', + }, + }; + const channelCredentialsSms: ChannelCredentialsSms = { + channel: 'SMS', + static_bearer: { + claimed_identity: 'sms_claimed_identity', + token: 'sms_token', + }, + }; + // const channelCredentialsSmsWithAppId: ChannelCredentialsSms = { + // channel: 'SMS', + // sms_credentials: { + // sms_app_id: 'sms_app_id', + // }, + // }; + const channelCredentialsTelegram: ChannelCredentialsTelegram = { + channel: 'TELEGRAM', + telegram_credentials: { + token: 'telegram_token', + }, + }; + const channelCredentialsViber: ChannelCredentialsViber = { + channel: 'VIBER', + static_token: { + token: 'viber_token', + }, + }; + const channelCredentialsViberBM: ChannelCredentialsViberBM = { + channel: 'VIBERBM', + static_bearer: { + claimed_identity: 'viberbm_claimed_identity', + token: 'viberbm_token', + }, + }; + const channelCredentialsWeChat: ChannelCredentialsWeChat = { + channel: 'WECHAT', + wechat_credentials: { + app_id: 'wechat_app_id', + app_secret: 'wechat_app_secret', + token: 'wechat_token', + aes_key: 'wechat_aes_key', + }, + }; + const channelCredetialsWhatsApp: ChannelCredentialsWhatsApp = { + channel: 'WHATSAPP', + static_bearer: { + claimed_identity: 'whatsapp_claimed_identity', + token: 'whatsapp_token', + }, + }; const requestData: CreateAppRequestData = { appCreateRequestBody: { display_name: 'Test App', channel_credentials: [ - { - channel: 'WHATSAPP', - static_bearer: { - claimed_identity: 'identity', - token: 'token', - }, - }, + channelCredentialsAppleBC, + channelCredentialsInstagram, + channelCredentialsKakaoTalk, + channelCredentialsKakaoTalkChat, + channelCredentialsLine, + channelCredentialsMms, + channelCredentialsMessenger, + channelCredentialsRcs, + channelCredentialsSms, + // channelCredentialsSmsWithAppId, + channelCredentialsTelegram, + channelCredentialsViber, + channelCredentialsViberBM, + channelCredentialsWeChat, + channelCredetialsWhatsApp, ], }, }; From 036aa84d31abe145ab797c87f43184d09dcc28b5 Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Wed, 7 Feb 2024 16:21:11 +0100 Subject: [PATCH 12/19] Fix merge issues --- packages/conversation/src/rest/v1/app/app-api.ts | 2 +- packages/sdk-client/src/api/api-client.ts | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/conversation/src/rest/v1/app/app-api.ts b/packages/conversation/src/rest/v1/app/app-api.ts index 54cc80af..0ffad1b9 100644 --- a/packages/conversation/src/rest/v1/app/app-api.ts +++ b/packages/conversation/src/rest/v1/app/app-api.ts @@ -171,7 +171,7 @@ export class AppApi extends ConversationDomainApi { const requestOptions = await this.client.prepareOptions(basePathUrl, 'PATCH', getParams, headers, body || undefined); - const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams, false, ','); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); return this.client.processCall({ url, diff --git a/packages/sdk-client/src/api/api-client.ts b/packages/sdk-client/src/api/api-client.ts index 8370c6da..cef60263 100644 --- a/packages/sdk-client/src/api/api-client.ts +++ b/packages/sdk-client/src/api/api-client.ts @@ -128,18 +128,16 @@ export class ApiClient { * @param {string} url - The base url to be used. * @param {Object.} queryParameters - Key-value pair with the parameters. If the value is undefined, the key is dropped. * @param {boolean} repeatParamArray - create as many single parameters with each value of the array - * @param {string} unexplodedSeparator - the separator to use between values when `explode` is false (default is ',') * @return {string} The prepared URL as a string. */ prepareUrl( url: string, queryParameters: { [key: string]: string | undefined } = {}, repeatParamArray?: boolean, - unexplodedSeparator?: string, ): string { const queryPart = Object.keys(queryParameters) .filter((name) => typeof queryParameters[name] !== 'undefined') - .map((name) => this.formatQueryParameter(name, queryParameters, repeatParamArray, unexplodedSeparator)) + .map((name) => this.formatQueryParameter(name, queryParameters, repeatParamArray)) .join('&'); const paramsPrefix = url.indexOf('?') > -1 ? '&' : '?'; @@ -152,14 +150,12 @@ export class ApiClient { * @param {string} name - The parameter name * @param {Object.} queryParameters - Key-value pair with the parameters. If the value is undefined, the key is dropped. * @param {boolean}repeatParamArray - Create as many single parameters with each value of the array - * @param {string} unexplodedSeparator - the separator to use between values when `explode` is false (default is `,`) * @return {string} The query parameter formatted as required by the API */ private formatQueryParameter = ( name: string, queryParameters: { [key: string]: string | undefined } = {}, repeatParamArray?: boolean, - unexplodedSeparator?: string, ): string => { const parameterValue = JSON.parse(queryParameters[name] || ''); if (Array.isArray(parameterValue)) { From 058da24745af30a6ee62558ea9ba37160524530e Mon Sep 17 00:00:00 2001 From: Antoine SEIN <142824551+asein-sinch@users.noreply.github.com> Date: Mon, 12 Feb 2024 09:18:03 +0100 Subject: [PATCH 13/19] DEVEXP-290: Support Templates API v1 and v2 (#20) --- examples/simple-examples/.env.template | 28 +- examples/simple-examples/README.md | 190 ++++++--- examples/simple-examples/package.json | 11 + examples/simple-examples/src/config.ts | 4 + .../src/conversation/templates-v1/create.ts | 37 ++ .../src/conversation/templates-v1/delete.ts | 20 + .../src/conversation/templates-v1/get.ts | 26 ++ .../src/conversation/templates-v1/list.ts | 28 ++ .../src/conversation/templates-v1/update.ts | 54 +++ .../src/conversation/templates-v2/create.ts | 36 ++ .../src/conversation/templates-v2/delete.ts | 20 + .../src/conversation/templates-v2/get.ts | 26 ++ .../templates-v2/list-translations.ts | 46 +++ .../src/conversation/templates-v2/list.ts | 28 ++ .../src/conversation/templates-v2/update.ts | 58 +++ .../v1/carousel-message/carousel-message.ts | 4 +- .../channel-template-override.ts | 12 + .../v1/channel-template-override/index.ts | 1 + .../channel-template-reference.ts | 9 + .../v1/channel-template-reference/index.ts | 1 + .../src/models/v1/choice-item/choice-item.ts | 4 + .../src/models/v1/choice-item/index.ts | 2 +- .../v1/choice-message/choice-message.ts | 4 +- .../src/models/v1/choice-message/index.ts | 2 +- .../src/models/v1/choice/choice.ts | 33 +- .../src/models/v1/choice/index.ts | 9 +- .../conversation-channel.ts | 10 + .../models/v1/conversation-channel/index.ts | 2 +- packages/conversation/src/models/v1/helper.ts | 163 ++++++++ packages/conversation/src/models/v1/index.ts | 13 +- .../src/models/v1/list-item/index.ts | 1 - .../src/models/v1/list-item/list-item.ts | 10 - .../models/v1/list-section/list-section.ts | 5 +- .../src/models/v1/template-variable/index.ts | 1 + .../v1/template-variable/template-variable.ts | 6 + .../v1/v1-list-templates-response/index.ts | 1 + .../v1-list-templates-response.ts | 6 + .../v1/v1-template-translation/index.ts | 1 + .../v1-template-translation.ts | 17 + .../src/models/v1/v1-template/index.ts | 1 + .../src/models/v1/v1-template/v1-template.ts | 20 + .../v1/v2-list-templates-response/index.ts | 1 + .../v2-list-templates-response.ts | 7 + .../v1/v2-list-translations-response/index.ts | 1 + .../v2-list-translations-response.ts | 7 + .../models/v1/v2-template-response/index.ts | 1 + .../v2-template-response.ts | 19 + .../v1/v2-template-translation/index.ts | 12 + .../v2-template-translation.ts | 45 +++ .../src/models/v1/v2-template/index.ts | 1 + .../src/models/v1/v2-template/v2-template.ts | 17 + .../src/rest/v1/conversation-domain-api.ts | 32 +- .../src/rest/v1/conversation-domain.ts | 9 + packages/conversation/src/rest/v1/index.ts | 2 + .../src/rest/v1/templates-v1/index.ts | 2 + .../templates-v1-api.jest.fixture.ts | 27 ++ .../rest/v1/templates-v1/templates-v1-api.ts | 184 +++++++++ .../src/rest/v1/templates-v2/index.ts | 2 + .../templates-v2-api.jest.fixture.ts | 31 ++ .../rest/v1/templates-v2/templates-v2-api.ts | 220 ++++++++++ .../tests/models/v1/helper.test.ts | 378 ++++++++++++++++++ .../rest/v1/conversation-domain-api.test.ts | 41 +- .../v1/templates-v1/templates-v1-api.test.ts | 247 ++++++++++++ .../v1/templates-v2/templates-v2-api.test.ts | 365 +++++++++++++++++ 64 files changed, 2495 insertions(+), 106 deletions(-) create mode 100644 examples/simple-examples/src/conversation/templates-v1/create.ts create mode 100644 examples/simple-examples/src/conversation/templates-v1/delete.ts create mode 100644 examples/simple-examples/src/conversation/templates-v1/get.ts create mode 100644 examples/simple-examples/src/conversation/templates-v1/list.ts create mode 100644 examples/simple-examples/src/conversation/templates-v1/update.ts create mode 100644 examples/simple-examples/src/conversation/templates-v2/create.ts create mode 100644 examples/simple-examples/src/conversation/templates-v2/delete.ts create mode 100644 examples/simple-examples/src/conversation/templates-v2/get.ts create mode 100644 examples/simple-examples/src/conversation/templates-v2/list-translations.ts create mode 100644 examples/simple-examples/src/conversation/templates-v2/list.ts create mode 100644 examples/simple-examples/src/conversation/templates-v2/update.ts create mode 100644 packages/conversation/src/models/v1/channel-template-override/channel-template-override.ts create mode 100644 packages/conversation/src/models/v1/channel-template-override/index.ts create mode 100644 packages/conversation/src/models/v1/channel-template-reference/channel-template-reference.ts create mode 100644 packages/conversation/src/models/v1/channel-template-reference/index.ts create mode 100644 packages/conversation/src/models/v1/helper.ts delete mode 100644 packages/conversation/src/models/v1/list-item/index.ts delete mode 100644 packages/conversation/src/models/v1/list-item/list-item.ts create mode 100644 packages/conversation/src/models/v1/template-variable/index.ts create mode 100644 packages/conversation/src/models/v1/template-variable/template-variable.ts create mode 100644 packages/conversation/src/models/v1/v1-list-templates-response/index.ts create mode 100644 packages/conversation/src/models/v1/v1-list-templates-response/v1-list-templates-response.ts create mode 100644 packages/conversation/src/models/v1/v1-template-translation/index.ts create mode 100644 packages/conversation/src/models/v1/v1-template-translation/v1-template-translation.ts create mode 100644 packages/conversation/src/models/v1/v1-template/index.ts create mode 100644 packages/conversation/src/models/v1/v1-template/v1-template.ts create mode 100644 packages/conversation/src/models/v1/v2-list-templates-response/index.ts create mode 100644 packages/conversation/src/models/v1/v2-list-templates-response/v2-list-templates-response.ts create mode 100644 packages/conversation/src/models/v1/v2-list-translations-response/index.ts create mode 100644 packages/conversation/src/models/v1/v2-list-translations-response/v2-list-translations-response.ts create mode 100644 packages/conversation/src/models/v1/v2-template-response/index.ts create mode 100644 packages/conversation/src/models/v1/v2-template-response/v2-template-response.ts create mode 100644 packages/conversation/src/models/v1/v2-template-translation/index.ts create mode 100644 packages/conversation/src/models/v1/v2-template-translation/v2-template-translation.ts create mode 100644 packages/conversation/src/models/v1/v2-template/index.ts create mode 100644 packages/conversation/src/models/v1/v2-template/v2-template.ts create mode 100644 packages/conversation/src/rest/v1/templates-v1/index.ts create mode 100644 packages/conversation/src/rest/v1/templates-v1/templates-v1-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/templates-v1/templates-v1-api.ts create mode 100644 packages/conversation/src/rest/v1/templates-v2/index.ts create mode 100644 packages/conversation/src/rest/v1/templates-v2/templates-v2-api.jest.fixture.ts create mode 100644 packages/conversation/src/rest/v1/templates-v2/templates-v2-api.ts create mode 100644 packages/conversation/tests/models/v1/helper.test.ts create mode 100644 packages/conversation/tests/rest/v1/templates-v1/templates-v1-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/templates-v2/templates-v2-api.test.ts diff --git a/examples/simple-examples/.env.template b/examples/simple-examples/.env.template index 8c769e24..8ce7a278 100644 --- a/examples/simple-examples/.env.template +++ b/examples/simple-examples/.env.template @@ -9,21 +9,31 @@ SMS_REGION=Value to determine according to your use case (default will be 'us') # Application credentials for Verification and Voice APIs SINCH_APPLICATION_KEY=application-key found at https://dashboard.sinch.com/verification/apps SINCH_APPLICATION_SECRET=application-secret found at https://dashboard.sinch.com/verification/apps -# Properties to fill according to some API responses +# The phone number you will use for your tests PHONE_NUMBER=phone-number to fill with one of your numbers rented with the Numbers API +# Generally, you phone number to interact with the API RECIPIENT_PHONE_NUMBER=phone-number to fill with the number to which you want to send a batch with the SMS API +## SMS API BATCH_ID=batch-id to fill with one the batches created with the SMS API GROUP_ID=group-id to fill with one of the groups created with the SMS API INBOUND_ID=inbound-id to fill with one of the ids found when listing inbound messages with the SMS API +## Verification API VERIFICATION_ID=verification-id to fill with the verification started with the Verification API VERIFICATION_IDENTITY=verification-identity to fill with the identity of the user VERIFICATION_REFERENCE=verification-reference to add when starting a verification or getting its status +VERIFICATION_CODE=verification-code received for a verification via SMS or callout +VERIFICATION_CLI=verification-cli received for a verification via flashCall +## Voice API +CALL_ID=call_id to fill with one of the callouts created with the Voice API +CONFERENCE_ID=unique identifier of the conference you want to interact with VOICE_CALLBACK_URL=URL found in the Voice dashboard to handle webhooks -CONVERSATION_APP_ID=app_id to fill with one of the conversation app created with the Conversation API or in the Dashboard -CONVERSATION_CONTACT_ID=contact_id to fill with one off the contacts -MESSENGER_TOKEN=static token to define credentials for a Messenger application -MESSENGER_USER_ID=Id of a user using messenger (can be found on a desktop by selecting a user: the user id will be in the URL) -CONVERSATION_ID=conversation_id to fill with one of the conversation create with the Conversation API -MESSAGE_ID=message_id to fill from a sent or injected message -WEBHOOK_ID=webhook_id to fill from a webhook creation with the Conversation API or the Dashboard -WEBHOOK_TARGET=URL of the webhook +## Conversation API +CONVERSATION_APP_ID=app_id (Conversation App) to fill with one of the Conversation App created with the Conversation API or in the Dashboard +CONVERSATION_CONTACT_ID=contact_id to fill with one of the contacts created by the Contact API or the Conversation API +MESSENGER_USER_ID=identity on the MESSENGER channel (can be found on a desktop by selecting a user: the user id will be in the URL) +MESSENGER_TOKEN=static_token to define credentials for a MESSENGER channel +CONVERSATION_ID=conversation_id to fill with one of the conversations created with the Conversation API +MESSAGE_ID=message_id to fill with one of the messages sent or injected with the Conversation API +TEMPLATE_ID=template_id to fill with one of the templates created with the Templates API (v1 or v2) +WEBHOOK_ID=webhook_id to fill with one of the webhooks created with the Conversation API or the Dashboard +WEBHOOK_TARGET=target URL where the events should be sent to diff --git a/examples/simple-examples/README.md b/examples/simple-examples/README.md index 8de47e5a..3e0491f2 100644 --- a/examples/simple-examples/README.md +++ b/examples/simple-examples/README.md @@ -40,20 +40,34 @@ SMS_REGION=Value to determine according to your use case (default will be 'us') # Application credentials for Verification and Voice APIs SINCH_APPLICATION_KEY=application-key found at https://dashboard.sinch.com/verification/apps SINCH_APPLICATION_SECRET=application-secret found at https://dashboard.sinch.com/verification/apps -# Properties to fill according to some API responses +# The phone number you will use for your tests PHONE_NUMBER=phone-number to fill with one of your numbers rented with the Numbers API +# Generally, you phone number to interact with the API RECIPIENT_PHONE_NUMBER=phone-number to fill with the number to which you want to send a batch with the SMS API +## SMS API BATCH_ID=batch-id to fill with one the batches created with the SMS API GROUP_ID=group-id to fill with one of the groups created with the SMS API INBOUND_ID=inbound-id to fill with one of the ids found when listing inbound messages with the SMS API +## Verification API VERIFICATION_ID=verification-id to fill with the verification started with the Verification API VERIFICATION_IDENTITY=verification-identity to fill with the identity of the user VERIFICATION_REFERENCE=verification-reference to add when starting a verification or getting its status VERIFICATION_CODE=verification-code received for a verification via SMS or callout VERIFICATION_CLI=verification-cli received for a verification via flashCall +## Voice API CALL_ID=call_id to fill with one of the callouts created with the Voice API CONFERENCE_ID=unique identifier of the conference you want to interact with VOICE_CALLBACK_URL=URL found in the Voice dashboard to handle webhooks +## Conversation API +CONVERSATION_APP_ID=app_id (Conversation App) to fill with one of the Conversation App created with the Conversation API or in the Dashboard +CONVERSATION_CONTACT_ID=contact_id to fill with one of the contacts created by the Contact API or the Conversation API +MESSENGER_USER_ID=identity on the MESSENGER channel (can be found on a desktop by selecting a user: the user id will be in the URL) +MESSENGER_TOKEN=static_token to define credentials for a MESSENGER channel +CONVERSATION_ID=conversation_id to fill with one of the conversations created with the Conversation API +MESSAGE_ID=message_id to fill with one of the messages sent or injected with the Conversation API +TEMPLATE_ID=template_id to fill with one of the templates created with the Templates API (v1 or v2) +WEBHOOK_ID=webhook_id to fill with one of the webhooks created with the Conversation API or the Dashboard +WEBHOOK_TARGET=target URL where the events should be sent to ``` **Note**: If you prefer using environment variables, the sample app is also supporting them: they take precedence over the value from the `.env` file. @@ -77,59 +91,123 @@ yarn run numbers:regions:list ## Available sample applications -| Domain | Service | Sample application name and location | Required parameters | -|--------------|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------| -| Numbers | Regions | [./src/numbers/regions/list.ts](./src/numbers/regions/list.ts) | | -| | Available | [./src/numbers/available/list.ts](./src/numbers/available/list.ts) | | -| | | [./src/numbers/available/checkAvailability.ts](./src/numbers/available/checkAvailability.ts) | `PHONE_NUMBER` | -| | | [./src/numbers/available/rent.ts](./src/numbers/available/rent.ts) | `PHONE_NUMBER` | -| | | [./src/numbers/available/rentAny.ts](./src/numbers/available/rentAny.ts) | | -| | Active | [./src/numbers/active/list.ts](./src/numbers/active/list.ts) | | -| | | [./src/numbers/active/get.ts](./src/numbers/active/get.ts) | `PHONE_NUMBER` | -| | | [./src/numbers/active/update.ts](./src/numbers/active/update.ts) | `PHONE_NUMBER` | -| | | [./src/numbers/active/release.ts](./src/numbers/active/release.ts) | `PHONE_NUMBER` | -| | Callbacks | [./src/numbers/callbacks/get.ts](src/numbers/callbacks/get.ts) | | -| | | [./src/numbers/callbacks/update.ts](src/numbers/callbacks/update.ts) | | -| SMS | Groups | [./src/sms/groups/list/list.ts](./src/sms/groups/list/list.ts) | | -| | | [./src/sms/groups/create/create.ts](./src/sms/groups/create/create.ts) | | -| | | [./src/sms/groups/get/get.ts](./src/sms/groups/get/get.ts) | `GROUP_ID` | -| | | [./src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts](./src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts) | `GROUP_ID` | -| | | [./src/sms/groups/replace/replace.ts](./src/sms/groups/replace/replace.ts) | `GROUP_ID` | -| | | [./src/sms/groups/update/update.ts](./src/sms/groups/update/update.ts) | `GROUP_ID` | -| | | [./src/sms/groups/delete/delete.ts](./src/sms/groups/delete/delete.ts) | `GROUP_ID` | -| | Batches | [./src/sms/batches/send.ts](./src/sms/batches/send.ts) | `RECIPIENT_PHONE_NUMBER` | -| | | [./src/sms/batches/list.ts](./src/sms/batches/list.ts) | | -| | | [./src/sms/batches/dry-run.ts](./src/sms/batches/dry-run.ts) | `RECIPIENT_PHONE_NUMBER` | -| | | [./src/sms/batches/get.ts](./src/sms/batches/get.ts) | `BATCH_ID` | -| | | [./src/sms/batches/update.ts](./src/sms/batches/update.ts) | `BATCH_ID` | -| | | [./src/sms/batches/replace.ts](./src/sms/batches/replace.ts) | `BATCH_ID` | -| | | [./src/sms/batches/cancel.ts](./src/sms/batches/cancel.ts) | `BATCH_ID` | -| | | [./src/sms/batches/delivery-feedback.ts](./src/sms/batches/delivery-feedback.ts) | `BATCH_ID` | -| | DeliveryReports | [./src/sms/delivery-reports/list.ts](./src/sms/delivery-reports/list.ts) | | -| | | [./src/sms/delivery-reports/getByBatchId.ts](./src/sms/delivery-reports/getByBatchId.ts) | `BATCH_ID` | -| | | [./src/sms/delivery-reports/getByPhoneNumber.ts](./src/sms/delivery-reports/getByPhoneNumber.ts) | `BATCH_ID`, `RECIPIENT_PHONE_NUMBER` | -| | Inbounds | [./src/sms/inbounds/list.ts](./src/sms/inbounds/list.ts) | | -| | | [./src/sms/inbounds/get.ts](./src/sms/inbounds/get.ts) | `INBOUND_ID` | -| Verification | Verifications | [./src/verification/verifications/start.ts](./src/verification/verifications/start.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_REFERENCE` | -| | | [./src/verification/verifications/report-with-id_.ts](./src/verification/verifications/report-with-id.ts) | `VERIFICATION_ID` + `VERIFICATION_CODE` or `VERIFICATION_CLI` (flashCall) | -| | | [./src/verification/verifications/report-with-identity.ts](./src/verification/verifications/report-with-identity.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_CODE` or `VERIFICATION_CLI` (flashCall) | -| | Verification-status | [./src/verification/verification-status/verification-by-id.ts](./src/verification/verification-status/verification-by-id.ts) | `VERIFICATION_ID` | -| | | [./src/verification/verification-status/verification-by-identity.ts](./src/verification/verification-status/verification-by-identity.ts) | `VERIFICATION_IDENTITY` | -| | | [./src/verification/verification-status/verification-by-reference.ts](./src/verification/verification-status/verification-by-reference.ts) | `VERIFICATION_REFERENCE` | -| Voice | Applications | [./src/voice/applications/assignNumbers.ts](./src/voice/applications/assignNumbers.ts) | `PHONE_NUMBER` + `SINCH_APPLICATION_KEY` | -| | | [./src/voice/applications/getCallbackURLs.ts](./src/voice/applications/getCallbackURLs.ts) | `SINCH_APPLICATION_KEY` | -| | | [./src/voice/applications/getNumbers.ts](./src/voice/applications/getNumbers.ts) | | -| | | [./src/voice/applications/queryNumber.ts](./src/voice/applications/queryNumber.ts) | `PHONE_NUMBER` | -| | | [./src/voice/applications/unassignNumber.ts](./src/voice/applications/unassignNumber.ts) | `PHONE_NUMBER` + `SINCH_APPLICATION_KEY` | -| | | [./src/voice/applications/updateCallbackURLs.ts](./src/voice/applications/updateCallbackURLs.ts) | `SINCH_APPLICATION_KEY` | -| | Callouts | [./src/voice/callouts/conference.ts](./src/voice/callouts/conference.ts) | `PHONE_NUMBER` + `RECIPIENT_PHONE_NUMBER` + `CONFERENCE_ID` | -| | | [./src/voice/callouts/custom.ts](./src/voice/callouts/custom.ts) | `PHONE_NUMBER` + `RECIPIENT_PHONE_NUMBER` + `VOICE_CALLBACK_URL` | -| | | [./src/voice/callouts/tts.ts](./src/voice/callouts/tts.ts) | `PHONE_NUMBER` + `RECIPIENT_PHONE_NUMBER` | -| | Calls | [./src/voice/calls/get.ts](./src/voice/calls/get.ts) | `CALL_ID` | -| | | [./src/voice/calls/manageWithCallLeg.ts](./src/voice/calls/manageWithCallLeg.ts) | `CALL_ID` | -| | | [./src/voice/calls/update.ts](./src/voice/calls/update.ts) | `CALL_ID` | -| | Conferences | [./src/voice/conferences/get.ts](./src/voice/conferences/get.ts) | `CONFERENCE_ID` | -| | | [./src/voice/conferences/kickAll.ts](./src/voice/conferences/kickAll.ts) | `CONFERENCE_ID` | -| | | [./src/voice/conferences/kickParticipant.ts](./src/voice/conferences/kickParticipant.ts) | `CONFERENCE_ID` + `CALL_ID` | -| | | [./src/voice/conferences/manageParticipant.ts](./src/voice/conferences/manageParticipant.ts) | `CONFERENCE_ID` + `CALL_ID` | +### Number + +| Service | Sample application name and location | Required parameters | +|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| Regions | [./src/numbers/regions/list.ts](./src/numbers/regions/list.ts) | | +| Available | [./src/numbers/available/list.ts](./src/numbers/available/list.ts) | | +| | [./src/numbers/available/checkAvailability.ts](./src/numbers/available/checkAvailability.ts) | `PHONE_NUMBER` | +| | [./src/numbers/available/rent.ts](./src/numbers/available/rent.ts) | `PHONE_NUMBER` | +| | [./src/numbers/available/rentAny.ts](./src/numbers/available/rentAny.ts) | | +| Active | [./src/numbers/active/list.ts](./src/numbers/active/list.ts) | | +| | [./src/numbers/active/get.ts](./src/numbers/active/get.ts) | `PHONE_NUMBER` | +| | [./src/numbers/active/update.ts](./src/numbers/active/update.ts) | `PHONE_NUMBER` | +| | [./src/numbers/active/release.ts](./src/numbers/active/release.ts) | `PHONE_NUMBER` | +| Callbacks | [./src/numbers/callbacks/get.ts](src/numbers/callbacks/get.ts) | | +| | [./src/numbers/callbacks/update.ts](src/numbers/callbacks/update.ts) | | + +### SMS + +| Service | Sample application name and location | Required parameters | +|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| Groups | [./src/sms/groups/list/list.ts](./src/sms/groups/list/list.ts) | | +| | [./src/sms/groups/create/create.ts](./src/sms/groups/create/create.ts) | | +| | [./src/sms/groups/get/get.ts](./src/sms/groups/get/get.ts) | `GROUP_ID` | +| | [./src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts](./src/sms/groups/getPhoneNumbers/getPhoneNumbers.ts) | `GROUP_ID` | +| | [./src/sms/groups/replace/replace.ts](./src/sms/groups/replace/replace.ts) | `GROUP_ID` | +| | [./src/sms/groups/update/update.ts](./src/sms/groups/update/update.ts) | `GROUP_ID` | +| | [./src/sms/groups/delete/delete.ts](./src/sms/groups/delete/delete.ts) | `GROUP_ID` | +| Batches | [./src/sms/batches/send.ts](./src/sms/batches/send.ts) | `RECIPIENT_PHONE_NUMBER` | +| | [./src/sms/batches/list.ts](./src/sms/batches/list.ts) | | +| | [./src/sms/batches/dry-run.ts](./src/sms/batches/dry-run.ts) | `RECIPIENT_PHONE_NUMBER` | +| | [./src/sms/batches/get.ts](./src/sms/batches/get.ts) | `BATCH_ID` | +| | [./src/sms/batches/update.ts](./src/sms/batches/update.ts) | `BATCH_ID` | +| | [./src/sms/batches/replace.ts](./src/sms/batches/replace.ts) | `BATCH_ID` | +| | [./src/sms/batches/cancel.ts](./src/sms/batches/cancel.ts) | `BATCH_ID` | +| | [./src/sms/batches/delivery-feedback.ts](./src/sms/batches/delivery-feedback.ts) | `BATCH_ID` | +| DeliveryReports | [./src/sms/delivery-reports/list.ts](./src/sms/delivery-reports/list.ts) | | +| | [./src/sms/delivery-reports/getByBatchId.ts](./src/sms/delivery-reports/getByBatchId.ts) | `BATCH_ID` | +| | [./src/sms/delivery-reports/getByPhoneNumber.ts](./src/sms/delivery-reports/getByPhoneNumber.ts) | `BATCH_ID`, `RECIPIENT_PHONE_NUMBER` | +| Inbounds | [./src/sms/inbounds/list.ts](./src/sms/inbounds/list.ts) | | +| | [./src/sms/inbounds/get.ts](./src/sms/inbounds/get.ts) | `INBOUND_ID` | + +### Verification + +| Service | Sample application name and location | Required parameters | +|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| Verifications | [./src/verification/verifications/start.ts](./src/verification/verifications/start.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_REFERENCE` | +| | [./src/verification/verifications/report-with-id_.ts](./src/verification/verifications/report-with-id.ts) | `VERIFICATION_ID` + `VERIFICATION_CODE` or `VERIFICATION_CLI` (flashCall) | +| | [./src/verification/verifications/report-with-identity.ts](./src/verification/verifications/report-with-identity.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_CODE` or `VERIFICATION_CLI` (flashCall) | +| Verification-status | [./src/verification/verification-status/verification-by-id.ts](./src/verification/verification-status/verification-by-id.ts) | `VERIFICATION_ID` | +| | [./src/verification/verification-status/verification-by-identity.ts](./src/verification/verification-status/verification-by-identity.ts) | `VERIFICATION_IDENTITY` | +| | [./src/verification/verification-status/verification-by-reference.ts](./src/verification/verification-status/verification-by-reference.ts) | `VERIFICATION_REFERENCE` | + +### Voice + +| Service | Sample application name and location | Required parameters | +|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| Applications | [./src/voice/applications/assignNumbers.ts](./src/voice/applications/assignNumbers.ts) | `PHONE_NUMBER` + `SINCH_APPLICATION_KEY` | +| | [./src/voice/applications/getCallbackURLs.ts](./src/voice/applications/getCallbackURLs.ts) | `SINCH_APPLICATION_KEY` | +| | [./src/voice/applications/getNumbers.ts](./src/voice/applications/getNumbers.ts) | | +| | [./src/voice/applications/queryNumber.ts](./src/voice/applications/queryNumber.ts) | `PHONE_NUMBER` | +| | [./src/voice/applications/unassignNumber.ts](./src/voice/applications/unassignNumber.ts) | `PHONE_NUMBER` + `SINCH_APPLICATION_KEY` | +| | [./src/voice/applications/updateCallbackURLs.ts](./src/voice/applications/updateCallbackURLs.ts) | `SINCH_APPLICATION_KEY` | +| Callouts | [./src/voice/callouts/conference.ts](./src/voice/callouts/conference.ts) | `PHONE_NUMBER` + `RECIPIENT_PHONE_NUMBER` + `CONFERENCE_ID` | +| | [./src/voice/callouts/custom.ts](./src/voice/callouts/custom.ts) | `PHONE_NUMBER` + `RECIPIENT_PHONE_NUMBER` + `VOICE_CALLBACK_URL` | +| | [./src/voice/callouts/tts.ts](./src/voice/callouts/tts.ts) | `PHONE_NUMBER` + `RECIPIENT_PHONE_NUMBER` | +| Calls | [./src/voice/calls/get.ts](./src/voice/calls/get.ts) | `CALL_ID` | +| | [./src/voice/calls/manageWithCallLeg.ts](./src/voice/calls/manageWithCallLeg.ts) | `CALL_ID` | +| | [./src/voice/calls/update.ts](./src/voice/calls/update.ts) | `CALL_ID` | +| Conferences | [./src/voice/conferences/get.ts](./src/voice/conferences/get.ts) | `CONFERENCE_ID` | +| | [./src/voice/conferences/kickAll.ts](./src/voice/conferences/kickAll.ts) | `CONFERENCE_ID` | +| | [./src/voice/conferences/kickParticipant.ts](./src/voice/conferences/kickParticipant.ts) | `CONFERENCE_ID` + `CALL_ID` | +| | [./src/voice/conferences/manageParticipant.ts](./src/voice/conferences/manageParticipant.ts) | `CONFERENCE_ID` + `CALL_ID` | + +### Conversation + +| Service | Sample application name and location | Required parameters | +|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| App | [./src/conversation/app/create.ts](./src/conversation/app/create.ts) | `MESSENGER_TOKEN` | +| | [./src/conversation/app/delete.ts](./src/conversation/app/delete.ts) | `CONVERSATION_APP_ID` | +| | [./src/conversation/app/get.ts](./src/conversation/app/get.ts) | `CONVERSATION_APP_ID` | +| | [./src/conversation/app/list.ts](./src/conversation/app/list.ts) | | +| | [./src/conversation/app/update.ts](./src/conversation/app/update.ts) | `CONVERSATION_APP_ID` | +| Capability | [./src/conversation/capability/lookup.ts](./src/conversation/capability/lookup.ts) | `CONVERSATION_APP_ID` + `CONVERSATION_CONTACT_ID` | +| Contact | [./src/conversation/contact/create.ts](./src/conversation/contact/create.ts) | `CONVERSATION_APP_ID` + `MESSENGER_USER_ID` + `PHONE_NUMBER` | +| | [./src/conversation/contact/delete.ts](./src/conversation/contact/delete.ts) | `CONVERSATION_CONTACT_ID` | +| | [./src/conversation/contact/get.ts](./src/conversation/contact/get.ts) | `CONVERSATION_CONTACT_ID` | +| | [./src/conversation/contact/getChannelProfile.ts](./src/conversation/contact/getChannelProfile.ts) | `CONVERSATION_CONTACT_ID` + `MESSENGER_USER_ID` | +| | [./src/conversation/contact/list.ts](./src/conversation/contact/list.ts) | | +| | [./src/conversation/contact/merge.ts](./src/conversation/contact/merge.ts) | `PHONE_NUMBER` | +| | [./src/conversation/contact/update.ts](./src/conversation/contact/update.ts) | `CONVERSATION_CONTACT_ID` | +| Conversation | [./src/conversation/conversation/create.ts](./src/conversation/conversation/create.ts) | `CONVERSATION_APP_ID` + `CONVERSATION_CONTACT_ID` | +| | [./src/conversation/conversation/delete.ts](./src/conversation/conversation/delete.ts) | `CONVERSATION_ID` | +| | [./src/conversation/conversation/get.ts](./src/conversation/conversation/get.ts) | `CONVERSATION_ID` | +| | [./src/conversation/conversation/injectMessage.ts](./src/conversation/conversation/injectMessage.ts) | `CONVERSATION_ID` + `MESSENGER_USER_ID`+ `CONVERSATION_APP_ID` + `CONVERSATION_CONTACT_ID` | +| | [./src/conversation/conversation/list.ts](./src/conversation/conversation/list.ts) | `CONVERSATION_APP_ID` | +| | [./src/conversation/conversation/stop.ts](./src/conversation/conversation/stop.ts) | `CONVERSATION_ID` | +| | [./src/conversation/conversation/update.ts](./src/conversation/conversation/update.ts) | `CONVERSATION_ID` | +| Events | [./src/conversation/events/send.ts](./src/conversation/events/send.ts) | `CONVERSATION_APP_ID` + `CONVERSATION_CONTACT_ID` | +| Messages | [./src/conversation/messages/delete.ts](./src/conversation/messages/delete.ts) | `MESSAGE_ID` | +| | [./src/conversation/messages/get.ts](./src/conversation/messages/get.ts) | `MESSAGE_ID` | +| | [./src/conversation/messages/list.ts](./src/conversation/messages/list.ts) | `CONVERSATION_APP_ID` + `CONVERSATION_CONTACT_ID` + `CONVERSATION_ID` | +| | [./src/conversation/messages/send.ts](./src/conversation/messages/send.ts) | `CONVERSATION_APP_ID` + `CONVERSATION_CONTACT_ID` | +| TemplatesV1 | [./src/conversation/templates-v1/create.ts](./src/conversation/templates-v1/create.ts) | | +| | [./src/conversation/templates-v1/delete.ts](./src/conversation/templates-v1/delete.ts) | `TEMPLATE_ID` | +| | [./src/conversation/templates-v1/get.ts](./src/conversation/templates-v1/get.ts) | `TEMPLATE_ID` | +| | [./src/conversation/templates-v1/list.ts](./src/conversation/templates-v1/list.ts) | | +| | [./src/conversation/templates-v1/update.ts](./src/conversation/templates-v1/update.ts) | `TEMPLATE_ID` | +| TemplatesV2 | [./src/conversation/templates-v2/create.ts](./src/conversation/templates-v2/create.ts) | | +| | [./src/conversation/templates-v2/delete.ts](./src/conversation/templates-v2/delete.ts) | `TEMPLATE_ID` | +| | [./src/conversation/templates-v2/get.ts](./src/conversation/templates-v2/get.ts) | `TEMPLATE_ID` | +| | [./src/conversation/templates-v2/list.ts](./src/conversation/templates-v2/list.ts) | | +| | [./src/conversation/templates-v2/list-translations.ts](./src/conversation/templates-v2/list-translations.ts) | `TEMPLATE_ID` | +| | [./src/conversation/templates-v2/update.ts](./src/conversation/templates-v2/update.ts) | `TEMPLATE_ID` | +| Transcoding | [./src/conversation/transcoding/transcode.ts](./src/conversation/transcoding/transcode.ts) | `CONVERSATION_APP_ID` | +| Webhooks | [./src/conversation/webhooks/create.ts](./src/conversation/webhooks/create.ts) | `CONVERSATION_APP_ID` + `WEBHOOK_TARGET` | +| | [./src/conversation/webhooks/delete.ts](./src/conversation/webhooks/delete.ts) | `WEBHOOK_ID` | +| | [./src/conversation/webhooks/get.ts](./src/conversation/webhooks/get.ts) | `WEBHOOK_ID` | +| | [./src/conversation/webhooks/list.ts](./src/conversation/webhooks/list.ts) | `CONVERSATION_APP_ID` | +| | [./src/conversation/webhooks/update.ts](./src/conversation/webhooks/update.ts) | `CONVERSATION_APP_ID` + `WEBHOOK_ID` | diff --git a/examples/simple-examples/package.json b/examples/simple-examples/package.json index 1cd6283a..f6410441 100644 --- a/examples/simple-examples/package.json +++ b/examples/simple-examples/package.json @@ -39,6 +39,17 @@ "conversation:webhooks:list": "ts-node src/conversation/webhooks/list.ts", "conversation:webhooks:update": "ts-node src/conversation/webhooks/update.ts", "conversation:webhooks:delete": "ts-node src/conversation/webhooks/delete.ts", + "conversation:templatev1:create": "ts-node src/conversation/templates-v1/create.ts", + "conversation:templatev1:get": "ts-node src/conversation/templates-v1/get.ts", + "conversation:templatev1:list": "ts-node src/conversation/templates-v1/list.ts", + "conversation:templatev1:update": "ts-node src/conversation/templates-v1/update.ts", + "conversation:templatev1:delete": "ts-node src/conversation/templates-v1/delete.ts", + "conversation:templatev2:create": "ts-node src/conversation/templates-v2/create.ts", + "conversation:templatev2:get": "ts-node src/conversation/templates-v2/get.ts", + "conversation:templatev2:list": "ts-node src/conversation/templates-v2/list.ts pretty", + "conversation:templatev2:listTranslations": "ts-node src/conversation/templates-v2/list-translations.ts pretty", + "conversation:templatev2:update": "ts-node src/conversation/templates-v2/update.ts", + "conversation:templatev2:delete": "ts-node src/conversation/templates-v2/delete.ts", "numbers:regions:list": "ts-node src/numbers/regions/list.ts", "numbers:available:list": "ts-node src/numbers/available/list.ts", "numbers:available:checkAvailability": "ts-node src/numbers/available/checkAvailability.ts", diff --git a/examples/simple-examples/src/config.ts b/examples/simple-examples/src/config.ts index 012b697d..87330869 100644 --- a/examples/simple-examples/src/config.ts +++ b/examples/simple-examples/src/config.ts @@ -133,6 +133,10 @@ export const getWebhookTargetFromConfig = () => { return readVariable('WEBHOOK_TARGET'); }; +export const getTemplateIdFromConfig = () => { + return readVariable('TEMPLATE_ID'); +}; + const readVariable = ( name: string): string => { const value = process.env[name]; if (!value) { diff --git a/examples/simple-examples/src/conversation/templates-v1/create.ts b/examples/simple-examples/src/conversation/templates-v1/create.ts new file mode 100644 index 00000000..b3d7bf04 --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v1/create.ts @@ -0,0 +1,37 @@ +import { CreateTemplateRequestData, templateV1Helper } from '@sinch/sdk-core'; +import { getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('****************************'); + console.log('* Templates_CreateTemplate *'); + console.log('****************************'); + + const requestData: CreateTemplateRequestData = { + createTemplateRequestBody: { + description: 'Template v1', + default_translation: 'en-US', + channel: 'CONVERSATION', + translations: [ + { + language_code: 'en-US', + version: '1', + content: templateV1Helper.buildTextMessageContent({ + text: 'Message from a template v1.', + }), + }, + ], + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV1.create(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`New template created with the id '${response.id}'.\nDefault translation: ${response.default_translation}\nList of translations: ${response.translations?.map((translation) => translation.language_code).join(', ')}`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/templates-v1/delete.ts b/examples/simple-examples/src/conversation/templates-v1/delete.ts new file mode 100644 index 00000000..ee9ddc4e --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v1/delete.ts @@ -0,0 +1,20 @@ +import { DeleteTemplateRequestData } from '@sinch/sdk-core'; +import { getTemplateIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('****************************'); + console.log('* Templates_DeleteTemplate *'); + console.log('****************************'); + + const templateId = getTemplateIdFromConfig(); + + const requestData: DeleteTemplateRequestData = { + template_id: templateId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV1.delete(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/templates-v1/get.ts b/examples/simple-examples/src/conversation/templates-v1/get.ts new file mode 100644 index 00000000..2896d2b0 --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v1/get.ts @@ -0,0 +1,26 @@ +import { GetTemplateRequestData } from '@sinch/sdk-core'; +import { getPrintFormat, getTemplateIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*************************'); + console.log('* Templates_GetTemplate *'); + console.log('*************************'); + + const templateId = getTemplateIdFromConfig(); + + const requestData: GetTemplateRequestData = { + template_id: templateId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV1.get(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Template retrieved from id '${response.id}'.\nDefault translation: ${response.default_translation}\nList of translations: ${response.translations?.map((translation) => translation.language_code).join(', ')}`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/templates-v1/list.ts b/examples/simple-examples/src/conversation/templates-v1/list.ts new file mode 100644 index 00000000..9ae7929b --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v1/list.ts @@ -0,0 +1,28 @@ +import { ListTemplatesRequestData, V1Template } from '@sinch/sdk-core'; +import { getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('***************************'); + console.log('* Templates_ListTemplates *'); + console.log('***************************'); + + + const requestData: ListTemplatesRequestData = { + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV1.list(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Templates:\n${response.templates?.map((template) => formatPrettyMessage(template)).join('\n')}`); + } else { + printFullResponse(response); + } + +})(); + +const formatPrettyMessage = (template: V1Template) => { + return ` - ID: ${template.id} - Default translation: ${template.default_translation} - Available translations: ${template.translations?.map((translation) => translation.language_code).join(',')}`; +}; diff --git a/examples/simple-examples/src/conversation/templates-v1/update.ts b/examples/simple-examples/src/conversation/templates-v1/update.ts new file mode 100644 index 00000000..ce92e93d --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v1/update.ts @@ -0,0 +1,54 @@ +import { templateV1Helper, UpdateTemplateRequestData } from '@sinch/sdk-core'; +import { getPrintFormat, getTemplateIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('****************************'); + console.log('* Templates_UpdateTemplate *'); + console.log('****************************'); + + const templateId = getTemplateIdFromConfig(); + + const requestData: UpdateTemplateRequestData = { + template_id: templateId, + updateTemplateRequestBody: { + description: 'Updated description for Template v1', + default_translation: 'en-US', + channel: 'CONVERSATION', + translations: [ + // Repeat previous content to not lose it on update + { + language_code: 'en-US', + version: '1', + content: templateV1Helper.buildTextMessageContent({ + text: 'Message from a template v1.', + }), + }, + // New translation added in the scope of the update + { + language_code: 'fr-FR', + version: '1', + content: templateV1Helper.buildLocationMessageContent({ + title: 'Phare d\'Eckmühl', + label: 'Pointe de Penmarch', + coordinates: { + latitude: 47.7981899, + longitude: -4.3727685, + }, + }), + }, + ], + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV1.update(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Template update for channel: '${response.channel}' (requested: '${requestData.updateTemplateRequestBody.channel}'):\nDefault translation: ${response.default_translation}\nList of translations:\n${response.translations?.map((translation) => ' - ' + translation.language_code + ' - ' + translation.content).join('\n')}`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/templates-v2/create.ts b/examples/simple-examples/src/conversation/templates-v2/create.ts new file mode 100644 index 00000000..4f695d70 --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v2/create.ts @@ -0,0 +1,36 @@ +import { templateV2Helper, V2CreateTemplateRequestData } from '@sinch/sdk-core'; +import { getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*******************************'); + console.log('* Templates_v2_CreateTemplate *'); + console.log('*******************************'); + + const requestData: V2CreateTemplateRequestData = { + createTemplateRequestBody: { + description: 'Template v2', + default_translation: 'en-US', + translations: [ + { + language_code: 'en-US', + version: '1', + ...templateV2Helper.buildTextMessageContent({ + text: 'Message from a template v2.', + }), + }, + ], + }, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV2.create(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`New template created with the id '${response.id}'.\nDefault translation: ${response.default_translation} - Version: ${response.version}\nList of translations: ${response.translations?.map((translation) => translation.language_code).join(', ')}`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/templates-v2/delete.ts b/examples/simple-examples/src/conversation/templates-v2/delete.ts new file mode 100644 index 00000000..43a000dd --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v2/delete.ts @@ -0,0 +1,20 @@ +import { V2DeleteTemplateRequestData } from '@sinch/sdk-core'; +import { getTemplateIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*******************************'); + console.log('* Templates_v2_DeleteTemplate *'); + console.log('*******************************'); + + const templateId = getTemplateIdFromConfig(); + + const requestData: V2DeleteTemplateRequestData = { + template_id: templateId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV2.delete(requestData); + + printFullResponse(response); + +})(); diff --git a/examples/simple-examples/src/conversation/templates-v2/get.ts b/examples/simple-examples/src/conversation/templates-v2/get.ts new file mode 100644 index 00000000..bce45b57 --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v2/get.ts @@ -0,0 +1,26 @@ +import { V2GetTemplateRequestData } from '@sinch/sdk-core'; +import { getPrintFormat, getTemplateIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('****************************'); + console.log('* Templates_v2_GetTemplate *'); + console.log('****************************'); + + const templateId = getTemplateIdFromConfig(); + + const requestData: V2GetTemplateRequestData = { + template_id: templateId, + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV2.get(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Template retrieved from id '${response.id}'.\nDefault translation: ${response.default_translation} - Version: ${response.version}\nList of translations: ${response.translations?.map((translation) => translation.language_code).join(', ')}`); + } else { + printFullResponse(response); + } + +})(); diff --git a/examples/simple-examples/src/conversation/templates-v2/list-translations.ts b/examples/simple-examples/src/conversation/templates-v2/list-translations.ts new file mode 100644 index 00000000..7153cdf4 --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v2/list-translations.ts @@ -0,0 +1,46 @@ +import { templateV2Helper, V2ListTranslationsRequestData, V2TemplateTranslation } from '@sinch/sdk-core'; +import { getPrintFormat, getTemplateIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*********************************'); + console.log('* Templates_v2_ListTranslations *'); + console.log('*********************************'); + + const templateId = getTemplateIdFromConfig(); + + const sinchClient = initClient(); + + const templateV2Response = await sinchClient.conversation.templatesV2.get({ + template_id: templateId, + }); + + if(!templateV2Response.translations || templateV2Response.translations.length === 0) { + throw new Error(`The template '${templateId}' has no translations`); + } + + // Get the first translation for the purpose of this example + const translation = templateV2Response.translations[0]; + + const requestData: V2ListTranslationsRequestData = { + template_id: templateId, + // Optional parameters + language_code: translation.language_code, + translation_version: 'latest', // translation.version, + }; + + const response = await sinchClient.conversation.templatesV2.listTranslations(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Translations:\n${response.translations?.map((translation) => formatPrettyMessage(translation)).join('\n')}`); + } else { + printFullResponse(response); + } + +})(); + +const formatPrettyMessage = (translation: V2TemplateTranslation) => { + const message = templateV2Helper.getMessageFromTranslation(translation); + return ` - Language code: ${translation.language_code} - Version: '${translation.version}' - Message: ${JSON.stringify(message.content)}`; +}; diff --git a/examples/simple-examples/src/conversation/templates-v2/list.ts b/examples/simple-examples/src/conversation/templates-v2/list.ts new file mode 100644 index 00000000..3ae6dfeb --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v2/list.ts @@ -0,0 +1,28 @@ +import { V2ListTemplatesRequestData, V2TemplateResponse } from '@sinch/sdk-core'; +import { getPrintFormat, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('******************************'); + console.log('* Templates_v2_ListTemplates *'); + console.log('******************************'); + + + const requestData: V2ListTemplatesRequestData = { + }; + + const sinchClient = initClient(); + const response = await sinchClient.conversation.templatesV2.list(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Templates:\n${response.templates?.map((template) => formatPrettyMessage(template)).join('\n')}`); + } else { + printFullResponse(response); + } + +})(); + +const formatPrettyMessage = (template: V2TemplateResponse) => { + return ` - ID: ${template.id} - Default translation: ${template.default_translation} - Version: ${template.version} - Available translations: ${template.translations?.map((translation) => translation.language_code + '(' +translation.version + ')').join(', ')}`; +}; diff --git a/examples/simple-examples/src/conversation/templates-v2/update.ts b/examples/simple-examples/src/conversation/templates-v2/update.ts new file mode 100644 index 00000000..a459a6a9 --- /dev/null +++ b/examples/simple-examples/src/conversation/templates-v2/update.ts @@ -0,0 +1,58 @@ +import { templateV2Helper, V2TemplateTranslation, V2UpdateTemplateRequestData } from '@sinch/sdk-core'; +import { getPrintFormat, getTemplateIdFromConfig, initClient, printFullResponse } from '../../config'; + +(async () => { + console.log('*******************************'); + console.log('* Templates_v2_UpdateTemplate *'); + console.log('*******************************'); + + const templateId = getTemplateIdFromConfig(); + + const sinchClient = initClient(); + const templateV2Response = await sinchClient.conversation.templatesV2.get({ + template_id: templateId, + }); + + const requestData: V2UpdateTemplateRequestData = { + template_id: templateId, + updateTemplateRequestBody: { + version: templateV2Response.version, + description: 'Updated description for Template v2', + default_translation: templateV2Response.default_translation, + translations: [ + // Repeat previous content to not lose it on update + ...templateV2Helper.getPreviousTranslations(templateV2Response.translations), + // New translation added in the scope of the update + { + language_code: 'fr-FR', + version: '1', + ...templateV2Helper.buildLocationMessageContent({ + title: 'Phare d\'Eckmühl', + label: 'Pointe de Penmarch', + coordinates: { + latitude: 47.7981899, + longitude: -4.3727685, + }, + }), + }, + ], + }, + }; + + const response = await sinchClient.conversation.templatesV2.update(requestData); + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(`Template update:\nDefault translation: ${response.default_translation}\nList of translations:\n${response.translations?.map((translation) => formatPrettyMessage(translation)).join('\n')}`); + } else { + printFullResponse(response); + } + +})(); + +const formatPrettyMessage = (translation: V2TemplateTranslation) => { + const message = templateV2Helper.getMessageFromTranslation(translation); + return ` - Language code: ${translation.language_code} - Version: '${translation.version}' - Message: ${JSON.stringify(message.content)}`; +}; + diff --git a/packages/conversation/src/models/v1/carousel-message/carousel-message.ts b/packages/conversation/src/models/v1/carousel-message/carousel-message.ts index 664fa2ec..807b3f1d 100644 --- a/packages/conversation/src/models/v1/carousel-message/carousel-message.ts +++ b/packages/conversation/src/models/v1/carousel-message/carousel-message.ts @@ -1,4 +1,4 @@ -import { CardMessage } from '../card-message'; +import { CardMessageItem } from '../card-message'; import { Choice } from '../choice'; /** @@ -13,7 +13,7 @@ export interface CarouselMessage { export interface CarouselMessageItem { /** A list of up to 10 cards. */ - cards: CardMessage[]; + cards: CardMessageItem[]; /** Optional. Outer choices on the carousel level. The number of outer choices is limited to 3. */ choices?: Choice[]; } diff --git a/packages/conversation/src/models/v1/channel-template-override/channel-template-override.ts b/packages/conversation/src/models/v1/channel-template-override/channel-template-override.ts new file mode 100644 index 00000000..eaabc50a --- /dev/null +++ b/packages/conversation/src/models/v1/channel-template-override/channel-template-override.ts @@ -0,0 +1,12 @@ +import { ChannelTemplateReference } from '../channel-template-reference'; + +/** + * Optional field to override the omnichannel template by referring to a channel-specific template. + */ +export interface ChannelTemplateOverride { + + /** @see ChannelTemplateReference */ + WHATSAPP?: ChannelTemplateReference; + /** @see ChannelTemplateReference */ + KAKAOTALK?: ChannelTemplateReference; +} diff --git a/packages/conversation/src/models/v1/channel-template-override/index.ts b/packages/conversation/src/models/v1/channel-template-override/index.ts new file mode 100644 index 00000000..87dbbb15 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-template-override/index.ts @@ -0,0 +1 @@ +export type { ChannelTemplateOverride } from './channel-template-override'; diff --git a/packages/conversation/src/models/v1/channel-template-reference/channel-template-reference.ts b/packages/conversation/src/models/v1/channel-template-reference/channel-template-reference.ts new file mode 100644 index 00000000..be8625a2 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-template-reference/channel-template-reference.ts @@ -0,0 +1,9 @@ +import { TemplateReference } from '../template-reference'; + +export interface ChannelTemplateReference { + + /** @see TemplateReference */ + template_reference?: TemplateReference; + /** A mapping between omni-template variables and the channel specific parameters. */ + parameter_mappings?: { [key: string]: string; }; +} diff --git a/packages/conversation/src/models/v1/channel-template-reference/index.ts b/packages/conversation/src/models/v1/channel-template-reference/index.ts new file mode 100644 index 00000000..b76f5dd4 --- /dev/null +++ b/packages/conversation/src/models/v1/channel-template-reference/index.ts @@ -0,0 +1 @@ +export type { ChannelTemplateReference } from './channel-template-reference'; diff --git a/packages/conversation/src/models/v1/choice-item/choice-item.ts b/packages/conversation/src/models/v1/choice-item/choice-item.ts index c8ab5463..0cdbe195 100644 --- a/packages/conversation/src/models/v1/choice-item/choice-item.ts +++ b/packages/conversation/src/models/v1/choice-item/choice-item.ts @@ -1,6 +1,10 @@ import { MediaMessage } from '../media-message'; export interface ChoiceItem { + choice: ChoiceItemItem; +} + +export interface ChoiceItemItem { /** Required parameter. Title for the choice item. */ title: string; diff --git a/packages/conversation/src/models/v1/choice-item/index.ts b/packages/conversation/src/models/v1/choice-item/index.ts index 91fab497..9bb775aa 100644 --- a/packages/conversation/src/models/v1/choice-item/index.ts +++ b/packages/conversation/src/models/v1/choice-item/index.ts @@ -1 +1 @@ -export type { ChoiceItem } from './choice-item'; +export type { ChoiceItem, ChoiceItemItem } from './choice-item'; diff --git a/packages/conversation/src/models/v1/choice-message/choice-message.ts b/packages/conversation/src/models/v1/choice-message/choice-message.ts index 2f4f83f6..97e0457a 100644 --- a/packages/conversation/src/models/v1/choice-message/choice-message.ts +++ b/packages/conversation/src/models/v1/choice-message/choice-message.ts @@ -1,5 +1,5 @@ +import { TextMessageItem } from '../text-message'; import { Choice } from '../choice'; -import { TextMessage } from '../text-message'; /** * Message containing choices/actions. @@ -15,5 +15,5 @@ export interface ChoiceMessageItem { /** The number of choices is limited to 10. */ choices: Choice[]; /** @see TextMessage */ - text_message?: TextMessage; + text_message?: TextMessageItem; } diff --git a/packages/conversation/src/models/v1/choice-message/index.ts b/packages/conversation/src/models/v1/choice-message/index.ts index 36313eea..e88f387a 100644 --- a/packages/conversation/src/models/v1/choice-message/index.ts +++ b/packages/conversation/src/models/v1/choice-message/index.ts @@ -1 +1 @@ -export type { ChoiceMessage } from './choice-message'; +export type { ChoiceMessage, ChoiceMessageItem } from './choice-message'; diff --git a/packages/conversation/src/models/v1/choice/choice.ts b/packages/conversation/src/models/v1/choice/choice.ts index 6964b4b9..2493cd74 100644 --- a/packages/conversation/src/models/v1/choice/choice.ts +++ b/packages/conversation/src/models/v1/choice/choice.ts @@ -6,18 +6,33 @@ import { UrlMessage } from '../url-message'; /** * A choice is an action the user can take such as buttons for quick replies or other call to actions. */ -export interface Choice { +export type Choice = + CallMessageChoice + | LocationMessageChoice + | TextMessageChoice + | UrlMessageChoice; +export interface ChoiceBase { + /** An optional field. This data will be returned in the ChoiceResponseMessage. The default is message_id_{text, title}. */ + postback_data?: string; +} + +export interface CallMessageChoice extends ChoiceBase { /** @see CallMessage */ - call_message: CallMessage; + call_message?: CallMessage; +} + +export interface LocationMessageChoice extends ChoiceBase { /** @see LocationMessage */ - location_message: LocationMessageItem; - /** An optional field. This data will be returned in the ChoiceResponseMessage. The default is message_id_{text, title}. */ - postback_data :string; - /** @see TextMessageItem */ - text_message: TextMessageItem; - /** @see UrlMessage */ - url_message: UrlMessage; + location_message?: LocationMessageItem; } +export interface TextMessageChoice extends ChoiceBase { + /** @see TextMessageItem */ + text_message?: TextMessageItem; +} +export interface UrlMessageChoice extends ChoiceBase { + /** @see UrlMessage */ + url_message?: UrlMessage; +} diff --git a/packages/conversation/src/models/v1/choice/index.ts b/packages/conversation/src/models/v1/choice/index.ts index 327cdc59..e5530fec 100644 --- a/packages/conversation/src/models/v1/choice/index.ts +++ b/packages/conversation/src/models/v1/choice/index.ts @@ -1 +1,8 @@ -export type { Choice } from './choice'; +export type { + Choice, + ChoiceBase, + CallMessageChoice, + LocationMessageChoice, + TextMessageChoice, + UrlMessageChoice, +} from './choice'; diff --git a/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts index 509db586..6f0fb682 100644 --- a/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts +++ b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts @@ -17,3 +17,13 @@ export type ConversationChannel = | 'WECHAT' | 'APPLEBC' | 'CHANNEL_UNSPECIFIED'; + +export type TemplateChannel = + 'UNSPECIFIED' + | 'CONVERSATION' + | 'MESSENGER' + | 'WHATSAPP' + | 'RCS' + | 'SMS' + | 'VIBER' + | 'VIBERBM'; diff --git a/packages/conversation/src/models/v1/conversation-channel/index.ts b/packages/conversation/src/models/v1/conversation-channel/index.ts index bad833a8..18c63305 100644 --- a/packages/conversation/src/models/v1/conversation-channel/index.ts +++ b/packages/conversation/src/models/v1/conversation-channel/index.ts @@ -1 +1 @@ -export type { ConversationChannel } from './conversation-channel'; +export type { ConversationChannel, TemplateChannel } from './conversation-channel'; diff --git a/packages/conversation/src/models/v1/helper.ts b/packages/conversation/src/models/v1/helper.ts new file mode 100644 index 00000000..b057f0d0 --- /dev/null +++ b/packages/conversation/src/models/v1/helper.ts @@ -0,0 +1,163 @@ +import { TextMessage, TextMessageItem } from './text-message'; +import { CardMessage, CardMessageItem } from './card-message'; +import { CarouselMessage, CarouselMessageItem } from './carousel-message'; +import { ChoiceMessage, ChoiceMessageItem } from './choice-message/choice-message'; +import { LocationMessage, LocationMessageItem } from './location-message'; +import { MediaMessage, MediaMessageItem } from './media-message'; +import { TemplateMessage, TemplateMessageItem } from './template-message'; +import { ListMessage, ListMessageItem } from './list-message'; +import { V2TemplateTranslation } from './v2-template-translation'; + +export const templateV1Helper = { + buildTextMessageContent: (textMessageItem: TextMessageItem): string => { + return JSON.stringify({ + text_message: textMessageItem, + } as TextMessage); + }, + buildCardMessageContent: (cardMessageItem: CardMessageItem): string => { + return JSON.stringify({ + card_message: cardMessageItem, + } as CardMessage); + }, + buildCarouselMessageContent: (carouselMessageItem: CarouselMessageItem): string => { + return JSON.stringify({ + carousel_message: carouselMessageItem, + } as CarouselMessage); + }, + buildChoiceMessageContent: (choiceMessageItem: ChoiceMessageItem): string => { + return JSON.stringify({ + choice_message: choiceMessageItem, + } as ChoiceMessage); + }, + buildLocationMessageContent: (locationMessageItem: LocationMessageItem): string => { + return JSON.stringify({ + location_message: locationMessageItem, + } as LocationMessage); + }, + buildMediaMessageContent: (mediaMessageItem: MediaMessageItem): string => { + return JSON.stringify({ + media_message: mediaMessageItem, + } as MediaMessage); + }, + buildTemplateMessageContent: (templateMessageItem: TemplateMessageItem): string => { + return JSON.stringify({ + template_message: templateMessageItem, + } as TemplateMessage); + }, + buildListMessageContent: (listMessageItem: ListMessageItem): string => { + return JSON.stringify({ + list_message: listMessageItem, + } as ListMessage); + }, +}; + +export const templateV2Helper = { + // Template V2 + buildTextMessageContent: (textMessageItem: TextMessageItem): TextMessage => { + return { + text_message: textMessageItem, + } as TextMessage; + }, + buildCardMessageContent: (cardMessageItem: CardMessageItem): CardMessage => { + return { + card_message: cardMessageItem, + } as CardMessage; + }, + buildCarouselMessageContent: (carouselMessageItem: CarouselMessageItem): CarouselMessage => { + return { + carousel_message: carouselMessageItem, + } as CarouselMessage; + }, + buildChoiceMessageContent: (choiceMessageItem: ChoiceMessageItem): ChoiceMessage => { + return { + choice_message: choiceMessageItem, + } as ChoiceMessage; + }, + buildLocationMessageContent: (locationMessageItem: LocationMessageItem): LocationMessage => { + return { + location_message: locationMessageItem, + } as LocationMessage; + }, + buildMediaMessageContent: (mediaMessageItem: MediaMessageItem): MediaMessage => { + return { + media_message: mediaMessageItem, + } as MediaMessage; + }, + buildTemplateMessageContent: (templateMessageItem: TemplateMessageItem): TemplateMessage => { + return { + template_message: templateMessageItem, + } as TemplateMessage; + }, + buildListMessageContent: (listMessageItem: ListMessageItem): ListMessage => { + return { + list_message: listMessageItem, + } as ListMessage; + }, + getMessageFromTranslation: (translation: V2TemplateTranslation) => { + if('text_message' in translation) { + return { + type: MessageType.TEXT, + content: translation.text_message, + }; + } else if ('card_message' in translation) { + return { + type: MessageType.CARD, + content: translation.card_message, + }; + } else if ('choice_message' in translation) { + return { + type: MessageType.CHOICE, + content: translation.choice_message, + }; + } else if ('carousel_message' in translation) { + return { + type: MessageType.CAROUSEL, + content: translation.carousel_message, + }; + } else if ('list_message' in translation) { + return { + type: MessageType.LIST, + content: translation.list_message, + }; + } else if ('location_message' in translation) { + return { + type: MessageType.LOCATION, + content: translation.location_message, + }; + } else if ('media_message' in translation) { + return { + type: MessageType.MEDIA, + content: translation.media_message, + }; + } else if ('template_message' in translation) { + return { + type: MessageType.TEMPLATE, + content: translation.template_message, + }; + } else { + return { + type: MessageType.UNDEFINED, + content: '', + }; + } + }, + getPreviousTranslations: (translations: V2TemplateTranslation[] | undefined) => { + if(!translations) { + return []; + } else { + return translations.filter((translation) => translation.version !== 'latest'); + } + }, +}; + +export const enum MessageType { + CARD = 'CardMessage', + CHOICE = 'ChoiceMessage', + CAROUSEL = 'CarouselMessage', + LIST = 'ListMessage', + LOCATION = 'LocationMessage', + MEDIA = 'MediaMessage', + TEMPLATE = 'TemplateMessage', + TEXT = 'TextMessage', + UNDEFINED = 'Undefined' +} diff --git a/packages/conversation/src/models/v1/index.ts b/packages/conversation/src/models/v1/index.ts index 16eed50b..cf6e915f 100644 --- a/packages/conversation/src/models/v1/index.ts +++ b/packages/conversation/src/models/v1/index.ts @@ -19,6 +19,8 @@ export * from './carousel-message'; export * from './channel-event'; export * from './channel-identities'; export * from './channel-identity'; +export * from './channel-template-override'; +export * from './channel-template-reference'; export * from './channel-recipient-identity'; export * from './choice'; export * from './choice-message'; @@ -70,7 +72,6 @@ export * from './kakaotalk-credentials'; export * from './kakaotalkchat-credentials'; export * from './line-credentials'; export * from './list-apps-response'; -export * from './list-item'; export * from './list-message'; export * from './list-message-message-properties'; export * from './list-section'; @@ -114,13 +115,23 @@ export * from './static-token-credential'; export * from './telegram-credentials'; export * from './template-message'; export * from './template-reference'; +export * from './template-variable'; export * from './text-message'; export * from './transcode-message-request'; export * from './transcode-message-response'; export * from './unsupported-callback-event'; export * from './url-message'; +export * from './v1-list-templates-response'; +export * from './v1-template'; +export * from './v1-template-translation'; +export * from './v2-list-templates-response'; +export * from './v2-list-translations-response'; +export * from './v2-template'; +export * from './v2-template-response'; +export * from './v2-template-translation'; export * from './wechat-credentials'; export * from './webhook'; export * from './webhook-target-type'; export * from './webhook-trigger'; export * from './enums'; +export * from './helper'; diff --git a/packages/conversation/src/models/v1/list-item/index.ts b/packages/conversation/src/models/v1/list-item/index.ts deleted file mode 100644 index 306dbbd8..00000000 --- a/packages/conversation/src/models/v1/list-item/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ListItem } from './list-item'; diff --git a/packages/conversation/src/models/v1/list-item/list-item.ts b/packages/conversation/src/models/v1/list-item/list-item.ts deleted file mode 100644 index 9ce17ea9..00000000 --- a/packages/conversation/src/models/v1/list-item/list-item.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Product } from '../product'; -import { Choice } from '../choice'; - -/** - * Item containing either choiceItem or ProductItem - */ -export interface ListItem { - - item: Choice | Product; -} diff --git a/packages/conversation/src/models/v1/list-section/list-section.ts b/packages/conversation/src/models/v1/list-section/list-section.ts index 6f6e4562..00d0dcb8 100644 --- a/packages/conversation/src/models/v1/list-section/list-section.ts +++ b/packages/conversation/src/models/v1/list-section/list-section.ts @@ -1,4 +1,5 @@ -import { ListItem } from '../list-item'; +import { ChoiceItem } from '../choice-item'; +import { Product } from '../product'; /** * Section for interactive whatsapp messages containing ListItem @@ -8,5 +9,5 @@ export interface ListSection { /** Optional parameter. Title for list section. */ title?: string; /** List of ListItems */ - items?: ListItem[]; + items?: (ChoiceItem | Product)[]; } diff --git a/packages/conversation/src/models/v1/template-variable/index.ts b/packages/conversation/src/models/v1/template-variable/index.ts new file mode 100644 index 00000000..3a42f7bf --- /dev/null +++ b/packages/conversation/src/models/v1/template-variable/index.ts @@ -0,0 +1 @@ +export type { TemplateVariable } from './template-variable'; diff --git a/packages/conversation/src/models/v1/template-variable/template-variable.ts b/packages/conversation/src/models/v1/template-variable/template-variable.ts new file mode 100644 index 00000000..30e7d7aa --- /dev/null +++ b/packages/conversation/src/models/v1/template-variable/template-variable.ts @@ -0,0 +1,6 @@ + +export interface TemplateVariable { + + key?: string; + preview_value?: string; +} diff --git a/packages/conversation/src/models/v1/v1-list-templates-response/index.ts b/packages/conversation/src/models/v1/v1-list-templates-response/index.ts new file mode 100644 index 00000000..ae8e5b70 --- /dev/null +++ b/packages/conversation/src/models/v1/v1-list-templates-response/index.ts @@ -0,0 +1 @@ +export type { V1ListTemplatesResponse } from './v1-list-templates-response'; diff --git a/packages/conversation/src/models/v1/v1-list-templates-response/v1-list-templates-response.ts b/packages/conversation/src/models/v1/v1-list-templates-response/v1-list-templates-response.ts new file mode 100644 index 00000000..3eb604ba --- /dev/null +++ b/packages/conversation/src/models/v1/v1-list-templates-response/v1-list-templates-response.ts @@ -0,0 +1,6 @@ +import { V1Template } from '../v1-template'; + +export interface V1ListTemplatesResponse { + + templates?: V1Template[]; +} diff --git a/packages/conversation/src/models/v1/v1-template-translation/index.ts b/packages/conversation/src/models/v1/v1-template-translation/index.ts new file mode 100644 index 00000000..1e344917 --- /dev/null +++ b/packages/conversation/src/models/v1/v1-template-translation/index.ts @@ -0,0 +1 @@ +export type { V1TemplateTranslation } from './v1-template-translation'; diff --git a/packages/conversation/src/models/v1/v1-template-translation/v1-template-translation.ts b/packages/conversation/src/models/v1/v1-template-translation/v1-template-translation.ts new file mode 100644 index 00000000..5916292e --- /dev/null +++ b/packages/conversation/src/models/v1/v1-template-translation/v1-template-translation.ts @@ -0,0 +1,17 @@ +import { TemplateVariable } from '../template-variable'; + +export interface V1TemplateTranslation { + + /** This is the definition of the template with the language specified in the language_code field. */ + content?: string; + /** Timestamp when the translation was created. */ + create_time?: Date; + /** The BCP-47 language code, such as `en-US` or `sr-Latn`. For more information, see http://www.unicode.org/reports/tr35/#Unicode_locale_identifier. */ + language_code?: string; + /** Timestamp of when the translation was updated. */ + update_time?: Date; + /** List of expected variables. Can be used for request validation. */ + variables?: TemplateVariable[]; + /** The version of template. */ + version?: string; +} diff --git a/packages/conversation/src/models/v1/v1-template/index.ts b/packages/conversation/src/models/v1/v1-template/index.ts new file mode 100644 index 00000000..8d174ebf --- /dev/null +++ b/packages/conversation/src/models/v1/v1-template/index.ts @@ -0,0 +1 @@ +export type { V1Template } from './v1-template'; diff --git a/packages/conversation/src/models/v1/v1-template/v1-template.ts b/packages/conversation/src/models/v1/v1-template/v1-template.ts new file mode 100644 index 00000000..bf9383ae --- /dev/null +++ b/packages/conversation/src/models/v1/v1-template/v1-template.ts @@ -0,0 +1,20 @@ +import { TemplateChannel } from '../conversation-channel'; +import { V1TemplateTranslation } from '../v1-template-translation'; + +export interface V1Template { + + /** @see TemplateChannel */ + channel?: TemplateChannel; + /** Timestamp when the template was created. */ + create_time?: Date; + /** The default translation to use if not specified. Specified as a BCP-47 `language_code` and the `language_code` must exist in the translations list. */ + default_translation?: string; + /** The description of the template. */ + description?: string; + /** The id of the template. Specify this yourself during creation otherwise we will generate an ID for you. This has to be unique for a given project. */ + id?: string; + /** List of translations for the template. */ + translations?: V1TemplateTranslation[]; + /** Timestamp when the template was updated. */ + update_time?: Date; +} diff --git a/packages/conversation/src/models/v1/v2-list-templates-response/index.ts b/packages/conversation/src/models/v1/v2-list-templates-response/index.ts new file mode 100644 index 00000000..d48f7c77 --- /dev/null +++ b/packages/conversation/src/models/v1/v2-list-templates-response/index.ts @@ -0,0 +1 @@ +export type { V2ListTemplatesResponse } from './v2-list-templates-response'; diff --git a/packages/conversation/src/models/v1/v2-list-templates-response/v2-list-templates-response.ts b/packages/conversation/src/models/v1/v2-list-templates-response/v2-list-templates-response.ts new file mode 100644 index 00000000..ac61d80d --- /dev/null +++ b/packages/conversation/src/models/v1/v2-list-templates-response/v2-list-templates-response.ts @@ -0,0 +1,7 @@ +import { V2TemplateResponse } from '../v2-template-response'; + +export interface V2ListTemplatesResponse { + + /** List of V2TemplateResponses */ + templates?: V2TemplateResponse[]; +} diff --git a/packages/conversation/src/models/v1/v2-list-translations-response/index.ts b/packages/conversation/src/models/v1/v2-list-translations-response/index.ts new file mode 100644 index 00000000..a6323ce6 --- /dev/null +++ b/packages/conversation/src/models/v1/v2-list-translations-response/index.ts @@ -0,0 +1 @@ +export type { V2ListTranslationsResponse } from './v2-list-translations-response'; diff --git a/packages/conversation/src/models/v1/v2-list-translations-response/v2-list-translations-response.ts b/packages/conversation/src/models/v1/v2-list-translations-response/v2-list-translations-response.ts new file mode 100644 index 00000000..07ff9c06 --- /dev/null +++ b/packages/conversation/src/models/v1/v2-list-translations-response/v2-list-translations-response.ts @@ -0,0 +1,7 @@ +import { V2TemplateTranslation } from '../v2-template-translation'; + +export interface V2ListTranslationsResponse { + + /** List of V2TemplateTranslationResponses */ + translations?: V2TemplateTranslation[]; +} diff --git a/packages/conversation/src/models/v1/v2-template-response/index.ts b/packages/conversation/src/models/v1/v2-template-response/index.ts new file mode 100644 index 00000000..8692cb7c --- /dev/null +++ b/packages/conversation/src/models/v1/v2-template-response/index.ts @@ -0,0 +1 @@ +export type { V2TemplateResponse } from './v2-template-response'; diff --git a/packages/conversation/src/models/v1/v2-template-response/v2-template-response.ts b/packages/conversation/src/models/v1/v2-template-response/v2-template-response.ts new file mode 100644 index 00000000..090e8738 --- /dev/null +++ b/packages/conversation/src/models/v1/v2-template-response/v2-template-response.ts @@ -0,0 +1,19 @@ +import { V2TemplateTranslation } from '../v2-template-translation'; + +export interface V2TemplateResponse { + + /** The id of the template. Specify this yourself during creation. Otherwise, we will generate an ID for you. This must be unique for a given project. */ + id: string; + /** The description of the template. */ + description?: string; + /** The version of the template. While creating a template, this will be defaulted to 1. When updating a template, you must supply the latest version of the template in order for the update to be successful. */ + version: number; + /** The default translation to use if translation not specified. Specified as a BCP-47 `language_code` and the `language_code` must exist in the translations list. */ + default_translation: string; + /** List of V2TemplateTranslationResponses */ + translations?: V2TemplateTranslation[]; + /** Timestamp when the template was created. */ + create_time?: Date; + /** Timestamp when the template was updated. */ + update_time?: Date; +} diff --git a/packages/conversation/src/models/v1/v2-template-translation/index.ts b/packages/conversation/src/models/v1/v2-template-translation/index.ts new file mode 100644 index 00000000..33f2d207 --- /dev/null +++ b/packages/conversation/src/models/v1/v2-template-translation/index.ts @@ -0,0 +1,12 @@ +export type { + V2TemplateTranslation, + V2TemplateTranslationBase, + V2TemplateTranslationCardMessage, + V2TemplateTranslationCarouselMessage, + V2TemplateTranslationChoiceMessage, + V2TemplateTranslationListMessage, + V2TemplateTranslationLocationMessage, + V2TemplateTranslationMediaMessage, + V2TemplateTranslationTemplateMessage, + V2TemplateTranslationTextMessage, +} from './v2-template-translation'; diff --git a/packages/conversation/src/models/v1/v2-template-translation/v2-template-translation.ts b/packages/conversation/src/models/v1/v2-template-translation/v2-template-translation.ts new file mode 100644 index 00000000..66d8f4ea --- /dev/null +++ b/packages/conversation/src/models/v1/v2-template-translation/v2-template-translation.ts @@ -0,0 +1,45 @@ +import { ChannelTemplateOverride } from '../channel-template-override'; +import { TemplateVariable } from '../template-variable'; +import { TextMessage } from '../text-message'; +import { CardMessage } from '../card-message'; +import { CarouselMessage } from '../carousel-message'; +import { ChoiceMessage } from '../choice-message'; +import { LocationMessage } from '../location-message'; +import { MediaMessage } from '../media-message'; +import { TemplateMessage } from '../template-message'; +import { ListMessage } from '../list-message'; + +export type V2TemplateTranslation = + V2TemplateTranslationCardMessage + | V2TemplateTranslationChoiceMessage + | V2TemplateTranslationCarouselMessage + | V2TemplateTranslationListMessage + | V2TemplateTranslationLocationMessage + | V2TemplateTranslationMediaMessage + | V2TemplateTranslationTemplateMessage + | V2TemplateTranslationTextMessage; + +export interface V2TemplateTranslationBase { + + /** The BCP-47 language code, such as `en-US` or `sr-Latn`. For more information, see http://www.unicode.org/reports/tr35/#Unicode_locale_identifier. */ + language_code: string; + /** The version of the translation. */ + version?: string; + /** @see ChannelTemplateOverride */ + channel_template_overrides?: ChannelTemplateOverride; + /** List of expected variables. Can be used for request validation. */ + variables?: TemplateVariable[]; + /** Timestamp when the translation was created. */ + create_time?: Date; + /** Timestamp of when the translation was updated. */ + update_time?: Date; +} + +export type V2TemplateTranslationTextMessage = V2TemplateTranslationBase & TextMessage; +export type V2TemplateTranslationCardMessage = V2TemplateTranslationBase & CardMessage; +export type V2TemplateTranslationCarouselMessage = V2TemplateTranslationBase & CarouselMessage; +export type V2TemplateTranslationChoiceMessage = V2TemplateTranslationBase & ChoiceMessage; +export type V2TemplateTranslationLocationMessage = V2TemplateTranslationBase & LocationMessage; +export type V2TemplateTranslationMediaMessage = V2TemplateTranslationBase & MediaMessage; +export type V2TemplateTranslationTemplateMessage = V2TemplateTranslationBase & TemplateMessage; +export type V2TemplateTranslationListMessage = V2TemplateTranslationBase & ListMessage; diff --git a/packages/conversation/src/models/v1/v2-template/index.ts b/packages/conversation/src/models/v1/v2-template/index.ts new file mode 100644 index 00000000..93224e9d --- /dev/null +++ b/packages/conversation/src/models/v1/v2-template/index.ts @@ -0,0 +1 @@ +export type { V2Template } from './v2-template'; diff --git a/packages/conversation/src/models/v1/v2-template/v2-template.ts b/packages/conversation/src/models/v1/v2-template/v2-template.ts new file mode 100644 index 00000000..223257c5 --- /dev/null +++ b/packages/conversation/src/models/v1/v2-template/v2-template.ts @@ -0,0 +1,17 @@ +import { V2TemplateTranslation } from '../v2-template-translation'; + +export interface V2Template { + + /** The description of the template. */ + description?: string; + /** The version of the template. While creating a template, this will be defaulted to 1. When updating a template, you must supply the latest version of the template in order for the update to be successful. */ + version?: number; + /** The default translation to use if not specified. Specified as a BCP-47 `language_code` and the `language_code` must exist in the translations list. */ + default_translation?: string; + /** List of V2TemplateTranslations */ + translations?: V2TemplateTranslation[]; + /** Timestamp when the template was created. */ + create_time?: Date; + /** Timestamp when the template was updated. */ + update_time?: Date; +} diff --git a/packages/conversation/src/rest/v1/conversation-domain-api.ts b/packages/conversation/src/rest/v1/conversation-domain-api.ts index 772aa109..ff577b5a 100644 --- a/packages/conversation/src/rest/v1/conversation-domain-api.ts +++ b/packages/conversation/src/rest/v1/conversation-domain-api.ts @@ -25,8 +25,24 @@ export class ConversationDomainApi implements Api { * @param {string} basePath - The new base path to use for the APIs. */ public setBasePath(basePath: string) { - this.client = this.getSinchClient(); - this.client.apiClientOptions.basePath = basePath; + try { + this.client = this.getSinchClient(); + this.client.apiClientOptions.basePath = basePath; + } catch (error) { + console.error('Impossible to set a new base path, the credentials need to be provided first.'); + throw error; + } + } + + /** + * Update the region in the basePath + * @param {Region} region - The new region to send the requests to + */ + public setRegion(region: Region) { + this.sinchClientParameters.region = region; + if (this.client) { + this.client.apiClientOptions.basePath = this.buildBasePath(region); + } } /** @@ -67,7 +83,7 @@ export class ConversationDomainApi implements Api { } const apiClientOptions = this.buildApiClientOptions(this.sinchClientParameters); this.client = new ApiFetchClient(apiClientOptions); - this.client.apiClientOptions.basePath = `https://${region}.conversation.api.sinch.com`; + this.client.apiClientOptions.basePath = this.buildBasePath(region); } return this.client; } @@ -84,4 +100,14 @@ export class ConversationDomainApi implements Api { }; } + private buildBasePath(region: Region) { + switch (this.apiName) { + case 'TemplatesV1Api': + case 'TemplatesV2Api': + return `https://${region}.template.api.sinch.com`; + default: + return `https://${region}.conversation.api.sinch.com`; + } + } + } diff --git a/packages/conversation/src/rest/v1/conversation-domain.ts b/packages/conversation/src/rest/v1/conversation-domain.ts index 55914537..15f915b5 100644 --- a/packages/conversation/src/rest/v1/conversation-domain.ts +++ b/packages/conversation/src/rest/v1/conversation-domain.ts @@ -7,6 +7,8 @@ import { TranscodingApi } from './transcoding'; import { CapabilityApi } from './capability'; import { ConversationApi } from './conversation'; import { WebhooksApi } from './webhooks'; +import { TemplatesV1Api } from './templates-v1'; +import { TemplatesV2Api } from './templates-v2'; export class ConversationDomain { public readonly contact: ContactApi; @@ -17,6 +19,9 @@ export class ConversationDomain { public readonly capability: CapabilityApi; public readonly conversation: ConversationApi; public readonly webhooks: WebhooksApi; + public readonly templatesV1: TemplatesV1Api; + public readonly templatesV2: TemplatesV2Api; + constructor(params: SinchClientParameters) { this.contact = new ContactApi(params); @@ -27,6 +32,8 @@ export class ConversationDomain { this.capability = new CapabilityApi(params); this.conversation = new ConversationApi(params); this.webhooks = new WebhooksApi(params); + this.templatesV1 = new TemplatesV1Api(params); + this.templatesV2 = new TemplatesV2Api(params); } /** @@ -43,5 +50,7 @@ export class ConversationDomain { this.capability.setBasePath(basePath); this.conversation.setBasePath(basePath); this.webhooks.setBasePath(basePath); + this.templatesV1.setBasePath(basePath); + this.templatesV2.setBasePath(basePath); } } diff --git a/packages/conversation/src/rest/v1/index.ts b/packages/conversation/src/rest/v1/index.ts index 04d972d9..417a2a50 100644 --- a/packages/conversation/src/rest/v1/index.ts +++ b/packages/conversation/src/rest/v1/index.ts @@ -5,6 +5,8 @@ export * from './contact'; export * from './conversation'; export * from './events'; export * from './messages'; +export * from './templates-v1'; +export * from './templates-v2'; export * from './transcoding'; export * from './webhooks'; export * from './enums'; diff --git a/packages/conversation/src/rest/v1/templates-v1/index.ts b/packages/conversation/src/rest/v1/templates-v1/index.ts new file mode 100644 index 00000000..9b7feb54 --- /dev/null +++ b/packages/conversation/src/rest/v1/templates-v1/index.ts @@ -0,0 +1,2 @@ +export * from './templates-v1-api'; +export * from './templates-v1-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/templates-v1/templates-v1-api.jest.fixture.ts b/packages/conversation/src/rest/v1/templates-v1/templates-v1-api.jest.fixture.ts new file mode 100644 index 00000000..bb79cc99 --- /dev/null +++ b/packages/conversation/src/rest/v1/templates-v1/templates-v1-api.jest.fixture.ts @@ -0,0 +1,27 @@ +import { V1Template, V1ListTemplatesResponse } from '../../../models'; +import { TemplatesV1Api, CreateTemplateRequestData, DeleteTemplateRequestData, GetTemplateRequestData, ListTemplatesRequestData, UpdateTemplateRequestData } from './templates-v1-api'; + +export class TemplatesV1ApiFixture implements Partial> { + + /** + * Fixture associated to function create + */ + public create: jest.Mock, [CreateTemplateRequestData]> = jest.fn(); + /** + * Fixture associated to function delete + */ + public delete: jest.Mock, [DeleteTemplateRequestData]> = jest.fn(); + /** + * Fixture associated to function get + */ + public get: jest.Mock, [GetTemplateRequestData]> = jest.fn(); + /** + * Fixture associated to function list + */ + public list: jest.Mock, [ListTemplatesRequestData]> = jest.fn(); + /** + * Fixture associated to function update + */ + public update: jest.Mock, [UpdateTemplateRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/templates-v1/templates-v1-api.ts b/packages/conversation/src/rest/v1/templates-v1/templates-v1-api.ts new file mode 100644 index 00000000..cd970e13 --- /dev/null +++ b/packages/conversation/src/rest/v1/templates-v1/templates-v1-api.ts @@ -0,0 +1,184 @@ +import { + V1Template, + V1ListTemplatesResponse, +} from '../../../models'; +import { + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface CreateTemplateRequestData { + /** Required. The template to create. */ + 'createTemplateRequestBody': V1Template; +} +export interface DeleteTemplateRequestData { + /** Required. The ID of the template to fetch. */ + 'template_id': string; +} +export interface GetTemplateRequestData { + /** Required. The ID of the template to fetch. */ + 'template_id': string; +} +export interface ListTemplatesRequestData { +} +export interface UpdateTemplateRequestData { + /** The id of the template to be updated. Specified or automatically generated during template creation. Unique per project. */ + 'template_id': string; + /** Required. The updated template. */ + 'updateTemplateRequestBody': V1Template; + /** The set of field mask paths. */ + 'update_mask'?: Array; +} + +export class TemplatesV1Api extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'TemplatesV1Api'); + } + + /** + * Creates a template + * + * @param { CreateTemplateRequestData } data - The data to provide to the API call. + */ + public async create(data: CreateTemplateRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody + = data['createTemplateRequestBody'] ? JSON.stringify(data['createTemplateRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/templates`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'CreateTemplate', + }); + } + + /** + * Delete a template. + * + * @param { DeleteTemplateRequestData } data - The data to provide to the API call. + */ + public async delete(data: DeleteTemplateRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/templates/${data['template_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'DeleteTemplate', + }); + } + + /** + * Get a template + * + * @param { GetTemplateRequestData } data - The data to provide to the API call. + */ + public async get(data: GetTemplateRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/templates/${data['template_id']}`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'GetTemplate', + }); + } + + /** + * List all templates belonging to a project ID. + * + * @param { ListTemplatesRequestData } data - The data to provide to the API call. + */ + public async list(data: ListTemplatesRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/templates`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'ListTemplates', + }); + } + + /** + * Updates a template. + * + * @param { UpdateTemplateRequestData } data - The data to provide to the API call. + */ + public async update(data: UpdateTemplateRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, ['update_mask']); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody + = data['updateTemplateRequestBody'] ? JSON.stringify(data['updateTemplateRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v1/projects/${this.client.apiClientOptions.projectId}/templates/${data['template_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'PATCH', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'UpdateTemplate', + }); + } + +} diff --git a/packages/conversation/src/rest/v1/templates-v2/index.ts b/packages/conversation/src/rest/v1/templates-v2/index.ts new file mode 100644 index 00000000..702c6ff0 --- /dev/null +++ b/packages/conversation/src/rest/v1/templates-v2/index.ts @@ -0,0 +1,2 @@ +export * from './templates-v2-api'; +export * from './templates-v2-api.jest.fixture'; diff --git a/packages/conversation/src/rest/v1/templates-v2/templates-v2-api.jest.fixture.ts b/packages/conversation/src/rest/v1/templates-v2/templates-v2-api.jest.fixture.ts new file mode 100644 index 00000000..9d6fc0e6 --- /dev/null +++ b/packages/conversation/src/rest/v1/templates-v2/templates-v2-api.jest.fixture.ts @@ -0,0 +1,31 @@ +import { V2ListTemplatesResponse, V2ListTranslationsResponse, V2TemplateResponse } from '../../../models'; +import { TemplatesV2Api, V2CreateTemplateRequestData, V2DeleteTemplateRequestData, V2GetTemplateRequestData, V2ListTemplatesRequestData, V2ListTranslationsRequestData, V2UpdateTemplateRequestData } from './templates-v2-api'; + +export class TemplatesV2ApiFixture implements Partial> { + + /** + * Fixture associated to function create + */ + public create: jest.Mock, [V2CreateTemplateRequestData]> = jest.fn(); + /** + * Fixture associated to function delete + */ + public delete: jest.Mock, [V2DeleteTemplateRequestData]> = jest.fn(); + /** + * Fixture associated to function get + */ + public get: jest.Mock, [V2GetTemplateRequestData]> = jest.fn(); + /** + * Fixture associated to function list + */ + public list: jest.Mock, [V2ListTemplatesRequestData]> = jest.fn(); + /** + * Fixture associated to function listTranslations + */ + public listTranslations: jest.Mock, [V2ListTranslationsRequestData]> = jest.fn(); + /** + * Fixture associated to function update + */ + public update: jest.Mock, [V2UpdateTemplateRequestData]> = jest.fn(); +} + diff --git a/packages/conversation/src/rest/v1/templates-v2/templates-v2-api.ts b/packages/conversation/src/rest/v1/templates-v2/templates-v2-api.ts new file mode 100644 index 00000000..abca8e56 --- /dev/null +++ b/packages/conversation/src/rest/v1/templates-v2/templates-v2-api.ts @@ -0,0 +1,220 @@ +import { + V2ListTemplatesResponse, + V2ListTranslationsResponse, + V2Template, + V2TemplateResponse, +} from '../../../models'; +import { + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface V2CreateTemplateRequestData { + /** Required. The template to create. */ + 'createTemplateRequestBody': V2Template; +} +export interface V2DeleteTemplateRequestData { + /** Required. The ID of the template to delete. */ + 'template_id': string; +} +export interface V2GetTemplateRequestData { + /** Required. The ID of the template to fetch. */ + 'template_id': string; +} +export interface V2ListTemplatesRequestData { +} +export interface V2ListTranslationsRequestData { + /** Required. The template ID. */ + 'template_id': string; + /** Optional. The translation's language code. */ + 'language_code'?: string; + /** Optional. The translation's version. */ + 'translation_version'?: string; +} +export interface V2UpdateTemplateRequestData { + /** The id of the template to be updated. Specified or automatically generated during template creation. Unique per project. */ + 'template_id': string; + /** Required. The updated template. */ + 'updateTemplateRequestBody': V2Template; +} + +export class TemplatesV2Api extends ConversationDomainApi { + + /** + * Initialize your interface + * + * @param {SinchClientParameters} sinchClientParameters - The parameters used to initialize the API Client. + */ + constructor(sinchClientParameters: SinchClientParameters) { + super(sinchClientParameters, 'TemplatesV2Api'); + } + + /** + * Creates a template + * + * @param { V2CreateTemplateRequestData } data - The data to provide to the API call. + */ + public async create(data: V2CreateTemplateRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody + = data['createTemplateRequestBody'] ? JSON.stringify(data['createTemplateRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v2/projects/${this.client.apiClientOptions.projectId}/templates`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'V2CreateTemplate', + }); + } + + /** + * Delete a template. + * + * @param { V2DeleteTemplateRequestData } data - The data to provide to the API call. + */ + public async delete(data: V2DeleteTemplateRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v2/projects/${this.client.apiClientOptions.projectId}/templates/${data['template_id']}`; + + const requestOptions + = await this.client.prepareOptions(basePathUrl, 'DELETE', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'V2DeleteTemplate', + }); + } + + /** + * Get a template + * + * @param { V2GetTemplateRequestData } data - The data to provide to the API call. + */ + public async get(data: V2GetTemplateRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v2/projects/${this.client.apiClientOptions.projectId}/templates/${data['template_id']}`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'V2GetTemplate', + }); + } + + /** + * List all templates belonging to a project ID. + * + * @param { V2ListTemplatesRequestData } data - The data to provide to the API call. + */ + public async list(data: V2ListTemplatesRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v2/projects/${this.client.apiClientOptions.projectId}/templates`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'V2ListTemplates', + }); + } + + /** + * List translations for a template + * + * @param { V2ListTranslationsRequestData } data - The data to provide to the API call. + */ + public async listTranslations(data: V2ListTranslationsRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams( + data, + ['language_code', 'translation_version']); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = ''; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v2/projects/${this.client.apiClientOptions.projectId}/templates/${data['template_id']}/translations`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'V2ListTranslations', + }); + } + + /** + * Updates a template. + * + * @param { V2UpdateTemplateRequestData } data - The data to provide to the API call. + */ + public async update(data: V2UpdateTemplateRequestData): Promise { + this.client = this.getSinchClient(); + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody + = data['updateTemplateRequestBody'] ? JSON.stringify(data['updateTemplateRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.basePath}/v2/projects/${this.client.apiClientOptions.projectId}/templates/${data['template_id']}`; + + const requestOptions = await this.client.prepareOptions(basePathUrl, 'PUT', getParams, headers, body || undefined); + const url = this.client.prepareUrl(requestOptions.basePath, requestOptions.queryParams); + + return this.client.processCall({ + url, + requestOptions, + apiName: this.apiName, + operationId: 'V2UpdateTemplate', + }); + } + +} diff --git a/packages/conversation/tests/models/v1/helper.test.ts b/packages/conversation/tests/models/v1/helper.test.ts new file mode 100644 index 00000000..8d449a5e --- /dev/null +++ b/packages/conversation/tests/models/v1/helper.test.ts @@ -0,0 +1,378 @@ +import { + CardMessage, CardMessageItem, + CarouselMessage, CarouselMessageItem, + ChoiceMessage, ChoiceMessageItem, + ListMessage, ListMessageItem, + LocationMessage, LocationMessageItem, + MediaMessage, MediaMessageItem, + TemplateMessage, TemplateMessageItem, + TextMessage, TextMessageItem, + V2TemplateTranslation, + MessageType, + templateV1Helper, + templateV2Helper, +} from '../../../src'; + +const textItem: TextMessageItem = { + text: 'text message', +}; + +const textMessage: TextMessage = { + text_message: textItem, +}; + +const cardMessageItem: CardMessageItem = { + title: 'title', + description: 'description', + media_message: { + url: 'url', + }, + height: 'MEDIUM', + choices: [ + { + text_message: { + text: 'Strawberry', + }, + }, + { + text_message: { + text: 'Blueberry', + }, + }, + ], +}; + +const cardMessage: CardMessage = { + card_message: cardMessageItem, +}; + +const carouselMessageItem: CarouselMessageItem = { + cards: [ + { + title: 'card #1', + description: 'description #1', + media_message: { + url: 'https://url1.com', + }, + choices: [ + { + text_message: { + text: 'This is the card #1', + }, + }, + ], + }, + { + title: 'card #2', + description: 'description #2', + media_message: { + url: 'https://url2.com', + }, + choices: [ + { + url_message: { + title: 'Website', + url: 'https://website.com', + }, + }, + ], + }, + { + title: 'card #3', + description: 'description #3', + media_message: { + url: 'https://url3.com', + }, + choices: [ + { + call_message: { + title: 'Support line', + phone_number: '46732000000', + }, + }, + ], + }, + ], +}; + +const carouselMessage: CarouselMessage = { + carousel_message: carouselMessageItem, +}; + +const choiceMessageItem: ChoiceMessageItem = { + text_message: { + text: 'Choose your icecream flavor', + }, + choices: [ + { + text_message: { + text: 'Strawberry', + }, + }, + { + text_message: { + text: 'Blueberry', + }, + }, + ], +}; + +const choiceMessage: ChoiceMessage = { + choice_message: choiceMessageItem, +}; + +const locationMessageItem: LocationMessageItem = { + title: 'Phare d\'Eckmühl', + label: 'Pointe de Penmarch', + coordinates: { + latitude: 47.7981899, + longitude: -4.3727685, + }, +}; + +const locationMessage: LocationMessage = { + location_message: locationMessageItem, +}; + +const mediaMessageItem: MediaMessageItem = { + url: 'https://url-to-media.com', + thumbnail_url: 'https://url-to-thumbnail.com', +}; + +const mediaMessage: MediaMessage = { + media_message: mediaMessageItem, +}; + +const templateMessageItem: TemplateMessageItem = { + omni_template: { + template_id: 'templateId', + version: '1', + language_code: 'en-US', + parameters: { + name: 'Value for the "name" parameter used in the version 1 and language "en-US" of the template', + }, + }, + channel_template: { + 'KAKAOTALK': { + template_id: 'templateIdForKakaoTalk', + version: '1', + language_code: 'en-US', + }, + }, +}; + +const templateMessage: TemplateMessage = { + template_message: templateMessageItem, +}; + +const listMessageItem: ListMessageItem = { + title: 'Choose your icecream flavor', + description: 'The best icecream in town!', + sections: [ + { + title: 'Fruit flavors', + items: [ + { + choice: { + title: 'Strawberry', + postback_data: 'Strawberry postback', + }, + }, + { + choice: { + title: 'Blueberry', + postback_data: 'Blueberry postback', + }, + }, + ], + }, + { + title: 'Other flavors', + items: [ + { + choice: { + title: 'Chocolate', + postback_data: 'Chocolate postback', + }, + }, + { + choice: { + title: 'Vanilla', + postback_data: 'Vanilla postback', + }, + }, + ], + }, + ], + message_properties: { + menu: 'menu text', + }, +}; + +const listMessage: ListMessage = { + list_message: listMessageItem, +}; + +describe('Conversation models helpers', () => { + + describe('Templates V1 helper', () => { + it('should build a TextMessage', () => { + const builtMessage = templateV1Helper.buildTextMessageContent(textItem); + expect(builtMessage).toBe(JSON.stringify(textMessage)); + }); + + it('should build a CardMessage', () => { + const builtMessage = templateV1Helper.buildCardMessageContent(cardMessageItem); + expect(builtMessage).toBe(JSON.stringify(cardMessage)); + }); + + it('should build a CarouselMessage', () => { + const builtMessage = templateV1Helper.buildCarouselMessageContent(carouselMessageItem); + expect(builtMessage).toBe(JSON.stringify(carouselMessage)); + }); + + it('should build a ChoiceMessage', () => { + const builtMessage = templateV1Helper.buildChoiceMessageContent(choiceMessageItem); + expect(builtMessage).toBe(JSON.stringify(choiceMessage)); + }); + + it('should build a LocationMessage', () => { + const builtMessage = templateV1Helper.buildLocationMessageContent(locationMessageItem); + expect(builtMessage).toBe(JSON.stringify(locationMessage)); + }); + + it('should build a MediaMessage', () => { + const builtMessage = templateV1Helper.buildMediaMessageContent(mediaMessageItem); + expect(builtMessage).toBe(JSON.stringify(mediaMessage)); + }); + + it('should build a TemplateMessage', () => { + const builtMessage = templateV1Helper.buildTemplateMessageContent(templateMessageItem); + expect(builtMessage).toBe(JSON.stringify(templateMessage)); + }); + + it('should build a ListMessage', () => { + const builtMessage = templateV1Helper.buildListMessageContent(listMessageItem); + expect(builtMessage).toBe(JSON.stringify(listMessage)); + }); + }); + + describe('Templates V2 helper', () => { + it('should build a TextMessage', () => { + const builtTextMessage = templateV2Helper.buildTextMessageContent(textItem); + expect(builtTextMessage).toEqual(textMessage); + }); + + it('should build a CardMessage', () => { + const builtTextMessage = templateV2Helper.buildCardMessageContent(cardMessageItem); + expect(builtTextMessage).toEqual(cardMessage); + }); + + it('should build a CarouselMessage', () => { + const builtMessage = templateV2Helper.buildCarouselMessageContent(carouselMessageItem); + expect(builtMessage).toEqual(carouselMessage); + }); + + it('should build a ChoiceMessage', () => { + const builtMessage = templateV2Helper.buildChoiceMessageContent(choiceMessageItem); + expect(builtMessage).toEqual(choiceMessage); + }); + + it('should build a LocationMessage', () => { + const builtMessage = templateV2Helper.buildLocationMessageContent(locationMessageItem); + expect(builtMessage).toEqual(locationMessage); + }); + + it('should build a MediaMessage', () => { + const builtMessage = templateV2Helper.buildMediaMessageContent(mediaMessageItem); + expect(builtMessage).toEqual(mediaMessage); + }); + + it('should build a TemplateMessage', () => { + const builtMessage = templateV2Helper.buildTemplateMessageContent(templateMessageItem); + expect(builtMessage).toEqual(templateMessage); + }); + + it('should build a ListMessage', () => { + const builtMessage = templateV2Helper.buildListMessageContent(listMessageItem); + expect(builtMessage).toEqual(listMessage); + }); + + it('should get the message content from the translation', () => { + let templateTranslation: V2TemplateTranslation; + const translationIdentifier = { + version: '1', + language_code: 'en-US', + }; + templateTranslation = { + ...translationIdentifier, + ...textMessage, + }; + expect(templateV2Helper.getMessageFromTranslation(templateTranslation).type).toBe(MessageType.TEXT); + + templateTranslation = { + ...translationIdentifier, + ...cardMessage, + }; + expect(templateV2Helper.getMessageFromTranslation(templateTranslation).type).toBe(MessageType.CARD); + + templateTranslation = { + ...translationIdentifier, + ...choiceMessage, + }; + expect(templateV2Helper.getMessageFromTranslation(templateTranslation).type).toBe(MessageType.CHOICE); + + templateTranslation = { + ...translationIdentifier, + ...carouselMessage, + }; + expect(templateV2Helper.getMessageFromTranslation(templateTranslation).type).toBe(MessageType.CAROUSEL); + + templateTranslation = { + ...translationIdentifier, + ...listMessage, + }; + expect(templateV2Helper.getMessageFromTranslation(templateTranslation).type).toBe(MessageType.LIST); + + templateTranslation = { + ...translationIdentifier, + ...locationMessage, + }; + expect(templateV2Helper.getMessageFromTranslation(templateTranslation).type).toBe(MessageType.LOCATION); + + templateTranslation = { + ...translationIdentifier, + ...mediaMessage, + }; + expect(templateV2Helper.getMessageFromTranslation(templateTranslation).type).toBe(MessageType.MEDIA); + + templateTranslation = { + ...translationIdentifier, + ...templateMessage, + }; + expect(templateV2Helper.getMessageFromTranslation(templateTranslation).type).toBe(MessageType.TEMPLATE); + }); + + it('should filter out the latest translations', () => { + const version1Translation: V2TemplateTranslation = { + version: '1', + language_code: 'en-US', + text_message: { + text: 'text', + }, + }; + const latestTranslation: V2TemplateTranslation = { + version: 'latest', + language_code: 'en-US', + text_message: { + text: 'text', + }, + }; + const translations = [version1Translation, latestTranslation]; + const filteredTranslations = templateV2Helper.getPreviousTranslations(translations); + expect(filteredTranslations.length).toBe(1); + expect(filteredTranslations[0].version).toBe('1'); + }); + }); + +}); diff --git a/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts b/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts index 6a0252e0..4ee62a91 100644 --- a/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts +++ b/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts @@ -1,7 +1,8 @@ -import { ConversationApi, Region, UnifiedCredentials } from '../../../src'; +import { ConversationDomainApi } from '../../../src/rest/v1/conversation-domain-api'; +import { Region, UnifiedCredentials } from '@sinch/sdk-client'; describe('Conversation API', () => { - let conversationApi: ConversationApi; + let conversationApi: ConversationDomainApi; let params: UnifiedCredentials; beforeEach(() => { @@ -13,7 +14,7 @@ describe('Conversation API', () => { }); it('should initialize the client with the default "us" region', () => { - conversationApi = new ConversationApi(params); + conversationApi = new ConversationDomainApi(params, 'dummy'); conversationApi.getSinchClient(); expect(conversationApi.client).toBeDefined(); expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://us.conversation.api.sinch.com'); @@ -21,16 +22,16 @@ describe('Conversation API', () => { it('should change the URL when specifying a different region', () => { params.region = Region.EUROPE; - conversationApi = new ConversationApi(params); + conversationApi = new ConversationDomainApi(params, 'dummy'); conversationApi.getSinchClient(); expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://eu.conversation.api.sinch.com'); }); it('should log a warning when using an unsupported region', async () => { params.region = Region.CANADA; - conversationApi = new ConversationApi(params); + conversationApi = new ConversationDomainApi(params, 'dummy'); const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation(() => {}); - await conversationApi.getSinchClient(); + conversationApi.getSinchClient(); // Add a small delay to allow jest to capture the warning setTimeout(() => { expect(consoleWarnSpy).toHaveBeenCalledWith('The region \'ca\' is not supported for the Conversation API'); @@ -39,10 +40,36 @@ describe('Conversation API', () => { }); it('should set a custom URL', () => { - conversationApi = new ConversationApi(params); + conversationApi = new ConversationDomainApi(params, 'dummy'); conversationApi.setBasePath('https:/foo.com'); expect(conversationApi.client).toBeDefined(); expect(conversationApi.client?.apiClientOptions.basePath).toBe('https:/foo.com'); }); + it ('should update the region', () => { + conversationApi = new ConversationDomainApi(params, 'dummy'); + conversationApi.setRegion(Region.EUROPE); + conversationApi.getSinchClient(); + expect(conversationApi.client).toBeDefined(); + expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://eu.conversation.api.sinch.com'); + }); + + it ('should update the template v1 region', () => { + conversationApi = new ConversationDomainApi(params, 'TemplatesV1Api'); + conversationApi.getSinchClient(); + expect(conversationApi.client).toBeDefined(); + expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://us.template.api.sinch.com'); + conversationApi.setRegion(Region.EUROPE); + expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://eu.template.api.sinch.com'); + }); + + it ('should update the template v2 region', () => { + conversationApi = new ConversationDomainApi(params, 'TemplatesV2Api'); + conversationApi.getSinchClient(); + expect(conversationApi.client).toBeDefined(); + expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://us.template.api.sinch.com'); + conversationApi.setRegion(Region.EUROPE); + expect(conversationApi.client?.apiClientOptions.basePath).toBe('https://eu.template.api.sinch.com'); + }); + }); diff --git a/packages/conversation/tests/rest/v1/templates-v1/templates-v1-api.test.ts b/packages/conversation/tests/rest/v1/templates-v1/templates-v1-api.test.ts new file mode 100644 index 00000000..7cf47aa2 --- /dev/null +++ b/packages/conversation/tests/rest/v1/templates-v1/templates-v1-api.test.ts @@ -0,0 +1,247 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { + DeleteTemplateRequestData, + GetTemplateRequestData, + ListTemplatesRequestData, + UpdateTemplateRequestData, + V1ListTemplatesResponse, + V1Template, + TemplatesV1Api, + TemplatesV1ApiFixture, + CreateTemplateRequestData } from '../../../../src'; + +describe('TemplatesV1Api', () => { + let templatesV1Api: TemplatesV1Api; + let fixture: TemplatesV1ApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new TemplatesV1ApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + templatesV1Api = new TemplatesV1Api(credentials); + }); + + + describe ('createTemplate', () => { + it('should make a POST request to create a template V1', async () => { + // Given + const requestData: CreateTemplateRequestData = { + createTemplateRequestBody: { + description: 'Template description', + default_translation: 'en-US', + translations: [ + { + language_code: 'en-US', + version: '1', + content: 'Hello ${name}', + variables: [ + { + key: 'name', + preview_value: 'John', + }, + ], + }, + ], + }, + }; + const expectedResponse: V1Template = { + id: 'templateId', + description: 'Template description', + translations: [ + { + language_code: 'en-US', + content: 'Hello ${name}', + version: '1', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + variables: [ + { + key: 'name', + preview_value: 'John', + }, + ], + }, + ], + default_translation: 'en-US', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + channel: 'UNSPECIFIED', + }; + + // When + fixture.create.mockResolvedValue(expectedResponse); + templatesV1Api.create = fixture.create; + const response = await templatesV1Api.create(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.create).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('deleteTemplate', () => { + it('should make a DELETE request to delete the template associated to the ID', async () => { + // Given + const requestData: DeleteTemplateRequestData = { + template_id: 'templateId', + }; + const expectedResponse: any = {}; + + // When + fixture.delete.mockResolvedValue(expectedResponse); + templatesV1Api.delete = fixture.delete; + const response = await templatesV1Api.delete(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.delete).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('getTemplate', () => { + it('should make a GET request to get the template associated to the ID', async () => { + // Given + const requestData: GetTemplateRequestData = { + template_id: 'templateId', + }; + const expectedResponse: V1Template = { + id: 'templateId', + description: 'Template description', + translations: [ + { + language_code: 'en-US', + content: 'Hello ${name}', + version: '1', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + variables: [ + { + key: 'name', + preview_value: 'John', + }, + ], + }, + ], + default_translation: 'en-US', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + channel: 'UNSPECIFIED', + }; + + // When + fixture.get.mockResolvedValue(expectedResponse); + templatesV1Api.get = fixture.get; + const response = await templatesV1Api.get(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.get).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('listTemplates', () => { + it('should make a GET request to list the templates belonging to the project ID', async () => { + // Given + const requestData: ListTemplatesRequestData = {}; + const expectedResponse: V1ListTemplatesResponse = { + templates: [ + { + id: 'templateId', + description: 'Template description', + translations: [ + { + language_code: 'en-US', + content: 'Hello ${name}', + version: '1', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + variables: [ + { + key: 'name', + preview_value: 'John', + }, + ], + }, + ], + default_translation: 'en-US', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + channel: 'UNSPECIFIED', + }, + ], + }; + + // When + fixture.list.mockResolvedValue(expectedResponse); + templatesV1Api.list = fixture.list; + const response = await templatesV1Api.list(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.list).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('updateTemplate', () => { + it('should make a PATCH request to update the template associated to the ID', async () => { + // Given + const requestData: UpdateTemplateRequestData = { + template_id: 'templateId', + updateTemplateRequestBody: { + description: 'Updated description', + default_translation: 'fr-FR', + translations: [ + { + language_code: 'fr-FR', + content: 'Bonjour ${name}', + variables: [ + { + key: 'name', + preview_value: 'John', + }, + ], + }, + ], + }, + }; + const expectedResponse: V1Template = { + id: 'templateId', + description: 'Updated description', + // Note that the translation array is entirely replaced by the one sent in the request + // If you want to preserve the previous translations, you need to send them again + translations: [ + { + language_code: 'fr-FR', + content: 'Bonjour ${name}', + version: '', + create_time: new Date('2024-02-07T22:16:07Z'), + update_time: new Date('2024-02-07T22:16:07Z'), + variables: [ + { + key: 'name', + preview_value: 'John', + }, + ], + }, + ], + default_translation: 'fr-FR', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T22:16:07Z'), + channel: 'UNSPECIFIED', + }; + + // When + fixture.update.mockResolvedValue(expectedResponse); + templatesV1Api.update = fixture.update; + const response = await templatesV1Api.update(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.update).toHaveBeenCalledWith(requestData); + }); + }); +}); diff --git a/packages/conversation/tests/rest/v1/templates-v2/templates-v2-api.test.ts b/packages/conversation/tests/rest/v1/templates-v2/templates-v2-api.test.ts new file mode 100644 index 00000000..05e35820 --- /dev/null +++ b/packages/conversation/tests/rest/v1/templates-v2/templates-v2-api.test.ts @@ -0,0 +1,365 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { + V2CreateTemplateRequestData, + V2DeleteTemplateRequestData, + V2GetTemplateRequestData, + V2ListTemplatesRequestData, + V2ListTemplatesResponse, + V2ListTranslationsRequestData, + V2UpdateTemplateRequestData, + V2ListTranslationsResponse, + V2TemplateResponse, + TemplatesV2Api, + TemplatesV2ApiFixture, +} from '../../../../src'; + +describe('TemplatesV2Api', () => { + let templatesV2Api: TemplatesV2Api; + let fixture: TemplatesV2ApiFixture; + let credentials: SinchClientParameters; + + beforeEach(() => { + fixture = new TemplatesV2ApiFixture(); + credentials = { + projectId: 'PROJECT_ID', + keyId: 'KEY_ID', + keySecret: 'KEY_SECRET', + }; + templatesV2Api = new TemplatesV2Api(credentials); + }); + + + describe ('v2CreateTemplate', () => { + it('should make a POST request to create a template V1', async () => { + // Given + const requestData: V2CreateTemplateRequestData = { + createTemplateRequestBody: { + description: 'Template v2 description', + default_translation: 'en-US', + translations: [ + { + language_code: 'en-US', + version: '1', + location_message: { + title: 'title', + coordinates: { + latitude: 0, + longitude: 0, + }, + label: 'label', + }, + }, + ], + }, + }; + const expectedResponse: V2TemplateResponse = { + id: 'templateV2Id', + description: 'Template v2 description', + version: 1, + translations: [ + { + language_code: 'en-US', + version: '1', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + location_message: { + title: 'title', + coordinates: { + latitude: 0, + longitude: 0, + }, + label: 'label', + }, + channel_template_overrides: {}, + }, + ], + default_translation: 'en-US', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + }; + + // When + fixture.create.mockResolvedValue(expectedResponse); + templatesV2Api.create = fixture.create; + const response = await templatesV2Api.create(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.create).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('v2DeleteTemplate', () => { + it('should make a DELETE request to delete the template associated to the ID', async () => { + // Given + const requestData: V2DeleteTemplateRequestData = { + template_id: 'templateV2Id', + }; + const expectedResponse: any = {}; + + // When + fixture.delete.mockResolvedValue(expectedResponse); + templatesV2Api.delete = fixture.delete; + const response = await templatesV2Api.delete(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.delete).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('v2GetTemplate', () => { + it('should make a GET request to get the template associated to the ID', async () => { + // Given + const requestData: V2GetTemplateRequestData = { + template_id: 'templateV2Id', + }; + const expectedResponse: V2TemplateResponse = { + id: 'templateV2Id', + description: 'Template v2 description', + version: 1, + translations: [ + { + language_code: 'en-US', + version: '1', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + location_message: { + title: 'title', + coordinates: { + latitude: 0, + longitude: 0, + }, + label: 'label', + }, + channel_template_overrides: {}, + }, + ], + default_translation: 'en-US', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + }; + + // When + fixture.get.mockResolvedValue(expectedResponse); + templatesV2Api.get = fixture.get; + const response = await templatesV2Api.get(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.get).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('v2ListTemplates', () => { + it('should make a GET request to list the templates belonging to the project ID', async () => { + // Given + const requestData: V2ListTemplatesRequestData = {}; + const expectedResponse: V2ListTemplatesResponse = { + templates: [ + { + id: 'templateV2Id', + description: 'Template v2 description', + version: 1, + translations: [ + { + language_code: 'en-US', + version: '1', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + location_message: { + title: 'title', + coordinates: { + latitude: 0, + longitude: 0, + }, + label: 'label', + }, + channel_template_overrides: {}, + }, + ], + default_translation: 'en-US', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + }, + ], + }; + + // When + fixture.list.mockResolvedValue(expectedResponse); + templatesV2Api.list = fixture.list; + const response = await templatesV2Api.list(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.list).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('v2ListTranslations', () => { + // eslint-disable-next-line max-len + it('should make a GET request to list the translations belonging to the template associated to the ID', async () => { + // Given + const requestData: V2ListTranslationsRequestData = { + template_id: 'templateV2Id', + language_code: 'en-US', + translation_version: 'latest', + }; + const expectedResponse: V2ListTranslationsResponse = { + translations: [ + { + language_code: 'en-US', + version: 'latest', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T15:25:42Z'), + location_message: { + title: 'title', + coordinates: { + latitude: 0, + longitude: 0, + }, + label: 'label', + }, + channel_template_overrides: {}, + }, + ], + }; + + // When + fixture.listTranslations.mockResolvedValue(expectedResponse); + templatesV2Api.listTranslations = fixture.listTranslations; + const response = await templatesV2Api.listTranslations(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.listTranslations).toHaveBeenCalledWith(requestData); + }); + }); + + describe ('v2UpdateTemplate', () => { + it('should make a PUT request to update the template associated to the ID', async () => { + // Given + const requestData: V2UpdateTemplateRequestData = { + template_id: 'templateV2Id', + updateTemplateRequestBody: { + version: 1, + description: 'Updated description v2', + default_translation: 'fr-FR', + translations: [ + { + language_code: 'fr-FR', + list_message: { + title: 'Choose your icecream flavor', + description: 'The best icecream in town!', + sections: [ + { + title: 'Fruit flavors', + items: [ + { + choice: { + title: 'Strawberry', + postback_data: 'Strawberry postback', + }, + }, + { + choice: { + title: 'Blueberry', + postback_data: 'Blueberry postback', + }, + }, + ], + }, + { + title: 'Other flavors', + items: [ + { + choice: { + title: 'Chocolate', + postback_data: 'Chocolate postback', + }, + }, + { + choice: { + title: 'Vanilla', + postback_data: 'Vanilla postback', + }, + }, + ], + }, + ], + }, + version: '4', + }, + ], + }, + }; + const expectedResponse: V2TemplateResponse = { + id: 'templateV2Id', + description: 'Updated description v2', + version: 2, + translations: [ + { + language_code: 'fr-FR', + version: '4', + create_time: new Date('2024-02-07T17:33:56Z'), + update_time: new Date('2024-02-07T17:33:56Z'), + variables: [], + list_message: { + title: 'Choose your icecream flavor', + description: 'The best icecream in town!', + sections: [ + { + title: 'Fruit flavors', + items: [ + { + choice: { + title: 'Strawberry', + postback_data: 'Strawberry postback', + }, + }, + { + choice: { + title: 'Blueberry', + postback_data: 'Blueberry postback', + }, + }, + ], + }, + { + title: 'Other flavors', + items: [ + { + choice: { + title: 'Chocolate', + postback_data: 'Chocolate postback', + }, + }, + { + choice: { + title: 'Vanilla', + postback_data: 'Vanilla postback', + }, + }, + ], + }, + ], + }, + channel_template_overrides: {}, + }, + ], + default_translation: 'fr-FR', + create_time: new Date('2024-02-07T15:25:42Z'), + update_time: new Date('2024-02-07T17:33:56Z'), + }; + + // When + fixture.update.mockResolvedValue(expectedResponse); + templatesV2Api.update = fixture.update; + const response = await templatesV2Api.update(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(fixture.update).toHaveBeenCalledWith(requestData); + }); + }); +}); From 367d28b1e94470c20524cb2b56db89101d9f7de5 Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Tue, 13 Feb 2024 10:59:51 +0100 Subject: [PATCH 14/19] Fix merge issues --- .../webhooks/src/controller/app.controller.ts | 10 +- .../rest/v1/callbacks/callbacks-webhook.ts | 297 ++++++++++-------- .../v1/callbacks-webhook/callbacks-webhook.ts | 2 +- .../client/api-client-pagination-helper.ts | 5 +- .../src/utils/authorization.helper.ts | 39 ++- .../tests/utils/authorization.helper.test.ts | 61 +++- 6 files changed, 252 insertions(+), 162 deletions(-) diff --git a/examples/webhooks/src/controller/app.controller.ts b/examples/webhooks/src/controller/app.controller.ts index ae6f8fe4..585b3ae5 100644 --- a/examples/webhooks/src/controller/app.controller.ts +++ b/examples/webhooks/src/controller/app.controller.ts @@ -1,6 +1,7 @@ import { Body, Controller, Post, Req, Res } from '@nestjs/common'; import { Request, Response } from 'express'; import { + ConversationCallbackWebhooks, NumbersCallbackWebhooks, SmsCallbackWebhooks, VerificationCallbackWebhooks, @@ -35,13 +36,18 @@ export class AppController { @Post('/conversation') public conversation(@Req() request: Request, @Res() res: Response) { - const validated = validateWebhookSignature(SINCH_CONVERSATION_APP_SECRET, request.headers, request['rawBody']); + // Initialize the class that will be used to validate the request and parse it + const conversationCallbackWebhook = new ConversationCallbackWebhooks(SINCH_CONVERSATION_APP_SECRET); + // 1 - The first thing to do is to verify the request is legit and has not been tampered with + const validated = conversationCallbackWebhook.validateAuthenticationHeader(request.headers, request['rawBody']); if (!validated) { res.status(401).send('Invalid webhook signature'); return; } try { - const event = parseConversationEventNotification(request.body); + // 2 - Before acting on the request, it must be parsed to verify it's supported and to revive its content + const event = conversationCallbackWebhook.parseEvent(request.body); + // 3 - Once steps 1 and 2 are ok, delegate the event management to the Conversation service this.conversationService.handleEvent(event); res.status(200).send(); } catch (error) { diff --git a/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts b/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts index f905f135..de2ee88d 100644 --- a/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts +++ b/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts @@ -16,144 +16,177 @@ import { MessageInboundSmartConversationRedactionEvent, MessageSubmitEvent, OptInEvent, - OptOutEvent, SmartConversationsEvent, UnsupportedCallbackEvent, + OptOutEvent, + SmartConversationsEvent, + UnsupportedCallbackEvent, WebhookTrigger, } from '../../../models'; +import { CallbackProcessor, validateWebhookSignature } from '@sinch/sdk-client'; +import { IncomingHttpHeaders } from 'http'; interface WebhookTriggerEvent { trigger: WebhookTrigger; } export type ConversationWebhookEventParsed = ConversationWebhookEvent & WebhookTriggerEvent; -/** - * Add the trigger corresponding to the trigger - * 'message' <==> MESSAGE_INBOUND - * 'message_redaction' <==> MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION - * 'message_submit_notification' <==> MESSAGE_SUBMIT - * 'message_delivery_report' <==> MESSAGE_DELIVERY - * 'event' <==> EVENT_INBOUND - * 'event_delivery_report' <==> EVENT_DELIVERY - * 'conversation_start_notification' <==> CONVERSATION_START - * 'conversation_stop_notification' <==> CONVERSATION_STOP - * 'conversation_delete_notification' <==> CONVERSATION_DELETE - * 'contact_create_notification' <==> CONTACT_CREATE - * 'contact_delete_notification' <==> CONTACT_DELETE - * 'contact_merge_notification' <==> CONTACT_MERGE - * 'contact_update_notification' <==> CONTACT_UPDATE - * 'duplicated_identities' <==> CONTACT_IDENTITIES_DUPLICATION - * 'capability_notification' <==> CAPABILITY - * 'opt_in_notification' <==> OPT_IN - * 'opt_out_notification' <==> OPT_OUT - * 'channel_event_notification' <==> CHANNEL_EVENT - * 'unsupported_callback' <==> UNSUPPORTED - * 'smart_conversation_notification' <==> SMART_CONVERSATIONS - * - * @param {any} eventBody - The conversation event to parse - * @return {ConversationWebhookEventParsed} - Parsed conversation event. - * @throws {Error} If the eventBody is not valid or cannot be parsed. - */ -export const parseConversationEventNotification = (eventBody: any): ConversationWebhookEventParsed => { - if('message' in eventBody) { - return { - ...eventBody, - trigger: 'MESSAGE_INBOUND', - } as MessageInboundEvent; - } else if('message_redaction' in eventBody) { - return { - ...eventBody, - trigger: 'MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION', - } as MessageInboundSmartConversationRedactionEvent; - } else if('message_submit_notification' in eventBody) { - return { - ...eventBody, - trigger: 'MESSAGE_SUBMIT', - } as MessageSubmitEvent; - } else if('message_delivery_report' in eventBody) { - return { - ...eventBody, - trigger: 'MESSAGE_DELIVERY', - } as MessageDeliveryReceiptEvent; - } else if('event' in eventBody) { - return { - ...eventBody, - trigger: 'EVENT_INBOUND', - } as EventInbound; - } else if('event_delivery_report' in eventBody) { - return { - ...eventBody, - trigger: 'EVENT_DELIVERY', - } as EventDelivery; - } else if('conversation_start_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CONVERSATION_START', - } as ConversationStartEvent; - } else if('conversation_stop_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CONVERSATION_STOP', - } as ConversationStopEvent; - } else if('conversation_delete_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CONVERSATION_DELETE', - } as ConversationDeleteEvent; - } else if('contact_create_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CONTACT_CREATE', - } as ContactCreateEvent; - } else if('contact_delete_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CONTACT_DELETE', - } as ContactDeleteEvent; - } else if('contact_merge_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CONTACT_MERGE', - } as ContactMergeEvent; - } else if('contact_update_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CONTACT_UPDATE', - } as ContactUpdateEvent; - } else if('duplicated_identities' in eventBody) { - return { - ...eventBody, - trigger: 'CONTACT_IDENTITIES_DUPLICATION', - } as ContactIdentitiesDuplicationEvent; - } else if('capability_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CAPABILITY', - } as CapabilityEvent; - } else if('opt_in_notification' in eventBody) { - return { - ...eventBody, - trigger: 'OPT_IN', - } as OptInEvent; - } else if('opt_out_notification' in eventBody) { - return { - ...eventBody, - trigger: 'OPT_OUT', - } as OptOutEvent; - } else if('channel_event_notification' in eventBody) { - return { - ...eventBody, - trigger: 'CHANNEL_EVENT', - } as ChannelEvent; - } else if('unsupported_callback' in eventBody) { - return { - ...eventBody, - trigger: 'UNSUPPORTED', - } as UnsupportedCallbackEvent; - } else if('smart_conversation_notification' in eventBody) { - return { - ...eventBody, - trigger: 'SMART_CONVERSATIONS', - } as SmartConversationsEvent; - } else { - throw new Error('Unknown Conversation event to parse'); +export class ConversationCallbackWebhooks implements CallbackProcessor { + private readonly appSecret: string; + + constructor(appSecret: string) { + this.appSecret = appSecret; + } + + /** + * Validate authorization header for callback request + * @param {IncomingHttpHeaders} headers - Incoming request's headers + * @param {any} body - Incoming request's body + * @param {string} _path - Incoming request's path + * @param {string} _method - Incoming request's HTTP method + * @return {boolean} - true if the X-Sinch-Signature header is valid + */ + public validateAuthenticationHeader( + headers: IncomingHttpHeaders, + body: any, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _path?: string, _method?: string, + ): boolean { + return validateWebhookSignature( + this.appSecret, + headers, + body, + ); } -}; + + /** + * Add the trigger corresponding to the trigger + * 'message' <==> MESSAGE_INBOUND + * 'message_redaction' <==> MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION + * 'message_submit_notification' <==> MESSAGE_SUBMIT + * 'message_delivery_report' <==> MESSAGE_DELIVERY + * 'event' <==> EVENT_INBOUND + * 'event_delivery_report' <==> EVENT_DELIVERY + * 'conversation_start_notification' <==> CONVERSATION_START + * 'conversation_stop_notification' <==> CONVERSATION_STOP + * 'conversation_delete_notification' <==> CONVERSATION_DELETE + * 'contact_create_notification' <==> CONTACT_CREATE + * 'contact_delete_notification' <==> CONTACT_DELETE + * 'contact_merge_notification' <==> CONTACT_MERGE + * 'contact_update_notification' <==> CONTACT_UPDATE + * 'duplicated_identities' <==> CONTACT_IDENTITIES_DUPLICATION + * 'capability_notification' <==> CAPABILITY + * 'opt_in_notification' <==> OPT_IN + * 'opt_out_notification' <==> OPT_OUT + * 'channel_event_notification' <==> CHANNEL_EVENT + * 'unsupported_callback' <==> UNSUPPORTED + * 'smart_conversation_notification' <==> SMART_CONVERSATIONS + * + * @param {any} eventBody - The conversation event to parse + * @return {ConversationWebhookEventParsed} - Parsed conversation event. + * @throws {Error} If the eventBody is not valid or cannot be parsed. + */ + public parseEvent(eventBody: any): ConversationWebhookEventParsed { + if ('message' in eventBody) { + return { + ...eventBody, + trigger: 'MESSAGE_INBOUND', + } as MessageInboundEvent; + } else if ('message_redaction' in eventBody) { + return { + ...eventBody, + trigger: 'MESSAGE_INBOUND_SMART_CONVERSATION_REDACTION', + } as MessageInboundSmartConversationRedactionEvent; + } else if ('message_submit_notification' in eventBody) { + return { + ...eventBody, + trigger: 'MESSAGE_SUBMIT', + } as MessageSubmitEvent; + } else if ('message_delivery_report' in eventBody) { + return { + ...eventBody, + trigger: 'MESSAGE_DELIVERY', + } as MessageDeliveryReceiptEvent; + } else if ('event' in eventBody) { + return { + ...eventBody, + trigger: 'EVENT_INBOUND', + } as EventInbound; + } else if ('event_delivery_report' in eventBody) { + return { + ...eventBody, + trigger: 'EVENT_DELIVERY', + } as EventDelivery; + } else if ('conversation_start_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONVERSATION_START', + } as ConversationStartEvent; + } else if ('conversation_stop_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONVERSATION_STOP', + } as ConversationStopEvent; + } else if ('conversation_delete_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONVERSATION_DELETE', + } as ConversationDeleteEvent; + } else if ('contact_create_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_CREATE', + } as ContactCreateEvent; + } else if ('contact_delete_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_DELETE', + } as ContactDeleteEvent; + } else if ('contact_merge_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_MERGE', + } as ContactMergeEvent; + } else if ('contact_update_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_UPDATE', + } as ContactUpdateEvent; + } else if ('duplicated_identities' in eventBody) { + return { + ...eventBody, + trigger: 'CONTACT_IDENTITIES_DUPLICATION', + } as ContactIdentitiesDuplicationEvent; + } else if ('capability_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CAPABILITY', + } as CapabilityEvent; + } else if ('opt_in_notification' in eventBody) { + return { + ...eventBody, + trigger: 'OPT_IN', + } as OptInEvent; + } else if ('opt_out_notification' in eventBody) { + return { + ...eventBody, + trigger: 'OPT_OUT', + } as OptOutEvent; + } else if ('channel_event_notification' in eventBody) { + return { + ...eventBody, + trigger: 'CHANNEL_EVENT', + } as ChannelEvent; + } else if ('unsupported_callback' in eventBody) { + return { + ...eventBody, + trigger: 'UNSUPPORTED', + } as UnsupportedCallbackEvent; + } else if ('smart_conversation_notification' in eventBody) { + return { + ...eventBody, + trigger: 'SMART_CONVERSATIONS', + } as SmartConversationsEvent; + } else { + throw new Error('Unknown Conversation event to parse'); + } + }; +} diff --git a/packages/numbers/src/rest/v1/callbacks-webhook/callbacks-webhook.ts b/packages/numbers/src/rest/v1/callbacks-webhook/callbacks-webhook.ts index 92254c11..adf4e574 100644 --- a/packages/numbers/src/rest/v1/callbacks-webhook/callbacks-webhook.ts +++ b/packages/numbers/src/rest/v1/callbacks-webhook/callbacks-webhook.ts @@ -4,7 +4,7 @@ import { CallbackProcessor, validateSignatureHeader } from '@sinch/sdk-client'; export type NumbersCallback = CallbackPayload; -export class NumbersCallbackWebhooks implements CallbackProcessor{ +export class NumbersCallbackWebhooks implements CallbackProcessor { private readonly callbackSecret: string; diff --git a/packages/sdk-client/src/client/api-client-pagination-helper.ts b/packages/sdk-client/src/client/api-client-pagination-helper.ts index c61a296b..0a1b6b22 100644 --- a/packages/sdk-client/src/client/api-client-pagination-helper.ts +++ b/packages/sdk-client/src/client/api-client-pagination-helper.ts @@ -87,13 +87,14 @@ const updateQueryParamsAndSendRequest = ( ...requestOptions.queryParams, ...newParams, }; + const extractedParams = apiClient.extractQueryParams(newQueryParams, Object.keys(newQueryParams)); const newRequestOptions: RequestOptions = { ...requestOptions, - queryParams: newQueryParams, + queryParams: extractedParams, }; const newUrl = apiClient.prepareUrl( requestOptions.basePath, - newQueryParams, + extractedParams, ); return apiClient.processCallWithPagination({ url: newUrl, diff --git a/packages/sdk-client/src/utils/authorization.helper.ts b/packages/sdk-client/src/utils/authorization.helper.ts index bed9e19d..60e8ef1d 100644 --- a/packages/sdk-client/src/utils/authorization.helper.ts +++ b/packages/sdk-client/src/utils/authorization.helper.ts @@ -36,10 +36,17 @@ export const generateAuthorizationHeader = ( return `Application ${applicationKey}:${signature}`; }; +/** + * Validate webhook signature headers for Conversation callback. + * @param {string} secret - secret associated to the Conversation app + * @param {IncomingHttpHeaders} headers - Incoming request's headers + * @param {any} body - Incoming request's body + * @return {boolean} - true if the signature header is valid + */ export const validateWebhookSignature = ( secret: string, headers: IncomingHttpHeaders, - body: string, + body: any, ): boolean => { const normalizedHeaders = normalizeHeaders(headers); const nonce = getHeader(normalizedHeaders['x-sinch-webhook-signature-nonce']); @@ -58,21 +65,6 @@ export const validateWebhookSignature = ( return headerSignature === signature; }; -export const computeSignedData = ( - body: string, - nonce: string, - timestamp: string, -): string => { - return `${body}.${nonce}.${timestamp}`; -}; - -export const calculateWebhookSignature = ( - signedData: string, - secret: string, -): string => { - return crypto.createHmac('sha256', secret).update(signedData).digest('base64'); -}; - /** * Validate authorization header for callback request on application-signed protected endpoints (Verification and Voice webhooks) * @param {string} applicationKey - application key (from dashboard) related to the event @@ -160,6 +152,21 @@ const computeHmacSignature = (body: string, secret: string): string => { return crypto.createHmac('sha1', secret).update(body).digest('hex'); }; +export const computeSignedData = ( + body: string, + nonce: string, + timestamp: string, +): string => { + return `${body}.${nonce}.${timestamp}`; +}; + +export const calculateWebhookSignature = ( + signedData: string, + secret: string, +): string => { + return crypto.createHmac('sha256', secret).update(signedData).digest('base64'); +}; + const validateApplicationAuth = ( authorizationValue: string, normalizedHeaders: {[p: string]: string | string[]}, diff --git a/packages/sdk-client/tests/utils/authorization.helper.test.ts b/packages/sdk-client/tests/utils/authorization.helper.test.ts index 7b258782..9c1538cb 100644 --- a/packages/sdk-client/tests/utils/authorization.helper.test.ts +++ b/packages/sdk-client/tests/utils/authorization.helper.test.ts @@ -4,7 +4,9 @@ import { calculateWebhookSignature, computeSignedData, generateAuthorizationHeader, - validateAuthenticationHeader, validateSignatureHeader, + validateAuthenticationHeader, + validateSignatureHeader, + validateWebhookSignature, } from '../../src'; describe('Authorization validation', () => { @@ -219,6 +221,12 @@ describe('Authorization validation', () => { describe('Webhook signature (Conversation API)', () => { + const CONVERSATION_BODY = `{"app_id":"","accepted_time":"2021-10-18T17:49:13.813615Z","project_id":"e2df3a34-a71b-4448-9db5-a8d2baad28e4","contact_create_notification":{"contact":{"id":"01FJA8B466Y0R2GNXD78MD9SM1","channel_identities":[{"channel":"SMS","identity":"48123456789","app_id":""}],"display_name":"New Test Contact","email":"new.contact@email.com","external_id":"","metadata":"","language":"EN_US"}},"message_metadata":""}`; + const NONCE = '01FJA8B4A7BM43YGWSG9GBV067'; + const TIMESTAMP = '1634579353'; + const APP_SECRET = 'foo_secret1234'; + const VALID_SIGNATURE = '6bpJoRmFoXVjfJIVglMoJzYXxnoxRujzR4k2GOXewOE='; + it('should compute the signed data', () => { const body = 'body'; const nonce = 'nonce'; @@ -228,15 +236,50 @@ describe('Webhook signature (Conversation API)', () => { }); it('should calculate the right signature', () => { - // eslint-disable-next-line max-len - const body = '{"app_id":"","accepted_time":"2021-10-18T17:49:13.813615Z","project_id":"e2df3a34-a71b-4448-9db5-a8d2baad28e4","contact_create_notification":{"contact":{"id":"01FJA8B466Y0R2GNXD78MD9SM1","channel_identities":[{"channel":"SMS","identity":"48123456789","app_id":""}],"display_name":"New Test Contact","email":"new.contact@email.com","external_id":"","metadata":"","language":"EN_US"}},"message_metadata":""}'; - const nonce = '01FJA8B4A7BM43YGWSG9GBV067'; - const timestamp= '1634579353'; - const signedData = computeSignedData(body, nonce, timestamp); - const secret = 'foo_secret1234'; - const signature = calculateWebhookSignature(signedData, secret); + const signedData = computeSignedData(CONVERSATION_BODY, NONCE, TIMESTAMP); + const signature = calculateWebhookSignature(signedData, APP_SECRET); + + expect(signature).toEqual(VALID_SIGNATURE); + }); - expect(signature).toEqual('6bpJoRmFoXVjfJIVglMoJzYXxnoxRujzR4k2GOXewOE='); + it('should validate the signature header when valid', () => { + const headers = { + 'x-sinch-webhook-signature': VALID_SIGNATURE, + 'x-sinch-webhook-signature-algorithm': 'HmacSHA256', + 'x-sinch-webhook-signature-nonce': NONCE, + 'x-sinch-webhook-signature-timestamp': TIMESTAMP, + }; + const validated = validateWebhookSignature( + APP_SECRET, + headers, + CONVERSATION_BODY, + ); + expect(validated).toBeTruthy(); + }); + + it('should reject the signature header when missing', () => { + const headers = {}; + const validated = validateWebhookSignature( + APP_SECRET, + headers, + CONVERSATION_BODY, + ); + expect(validated).toBeFalsy(); + }); + + it('should reject the signature header when invalid', () => { + const headers = { + 'x-sinch-webhook-signature': 'invalid-signature', + 'x-sinch-webhook-signature-algorithm': 'HmacSHA256', + 'x-sinch-webhook-signature-nonce': NONCE, + 'x-sinch-webhook-signature-timestamp': TIMESTAMP, + }; + const validated = validateWebhookSignature( + APP_SECRET, + headers, + CONVERSATION_BODY, + ); + expect(validated).toBeFalsy(); }); }); From 003d206c29e859edf71566686236292d1fa9078d Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Tue, 13 Feb 2024 16:47:48 +0100 Subject: [PATCH 15/19] Add message builder helper --- .../src/services/conversation.service.ts | 27 ++--- .../src/models/v1/choice-item/choice-item.ts | 6 +- packages/conversation/src/models/v1/helper.ts | 109 ++++++++++-------- .../tests/models/v1/helper.test.ts | 44 ++++++- 4 files changed, 116 insertions(+), 70 deletions(-) diff --git a/examples/webhooks/src/services/conversation.service.ts b/examples/webhooks/src/services/conversation.service.ts index 5fae5a9a..80e9c5a9 100644 --- a/examples/webhooks/src/services/conversation.service.ts +++ b/examples/webhooks/src/services/conversation.service.ts @@ -3,9 +3,8 @@ import { SinchClient, ConversationWebhookEventParsed, ContactMessage, - MediaMessage, - TextMessage, SendMessageRequestData, + messageBuilder, } from '@sinch/sdk-core'; @Injectable() @@ -26,25 +25,19 @@ export class ConversationService { private buildTextMessage(contactMessage: ContactMessage) { if ('text_message' in contactMessage) { - return { - text_message: { - text: `Parrot mode 🦜: ${contactMessage.text_message.text}`, - } - } as TextMessage; + return messageBuilder.text({ + text: `Parrot mode 🦜: ${contactMessage.text_message.text}`, + }); } if ('media_message' in contactMessage) { - return { - media_message: { - url: contactMessage.media_message.url, - } - } as MediaMessage; + return messageBuilder.media({ + url: contactMessage.media_message.url, + }); } if ('fallback_message' in contactMessage) { - return { - text_message: { - text: `Error: ${contactMessage.fallback_message.reason.code} (${contactMessage.fallback_message.reason.sub_code})\n${contactMessage.fallback_message.reason.description}` - } - } as TextMessage + return messageBuilder.text({ + text: `Error: ${contactMessage.fallback_message.reason.code} (${contactMessage.fallback_message.reason.sub_code})\n${contactMessage.fallback_message.reason.description}` + }); } } diff --git a/packages/conversation/src/models/v1/choice-item/choice-item.ts b/packages/conversation/src/models/v1/choice-item/choice-item.ts index 0cdbe195..34c5dd46 100644 --- a/packages/conversation/src/models/v1/choice-item/choice-item.ts +++ b/packages/conversation/src/models/v1/choice-item/choice-item.ts @@ -1,4 +1,4 @@ -import { MediaMessage } from '../media-message'; +import { MediaMessageItem } from '../media-message'; export interface ChoiceItem { choice: ChoiceItemItem; @@ -10,8 +10,8 @@ export interface ChoiceItemItem { title: string; /** Optional parameter. The description (or subtitle) of this choice item. */ description?: string; - /** @see MediaMessage */ - media?: MediaMessage; + /** @see MediaMessageItem */ + media_message?: MediaMessageItem; /** Optional parameter. Postback data that will be returned in the MO if the user selects this option. */ postback_data?: string; } diff --git a/packages/conversation/src/models/v1/helper.ts b/packages/conversation/src/models/v1/helper.ts index b057f0d0..ebdf48c5 100644 --- a/packages/conversation/src/models/v1/helper.ts +++ b/packages/conversation/src/models/v1/helper.ts @@ -1,97 +1,108 @@ import { TextMessage, TextMessageItem } from './text-message'; import { CardMessage, CardMessageItem } from './card-message'; import { CarouselMessage, CarouselMessageItem } from './carousel-message'; -import { ChoiceMessage, ChoiceMessageItem } from './choice-message/choice-message'; +import { ChoiceMessage, ChoiceMessageItem } from './choice-message'; import { LocationMessage, LocationMessageItem } from './location-message'; import { MediaMessage, MediaMessageItem } from './media-message'; import { TemplateMessage, TemplateMessageItem } from './template-message'; import { ListMessage, ListMessageItem } from './list-message'; import { V2TemplateTranslation } from './v2-template-translation'; +export const messageBuilder = { + card: (cardMessageItem: CardMessageItem): CardMessage => { + return { + card_message: cardMessageItem, + } as CardMessage; + }, + carousel: (carouselMessageItem: CarouselMessageItem): CarouselMessage => { + return { + carousel_message: carouselMessageItem, + } as CarouselMessage; + }, + choice: (choiceMessageItem: ChoiceMessageItem): ChoiceMessage => { + return { + choice_message: choiceMessageItem, + } as ChoiceMessage; + }, + list: (listMessageItem: ListMessageItem): ListMessage => { + return { + list_message: listMessageItem, + } as ListMessage; + }, + location: (locationMessageItem: LocationMessageItem): LocationMessage => { + return { + location_message: locationMessageItem, + } as LocationMessage; + }, + media: (mediaMessageItem: MediaMessageItem): MediaMessage => { + return { + media_message: mediaMessageItem, + } as MediaMessage; + }, + template: (templateMessageItem: TemplateMessageItem): TemplateMessage => { + return { + template_message: templateMessageItem, + } as TemplateMessage; + }, + text: (textMessageItem: TextMessageItem): TextMessage => { + return { + text_message: textMessageItem, + } as TextMessage; + }, +}; + export const templateV1Helper = { buildTextMessageContent: (textMessageItem: TextMessageItem): string => { - return JSON.stringify({ - text_message: textMessageItem, - } as TextMessage); + return JSON.stringify(messageBuilder.text(textMessageItem)); }, buildCardMessageContent: (cardMessageItem: CardMessageItem): string => { - return JSON.stringify({ - card_message: cardMessageItem, - } as CardMessage); + return JSON.stringify(messageBuilder.card(cardMessageItem)); }, buildCarouselMessageContent: (carouselMessageItem: CarouselMessageItem): string => { - return JSON.stringify({ - carousel_message: carouselMessageItem, - } as CarouselMessage); + return JSON.stringify(messageBuilder.carousel(carouselMessageItem)); }, buildChoiceMessageContent: (choiceMessageItem: ChoiceMessageItem): string => { - return JSON.stringify({ - choice_message: choiceMessageItem, - } as ChoiceMessage); + return JSON.stringify(messageBuilder.choice(choiceMessageItem)); }, buildLocationMessageContent: (locationMessageItem: LocationMessageItem): string => { - return JSON.stringify({ - location_message: locationMessageItem, - } as LocationMessage); + return JSON.stringify(messageBuilder.location(locationMessageItem)); }, buildMediaMessageContent: (mediaMessageItem: MediaMessageItem): string => { - return JSON.stringify({ - media_message: mediaMessageItem, - } as MediaMessage); + return JSON.stringify(messageBuilder.media(mediaMessageItem)); }, buildTemplateMessageContent: (templateMessageItem: TemplateMessageItem): string => { - return JSON.stringify({ - template_message: templateMessageItem, - } as TemplateMessage); + return JSON.stringify(messageBuilder.template(templateMessageItem)); }, buildListMessageContent: (listMessageItem: ListMessageItem): string => { - return JSON.stringify({ - list_message: listMessageItem, - } as ListMessage); + return JSON.stringify(messageBuilder.list(listMessageItem)); }, }; export const templateV2Helper = { // Template V2 buildTextMessageContent: (textMessageItem: TextMessageItem): TextMessage => { - return { - text_message: textMessageItem, - } as TextMessage; + return messageBuilder.text(textMessageItem); }, buildCardMessageContent: (cardMessageItem: CardMessageItem): CardMessage => { - return { - card_message: cardMessageItem, - } as CardMessage; + return messageBuilder.card(cardMessageItem); }, buildCarouselMessageContent: (carouselMessageItem: CarouselMessageItem): CarouselMessage => { - return { - carousel_message: carouselMessageItem, - } as CarouselMessage; + return messageBuilder.carousel(carouselMessageItem); }, buildChoiceMessageContent: (choiceMessageItem: ChoiceMessageItem): ChoiceMessage => { - return { - choice_message: choiceMessageItem, - } as ChoiceMessage; + return messageBuilder.choice(choiceMessageItem); }, buildLocationMessageContent: (locationMessageItem: LocationMessageItem): LocationMessage => { - return { - location_message: locationMessageItem, - } as LocationMessage; + return messageBuilder.location(locationMessageItem); }, buildMediaMessageContent: (mediaMessageItem: MediaMessageItem): MediaMessage => { - return { - media_message: mediaMessageItem, - } as MediaMessage; + return messageBuilder.media(mediaMessageItem); }, buildTemplateMessageContent: (templateMessageItem: TemplateMessageItem): TemplateMessage => { - return { - template_message: templateMessageItem, - } as TemplateMessage; + return messageBuilder.template(templateMessageItem); }, buildListMessageContent: (listMessageItem: ListMessageItem): ListMessage => { - return { - list_message: listMessageItem, - } as ListMessage; + return messageBuilder.list(listMessageItem); }, getMessageFromTranslation: (translation: V2TemplateTranslation) => { if('text_message' in translation) { diff --git a/packages/conversation/tests/models/v1/helper.test.ts b/packages/conversation/tests/models/v1/helper.test.ts index 8d449a5e..50331272 100644 --- a/packages/conversation/tests/models/v1/helper.test.ts +++ b/packages/conversation/tests/models/v1/helper.test.ts @@ -10,7 +10,7 @@ import { V2TemplateTranslation, MessageType, templateV1Helper, - templateV2Helper, + templateV2Helper, messageBuilder, } from '../../../src'; const textItem: TextMessageItem = { @@ -375,4 +375,46 @@ describe('Conversation models helpers', () => { }); }); + describe('Message builder helper', () => { + it('should build a TextMessage', () => { + const builtTextMessage = messageBuilder.text(textItem); + expect(builtTextMessage).toEqual(textMessage); + }); + + it('should build a CardMessage', () => { + const builtTextMessage = messageBuilder.card(cardMessageItem); + expect(builtTextMessage).toEqual(cardMessage); + }); + + it('should build a CarouselMessage', () => { + const builtMessage = messageBuilder.carousel(carouselMessageItem); + expect(builtMessage).toEqual(carouselMessage); + }); + + it('should build a ChoiceMessage', () => { + const builtMessage = messageBuilder.choice(choiceMessageItem); + expect(builtMessage).toEqual(choiceMessage); + }); + + it('should build a LocationMessage', () => { + const builtMessage = messageBuilder.location(locationMessageItem); + expect(builtMessage).toEqual(locationMessage); + }); + + it('should build a MediaMessage', () => { + const builtMessage = messageBuilder.media(mediaMessageItem); + expect(builtMessage).toEqual(mediaMessage); + }); + + it('should build a TemplateMessage', () => { + const builtMessage = messageBuilder.template(templateMessageItem); + expect(builtMessage).toEqual(templateMessage); + }); + + it('should build a ListMessage', () => { + const builtMessage = messageBuilder.list(listMessageItem); + expect(builtMessage).toEqual(listMessage); + }); + }); + }); From 3e18a931923653e6895e256c8776901573724ff7 Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Tue, 13 Feb 2024 18:49:14 +0100 Subject: [PATCH 16/19] refactor enums --- .../app-create-request/app-create-request.ts | 3 +- .../app-message-additional-properties.ts | 8 --- .../index.ts | 1 - .../src/models/v1/app-message/app-message.ts | 10 +++- .../models/v1/app-response/app-response.ts | 3 +- .../app-update-request/app-update-request.ts | 3 +- .../v1/capability-event/capability-event.ts | 3 +- .../src/models/v1/card-height/card-height.ts | 4 -- .../src/models/v1/card-height/index.ts | 1 - .../models/v1/card-message/card-message.ts | 2 +- .../channel-identities/channel-identities.ts | 7 --- .../src/models/v1/channel-identities/index.ts | 1 - .../conversation-direction.ts | 1 - .../models/v1/conversation-direction/index.ts | 1 - .../conversation-merge-strategy.ts | 1 - .../v1/conversation-merge-strategy/index.ts | 1 - .../conversation-message-injected.ts | 2 +- .../conversation-message.ts | 3 +- .../conversation-messages-view.ts | 1 - .../v1/conversation-messages-view/index.ts | 1 - .../conversation-metadata-report-view.ts | 1 - .../index.ts | 1 - .../conversation-metadata-update-strategy.ts | 1 - .../index.ts | 1 - .../v1/delivery-status/delivery-status.ts | 6 --- .../src/models/v1/delivery-status/index.ts | 1 - .../dispatch-retention-policy-type.ts | 1 - .../dispatch-retention-policy-type/index.ts | 1 - .../dispatch-retention-policy.ts | 2 +- packages/conversation/src/models/v1/enums.ts | 54 ++++++++++++++----- .../v1/event-delivery/event-delivery.ts | 3 +- .../models/v1/event-inbound/event-inbound.ts | 9 ++-- ...et-channel-profile-conversation-channel.ts | 4 -- .../index.ts | 1 - .../get-channel-profile-request.ts | 2 +- .../models/v1/identified-by/identified-by.ts | 2 +- packages/conversation/src/models/v1/index.ts | 15 ------ .../merge-contact-request.ts | 3 +- .../message-delivery-receipt-event.ts | 3 +- .../message-inbound-event-item.ts | 5 +- .../src/models/v1/message-queue/index.ts | 1 - .../models/v1/message-queue/message-queue.ts | 4 -- .../message-submit-event.ts | 2 +- .../models/v1/opt-in-event/opt-in-event.ts | 5 +- .../models/v1/opt-out-event/opt-out-event.ts | 5 +- .../src/models/v1/processing-mode/index.ts | 1 - .../v1/processing-mode/processing-mode.ts | 1 - .../models/v1/processing-strategy/index.ts | 1 - .../processing-strategy.ts | 1 - .../send-event-request/send-event-request.ts | 2 +- .../send-message-request.ts | 4 +- .../unsupported-callback-event.ts | 2 +- .../models/v1/webhook-target-type/index.ts | 1 - .../webhook-target-type.ts | 1 - .../src/models/v1/webhook/webhook.ts | 2 +- 55 files changed, 77 insertions(+), 129 deletions(-) delete mode 100644 packages/conversation/src/models/v1/app-message-additional-properties/app-message-additional-properties.ts delete mode 100644 packages/conversation/src/models/v1/app-message-additional-properties/index.ts delete mode 100644 packages/conversation/src/models/v1/card-height/card-height.ts delete mode 100644 packages/conversation/src/models/v1/card-height/index.ts delete mode 100644 packages/conversation/src/models/v1/channel-identities/channel-identities.ts delete mode 100644 packages/conversation/src/models/v1/channel-identities/index.ts delete mode 100644 packages/conversation/src/models/v1/conversation-direction/conversation-direction.ts delete mode 100644 packages/conversation/src/models/v1/conversation-direction/index.ts delete mode 100644 packages/conversation/src/models/v1/conversation-merge-strategy/conversation-merge-strategy.ts delete mode 100644 packages/conversation/src/models/v1/conversation-merge-strategy/index.ts delete mode 100644 packages/conversation/src/models/v1/conversation-messages-view/conversation-messages-view.ts delete mode 100644 packages/conversation/src/models/v1/conversation-messages-view/index.ts delete mode 100644 packages/conversation/src/models/v1/conversation-metadata-report-view/conversation-metadata-report-view.ts delete mode 100644 packages/conversation/src/models/v1/conversation-metadata-report-view/index.ts delete mode 100644 packages/conversation/src/models/v1/conversation-metadata-update-strategy/conversation-metadata-update-strategy.ts delete mode 100644 packages/conversation/src/models/v1/conversation-metadata-update-strategy/index.ts delete mode 100644 packages/conversation/src/models/v1/delivery-status/delivery-status.ts delete mode 100644 packages/conversation/src/models/v1/delivery-status/index.ts delete mode 100644 packages/conversation/src/models/v1/dispatch-retention-policy-type/dispatch-retention-policy-type.ts delete mode 100644 packages/conversation/src/models/v1/dispatch-retention-policy-type/index.ts delete mode 100644 packages/conversation/src/models/v1/get-channel-profile-conversation-channel/get-channel-profile-conversation-channel.ts delete mode 100644 packages/conversation/src/models/v1/get-channel-profile-conversation-channel/index.ts delete mode 100644 packages/conversation/src/models/v1/message-queue/index.ts delete mode 100644 packages/conversation/src/models/v1/message-queue/message-queue.ts delete mode 100644 packages/conversation/src/models/v1/processing-mode/index.ts delete mode 100644 packages/conversation/src/models/v1/processing-mode/processing-mode.ts delete mode 100644 packages/conversation/src/models/v1/processing-strategy/index.ts delete mode 100644 packages/conversation/src/models/v1/processing-strategy/processing-strategy.ts delete mode 100644 packages/conversation/src/models/v1/webhook-target-type/index.ts delete mode 100644 packages/conversation/src/models/v1/webhook-target-type/webhook-target-type.ts diff --git a/packages/conversation/src/models/v1/app-create-request/app-create-request.ts b/packages/conversation/src/models/v1/app-create-request/app-create-request.ts index be17bc41..6cab3293 100644 --- a/packages/conversation/src/models/v1/app-create-request/app-create-request.ts +++ b/packages/conversation/src/models/v1/app-create-request/app-create-request.ts @@ -1,10 +1,9 @@ import { CallbackSettings } from '../callback-settings'; import { ConversationChannelCredential } from '../conversation-channel-credential'; -import { ConversationMetadataReportView } from '../conversation-metadata-report-view'; import { DispatchRetentionPolicy } from '../dispatch-retention-policy'; import { RetentionPolicy } from '../retention-policy'; import { SmartConversation } from '../smart-conversation'; -import { ProcessingMode } from '../processing-mode'; +import { ConversationMetadataReportView, ProcessingMode } from '../enums'; /** * The request sent to the API endpoint to create a new app. diff --git a/packages/conversation/src/models/v1/app-message-additional-properties/app-message-additional-properties.ts b/packages/conversation/src/models/v1/app-message-additional-properties/app-message-additional-properties.ts deleted file mode 100644 index 6567852b..00000000 --- a/packages/conversation/src/models/v1/app-message-additional-properties/app-message-additional-properties.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Additional properties of the message. - */ -export interface AppMessageAdditionalProperties { - - /** The `display_name` of the newly created contact in case it doesn't exist. */ - contact_name?: string; -} diff --git a/packages/conversation/src/models/v1/app-message-additional-properties/index.ts b/packages/conversation/src/models/v1/app-message-additional-properties/index.ts deleted file mode 100644 index b6e4ef9c..00000000 --- a/packages/conversation/src/models/v1/app-message-additional-properties/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { AppMessageAdditionalProperties } from './app-message-additional-properties'; diff --git a/packages/conversation/src/models/v1/app-message/app-message.ts b/packages/conversation/src/models/v1/app-message/app-message.ts index fc7a74cb..71da85b2 100644 --- a/packages/conversation/src/models/v1/app-message/app-message.ts +++ b/packages/conversation/src/models/v1/app-message/app-message.ts @@ -1,4 +1,3 @@ -import { AppMessageAdditionalProperties } from '../app-message-additional-properties'; import { AppMessageMessage } from '../app-message-message'; import { Agent } from '../agent'; import { LocationMessageItem } from '../location-message'; @@ -73,3 +72,12 @@ interface AppMessageBase { /** */ explicit_channel_omni_message?: { [key: string]: AppMessageMessage; }; } + +/** + * Additional properties of the message. + */ +export interface AppMessageAdditionalProperties { + + /** The `display_name` of the newly created contact in case it doesn't exist. */ + contact_name?: string; +} diff --git a/packages/conversation/src/models/v1/app-response/app-response.ts b/packages/conversation/src/models/v1/app-response/app-response.ts index 2a32bad7..9acaa02d 100644 --- a/packages/conversation/src/models/v1/app-response/app-response.ts +++ b/packages/conversation/src/models/v1/app-response/app-response.ts @@ -1,12 +1,11 @@ import { ConversationChannelCredential } from '../conversation-channel-credential'; -import { ConversationMetadataReportView } from '../conversation-metadata-report-view'; import { DispatchRetentionPolicy } from '../dispatch-retention-policy'; import { QueueStats } from '../queue-stats'; import { RateLimits } from '../rate-limits'; import { RetentionPolicy } from '../retention-policy'; import { SmartConversation } from '../smart-conversation'; -import { ProcessingMode } from '../processing-mode'; import { CallbackSettings } from '../callback-settings'; +import { ConversationMetadataReportView, ProcessingMode } from '../enums'; /** * The response showing information about the app. diff --git a/packages/conversation/src/models/v1/app-update-request/app-update-request.ts b/packages/conversation/src/models/v1/app-update-request/app-update-request.ts index 2be890a1..d698da3a 100644 --- a/packages/conversation/src/models/v1/app-update-request/app-update-request.ts +++ b/packages/conversation/src/models/v1/app-update-request/app-update-request.ts @@ -1,10 +1,9 @@ import { CallbackSettings } from '../callback-settings'; import { ConversationChannelCredential } from '../conversation-channel-credential'; -import { ConversationMetadataReportView } from '../conversation-metadata-report-view'; import { DispatchRetentionPolicy } from '../dispatch-retention-policy'; import { RetentionPolicy } from '../retention-policy'; import { SmartConversation } from '../smart-conversation'; -import { ProcessingMode } from '../processing-mode'; +import { ConversationMetadataReportView, ProcessingMode } from '../enums'; /** * The request sent to the API endpoint to update the configuration of an app. diff --git a/packages/conversation/src/models/v1/capability-event/capability-event.ts b/packages/conversation/src/models/v1/capability-event/capability-event.ts index 2aaee558..2844e843 100644 --- a/packages/conversation/src/models/v1/capability-event/capability-event.ts +++ b/packages/conversation/src/models/v1/capability-event/capability-event.ts @@ -36,10 +36,9 @@ export interface CapabilityNotification { /** The channel identity. For example, a phone number for SMS, WhatsApp, and Viber Business. */ identity?: string; /** Status indicating the recipient\'s capability on the channel. */ - capability_status?: CapabilityStatusEnum; + capability_status?: 'CAPABILITY_UNKNOWN' | 'CAPABILITY_FULL' | 'CAPABILITY_PARTIAL' | 'NO_CAPABILITY'; /** When capability_status is set to CAPABILITY_PARTIAL, this field includes a list of the supported channel-specific capabilities reported by the channel. */ channel_capabilities?: string[]; /** @see Reason */ reason?: Reason; } -export type CapabilityStatusEnum = 'CAPABILITY_UNKNOWN' | 'CAPABILITY_FULL' | 'CAPABILITY_PARTIAL' | 'NO_CAPABILITY'; diff --git a/packages/conversation/src/models/v1/card-height/card-height.ts b/packages/conversation/src/models/v1/card-height/card-height.ts deleted file mode 100644 index a5a79fa1..00000000 --- a/packages/conversation/src/models/v1/card-height/card-height.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * You can set the desired size of the card in the message. - */ -export type CardHeight = 'UNSPECIFIED_HEIGHT' | 'SHORT' | 'MEDIUM' | 'TALL'; diff --git a/packages/conversation/src/models/v1/card-height/index.ts b/packages/conversation/src/models/v1/card-height/index.ts deleted file mode 100644 index 6cad63c1..00000000 --- a/packages/conversation/src/models/v1/card-height/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { CardHeight } from './card-height'; diff --git a/packages/conversation/src/models/v1/card-message/card-message.ts b/packages/conversation/src/models/v1/card-message/card-message.ts index f8bb5253..3fa590f9 100644 --- a/packages/conversation/src/models/v1/card-message/card-message.ts +++ b/packages/conversation/src/models/v1/card-message/card-message.ts @@ -1,6 +1,6 @@ -import { CardHeight } from '../card-height'; import { MediaCarouselMessage } from '../media-carousel-message'; import { Choice } from '../choice'; +import { CardHeight } from '../enums'; /** * Message containing text, media and choices. diff --git a/packages/conversation/src/models/v1/channel-identities/channel-identities.ts b/packages/conversation/src/models/v1/channel-identities/channel-identities.ts deleted file mode 100644 index d5acfb48..00000000 --- a/packages/conversation/src/models/v1/channel-identities/channel-identities.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ChannelRecipientIdentity } from '../channel-recipient-identity'; - -export interface ChannelIdentities { - - /** A list of specific channel identities. The API will use these identities when sending to specific channels. */ - channel_identities: ChannelRecipientIdentity[]; -} diff --git a/packages/conversation/src/models/v1/channel-identities/index.ts b/packages/conversation/src/models/v1/channel-identities/index.ts deleted file mode 100644 index ba4a5570..00000000 --- a/packages/conversation/src/models/v1/channel-identities/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ChannelIdentities } from './channel-identities'; diff --git a/packages/conversation/src/models/v1/conversation-direction/conversation-direction.ts b/packages/conversation/src/models/v1/conversation-direction/conversation-direction.ts deleted file mode 100644 index 7a7cfe6c..00000000 --- a/packages/conversation/src/models/v1/conversation-direction/conversation-direction.ts +++ /dev/null @@ -1 +0,0 @@ -export type ConversationDirection = 'UNDEFINED_DIRECTION' | 'TO_APP' | 'TO_CONTACT'; diff --git a/packages/conversation/src/models/v1/conversation-direction/index.ts b/packages/conversation/src/models/v1/conversation-direction/index.ts deleted file mode 100644 index 21f27f27..00000000 --- a/packages/conversation/src/models/v1/conversation-direction/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ConversationDirection } from './conversation-direction'; diff --git a/packages/conversation/src/models/v1/conversation-merge-strategy/conversation-merge-strategy.ts b/packages/conversation/src/models/v1/conversation-merge-strategy/conversation-merge-strategy.ts deleted file mode 100644 index c328128e..00000000 --- a/packages/conversation/src/models/v1/conversation-merge-strategy/conversation-merge-strategy.ts +++ /dev/null @@ -1 +0,0 @@ -export type ConversationMergeStrategy = 'MERGE'; diff --git a/packages/conversation/src/models/v1/conversation-merge-strategy/index.ts b/packages/conversation/src/models/v1/conversation-merge-strategy/index.ts deleted file mode 100644 index 0cc6315d..00000000 --- a/packages/conversation/src/models/v1/conversation-merge-strategy/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ConversationMergeStrategy } from './conversation-merge-strategy'; diff --git a/packages/conversation/src/models/v1/conversation-message-injected/conversation-message-injected.ts b/packages/conversation/src/models/v1/conversation-message-injected/conversation-message-injected.ts index bec6b788..0fef2a76 100644 --- a/packages/conversation/src/models/v1/conversation-message-injected/conversation-message-injected.ts +++ b/packages/conversation/src/models/v1/conversation-message-injected/conversation-message-injected.ts @@ -1,7 +1,7 @@ import { AppMessage } from '../app-message'; import { ChannelIdentity } from '../channel-identity'; import { ContactMessage } from '../contact-message'; -import { ConversationDirection } from '../conversation-direction'; +import { ConversationDirection } from '../enums'; /** * A message on a particular channel. diff --git a/packages/conversation/src/models/v1/conversation-message/conversation-message.ts b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts index e77e504e..4a582556 100644 --- a/packages/conversation/src/models/v1/conversation-message/conversation-message.ts +++ b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts @@ -1,8 +1,7 @@ import { AppMessage } from '../app-message'; import { ChannelIdentity } from '../channel-identity'; import { ContactMessage } from '../contact-message'; -import { ConversationDirection } from '../conversation-direction'; -import { ProcessingMode } from '../processing-mode'; +import { ConversationDirection, ProcessingMode } from '../enums'; /** * A message on a particular channel. diff --git a/packages/conversation/src/models/v1/conversation-messages-view/conversation-messages-view.ts b/packages/conversation/src/models/v1/conversation-messages-view/conversation-messages-view.ts deleted file mode 100644 index 144fd50d..00000000 --- a/packages/conversation/src/models/v1/conversation-messages-view/conversation-messages-view.ts +++ /dev/null @@ -1 +0,0 @@ -export type ConversationMessagesView = 'WITH_METADATA' | 'WITHOUT_METADATA'; diff --git a/packages/conversation/src/models/v1/conversation-messages-view/index.ts b/packages/conversation/src/models/v1/conversation-messages-view/index.ts deleted file mode 100644 index 5e348951..00000000 --- a/packages/conversation/src/models/v1/conversation-messages-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ConversationMessagesView } from './conversation-messages-view'; diff --git a/packages/conversation/src/models/v1/conversation-metadata-report-view/conversation-metadata-report-view.ts b/packages/conversation/src/models/v1/conversation-metadata-report-view/conversation-metadata-report-view.ts deleted file mode 100644 index 44b1e7ba..00000000 --- a/packages/conversation/src/models/v1/conversation-metadata-report-view/conversation-metadata-report-view.ts +++ /dev/null @@ -1 +0,0 @@ -export type ConversationMetadataReportView = 'NONE' | 'FULL'; diff --git a/packages/conversation/src/models/v1/conversation-metadata-report-view/index.ts b/packages/conversation/src/models/v1/conversation-metadata-report-view/index.ts deleted file mode 100644 index 3c5b784f..00000000 --- a/packages/conversation/src/models/v1/conversation-metadata-report-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ConversationMetadataReportView } from './conversation-metadata-report-view'; diff --git a/packages/conversation/src/models/v1/conversation-metadata-update-strategy/conversation-metadata-update-strategy.ts b/packages/conversation/src/models/v1/conversation-metadata-update-strategy/conversation-metadata-update-strategy.ts deleted file mode 100644 index 71009e51..00000000 --- a/packages/conversation/src/models/v1/conversation-metadata-update-strategy/conversation-metadata-update-strategy.ts +++ /dev/null @@ -1 +0,0 @@ -export type ConversationMetadataUpdateStrategy = 'REPLACE' | 'MERGE_PATCH'; diff --git a/packages/conversation/src/models/v1/conversation-metadata-update-strategy/index.ts b/packages/conversation/src/models/v1/conversation-metadata-update-strategy/index.ts deleted file mode 100644 index f964857c..00000000 --- a/packages/conversation/src/models/v1/conversation-metadata-update-strategy/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ConversationMetadataUpdateStrategy } from './conversation-metadata-update-strategy'; diff --git a/packages/conversation/src/models/v1/delivery-status/delivery-status.ts b/packages/conversation/src/models/v1/delivery-status/delivery-status.ts deleted file mode 100644 index 431830a7..00000000 --- a/packages/conversation/src/models/v1/delivery-status/delivery-status.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type DeliveryStatus = - 'QUEUED_ON_CHANNEL' - | 'DELIVERED' - | 'READ' - | 'FAILED' - | 'SWITCHING_CHANNEL'; diff --git a/packages/conversation/src/models/v1/delivery-status/index.ts b/packages/conversation/src/models/v1/delivery-status/index.ts deleted file mode 100644 index ead5f089..00000000 --- a/packages/conversation/src/models/v1/delivery-status/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { DeliveryStatus } from './delivery-status'; diff --git a/packages/conversation/src/models/v1/dispatch-retention-policy-type/dispatch-retention-policy-type.ts b/packages/conversation/src/models/v1/dispatch-retention-policy-type/dispatch-retention-policy-type.ts deleted file mode 100644 index ad2b1afb..00000000 --- a/packages/conversation/src/models/v1/dispatch-retention-policy-type/dispatch-retention-policy-type.ts +++ /dev/null @@ -1 +0,0 @@ -export type DispatchRetentionPolicyType = 'MESSAGE_EXPIRE_POLICY'; diff --git a/packages/conversation/src/models/v1/dispatch-retention-policy-type/index.ts b/packages/conversation/src/models/v1/dispatch-retention-policy-type/index.ts deleted file mode 100644 index 162a8247..00000000 --- a/packages/conversation/src/models/v1/dispatch-retention-policy-type/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { DispatchRetentionPolicyType } from './dispatch-retention-policy-type'; diff --git a/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts b/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts index a5cc472b..d64b23c6 100644 --- a/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts +++ b/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts @@ -1,4 +1,4 @@ -import { DispatchRetentionPolicyType } from '../dispatch-retention-policy-type'; +import { DispatchRetentionPolicyType } from '../enums'; /** * The retention policy configured for messages in [Dispatch Mode](../../../../../conversation/processing-modes/). Currently only `MESSAGE_EXPIRE_POLICY` is available. For more information about retention policies, see [Retention Policy](/docs/conversation/keyconcepts/#retention-policy). diff --git a/packages/conversation/src/models/v1/enums.ts b/packages/conversation/src/models/v1/enums.ts index 8f0fdc70..1d726541 100644 --- a/packages/conversation/src/models/v1/enums.ts +++ b/packages/conversation/src/models/v1/enums.ts @@ -1,9 +1,4 @@ export type { - CapabilityStatusEnum as CapabilityNotificationCapabilityStatusEnum, -} from './capability-event/capability-event'; -export type { - DirectionEnum as EventInboundDirectionEnum, - CommentTypeEnum as CommentEventCommentTypeEnum, PaymentStatusEnum as PaymentStatusUpdateEventPaymentStatusEnum, PaymentTransactionStatusEnum as PaymentStatusUpdateEventPaymentTransactionStatusEnum, } from './event-inbound/event-inbound'; @@ -11,12 +6,43 @@ export type { SentimentResult as MachineLearningSentimentEnum, EvaluationEnum as OffensiveAnalysisEvaluationEnum, } from './smart-conversations-event/smart-conversations-event'; -export type { - DirectionEnum as MessageInboundEventItemDirectionEnum, -} from './message-inbound-event-item/message-inbound-event-item'; -export type { - StatusEnum as OptInNotificationStatusEnum, -} from './opt-in-event/opt-in-event'; -export type { - StatusEnum as OptOutEventOptOutNotificationStatusEnum, -} from './opt-out-event/opt-out-event'; + +export type ConversationMetadataReportView = 'NONE' | 'FULL'; + +export type ConversationMetadataUpdateStrategy = 'REPLACE' | 'MERGE_PATCH'; + +/** + * You can set the desired size of the card in the message. + */ +export type CardHeight = 'UNSPECIFIED_HEIGHT' | 'SHORT' | 'MEDIUM' | 'TALL'; + +export type ConversationDirection = 'UNDEFINED_DIRECTION' | 'TO_APP' | 'TO_CONTACT'; + +export type ConversationMergeStrategy = 'MERGE'; + +export type ConversationMessagesView = 'WITH_METADATA' | 'WITHOUT_METADATA'; + +export type DeliveryStatus = + 'QUEUED_ON_CHANNEL' + | 'DELIVERED' + | 'READ' + | 'FAILED' + | 'SWITCHING_CHANNEL'; + +export type DispatchRetentionPolicyType = 'MESSAGE_EXPIRE_POLICY'; + +/** + * The channel. Must be one of the supported channels for this operation. + */ +export type GetChannelProfileConversationChannel = 'MESSENGER' | 'INSTAGRAM' | 'VIBER' | 'LINE'; + +/** + * Select the priority type for the message + */ +export type MessageQueue = 'NORMAL_PRIORITY' | 'HIGH_PRIORITY'; + +export type ProcessingMode = 'CONVERSATION' | 'DISPATCH'; + +export type ProcessingStrategy = 'DEFAULT' | 'DISPATCH_ONLY'; + +export type WebhookTargetType = 'DISMISS' | 'HTTP'; diff --git a/packages/conversation/src/models/v1/event-delivery/event-delivery.ts b/packages/conversation/src/models/v1/event-delivery/event-delivery.ts index edc19c73..51ab7d4a 100644 --- a/packages/conversation/src/models/v1/event-delivery/event-delivery.ts +++ b/packages/conversation/src/models/v1/event-delivery/event-delivery.ts @@ -1,8 +1,7 @@ import { ChannelIdentity } from '../channel-identity'; import { Reason } from '../reason'; -import { ProcessingMode } from '../processing-mode'; -import { DeliveryStatus } from '../delivery-status'; import { ConversationEvent } from '../conversation-event'; +import { DeliveryStatus, ProcessingMode } from '../enums'; export interface EventDelivery extends ConversationEvent{ diff --git a/packages/conversation/src/models/v1/event-inbound/event-inbound.ts b/packages/conversation/src/models/v1/event-inbound/event-inbound.ts index 8d417738..3b2d8dbe 100644 --- a/packages/conversation/src/models/v1/event-inbound/event-inbound.ts +++ b/packages/conversation/src/models/v1/event-inbound/event-inbound.ts @@ -1,6 +1,6 @@ -import { ProcessingMode } from '../processing-mode'; import { ChannelIdentity } from '../channel-identity'; import { ConversationEvent } from '../conversation-event'; +import { ProcessingMode } from '../enums'; export interface EventInbound extends ConversationEvent { @@ -27,7 +27,7 @@ export interface EventInboundEvent { /** The event ID. */ id?: string; /** The direction of the event. It\'s always TO_APP for contact events. */ - direction?: DirectionEnum; + direction?: 'TO_APP'; /** @see ContactEvent */ contact_event?: ContactEvent; /** @see ContactMessageEvent */ @@ -44,8 +44,6 @@ export interface EventInboundEvent { processing_mode?: ProcessingMode; } -export type DirectionEnum = 'TO_APP'; - export interface ContactEvent { /** Empty object denoting the contact is composing a message. */ @@ -63,13 +61,12 @@ export interface CommentEvent { /** Comment\'s text */ text?: string; /** Either LIVE or FEED. Indicates the type of media on which the comment was made. */ - comment_type?: CommentTypeEnum; + comment_type?: 'FEED' | 'LIVE'; /** Instagram\'s URL of the live broadcast or the post on which the comment was made (permalink). */ commented_on?: string; /** Username of the account that commented in the live broadcast or post. */ user?: string; } -export type CommentTypeEnum = 'FEED' | 'LIVE'; /** * The content of the event when contact_event is not populated. Note that this object is currently only available to select customers for beta testing. Mutually exclusive with contact_event. diff --git a/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/get-channel-profile-conversation-channel.ts b/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/get-channel-profile-conversation-channel.ts deleted file mode 100644 index 42d52e3c..00000000 --- a/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/get-channel-profile-conversation-channel.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * The channel. Must be one of the supported channels for this operation. - */ -export type GetChannelProfileConversationChannel = 'MESSENGER' | 'INSTAGRAM' | 'VIBER' | 'LINE'; diff --git a/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/index.ts b/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/index.ts deleted file mode 100644 index 6a84b96c..00000000 --- a/packages/conversation/src/models/v1/get-channel-profile-conversation-channel/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { GetChannelProfileConversationChannel } from './get-channel-profile-conversation-channel'; diff --git a/packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts b/packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts index a01ba935..0baafd70 100644 --- a/packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts +++ b/packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts @@ -1,5 +1,5 @@ -import { GetChannelProfileConversationChannel } from '../get-channel-profile-conversation-channel'; import { Recipient } from '../recipient'; +import { GetChannelProfileConversationChannel } from '../enums'; export interface GetChannelProfileRequest { diff --git a/packages/conversation/src/models/v1/identified-by/identified-by.ts b/packages/conversation/src/models/v1/identified-by/identified-by.ts index c9505826..8fdeefe2 100644 --- a/packages/conversation/src/models/v1/identified-by/identified-by.ts +++ b/packages/conversation/src/models/v1/identified-by/identified-by.ts @@ -8,6 +8,6 @@ export interface IdentifiedBy { } export interface IdentifiedByItem { - /** @see IdentifiedBy */ + /** A list of specific channel identities. The API will use these identities when sending to specific channels. */ channel_identities: ChannelRecipientIdentity[]; } diff --git a/packages/conversation/src/models/v1/index.ts b/packages/conversation/src/models/v1/index.ts index cf6e915f..587b322e 100644 --- a/packages/conversation/src/models/v1/index.ts +++ b/packages/conversation/src/models/v1/index.ts @@ -4,7 +4,6 @@ export * from './agent-left-event'; export * from './app-create-request'; export * from './app-event'; export * from './app-message'; -export * from './app-message-additional-properties'; export * from './app-message-message'; export * from './app-response'; export * from './app-update-request'; @@ -13,11 +12,9 @@ export * from './basic-auth-credential'; export * from './call-message'; export * from './callback-settings'; export * from './capability-event'; -export * from './card-height'; export * from './card-message'; export * from './carousel-message'; export * from './channel-event'; -export * from './channel-identities'; export * from './channel-identity'; export * from './channel-template-override'; export * from './channel-template-reference'; @@ -44,26 +41,18 @@ export * from './conversation'; export * from './conversation-channel'; export * from './conversation-channel-credential'; export * from './conversation-delete-event'; -export * from './conversation-direction'; -export * from './conversation-merge-strategy'; export * from './conversation-message'; export * from './conversation-message-injected'; -export * from './conversation-messages-view'; -export * from './conversation-metadata-report-view'; -export * from './conversation-metadata-update-strategy'; export * from './conversation-start-event'; export * from './conversation-stop-event'; export * from './conversation-webhook-event'; export * from './coordinates'; export * from './create-conversation-request'; -export * from './delivery-status'; export * from './dispatch-retention-policy'; -export * from './dispatch-retention-policy-type'; export * from './event-delivery'; export * from './event-inbound'; export * from './fallback-message'; export * from './generic-event'; -export * from './get-channel-profile-conversation-channel'; export * from './get-channel-profile-request'; export * from './get-channel-profile-response'; export * from './identified-by'; @@ -88,10 +77,7 @@ export * from './media-carousel-message'; export * from './media-message'; export * from './merge-contact-request'; export * from './message-delivery-receipt-event'; -export * from './message-queue'; export * from './message-submit-event'; -export * from './processing-mode'; -export * from './processing-strategy'; export * from './product'; export * from './error-detail'; export * from './lookup-capability'; @@ -131,7 +117,6 @@ export * from './v2-template-response'; export * from './v2-template-translation'; export * from './wechat-credentials'; export * from './webhook'; -export * from './webhook-target-type'; export * from './webhook-trigger'; export * from './enums'; export * from './helper'; diff --git a/packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts b/packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts index a374ff10..432ae693 100644 --- a/packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts +++ b/packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts @@ -1,4 +1,5 @@ -import { ConversationMergeStrategy } from '../conversation-merge-strategy'; +import { ConversationMergeStrategy } from '../enums'; + export interface MergeContactRequest { diff --git a/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts b/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts index 84959189..7a549bc2 100644 --- a/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts +++ b/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts @@ -1,8 +1,7 @@ import { ChannelIdentity } from '../channel-identity'; import { Reason } from '../reason'; -import { ProcessingMode } from '../processing-mode'; -import { DeliveryStatus } from '../delivery-status'; import { ConversationEvent } from '../conversation-event'; +import { DeliveryStatus, ProcessingMode } from '../enums'; /** * This callback notifies the API clients about status changes of already sent app message. diff --git a/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts b/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts index 7baee0be..3bca2d7d 100644 --- a/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts +++ b/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts @@ -1,13 +1,13 @@ import { ChannelIdentity } from '../channel-identity'; import { ContactMessage } from '../contact-message'; -import { ProcessingMode } from '../processing-mode'; +import { ProcessingMode } from '../enums'; export interface MessageInboundEventItem { /** The message ID. */ id?: string; /** The direction of the message, it\'s always TO_APP for contact messages. */ - direction?: DirectionEnum; + direction?: 'TO_APP'; /** @see ContactMessage */ contact_message?: ContactMessage; /** @see ChannelIdentity */ @@ -27,4 +27,3 @@ export interface MessageInboundEventItem { /** Flag for whether this message was injected. */ injected?: boolean; } -export type DirectionEnum = 'TO_APP'; diff --git a/packages/conversation/src/models/v1/message-queue/index.ts b/packages/conversation/src/models/v1/message-queue/index.ts deleted file mode 100644 index 897648f7..00000000 --- a/packages/conversation/src/models/v1/message-queue/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { MessageQueue } from './message-queue'; diff --git a/packages/conversation/src/models/v1/message-queue/message-queue.ts b/packages/conversation/src/models/v1/message-queue/message-queue.ts deleted file mode 100644 index 8c95c9b4..00000000 --- a/packages/conversation/src/models/v1/message-queue/message-queue.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Select the priority type for the message - */ -export type MessageQueue = 'NORMAL_PRIORITY' | 'HIGH_PRIORITY'; diff --git a/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts b/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts index 1bfba31c..dffe04af 100644 --- a/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts +++ b/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts @@ -1,7 +1,7 @@ import { ChannelIdentity } from '../channel-identity'; import { ContactMessage } from '../contact-message'; -import { ProcessingMode } from '../processing-mode'; import { ConversationEvent } from '../conversation-event'; +import { ProcessingMode } from '../enums'; /** * This callback provides a notification to the API clients that the corresponding app message was submitted to a channel. This notification is created before any confirmation from Delivery Receipts. diff --git a/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts b/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts index 154a01e0..229d60dc 100644 --- a/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts +++ b/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts @@ -1,6 +1,6 @@ import { ConversationChannel } from '../conversation-channel'; -import { ProcessingMode } from '../processing-mode'; import { ConversationEvent } from '../conversation-event'; +import { ProcessingMode } from '../enums'; /** * This callback is used to deliver opt-in notifications from the channels. @@ -36,13 +36,12 @@ export interface OptInNotification { /** The channel identity. For example, a phone number for SMS, WhatsApp and Viber Business. */ identity?: string; /** Status of the opt-in registration. */ - status?: StatusEnum; + status?: 'OPT_IN_SUCCEEDED' | 'OPT_IN_FAILED' | 'OPT_IN_STATUS_UNSPECIFIED'; /** @see OptInNotificationErrorDetails */ error_details?:OptInNotificationErrorDetails; /** @see ProcessingMode */ processing_mode?: ProcessingMode; } -export type StatusEnum = 'OPT_IN_SUCCEEDED' | 'OPT_IN_FAILED' | 'OPT_IN_STATUS_UNSPECIFIED'; /** * This field is populated if the opt-in failed. diff --git a/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts b/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts index 0a287f04..afe81378 100644 --- a/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts +++ b/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts @@ -1,6 +1,6 @@ import { ConversationChannel } from '../conversation-channel'; -import { ProcessingMode } from '../processing-mode'; import { ConversationEvent } from '../conversation-event'; +import { ProcessingMode } from '../enums'; /** * This callback is used to deliver opt-out notifications from the channels. @@ -36,13 +36,12 @@ export interface OptOutNotification { /** The channel identity. For example, a phone number for SMS, WhatsApp and Viber Business. */ identity?: string; /** Status of the opt-out registration. */ - status?: StatusEnum; + status?: 'OPT_OUT_SUCCEEDED' | 'OPT_OUT_FAILED' | 'OPT_OUT_STATUS_UNSPECIFIED'; /** @see OptOutNotificationErrorDetails */ error_details?: OptOutNotificationErrorDetails; /** @see ProcessingMode */ processing_mode?: ProcessingMode; } -export type StatusEnum = 'OPT_OUT_SUCCEEDED' | 'OPT_OUT_FAILED' | 'OPT_OUT_STATUS_UNSPECIFIED'; /** * This field is populated if the opt-out failed. diff --git a/packages/conversation/src/models/v1/processing-mode/index.ts b/packages/conversation/src/models/v1/processing-mode/index.ts deleted file mode 100644 index 723d6bbf..00000000 --- a/packages/conversation/src/models/v1/processing-mode/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ProcessingMode } from './processing-mode'; diff --git a/packages/conversation/src/models/v1/processing-mode/processing-mode.ts b/packages/conversation/src/models/v1/processing-mode/processing-mode.ts deleted file mode 100644 index 65f941b6..00000000 --- a/packages/conversation/src/models/v1/processing-mode/processing-mode.ts +++ /dev/null @@ -1 +0,0 @@ -export type ProcessingMode = 'CONVERSATION' | 'DISPATCH'; diff --git a/packages/conversation/src/models/v1/processing-strategy/index.ts b/packages/conversation/src/models/v1/processing-strategy/index.ts deleted file mode 100644 index 3d72e04f..00000000 --- a/packages/conversation/src/models/v1/processing-strategy/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { ProcessingStrategy } from './processing-strategy'; diff --git a/packages/conversation/src/models/v1/processing-strategy/processing-strategy.ts b/packages/conversation/src/models/v1/processing-strategy/processing-strategy.ts deleted file mode 100644 index 7efe5c28..00000000 --- a/packages/conversation/src/models/v1/processing-strategy/processing-strategy.ts +++ /dev/null @@ -1 +0,0 @@ -export type ProcessingStrategy = 'DEFAULT' | 'DISPATCH_ONLY'; diff --git a/packages/conversation/src/models/v1/send-event-request/send-event-request.ts b/packages/conversation/src/models/v1/send-event-request/send-event-request.ts index b6bd6bf6..4e8f6494 100644 --- a/packages/conversation/src/models/v1/send-event-request/send-event-request.ts +++ b/packages/conversation/src/models/v1/send-event-request/send-event-request.ts @@ -1,7 +1,7 @@ import { AppEvent } from '../app-event'; import { ConversationChannel } from '../conversation-channel'; -import { MessageQueue } from '../message-queue'; import { Recipient } from '../recipient'; +import { MessageQueue } from '../enums'; export interface SendEventRequest { diff --git a/packages/conversation/src/models/v1/send-message-request/send-message-request.ts b/packages/conversation/src/models/v1/send-message-request/send-message-request.ts index d1e36398..545ee9f3 100644 --- a/packages/conversation/src/models/v1/send-message-request/send-message-request.ts +++ b/packages/conversation/src/models/v1/send-message-request/send-message-request.ts @@ -1,9 +1,7 @@ import { ConversationChannel } from '../conversation-channel'; -import { MessageQueue } from '../message-queue'; import { Recipient } from '../recipient'; -import { ProcessingStrategy } from '../processing-strategy'; -import { ConversationMetadataUpdateStrategy } from '../conversation-metadata-update-strategy'; import { AppMessageMessage } from '../app-message-message'; +import { ConversationMetadataUpdateStrategy, MessageQueue, ProcessingStrategy } from '../enums'; /** * This is the request body for sending a message. `app_id`, `recipient`, and `message` are all required fields. diff --git a/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts b/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts index c8459270..b9bf2202 100644 --- a/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts +++ b/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts @@ -1,7 +1,7 @@ import { ConversationChannel } from '../conversation-channel'; -import { ProcessingMode } from '../processing-mode'; import { ChannelIdentity } from '../channel-identity'; import { ConversationEvent } from '../conversation-event'; +import { ProcessingMode } from '../enums'; /** * Some of the callbacks received from the underlying channels might be specific to a single channel or may not have a proper mapping in Conversation API yet. diff --git a/packages/conversation/src/models/v1/webhook-target-type/index.ts b/packages/conversation/src/models/v1/webhook-target-type/index.ts deleted file mode 100644 index feb0b26d..00000000 --- a/packages/conversation/src/models/v1/webhook-target-type/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { WebhookTargetType } from './webhook-target-type'; diff --git a/packages/conversation/src/models/v1/webhook-target-type/webhook-target-type.ts b/packages/conversation/src/models/v1/webhook-target-type/webhook-target-type.ts deleted file mode 100644 index 661eff6f..00000000 --- a/packages/conversation/src/models/v1/webhook-target-type/webhook-target-type.ts +++ /dev/null @@ -1 +0,0 @@ -export type WebhookTargetType = 'DISMISS' | 'HTTP'; diff --git a/packages/conversation/src/models/v1/webhook/webhook.ts b/packages/conversation/src/models/v1/webhook/webhook.ts index 458b33c3..af60e63d 100644 --- a/packages/conversation/src/models/v1/webhook/webhook.ts +++ b/packages/conversation/src/models/v1/webhook/webhook.ts @@ -1,6 +1,6 @@ import { ClientCredentials } from '../client-credentials'; -import { WebhookTargetType } from '../webhook-target-type'; import { WebhookTrigger } from '../webhook-trigger'; +import { WebhookTargetType } from '../enums'; /** * Represents a destination for receiving callbacks from the Conversation API. From d2772e1e04b42b9930dfea9653916773a333e2e1 Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Tue, 13 Feb 2024 19:21:42 +0100 Subject: [PATCH 17/19] refactor callback-events and credentials --- .../conversation-channel-credential.ts | 24 ++++++------ packages/conversation/src/models/v1/enums.ts | 4 +- packages/conversation/src/models/v1/index.ts | 37 +------------------ .../capability-event/capability-event.ts | 4 +- .../capability-event/index.ts | 0 .../channel-event/channel-event.ts | 2 +- .../channel-event/index.ts | 0 .../contact-create-event.ts | 0 .../contact-create-event/index.ts | 0 .../contact-delete-event.ts | 0 .../contact-delete-event/index.ts | 0 .../contact-identities-duplication-event.ts | 2 +- .../index.ts | 0 .../contact-merge-event.ts | 2 +- .../contact-merge-event/index.ts | 0 .../contact-notification.ts | 2 +- .../contact-notification/index.ts | 0 .../contact-update-event.ts | 0 .../contact-update-event/index.ts | 0 .../conversation-delete-event.ts | 2 +- .../conversation-delete-event/index.ts | 0 .../conversation-event/conversation-event.ts | 2 +- .../conversation-event/index.ts | 0 .../conversation-start-event.ts | 2 +- .../conversation-start-event/index.ts | 0 .../conversation-stop-event.ts | 2 +- .../conversation-stop-event/index.ts | 0 .../conversation-webhook-event.ts | 0 .../conversation-webhook-event/index.ts | 0 .../event-delivery/event-delivery.ts | 6 +-- .../event-delivery/index.ts | 0 .../event-inbound/event-inbound.ts | 4 +- .../event-inbound/index.ts | 0 .../models/v1/mod-callback-events/index.ts | 23 ++++++++++++ .../message-delivery-receipt-event/index.ts | 0 .../message-delivery-receipt-event.ts | 6 +-- .../message-inbound-event-item/index.ts | 0 .../message-inbound-event-item.ts | 6 +-- .../message-inbound-event/index.ts | 0 .../message-inbound-event.ts | 0 .../index.ts | 0 ...ound-smart-conversation-redaction-event.ts | 0 .../message-submit-event/index.ts | 0 .../message-submit-event.ts | 6 +-- .../opt-in-event/index.ts | 0 .../opt-in-event/opt-in-event.ts | 4 +- .../opt-out-event/index.ts | 0 .../opt-out-event/opt-out-event.ts | 4 +- .../smart-conversations-event/index.ts | 0 .../smart-conversations-event.ts | 2 +- .../unsupported-callback-event/index.ts | 0 .../unsupported-callback-event.ts | 6 +-- .../applebc-credentials.ts | 0 .../applebc-credentials/index.ts | 0 .../basic-auth-credential.ts | 0 .../basic-auth-credential/index.ts | 0 .../src/models/v1/mod-credentials/index.ts | 12 ++++++ .../instagram-credentials/index.ts | 0 .../instagram-credentials.ts | 0 .../kakaotalk-credentials/index.ts | 0 .../kakaotalk-credentials.ts | 0 .../kakaotalkchat-credentials/index.ts | 0 .../kakaotalkchat-credentials.ts | 0 .../line-credentials/index.ts | 0 .../line-credentials/line-credentials.ts | 0 .../mms-credentials/index.ts | 0 .../mms-credentials/mms-credentials.ts | 0 .../sms-credentials/index.ts | 0 .../sms-credentials/sms-credentials.ts | 0 .../static-bearer-credential/index.ts | 0 .../static-bearer-credential.ts | 0 .../static-token-credential/index.ts | 0 .../static-token-credential.ts | 0 .../telegram-credentials/index.ts | 0 .../telegram-credentials.ts | 0 .../wechat-credentials/index.ts | 0 .../wechat-credentials/wechat-credentials.ts | 0 77 files changed, 84 insertions(+), 80 deletions(-) rename packages/conversation/src/models/v1/{ => mod-callback-events}/capability-event/capability-event.ts (94%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/capability-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/channel-event/channel-event.ts (95%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/channel-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-create-event/contact-create-event.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-create-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-delete-event/contact-delete-event.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-delete-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-identities-duplication-event/contact-identities-duplication-event.ts (95%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-identities-duplication-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-merge-event/contact-merge-event.ts (96%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-merge-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-notification/contact-notification.ts (67%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-notification/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-update-event/contact-update-event.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/contact-update-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-delete-event/conversation-delete-event.ts (96%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-delete-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-event/conversation-event.ts (54%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-start-event/conversation-start-event.ts (95%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-start-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-stop-event/conversation-stop-event.ts (95%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-stop-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-webhook-event/conversation-webhook-event.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/conversation-webhook-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/event-delivery/event-delivery.ts (90%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/event-delivery/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/event-inbound/event-inbound.ts (97%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/event-inbound/index.ts (100%) create mode 100644 packages/conversation/src/models/v1/mod-callback-events/index.ts rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-delivery-receipt-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-delivery-receipt-event/message-delivery-receipt-event.ts (91%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-inbound-event-item/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-inbound-event-item/message-inbound-event-item.ts (90%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-inbound-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-inbound-event/message-inbound-event.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-inbound-smart-conversation-redaction-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-submit-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/message-submit-event/message-submit-event.ts (91%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/opt-in-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/opt-in-event/opt-in-event.ts (94%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/opt-out-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/opt-out-event/opt-out-event.ts (94%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/smart-conversations-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/smart-conversations-event/smart-conversations-event.ts (99%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/unsupported-callback-event/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-callback-events}/unsupported-callback-event/unsupported-callback-event.ts (90%) rename packages/conversation/src/models/v1/{ => mod-credentials}/applebc-credentials/applebc-credentials.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/applebc-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/basic-auth-credential/basic-auth-credential.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/basic-auth-credential/index.ts (100%) create mode 100644 packages/conversation/src/models/v1/mod-credentials/index.ts rename packages/conversation/src/models/v1/{ => mod-credentials}/instagram-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/instagram-credentials/instagram-credentials.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/kakaotalk-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/kakaotalk-credentials/kakaotalk-credentials.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/kakaotalkchat-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/kakaotalkchat-credentials/kakaotalkchat-credentials.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/line-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/line-credentials/line-credentials.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/mms-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/mms-credentials/mms-credentials.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/sms-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/sms-credentials/sms-credentials.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/static-bearer-credential/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/static-bearer-credential/static-bearer-credential.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/static-token-credential/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/static-token-credential/static-token-credential.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/telegram-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/telegram-credentials/telegram-credentials.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/wechat-credentials/index.ts (100%) rename packages/conversation/src/models/v1/{ => mod-credentials}/wechat-credentials/wechat-credentials.ts (100%) diff --git a/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts index a0fd4cf8..717129f5 100644 --- a/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts +++ b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts @@ -1,15 +1,17 @@ import { ConversationChannel } from '../conversation-channel'; -import { KakaoTalkCredentials } from '../kakaotalk-credentials'; -import { KakaoTalkChatCredentials } from '../kakaotalkchat-credentials'; -import { LineCredentials } from '../line-credentials'; -import { MMSCredentials } from '../mms-credentials'; -import { SMSCredentials } from '../sms-credentials'; -import { StaticBearerCredential } from '../static-bearer-credential'; -import { StaticTokenCredential } from '../static-token-credential'; -import { TelegramCredentials } from '../telegram-credentials'; -import { WeChatCredentials } from '../wechat-credentials'; -import { InstagramCredentials } from '../instagram-credentials'; -import { AppleBcCredentials } from '../applebc-credentials'; +import { + AppleBcCredentials, + InstagramCredentials, + KakaoTalkChatCredentials, + KakaoTalkCredentials, + LineCredentials, + MMSCredentials, + SMSCredentials, + StaticBearerCredential, + StaticTokenCredential, + TelegramCredentials, + WeChatCredentials, +} from '../mod-credentials'; /** * Enables access to the underlying messaging channel. diff --git a/packages/conversation/src/models/v1/enums.ts b/packages/conversation/src/models/v1/enums.ts index 1d726541..27013a18 100644 --- a/packages/conversation/src/models/v1/enums.ts +++ b/packages/conversation/src/models/v1/enums.ts @@ -1,11 +1,11 @@ export type { PaymentStatusEnum as PaymentStatusUpdateEventPaymentStatusEnum, PaymentTransactionStatusEnum as PaymentStatusUpdateEventPaymentTransactionStatusEnum, -} from './event-inbound/event-inbound'; +} from './mod-callback-events/event-inbound/event-inbound'; export type { SentimentResult as MachineLearningSentimentEnum, EvaluationEnum as OffensiveAnalysisEvaluationEnum, -} from './smart-conversations-event/smart-conversations-event'; +} from './mod-callback-events/smart-conversations-event/smart-conversations-event'; export type ConversationMetadataReportView = 'NONE' | 'FULL'; diff --git a/packages/conversation/src/models/v1/index.ts b/packages/conversation/src/models/v1/index.ts index 587b322e..44718df9 100644 --- a/packages/conversation/src/models/v1/index.ts +++ b/packages/conversation/src/models/v1/index.ts @@ -7,14 +7,10 @@ export * from './app-message'; export * from './app-message-message'; export * from './app-response'; export * from './app-update-request'; -export * from './applebc-credentials'; -export * from './basic-auth-credential'; export * from './call-message'; export * from './callback-settings'; -export * from './capability-event'; export * from './card-message'; export * from './carousel-message'; -export * from './channel-event'; export * from './channel-identity'; export * from './channel-template-override'; export * from './channel-template-reference'; @@ -27,57 +23,33 @@ export * from './comment-reply-event'; export * from './composing-end-event'; export * from './composing-event'; export * from './contact'; -export * from './contact-create-event'; export * from './contact-create-request'; -export * from './contact-delete-event'; export * from './contact-id'; -export * from './contact-identities-duplication-event'; -export * from './contact-merge-event'; export * from './contact-language'; export * from './contact-message'; -export * from './contact-notification'; -export * from './contact-update-event'; export * from './conversation'; export * from './conversation-channel'; export * from './conversation-channel-credential'; -export * from './conversation-delete-event'; export * from './conversation-message'; export * from './conversation-message-injected'; -export * from './conversation-start-event'; -export * from './conversation-stop-event'; -export * from './conversation-webhook-event'; export * from './coordinates'; export * from './create-conversation-request'; export * from './dispatch-retention-policy'; -export * from './event-delivery'; -export * from './event-inbound'; export * from './fallback-message'; export * from './generic-event'; export * from './get-channel-profile-request'; export * from './get-channel-profile-response'; export * from './identified-by'; -export * from './instagram-credentials'; -export * from './kakaotalk-credentials'; -export * from './kakaotalkchat-credentials'; -export * from './line-credentials'; export * from './list-apps-response'; export * from './list-message'; export * from './list-message-message-properties'; export * from './list-section'; export * from './list-webhooks-response'; export * from './location-message'; -export * from './message-inbound-event'; -export * from './message-inbound-event-item'; -export * from './message-inbound-smart-conversation-redaction-event'; -export * from './mms-credentials'; -export * from './opt-in-event'; -export * from './opt-out-event'; export * from './media-card-message'; export * from './media-carousel-message'; export * from './media-message'; export * from './merge-contact-request'; -export * from './message-delivery-receipt-event'; -export * from './message-submit-event'; export * from './product'; export * from './error-detail'; export * from './lookup-capability'; @@ -94,18 +66,12 @@ export * from './send-event-response'; export * from './send-message-request'; export * from './send-message-response'; export * from './smart-conversation'; -export * from './smart-conversations-event'; -export * from './sms-credentials'; -export * from './static-bearer-credential'; -export * from './static-token-credential'; -export * from './telegram-credentials'; export * from './template-message'; export * from './template-reference'; export * from './template-variable'; export * from './text-message'; export * from './transcode-message-request'; export * from './transcode-message-response'; -export * from './unsupported-callback-event'; export * from './url-message'; export * from './v1-list-templates-response'; export * from './v1-template'; @@ -115,8 +81,9 @@ export * from './v2-list-translations-response'; export * from './v2-template'; export * from './v2-template-response'; export * from './v2-template-translation'; -export * from './wechat-credentials'; export * from './webhook'; export * from './webhook-trigger'; export * from './enums'; export * from './helper'; +export * from './mod-callback-events'; +export * from './mod-credentials'; diff --git a/packages/conversation/src/models/v1/capability-event/capability-event.ts b/packages/conversation/src/models/v1/mod-callback-events/capability-event/capability-event.ts similarity index 94% rename from packages/conversation/src/models/v1/capability-event/capability-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/capability-event/capability-event.ts index 2844e843..233d8420 100644 --- a/packages/conversation/src/models/v1/capability-event/capability-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/capability-event/capability-event.ts @@ -1,5 +1,5 @@ -import { ConversationChannel } from '../conversation-channel'; -import { Reason } from '../reason'; +import { ConversationChannel } from '../../conversation-channel'; +import { Reason } from '../../reason'; import { ConversationEvent } from '../conversation-event'; /** diff --git a/packages/conversation/src/models/v1/capability-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/capability-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/capability-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/capability-event/index.ts diff --git a/packages/conversation/src/models/v1/channel-event/channel-event.ts b/packages/conversation/src/models/v1/mod-callback-events/channel-event/channel-event.ts similarity index 95% rename from packages/conversation/src/models/v1/channel-event/channel-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/channel-event/channel-event.ts index fd4c879e..a20eef6a 100644 --- a/packages/conversation/src/models/v1/channel-event/channel-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/channel-event/channel-event.ts @@ -1,4 +1,4 @@ -import { ConversationChannel } from '../conversation-channel'; +import { ConversationChannel } from '../../conversation-channel'; import { ConversationEvent } from '../conversation-event'; /** diff --git a/packages/conversation/src/models/v1/channel-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/channel-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/channel-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/channel-event/index.ts diff --git a/packages/conversation/src/models/v1/contact-create-event/contact-create-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-create-event/contact-create-event.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-create-event/contact-create-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-create-event/contact-create-event.ts diff --git a/packages/conversation/src/models/v1/contact-create-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-create-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-create-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-create-event/index.ts diff --git a/packages/conversation/src/models/v1/contact-delete-event/contact-delete-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/contact-delete-event.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-delete-event/contact-delete-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/contact-delete-event.ts diff --git a/packages/conversation/src/models/v1/contact-delete-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-delete-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/index.ts diff --git a/packages/conversation/src/models/v1/contact-identities-duplication-event/contact-identities-duplication-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-identities-duplication-event/contact-identities-duplication-event.ts similarity index 95% rename from packages/conversation/src/models/v1/contact-identities-duplication-event/contact-identities-duplication-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-identities-duplication-event/contact-identities-duplication-event.ts index 9e541831..055f413f 100644 --- a/packages/conversation/src/models/v1/contact-identities-duplication-event/contact-identities-duplication-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/contact-identities-duplication-event/contact-identities-duplication-event.ts @@ -1,4 +1,4 @@ -import { ConversationChannel } from '../conversation-channel'; +import { ConversationChannel } from '../../conversation-channel'; import { ConversationEvent } from '../conversation-event'; /** diff --git a/packages/conversation/src/models/v1/contact-identities-duplication-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-identities-duplication-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-identities-duplication-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-identities-duplication-event/index.ts diff --git a/packages/conversation/src/models/v1/contact-merge-event/contact-merge-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/contact-merge-event.ts similarity index 96% rename from packages/conversation/src/models/v1/contact-merge-event/contact-merge-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/contact-merge-event.ts index 442ec1f5..cc74b054 100644 --- a/packages/conversation/src/models/v1/contact-merge-event/contact-merge-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/contact-merge-event.ts @@ -1,4 +1,4 @@ -import { Contact } from '../contact'; +import { Contact } from '../../contact'; import { ConversationEvent } from '../conversation-event'; /** diff --git a/packages/conversation/src/models/v1/contact-merge-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-merge-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/index.ts diff --git a/packages/conversation/src/models/v1/contact-notification/contact-notification.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-notification/contact-notification.ts similarity index 67% rename from packages/conversation/src/models/v1/contact-notification/contact-notification.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-notification/contact-notification.ts index c116ae09..b80461e2 100644 --- a/packages/conversation/src/models/v1/contact-notification/contact-notification.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/contact-notification/contact-notification.ts @@ -1,4 +1,4 @@ -import { Contact } from '../contact'; +import { Contact } from '../../contact'; export interface ContactNotification { diff --git a/packages/conversation/src/models/v1/contact-notification/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-notification/index.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-notification/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-notification/index.ts diff --git a/packages/conversation/src/models/v1/contact-update-event/contact-update-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-update-event/contact-update-event.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-update-event/contact-update-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-update-event/contact-update-event.ts diff --git a/packages/conversation/src/models/v1/contact-update-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-update-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/contact-update-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/contact-update-event/index.ts diff --git a/packages/conversation/src/models/v1/conversation-delete-event/conversation-delete-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/conversation-delete-event.ts similarity index 96% rename from packages/conversation/src/models/v1/conversation-delete-event/conversation-delete-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/conversation-delete-event.ts index d136e44c..4979d938 100644 --- a/packages/conversation/src/models/v1/conversation-delete-event/conversation-delete-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/conversation-delete-event.ts @@ -1,4 +1,4 @@ -import { Conversation } from '../conversation'; +import { Conversation } from '../../conversation'; import { ConversationEvent } from '../conversation-event'; /** diff --git a/packages/conversation/src/models/v1/conversation-delete-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/conversation-delete-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/index.ts diff --git a/packages/conversation/src/models/v1/conversation-event/conversation-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-event/conversation-event.ts similarity index 54% rename from packages/conversation/src/models/v1/conversation-event/conversation-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-event/conversation-event.ts index f52df4d6..d6feeb32 100644 --- a/packages/conversation/src/models/v1/conversation-event/conversation-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-event/conversation-event.ts @@ -1,4 +1,4 @@ -import { WebhookTrigger } from '../webhook-trigger'; +import { WebhookTrigger } from '../../webhook-trigger'; export interface ConversationEvent { trigger: WebhookTrigger; diff --git a/packages/conversation/src/models/v1/conversation-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/conversation-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-event/index.ts diff --git a/packages/conversation/src/models/v1/conversation-start-event/conversation-start-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/conversation-start-event.ts similarity index 95% rename from packages/conversation/src/models/v1/conversation-start-event/conversation-start-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/conversation-start-event.ts index c5a6d51e..395ede02 100644 --- a/packages/conversation/src/models/v1/conversation-start-event/conversation-start-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/conversation-start-event.ts @@ -1,4 +1,4 @@ -import { Conversation } from '../conversation'; +import { Conversation } from '../../conversation'; import { ConversationEvent } from '../conversation-event'; /** diff --git a/packages/conversation/src/models/v1/conversation-start-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/conversation-start-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/index.ts diff --git a/packages/conversation/src/models/v1/conversation-stop-event/conversation-stop-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/conversation-stop-event.ts similarity index 95% rename from packages/conversation/src/models/v1/conversation-stop-event/conversation-stop-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/conversation-stop-event.ts index 4946d7a9..f382b33c 100644 --- a/packages/conversation/src/models/v1/conversation-stop-event/conversation-stop-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/conversation-stop-event.ts @@ -1,4 +1,4 @@ -import { Conversation } from '../conversation'; +import { Conversation } from '../../conversation'; import { ConversationEvent } from '../conversation-event'; /** diff --git a/packages/conversation/src/models/v1/conversation-stop-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/conversation-stop-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/index.ts diff --git a/packages/conversation/src/models/v1/conversation-webhook-event/conversation-webhook-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/conversation-webhook-event.ts similarity index 100% rename from packages/conversation/src/models/v1/conversation-webhook-event/conversation-webhook-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/conversation-webhook-event.ts diff --git a/packages/conversation/src/models/v1/conversation-webhook-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/conversation-webhook-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/index.ts diff --git a/packages/conversation/src/models/v1/event-delivery/event-delivery.ts b/packages/conversation/src/models/v1/mod-callback-events/event-delivery/event-delivery.ts similarity index 90% rename from packages/conversation/src/models/v1/event-delivery/event-delivery.ts rename to packages/conversation/src/models/v1/mod-callback-events/event-delivery/event-delivery.ts index 51ab7d4a..67257cb2 100644 --- a/packages/conversation/src/models/v1/event-delivery/event-delivery.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/event-delivery/event-delivery.ts @@ -1,7 +1,7 @@ -import { ChannelIdentity } from '../channel-identity'; -import { Reason } from '../reason'; +import { ChannelIdentity } from '../../channel-identity'; +import { Reason } from '../../reason'; import { ConversationEvent } from '../conversation-event'; -import { DeliveryStatus, ProcessingMode } from '../enums'; +import { DeliveryStatus, ProcessingMode } from '../../enums'; export interface EventDelivery extends ConversationEvent{ diff --git a/packages/conversation/src/models/v1/event-delivery/index.ts b/packages/conversation/src/models/v1/mod-callback-events/event-delivery/index.ts similarity index 100% rename from packages/conversation/src/models/v1/event-delivery/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/event-delivery/index.ts diff --git a/packages/conversation/src/models/v1/event-inbound/event-inbound.ts b/packages/conversation/src/models/v1/mod-callback-events/event-inbound/event-inbound.ts similarity index 97% rename from packages/conversation/src/models/v1/event-inbound/event-inbound.ts rename to packages/conversation/src/models/v1/mod-callback-events/event-inbound/event-inbound.ts index 3b2d8dbe..546238ee 100644 --- a/packages/conversation/src/models/v1/event-inbound/event-inbound.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/event-inbound/event-inbound.ts @@ -1,6 +1,6 @@ -import { ChannelIdentity } from '../channel-identity'; +import { ChannelIdentity } from '../../channel-identity'; import { ConversationEvent } from '../conversation-event'; -import { ProcessingMode } from '../enums'; +import { ProcessingMode } from '../../enums'; export interface EventInbound extends ConversationEvent { diff --git a/packages/conversation/src/models/v1/event-inbound/index.ts b/packages/conversation/src/models/v1/mod-callback-events/event-inbound/index.ts similarity index 100% rename from packages/conversation/src/models/v1/event-inbound/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/event-inbound/index.ts diff --git a/packages/conversation/src/models/v1/mod-callback-events/index.ts b/packages/conversation/src/models/v1/mod-callback-events/index.ts new file mode 100644 index 00000000..cdfbe384 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/index.ts @@ -0,0 +1,23 @@ +export * from './capability-event'; +export * from './channel-event'; +export * from './contact-create-event'; +export * from './contact-delete-event'; +export * from './contact-identities-duplication-event'; +export * from './contact-merge-event'; +export * from './contact-notification'; +export * from './contact-update-event'; +export * from './conversation-delete-event'; +export * from './conversation-start-event'; +export * from './conversation-stop-event'; +export * from './conversation-webhook-event'; +export * from './event-delivery'; +export * from './event-inbound'; +export * from './message-inbound-event'; +export * from './message-inbound-event-item'; +export * from './message-inbound-smart-conversation-redaction-event'; +export * from './opt-in-event'; +export * from './opt-out-event'; +export * from './message-delivery-receipt-event'; +export * from './message-submit-event'; +export * from './smart-conversations-event'; +export * from './unsupported-callback-event'; diff --git a/packages/conversation/src/models/v1/message-delivery-receipt-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/message-delivery-receipt-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/index.ts diff --git a/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts b/packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/message-delivery-receipt-event.ts similarity index 91% rename from packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/message-delivery-receipt-event.ts index 7a549bc2..cb82f2fc 100644 --- a/packages/conversation/src/models/v1/message-delivery-receipt-event/message-delivery-receipt-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/message-delivery-receipt-event.ts @@ -1,7 +1,7 @@ -import { ChannelIdentity } from '../channel-identity'; -import { Reason } from '../reason'; +import { ChannelIdentity } from '../../channel-identity'; +import { Reason } from '../../reason'; import { ConversationEvent } from '../conversation-event'; -import { DeliveryStatus, ProcessingMode } from '../enums'; +import { DeliveryStatus, ProcessingMode } from '../../enums'; /** * This callback notifies the API clients about status changes of already sent app message. diff --git a/packages/conversation/src/models/v1/message-inbound-event-item/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/index.ts similarity index 100% rename from packages/conversation/src/models/v1/message-inbound-event-item/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/index.ts diff --git a/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/message-inbound-event-item.ts similarity index 90% rename from packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/message-inbound-event-item.ts index 3bca2d7d..a4897550 100644 --- a/packages/conversation/src/models/v1/message-inbound-event-item/message-inbound-event-item.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/message-inbound-event-item.ts @@ -1,6 +1,6 @@ -import { ChannelIdentity } from '../channel-identity'; -import { ContactMessage } from '../contact-message'; -import { ProcessingMode } from '../enums'; +import { ChannelIdentity } from '../../channel-identity'; +import { ContactMessage } from '../../contact-message'; +import { ProcessingMode } from '../../enums'; export interface MessageInboundEventItem { diff --git a/packages/conversation/src/models/v1/message-inbound-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/message-inbound-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/index.ts diff --git a/packages/conversation/src/models/v1/message-inbound-event/message-inbound-event.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/message-inbound-event.ts similarity index 100% rename from packages/conversation/src/models/v1/message-inbound-event/message-inbound-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/message-inbound-event.ts diff --git a/packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-smart-conversation-redaction-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-inbound-smart-conversation-redaction-event/index.ts diff --git a/packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts similarity index 100% rename from packages/conversation/src/models/v1/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts diff --git a/packages/conversation/src/models/v1/message-submit-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-submit-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/message-submit-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-submit-event/index.ts diff --git a/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts b/packages/conversation/src/models/v1/mod-callback-events/message-submit-event/message-submit-event.ts similarity index 91% rename from packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/message-submit-event/message-submit-event.ts index dffe04af..f349d54e 100644 --- a/packages/conversation/src/models/v1/message-submit-event/message-submit-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/message-submit-event/message-submit-event.ts @@ -1,7 +1,7 @@ -import { ChannelIdentity } from '../channel-identity'; -import { ContactMessage } from '../contact-message'; +import { ChannelIdentity } from '../../channel-identity'; +import { ContactMessage } from '../../contact-message'; import { ConversationEvent } from '../conversation-event'; -import { ProcessingMode } from '../enums'; +import { ProcessingMode } from '../../enums'; /** * This callback provides a notification to the API clients that the corresponding app message was submitted to a channel. This notification is created before any confirmation from Delivery Receipts. diff --git a/packages/conversation/src/models/v1/opt-in-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/opt-in-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/opt-in-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/opt-in-event/index.ts diff --git a/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts b/packages/conversation/src/models/v1/mod-callback-events/opt-in-event/opt-in-event.ts similarity index 94% rename from packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/opt-in-event/opt-in-event.ts index 229d60dc..47f7a321 100644 --- a/packages/conversation/src/models/v1/opt-in-event/opt-in-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/opt-in-event/opt-in-event.ts @@ -1,6 +1,6 @@ -import { ConversationChannel } from '../conversation-channel'; +import { ConversationChannel } from '../../conversation-channel'; import { ConversationEvent } from '../conversation-event'; -import { ProcessingMode } from '../enums'; +import { ProcessingMode } from '../../enums'; /** * This callback is used to deliver opt-in notifications from the channels. diff --git a/packages/conversation/src/models/v1/opt-out-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/opt-out-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/opt-out-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/opt-out-event/index.ts diff --git a/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts b/packages/conversation/src/models/v1/mod-callback-events/opt-out-event/opt-out-event.ts similarity index 94% rename from packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/opt-out-event/opt-out-event.ts index afe81378..b49bf771 100644 --- a/packages/conversation/src/models/v1/opt-out-event/opt-out-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/opt-out-event/opt-out-event.ts @@ -1,6 +1,6 @@ -import { ConversationChannel } from '../conversation-channel'; +import { ConversationChannel } from '../../conversation-channel'; import { ConversationEvent } from '../conversation-event'; -import { ProcessingMode } from '../enums'; +import { ProcessingMode } from '../../enums'; /** * This callback is used to deliver opt-out notifications from the channels. diff --git a/packages/conversation/src/models/v1/smart-conversations-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/smart-conversations-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/index.ts diff --git a/packages/conversation/src/models/v1/smart-conversations-event/smart-conversations-event.ts b/packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/smart-conversations-event.ts similarity index 99% rename from packages/conversation/src/models/v1/smart-conversations-event/smart-conversations-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/smart-conversations-event.ts index 1e61e02b..4c4bfb48 100644 --- a/packages/conversation/src/models/v1/smart-conversations-event/smart-conversations-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/smart-conversations-event.ts @@ -1,4 +1,4 @@ -import { ConversationChannel } from '../conversation-channel'; +import { ConversationChannel } from '../../conversation-channel'; import { ConversationEvent } from '../conversation-event'; /** diff --git a/packages/conversation/src/models/v1/unsupported-callback-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/index.ts similarity index 100% rename from packages/conversation/src/models/v1/unsupported-callback-event/index.ts rename to packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/index.ts diff --git a/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts b/packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/unsupported-callback-event.ts similarity index 90% rename from packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts rename to packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/unsupported-callback-event.ts index b9bf2202..0a602d0e 100644 --- a/packages/conversation/src/models/v1/unsupported-callback-event/unsupported-callback-event.ts +++ b/packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/unsupported-callback-event.ts @@ -1,7 +1,7 @@ -import { ConversationChannel } from '../conversation-channel'; -import { ChannelIdentity } from '../channel-identity'; +import { ConversationChannel } from '../../conversation-channel'; +import { ChannelIdentity } from '../../channel-identity'; import { ConversationEvent } from '../conversation-event'; -import { ProcessingMode } from '../enums'; +import { ProcessingMode } from '../../enums'; /** * Some of the callbacks received from the underlying channels might be specific to a single channel or may not have a proper mapping in Conversation API yet. diff --git a/packages/conversation/src/models/v1/applebc-credentials/applebc-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/applebc-credentials/applebc-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/applebc-credentials/applebc-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/applebc-credentials/applebc-credentials.ts diff --git a/packages/conversation/src/models/v1/applebc-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/applebc-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/applebc-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/applebc-credentials/index.ts diff --git a/packages/conversation/src/models/v1/basic-auth-credential/basic-auth-credential.ts b/packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/basic-auth-credential.ts similarity index 100% rename from packages/conversation/src/models/v1/basic-auth-credential/basic-auth-credential.ts rename to packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/basic-auth-credential.ts diff --git a/packages/conversation/src/models/v1/basic-auth-credential/index.ts b/packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/index.ts similarity index 100% rename from packages/conversation/src/models/v1/basic-auth-credential/index.ts rename to packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/index.ts diff --git a/packages/conversation/src/models/v1/mod-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/index.ts new file mode 100644 index 00000000..c1ed3b00 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/index.ts @@ -0,0 +1,12 @@ +export * from './applebc-credentials'; +export * from './basic-auth-credential'; +export * from './instagram-credentials'; +export * from './kakaotalk-credentials'; +export * from './kakaotalkchat-credentials'; +export * from './line-credentials'; +export * from './mms-credentials'; +export * from './sms-credentials'; +export * from './static-bearer-credential'; +export * from './static-token-credential'; +export * from './telegram-credentials'; +export * from './wechat-credentials'; diff --git a/packages/conversation/src/models/v1/instagram-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/instagram-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/instagram-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/instagram-credentials/index.ts diff --git a/packages/conversation/src/models/v1/instagram-credentials/instagram-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/instagram-credentials/instagram-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/instagram-credentials/instagram-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/instagram-credentials/instagram-credentials.ts diff --git a/packages/conversation/src/models/v1/kakaotalk-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/kakaotalk-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/index.ts diff --git a/packages/conversation/src/models/v1/kakaotalk-credentials/kakaotalk-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/kakaotalk-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/kakaotalk-credentials/kakaotalk-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/kakaotalk-credentials.ts diff --git a/packages/conversation/src/models/v1/kakaotalkchat-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/kakaotalkchat-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/index.ts diff --git a/packages/conversation/src/models/v1/kakaotalkchat-credentials/kakaotalkchat-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/kakaotalkchat-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/kakaotalkchat-credentials/kakaotalkchat-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/kakaotalkchat-credentials.ts diff --git a/packages/conversation/src/models/v1/line-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/line-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/line-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/line-credentials/index.ts diff --git a/packages/conversation/src/models/v1/line-credentials/line-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/line-credentials/line-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/line-credentials/line-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/line-credentials/line-credentials.ts diff --git a/packages/conversation/src/models/v1/mms-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/mms-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/mms-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/mms-credentials/index.ts diff --git a/packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/mms-credentials/mms-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/mms-credentials/mms-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/mms-credentials/mms-credentials.ts diff --git a/packages/conversation/src/models/v1/sms-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/sms-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/sms-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/sms-credentials/index.ts diff --git a/packages/conversation/src/models/v1/sms-credentials/sms-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/sms-credentials/sms-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/sms-credentials/sms-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/sms-credentials/sms-credentials.ts diff --git a/packages/conversation/src/models/v1/static-bearer-credential/index.ts b/packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/index.ts similarity index 100% rename from packages/conversation/src/models/v1/static-bearer-credential/index.ts rename to packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/index.ts diff --git a/packages/conversation/src/models/v1/static-bearer-credential/static-bearer-credential.ts b/packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/static-bearer-credential.ts similarity index 100% rename from packages/conversation/src/models/v1/static-bearer-credential/static-bearer-credential.ts rename to packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/static-bearer-credential.ts diff --git a/packages/conversation/src/models/v1/static-token-credential/index.ts b/packages/conversation/src/models/v1/mod-credentials/static-token-credential/index.ts similarity index 100% rename from packages/conversation/src/models/v1/static-token-credential/index.ts rename to packages/conversation/src/models/v1/mod-credentials/static-token-credential/index.ts diff --git a/packages/conversation/src/models/v1/static-token-credential/static-token-credential.ts b/packages/conversation/src/models/v1/mod-credentials/static-token-credential/static-token-credential.ts similarity index 100% rename from packages/conversation/src/models/v1/static-token-credential/static-token-credential.ts rename to packages/conversation/src/models/v1/mod-credentials/static-token-credential/static-token-credential.ts diff --git a/packages/conversation/src/models/v1/telegram-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/telegram-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/telegram-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/telegram-credentials/index.ts diff --git a/packages/conversation/src/models/v1/telegram-credentials/telegram-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/telegram-credentials/telegram-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/telegram-credentials/telegram-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/telegram-credentials/telegram-credentials.ts diff --git a/packages/conversation/src/models/v1/wechat-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/wechat-credentials/index.ts similarity index 100% rename from packages/conversation/src/models/v1/wechat-credentials/index.ts rename to packages/conversation/src/models/v1/mod-credentials/wechat-credentials/index.ts diff --git a/packages/conversation/src/models/v1/wechat-credentials/wechat-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/wechat-credentials/wechat-credentials.ts similarity index 100% rename from packages/conversation/src/models/v1/wechat-credentials/wechat-credentials.ts rename to packages/conversation/src/models/v1/mod-credentials/wechat-credentials/wechat-credentials.ts From 0760eae80fce76b509ea8a8d87b29cefc78cf4ea Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Tue, 13 Feb 2024 22:39:24 +0100 Subject: [PATCH 18/19] Revive dates --- .../src/client/api-client-helpers.ts | 31 ++++++++++++ .../client/api-client-pagination-helper.ts | 5 +- .../sdk-client/src/client/api-fetch-client.ts | 50 ++++++++++++++++--- .../tests/client/api-client-helpers.test.ts | 47 +++++++++++++++++ 4 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 packages/sdk-client/tests/client/api-client-helpers.test.ts diff --git a/packages/sdk-client/src/client/api-client-helpers.ts b/packages/sdk-client/src/client/api-client-helpers.ts index 764ef29a..a7adcdf7 100644 --- a/packages/sdk-client/src/client/api-client-helpers.ts +++ b/packages/sdk-client/src/client/api-client-helpers.ts @@ -62,3 +62,34 @@ export async function invalidateAndRegenerateJwt( throw new GenericError(errorMessage, errorContext); } } + +/** + * Go through all an object's properties and transform to date the values that match the right format + * @param {any} input - the response object after all the response plugins have been run + * @return {any} - the response where the values matching a date are revived as Date objects + */ +export const reviveDates = (input: any): any => { + if (Array.isArray(input)) { + // Process array elements recursively + return input.map((item) => reviveDates(item)); + } else if (typeof input === 'object' && input !== null) { + // Process object properties recursively + const newObj: any = {}; + for (const key in input) { + if (Object.prototype.hasOwnProperty.call(input, key)) { + newObj[key] = reviveDates(input[key]); + } + } + return newObj; + } else if (isDateString(input)) { + // Convert string date to Date object + return new Date(input); + } else { + // Return other types as-is + return input; + } +}; + +const isDateString = (value: any): boolean => { + return typeof value === 'string' && !isNaN(Date.parse(value)); +}; diff --git a/packages/sdk-client/src/client/api-client-pagination-helper.ts b/packages/sdk-client/src/client/api-client-pagination-helper.ts index 0a1b6b22..c61a296b 100644 --- a/packages/sdk-client/src/client/api-client-pagination-helper.ts +++ b/packages/sdk-client/src/client/api-client-pagination-helper.ts @@ -87,14 +87,13 @@ const updateQueryParamsAndSendRequest = ( ...requestOptions.queryParams, ...newParams, }; - const extractedParams = apiClient.extractQueryParams(newQueryParams, Object.keys(newQueryParams)); const newRequestOptions: RequestOptions = { ...requestOptions, - queryParams: extractedParams, + queryParams: newQueryParams, }; const newUrl = apiClient.prepareUrl( requestOptions.basePath, - extractedParams, + newQueryParams, ); return apiClient.processCallWithPagination({ url: newUrl, diff --git a/packages/sdk-client/src/client/api-fetch-client.ts b/packages/sdk-client/src/client/api-fetch-client.ts index 6a03eb7b..af344cab 100644 --- a/packages/sdk-client/src/client/api-fetch-client.ts +++ b/packages/sdk-client/src/client/api-fetch-client.ts @@ -12,7 +12,7 @@ import { ResponseJSONParseError, ApiCallParametersWithPagination, PageResult, } from '../api'; import fetch, { Response, Headers } from 'node-fetch'; -import { buildErrorContext, manageExpiredToken } from './api-client-helpers'; +import { buildErrorContext, manageExpiredToken, reviveDates } from './api-client-helpers'; import { buildPaginationContext, calculateNextPage, @@ -94,8 +94,8 @@ export class ApiFetchClient extends ApiClient { throw exception; } - // If everything went fine, we return the transformed API response - return transformedResponse; + // If everything went fine, we apply a last transformation to revive the dates, and we return the transformed API response + return reviveDates(transformedResponse); } private async sinchFetch( @@ -125,13 +125,15 @@ export class ApiFetchClient extends ApiClient { const errorContext: ErrorContext = buildErrorContext(props, origin); // Execute call - return this.sinchFetchWithPagination(props, errorContext); + return this.sinchFetchWithPagination(props, errorContext, origin); }; private async sinchFetchWithPagination( apiCallParameters: ApiCallParametersWithPagination, errorContext: ErrorContext, + origin: string | null, ): Promise> { + let exception: Error | undefined; const response = await fetch(apiCallParameters.url, apiCallParameters.requestOptions); if ( response.status === 401 @@ -146,14 +148,46 @@ export class ApiFetchClient extends ApiClient { } // When handling pagination, we won't return the raw response but a PageResult const body = await response.text(); - const result = JSON.parse(body); + let result; + try { + // Try to parse the body if there is one + result = body ? JSON.parse(body) : undefined; + } catch (error: any) { + exception = new ResponseJSONParseError( + error.message || 'Fail to parse response body', + (response && response.status) || 0, + errorContext, + body, + ); + } + + // Load and invoke the response plugins to transform the response + const responsePlugins = this.loadResponsePlugins( + this.apiClientOptions.responsePlugins, + apiCallParameters, + response, + exception, + origin); + let transformedResponse = result; + for (const pluginRunner of responsePlugins) { + transformedResponse = await pluginRunner.transform(transformedResponse); + } + + // Revive Date objects + transformedResponse = reviveDates(transformedResponse); + + // If there has been an error at some point in the process, throw it + if (exception) { + throw exception; + } + // Read the elements' array with its key - const responseData: Array = result[apiCallParameters.dataKey]; + const responseData: Array = transformedResponse[apiCallParameters.dataKey]; // Build the PageResult object - const nextPage = calculateNextPage(result, buildPaginationContext(apiCallParameters)); + const nextPage = JSON.stringify(calculateNextPage(transformedResponse, buildPaginationContext(apiCallParameters))); return { data: responseData || [], - hasNextPage: hasMore(result, buildPaginationContext(apiCallParameters)), + hasNextPage: hasMore(transformedResponse, buildPaginationContext(apiCallParameters)), nextPageValue: nextPage, nextPage: () => createNextPageMethod( this, buildPaginationContext(apiCallParameters), apiCallParameters.requestOptions, nextPage), diff --git a/packages/sdk-client/tests/client/api-client-helpers.test.ts b/packages/sdk-client/tests/client/api-client-helpers.test.ts new file mode 100644 index 00000000..5c0e3dfe --- /dev/null +++ b/packages/sdk-client/tests/client/api-client-helpers.test.ts @@ -0,0 +1,47 @@ +import { reviveDates } from '../../src/client/api-client-helpers'; + +describe('API client helpers', () => { + + it('should revive Dates', () => { + const obj = { + date1: '2024-01-31T12:00:00.000Z', + nested: { + date2: '2024-02-15T18:30:00.000Z', + }, + array: [ + { + date3: '2024-02-03T04:15:00.000Z', + }, + { + date3: '2024-02-04T20:22:00.123Z', + }, + ], + otherProp: 'otherValue', + otherNumber: 0, + otherBoolean: true, + otherUndefined: undefined, + otherNull: null, + }; + const expected = { + date1: new Date('2024-01-31T12:00:00.000Z'), + nested: { + date2: new Date('2024-02-15T18:30:00.000Z'), + }, + array: [ + { + date3: new Date('2024-02-03T04:15:00.000Z'), + }, + { + date3: new Date('2024-02-04T20:22:00.123Z'), + }, + ], + otherProp: 'otherValue', + otherNumber: 0, + otherBoolean: true, + otherUndefined: undefined, + otherNull: null, + }; + expect(reviveDates(obj)).toStrictEqual(expected); + }); + +}); From fcf602036276493a6e4ebe51ebbd689f7dbcf213 Mon Sep 17 00:00:00 2001 From: Antoine Sein Date: Wed, 14 Feb 2024 09:51:03 +0100 Subject: [PATCH 19/19] Harmonize naming across APIs --- ...tion-domain.ts => conversation-service.ts} | 2 +- packages/conversation/src/rest/v1/index.ts | 2 +- .../v1/active-number/active-number-api.ts | 4 +-- .../available-number/available-number-api.ts | 4 +-- .../available-regions-api.ts | 4 +-- .../src/rest/v1/callbacks/callbacks-api.ts | 4 +-- packages/numbers/src/rest/v1/index.ts | 2 +- .../{numbers-api.ts => numbers-domain-api.ts} | 4 +-- .../v1/{numbers.ts => numbers-service.ts} | 8 +---- .../numbers/tests/rest/v1/numbers-api.test.ts | 10 +++---- packages/sdk-core/src/sinch-client.ts | 30 +++++++++---------- .../sms/src/rest/v1/batches/batches-api.ts | 4 +-- .../delivery-reports/delivery-reports-api.ts | 4 +-- packages/sms/src/rest/v1/groups/groups-api.ts | 4 +-- .../sms/src/rest/v1/inbounds/inbounds-api.ts | 4 +-- packages/sms/src/rest/v1/index.ts | 2 +- .../rest/v1/{sms-api.ts => sms-domain-api.ts} | 2 +- .../src/rest/v1/{sms.ts => sms-service.ts} | 8 +---- packages/sms/tests/rest/v1/sms-api.test.ts | 18 +++++------ packages/verification/src/rest/v1/index.ts | 2 +- ...tion-api.ts => verification-domain-api.ts} | 2 +- ...erification.ts => verification-service.ts} | 2 +- .../verification-status-api.ts | 4 +-- .../v1/verifications/verifications-api.ts | 4 +-- .../tests/rest/v1/verification-api.test.ts | 10 +++---- .../rest/v1/applications/applications-api.ts | 4 +-- .../src/rest/v1/callouts/callouts-api.ts | 4 +-- packages/voice/src/rest/v1/calls/calls-api.ts | 4 +-- .../rest/v1/conferences/conferences-api.ts | 4 +-- packages/voice/src/rest/v1/index.ts | 2 +- .../v1/{voice-api.ts => voice-domain-api.ts} | 2 +- .../rest/v1/{voice.ts => voice-service.ts} | 8 +---- 32 files changed, 77 insertions(+), 95 deletions(-) rename packages/conversation/src/rest/v1/{conversation-domain.ts => conversation-service.ts} (98%) rename packages/numbers/src/rest/v1/{numbers-api.ts => numbers-domain-api.ts} (96%) rename packages/numbers/src/rest/v1/{numbers.ts => numbers-service.ts} (90%) rename packages/sms/src/rest/v1/{sms-api.ts => sms-domain-api.ts} (98%) rename packages/sms/src/rest/v1/{sms.ts => sms-service.ts} (90%) rename packages/verification/src/rest/v1/{verification-api.ts => verification-domain-api.ts} (97%) rename packages/verification/src/rest/v1/{verification.ts => verification-service.ts} (95%) rename packages/voice/src/rest/v1/{voice-api.ts => voice-domain-api.ts} (98%) rename packages/voice/src/rest/v1/{voice.ts => voice-service.ts} (90%) diff --git a/packages/conversation/src/rest/v1/conversation-domain.ts b/packages/conversation/src/rest/v1/conversation-service.ts similarity index 98% rename from packages/conversation/src/rest/v1/conversation-domain.ts rename to packages/conversation/src/rest/v1/conversation-service.ts index 15f915b5..391721d1 100644 --- a/packages/conversation/src/rest/v1/conversation-domain.ts +++ b/packages/conversation/src/rest/v1/conversation-service.ts @@ -10,7 +10,7 @@ import { WebhooksApi } from './webhooks'; import { TemplatesV1Api } from './templates-v1'; import { TemplatesV2Api } from './templates-v2'; -export class ConversationDomain { +export class ConversationService { public readonly contact: ContactApi; public readonly app: AppApi; public readonly events: EventsApi; diff --git a/packages/conversation/src/rest/v1/index.ts b/packages/conversation/src/rest/v1/index.ts index 417a2a50..d86bda6b 100644 --- a/packages/conversation/src/rest/v1/index.ts +++ b/packages/conversation/src/rest/v1/index.ts @@ -10,4 +10,4 @@ export * from './templates-v2'; export * from './transcoding'; export * from './webhooks'; export * from './enums'; -export * from './conversation-domain'; +export * from './conversation-service'; diff --git a/packages/numbers/src/rest/v1/active-number/active-number-api.ts b/packages/numbers/src/rest/v1/active-number/active-number-api.ts index 78c1164b..98d003f0 100644 --- a/packages/numbers/src/rest/v1/active-number/active-number-api.ts +++ b/packages/numbers/src/rest/v1/active-number/active-number-api.ts @@ -14,7 +14,7 @@ import { buildPageResultPromise, createIteratorMethodsForPagination, } from '@sinch/sdk-client'; -import { NumbersApi } from '../numbers-api'; +import { NumbersDomainApi } from '../numbers-domain-api'; export interface GetActiveNumberRequestData { /** Output only. The phone number in E.164 format with leading `+`. */ @@ -50,7 +50,7 @@ export interface UpdateActiveNumberRequestData { activeNumberRequestBody?: ActiveNumberRequest; } -export class ActiveNumberApi extends NumbersApi { +export class ActiveNumberApi extends NumbersDomainApi { /** * Initialize your interface with the provided API client. diff --git a/packages/numbers/src/rest/v1/available-number/available-number-api.ts b/packages/numbers/src/rest/v1/available-number/available-number-api.ts index ffd383b1..7c76fe72 100644 --- a/packages/numbers/src/rest/v1/available-number/available-number-api.ts +++ b/packages/numbers/src/rest/v1/available-number/available-number-api.ts @@ -12,7 +12,7 @@ import { RequestBody, SinchClientParameters, } from '@sinch/sdk-client'; -import { NumbersApi } from '../numbers-api'; +import { NumbersDomainApi } from '../numbers-domain-api'; export interface GetAvailableNumberRequestData { /** Output only. The phone number in E.164 format with leading `+`. */ @@ -43,7 +43,7 @@ export interface RentNumberRequestData { rentNumberRequestBody: RentNumberRequest; } -export class AvailableNumberApi extends NumbersApi { +export class AvailableNumberApi extends NumbersDomainApi { /** * Initialize your interface with the provided API client. diff --git a/packages/numbers/src/rest/v1/available-regions/available-regions-api.ts b/packages/numbers/src/rest/v1/available-regions/available-regions-api.ts index d730b7b2..a9c44f82 100644 --- a/packages/numbers/src/rest/v1/available-regions/available-regions-api.ts +++ b/packages/numbers/src/rest/v1/available-regions/available-regions-api.ts @@ -3,7 +3,7 @@ import { RequestBody, SinchClientParameters, } from '@sinch/sdk-client'; -import { NumbersApi } from '../numbers-api'; +import { NumbersDomainApi } from '../numbers-domain-api'; export type RegionNumberTypeEnum = 'NUMBER_TYPE_UNSPECIFIED' | 'MOBILE' | 'LOCAL' | 'TOLL_FREE'; @@ -17,7 +17,7 @@ export interface ListAvailableRegionsRequestData { types?: Array; } -export class AvailableRegionsApi extends NumbersApi { +export class AvailableRegionsApi extends NumbersDomainApi { /** * Initialize your interface with the provided API client. diff --git a/packages/numbers/src/rest/v1/callbacks/callbacks-api.ts b/packages/numbers/src/rest/v1/callbacks/callbacks-api.ts index 93ccde0f..4dd8b110 100644 --- a/packages/numbers/src/rest/v1/callbacks/callbacks-api.ts +++ b/packages/numbers/src/rest/v1/callbacks/callbacks-api.ts @@ -3,7 +3,7 @@ import { RequestBody, SinchClientParameters, } from '@sinch/sdk-client'; -import { NumbersApi } from '../numbers-api'; +import { NumbersDomainApi } from '../numbers-domain-api'; export interface GetCallbackConfigurationRequestData {} export interface UpdateCallbackConfigurationRequestData { @@ -11,7 +11,7 @@ export interface UpdateCallbackConfigurationRequestData { callbackConfigurationUpdateRequestBody?: CallbackConfigurationUpdate; } -export class CallbacksApi extends NumbersApi { +export class CallbacksApi extends NumbersDomainApi { /** * Initialize your interface with the provided API client. diff --git a/packages/numbers/src/rest/v1/index.ts b/packages/numbers/src/rest/v1/index.ts index 0ee83a3a..292b7834 100644 --- a/packages/numbers/src/rest/v1/index.ts +++ b/packages/numbers/src/rest/v1/index.ts @@ -3,4 +3,4 @@ export * from './available-number'; export * from './available-regions'; export * from './callbacks'; export * from './callbacks-webhook'; -export * from './numbers'; +export * from './numbers-service'; diff --git a/packages/numbers/src/rest/v1/numbers-api.ts b/packages/numbers/src/rest/v1/numbers-domain-api.ts similarity index 96% rename from packages/numbers/src/rest/v1/numbers-api.ts rename to packages/numbers/src/rest/v1/numbers-domain-api.ts index 07d49fee..59993864 100644 --- a/packages/numbers/src/rest/v1/numbers-api.ts +++ b/packages/numbers/src/rest/v1/numbers-domain-api.ts @@ -6,7 +6,7 @@ import { Oauth2TokenRequest, UnifiedCredentials, } from '@sinch/sdk-client'; -export class NumbersApi implements Api { +export class NumbersDomainApi implements Api { public readonly apiName: string; public client?: ApiClient; private sinchClientParameters: SinchClientParameters; @@ -27,7 +27,7 @@ export class NumbersApi implements Api { /** * Updates the credentials used to authenticate API requests - * @param {UnifiedCredentials} credentials + * @param {UnifiedCredentials} credentials */ public setCredentials(credentials: UnifiedCredentials) { const parametersBackup = { ...this.sinchClientParameters }; diff --git a/packages/numbers/src/rest/v1/numbers.ts b/packages/numbers/src/rest/v1/numbers-service.ts similarity index 90% rename from packages/numbers/src/rest/v1/numbers.ts rename to packages/numbers/src/rest/v1/numbers-service.ts index bc1e336b..2e8570b1 100644 --- a/packages/numbers/src/rest/v1/numbers.ts +++ b/packages/numbers/src/rest/v1/numbers-service.ts @@ -1,16 +1,10 @@ -/** - * Domain: numbers - * - * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. - * - */ import { SinchClientParameters } from '@sinch/sdk-client'; import { AvailableRegionsApi } from './available-regions'; import { CallbacksApi } from './callbacks'; import { AvailableNumberApi } from './available-number'; import { ActiveNumberApi } from './active-number'; -export class Numbers { +export class NumbersService { public readonly availableRegions: AvailableRegionsApi; public readonly callbacks: CallbacksApi; public readonly availableNumber: AvailableNumberApi; diff --git a/packages/numbers/tests/rest/v1/numbers-api.test.ts b/packages/numbers/tests/rest/v1/numbers-api.test.ts index a69a971c..efde96ca 100644 --- a/packages/numbers/tests/rest/v1/numbers-api.test.ts +++ b/packages/numbers/tests/rest/v1/numbers-api.test.ts @@ -1,8 +1,8 @@ -import { NumbersApi } from '../../../src/rest/v1/numbers-api'; +import { NumbersDomainApi } from '../../../src/rest/v1/numbers-domain-api'; import { SinchClientParameters } from '@sinch/sdk-client'; describe('Numbers API', () => { - let numbersApi: NumbersApi; + let numbersApi: NumbersDomainApi; let params: SinchClientParameters; beforeEach(() => { @@ -14,7 +14,7 @@ describe('Numbers API', () => { }); it('should initialize the client', () => { - numbersApi = new NumbersApi(params, 'dummy'); + numbersApi = new NumbersDomainApi(params, 'dummy'); numbersApi.getSinchClient(); expect(numbersApi.client).toBeDefined(); expect(numbersApi.client?.apiClientOptions.projectId).toBe('PROJECT_ID'); @@ -23,13 +23,13 @@ describe('Numbers API', () => { it('should update the basePath', () => { const newPath = 'https://new.base.path'; - numbersApi = new NumbersApi(params, 'dummy'); + numbersApi = new NumbersDomainApi(params, 'dummy'); numbersApi.setBasePath(newPath); expect(numbersApi.client?.apiClientOptions.basePath).toBe(newPath); }); it('should update the credentials', () => { - numbersApi = new NumbersApi(params, 'dummy'); + numbersApi = new NumbersDomainApi(params, 'dummy'); numbersApi.setCredentials({ projectId: 'NEW_PROJECT_ID', keyId: 'NEW_KEY_ID', diff --git a/packages/sdk-core/src/sinch-client.ts b/packages/sdk-core/src/sinch-client.ts index 4a5df9fb..97c23c5d 100644 --- a/packages/sdk-core/src/sinch-client.ts +++ b/packages/sdk-core/src/sinch-client.ts @@ -1,18 +1,18 @@ -import { Numbers } from '@sinch/numbers'; -import { Sms } from '@sinch/sms'; -import { Verification } from '@sinch/verification'; +import { ConversationService } from '@sinch/conversation'; +import { NumbersService } from '@sinch/numbers'; +import { SmsService } from '@sinch/sms'; +import { VerificationService } from '@sinch/verification'; +import { VoiceService } from '@sinch/voice'; import { SinchClientParameters } from '@sinch/sdk-client'; -import { Voice } from '@sinch/voice'; -import { ConversationDomain } from '@sinch/conversation'; /** Sinch Client to declare and initialize the supported APIs */ export class SinchClient { - public readonly conversation: ConversationDomain; - public readonly numbers: Numbers; - public readonly sms: Sms; - public readonly verification: Verification; - public readonly voice: Voice; + public readonly conversation: ConversationService; + public readonly numbers: NumbersService; + public readonly sms: SmsService; + public readonly verification: VerificationService; + public readonly voice: VoiceService; /** * Initialize your API Client instance with the provided credentials. @@ -21,18 +21,18 @@ export class SinchClient { */ constructor(params: SinchClientParameters) { // Initialize the "Conversation" API - this.conversation = new ConversationDomain(params); + this.conversation = new ConversationService(params); // Initialize the "Numbers" API - this.numbers = new Numbers(params); + this.numbers = new NumbersService(params); // Initialize the "SMS" API. - this.sms = new Sms(params); + this.sms = new SmsService(params); // Initialize the "Verification" API - this.verification = new Verification(params); + this.verification = new VerificationService(params); // Initialize the "Voice" API - this.voice = new Voice(params); + this.voice = new VoiceService(params); } } diff --git a/packages/sms/src/rest/v1/batches/batches-api.ts b/packages/sms/src/rest/v1/batches/batches-api.ts index 7ef20b28..65e71d3e 100644 --- a/packages/sms/src/rest/v1/batches/batches-api.ts +++ b/packages/sms/src/rest/v1/batches/batches-api.ts @@ -19,7 +19,7 @@ import { buildPageResultPromise, createIteratorMethodsForPagination, } from '@sinch/sdk-client'; -import { SmsApi } from '../sms-api'; +import { SmsDomainApi } from '../sms-domain-api'; export interface CancelBatchMessageRequestData { /** The batch ID you received from sending a message. */ @@ -74,7 +74,7 @@ export interface UpdateBatchMessageRequestData { 'updateBatchMessageRequestBody'?: UpdateBatchMessageRequest; } -export class BatchesApi extends SmsApi { +export class BatchesApi extends SmsDomainApi { /** * Initialize your interface diff --git a/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.ts b/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.ts index 3ba4cb47..f0e02c54 100644 --- a/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.ts +++ b/packages/sms/src/rest/v1/delivery-reports/delivery-reports-api.ts @@ -12,7 +12,7 @@ import { buildPageResultPromise, createIteratorMethodsForPagination, } from '@sinch/sdk-client'; -import { SmsApi } from '../sms-api'; +import { SmsDomainApi } from '../sms-domain-api'; export type GetDeliveryReportByBatchIdTypeEnum = 'summary' | 'full'; export interface GetDeliveryReportByBatchIdRequestData { @@ -48,7 +48,7 @@ export interface GetDeliveryReportsRequestData { 'client_reference'?: string; } -export class DeliveryReportsApi extends SmsApi { +export class DeliveryReportsApi extends SmsDomainApi { /** * Initialize your interface diff --git a/packages/sms/src/rest/v1/groups/groups-api.ts b/packages/sms/src/rest/v1/groups/groups-api.ts index 20286cb8..94bbf7f8 100644 --- a/packages/sms/src/rest/v1/groups/groups-api.ts +++ b/packages/sms/src/rest/v1/groups/groups-api.ts @@ -16,7 +16,7 @@ import { buildPageResultPromise, createIteratorMethodsForPagination, } from '@sinch/sdk-client'; -import { SmsApi } from '../sms-api'; +import { SmsDomainApi } from '../sms-domain-api'; export interface CreateGroupRequestData { /** */ @@ -53,7 +53,7 @@ export interface UpdateGroupRequestData { 'updateGroupRequestBody'?: UpdateGroupRequest; } -export class GroupsApi extends SmsApi { +export class GroupsApi extends SmsDomainApi { /** * Initialize your interface diff --git a/packages/sms/src/rest/v1/inbounds/inbounds-api.ts b/packages/sms/src/rest/v1/inbounds/inbounds-api.ts index ff0299d9..57403cc5 100644 --- a/packages/sms/src/rest/v1/inbounds/inbounds-api.ts +++ b/packages/sms/src/rest/v1/inbounds/inbounds-api.ts @@ -10,7 +10,7 @@ import { buildPageResultPromise, createIteratorMethodsForPagination, } from '@sinch/sdk-client'; -import { SmsApi } from '../sms-api'; +import { SmsDomainApi } from '../sms-domain-api'; export interface ListInboundMessagesRequestData { /** The page number starting from 0. */ @@ -31,7 +31,7 @@ export interface GetInboundMessageRequestData { 'inbound_id': string; } -export class InboundsApi extends SmsApi { +export class InboundsApi extends SmsDomainApi { /** * Initialize your interface diff --git a/packages/sms/src/rest/v1/index.ts b/packages/sms/src/rest/v1/index.ts index 493f6c8c..d866bbc1 100644 --- a/packages/sms/src/rest/v1/index.ts +++ b/packages/sms/src/rest/v1/index.ts @@ -5,4 +5,4 @@ export * from './groups'; export * from './inbounds'; export * from './enums'; export * from './fixtures.jest'; -export * from './sms'; +export * from './sms-service'; diff --git a/packages/sms/src/rest/v1/sms-api.ts b/packages/sms/src/rest/v1/sms-domain-api.ts similarity index 98% rename from packages/sms/src/rest/v1/sms-api.ts rename to packages/sms/src/rest/v1/sms-domain-api.ts index 8c38a857..ccff6a3c 100644 --- a/packages/sms/src/rest/v1/sms-api.ts +++ b/packages/sms/src/rest/v1/sms-domain-api.ts @@ -9,7 +9,7 @@ import { Oauth2TokenRequest, UnifiedCredentials, ServicePlanIdCredentials, } from '@sinch/sdk-client'; -export class SmsApi implements Api { +export class SmsDomainApi implements Api { public readonly apiName: string; public client?: ApiClient; private sinchClientParameters: SinchClientParameters; diff --git a/packages/sms/src/rest/v1/sms.ts b/packages/sms/src/rest/v1/sms-service.ts similarity index 90% rename from packages/sms/src/rest/v1/sms.ts rename to packages/sms/src/rest/v1/sms-service.ts index a96aeff6..ce146d9c 100644 --- a/packages/sms/src/rest/v1/sms.ts +++ b/packages/sms/src/rest/v1/sms-service.ts @@ -1,9 +1,3 @@ -/** - * Domain: sms - * - * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. - * - */ import { SinchClientParameters, } from '@sinch/sdk-client'; @@ -12,7 +6,7 @@ import { DeliveryReportsApi } from './delivery-reports'; import { BatchesApi } from './batches'; import { InboundsApi } from './inbounds'; -export class Sms { +export class SmsService { public readonly groups: GroupsApi; public readonly deliveryReports: DeliveryReportsApi; public readonly batches: BatchesApi; diff --git a/packages/sms/tests/rest/v1/sms-api.test.ts b/packages/sms/tests/rest/v1/sms-api.test.ts index 3c9166cf..b924f65a 100644 --- a/packages/sms/tests/rest/v1/sms-api.test.ts +++ b/packages/sms/tests/rest/v1/sms-api.test.ts @@ -1,8 +1,8 @@ import { Region, ServicePlanIdCredentials, UnifiedCredentials } from '../../../src'; -import { SmsApi } from '../../../src/rest/v1/sms-api'; +import { SmsDomainApi } from '../../../src/rest/v1/sms-domain-api'; describe('SMS API', () => { - let smsApi: SmsApi; + let smsApi: SmsDomainApi; let paramsWithServicePlanId: ServicePlanIdCredentials; let paramsWithProjectId: UnifiedCredentials; @@ -19,7 +19,7 @@ describe('SMS API', () => { }); it('should initialize the client with unified credentials and use the "zt." URL', () => { - smsApi = new SmsApi(paramsWithProjectId, 'dummy'); + smsApi = new SmsDomainApi(paramsWithProjectId, 'dummy'); smsApi.getSinchClient(); expect(smsApi.client).toBeDefined(); expect(smsApi.client?.apiClientOptions.projectId).toBe('PROJECT_ID'); @@ -27,7 +27,7 @@ describe('SMS API', () => { }); it('should initialize the client with servicePlanId credentials and use standard URL', () => { - smsApi = new SmsApi(paramsWithServicePlanId, 'dummy'); + smsApi = new SmsDomainApi(paramsWithServicePlanId, 'dummy'); smsApi.getSinchClient(); expect(smsApi.client).toBeDefined(); expect(smsApi.client?.apiClientOptions.projectId).toBe('SERVICE_PLAN_ID'); @@ -36,20 +36,20 @@ describe('SMS API', () => { it('should change the URL when specifying a different region', () => { paramsWithServicePlanId.region = Region.CANADA; - smsApi = new SmsApi(paramsWithServicePlanId, 'dummy'); + smsApi = new SmsDomainApi(paramsWithServicePlanId, 'dummy'); smsApi.getSinchClient(); expect(smsApi.client?.apiClientOptions.basePath).toBe('https://ca.sms.api.sinch.com'); }); it('should update the base path', () => { const newPath = 'https://new.base.path'; - smsApi = new SmsApi(paramsWithServicePlanId, 'dummy'); + smsApi = new SmsDomainApi(paramsWithServicePlanId, 'dummy'); smsApi.setBasePath(newPath); expect(smsApi.client?.apiClientOptions.basePath).toBe(newPath); }); it('should not update the credentials when adding servicePlanId credentials on default region', () => { - smsApi = new SmsApi(paramsWithProjectId, 'dummy'); + smsApi = new SmsDomainApi(paramsWithProjectId, 'dummy'); smsApi.getSinchClient(); expect(smsApi.client?.apiClientOptions.projectId).toBe('PROJECT_ID'); expect(smsApi.client?.apiClientOptions.basePath).toBe('https://zt.us.sms.api.sinch.com'); @@ -59,7 +59,7 @@ describe('SMS API', () => { }); it('should update the credentials and URL when forcing servicePlanId credentials', () => { - smsApi = new SmsApi(paramsWithProjectId, 'dummy'); + smsApi = new SmsDomainApi(paramsWithProjectId, 'dummy'); smsApi.getSinchClient(); expect(smsApi.client?.apiClientOptions.projectId).toBe('PROJECT_ID'); expect(smsApi.client?.apiClientOptions.basePath).toBe('https://zt.us.sms.api.sinch.com'); @@ -72,7 +72,7 @@ describe('SMS API', () => { }); it('should update the credentials and URL when adding servicePlanId credentials on BR region', () => { - smsApi = new SmsApi(paramsWithProjectId, 'dummy'); + smsApi = new SmsDomainApi(paramsWithProjectId, 'dummy'); smsApi.getSinchClient(); expect(smsApi.client?.apiClientOptions.projectId).toBe('PROJECT_ID'); expect(smsApi.client?.apiClientOptions.basePath).toBe('https://zt.us.sms.api.sinch.com'); diff --git a/packages/verification/src/rest/v1/index.ts b/packages/verification/src/rest/v1/index.ts index 4c30451e..248310a9 100644 --- a/packages/verification/src/rest/v1/index.ts +++ b/packages/verification/src/rest/v1/index.ts @@ -2,4 +2,4 @@ export * from './callbacks'; export * from './verification-status'; export * from './verifications'; export * from './enums'; -export * from './verification'; +export * from './verification-service'; diff --git a/packages/verification/src/rest/v1/verification-api.ts b/packages/verification/src/rest/v1/verification-domain-api.ts similarity index 97% rename from packages/verification/src/rest/v1/verification-api.ts rename to packages/verification/src/rest/v1/verification-domain-api.ts index f20d9f6e..210f7db5 100644 --- a/packages/verification/src/rest/v1/verification-api.ts +++ b/packages/verification/src/rest/v1/verification-domain-api.ts @@ -6,7 +6,7 @@ import { SigningRequest, XTimestampRequest, ApplicationCredentials, } from '@sinch/sdk-client'; -export class VerificationApi implements Api { +export class VerificationDomainApi implements Api { public readonly apiName: string; public client?: ApiClient; private sinchClientParameters: SinchClientParameters; diff --git a/packages/verification/src/rest/v1/verification.ts b/packages/verification/src/rest/v1/verification-service.ts similarity index 95% rename from packages/verification/src/rest/v1/verification.ts rename to packages/verification/src/rest/v1/verification-service.ts index ceafac16..8d367f51 100644 --- a/packages/verification/src/rest/v1/verification.ts +++ b/packages/verification/src/rest/v1/verification-service.ts @@ -2,7 +2,7 @@ import { SinchClientParameters } from '@sinch/sdk-client'; import { VerificationStatusApi } from './verification-status'; import { VerificationsApi } from './verifications'; -export class Verification { +export class VerificationService { public readonly verificationStatus: VerificationStatusApi; public readonly verifications: VerificationsApi; diff --git a/packages/verification/src/rest/v1/verification-status/verification-status-api.ts b/packages/verification/src/rest/v1/verification-status/verification-status-api.ts index 98c8f1b7..2957e64a 100644 --- a/packages/verification/src/rest/v1/verification-status/verification-status-api.ts +++ b/packages/verification/src/rest/v1/verification-status/verification-status-api.ts @@ -3,7 +3,7 @@ import { SinchClientParameters, } from '@sinch/sdk-client'; import { VerificationReportResponse } from '../../../models'; -import { VerificationApi } from '../verification-api'; +import { VerificationDomainApi } from '../verification-domain-api'; export interface VerificationStatusByIdRequestData { /** The ID of the verification. */ @@ -20,7 +20,7 @@ export interface VerificationStatusByReferenceRequestData { 'reference': string; } -export class VerificationStatusApi extends VerificationApi { +export class VerificationStatusApi extends VerificationDomainApi { /** * Initialize your interface diff --git a/packages/verification/src/rest/v1/verifications/verifications-api.ts b/packages/verification/src/rest/v1/verifications/verifications-api.ts index 4bf9d4e0..7a421b90 100644 --- a/packages/verification/src/rest/v1/verifications/verifications-api.ts +++ b/packages/verification/src/rest/v1/verifications/verifications-api.ts @@ -12,7 +12,7 @@ import { RequestBody, SinchClientParameters, } from '@sinch/sdk-client'; -import { VerificationApi } from '../verification-api'; +import { VerificationDomainApi } from '../verification-domain-api'; interface ReportVerificationByIdRequestDataBase { /** The ID of the verification. */ @@ -74,7 +74,7 @@ export interface StartSeamlessVerificationRequestData { 'startSeamlessVerificationRequestBody': StartSeamlessVerification; } -export class VerificationsApi extends VerificationApi { +export class VerificationsApi extends VerificationDomainApi { /** * Initialize your interface diff --git a/packages/verification/tests/rest/v1/verification-api.test.ts b/packages/verification/tests/rest/v1/verification-api.test.ts index 26e605a1..5b0aad94 100644 --- a/packages/verification/tests/rest/v1/verification-api.test.ts +++ b/packages/verification/tests/rest/v1/verification-api.test.ts @@ -1,8 +1,8 @@ -import { VerificationApi } from '../../../src/rest/v1/verification-api'; +import { VerificationDomainApi } from '../../../src/rest/v1/verification-domain-api'; import { ApplicationCredentials, SigningRequest } from '@sinch/sdk-client'; describe('Verification API', () => { - let verificationApi: VerificationApi; + let verificationApi: VerificationDomainApi; let params: ApplicationCredentials; beforeEach(() => { @@ -13,7 +13,7 @@ describe('Verification API', () => { }); it('should initialize the client', () => { - verificationApi = new VerificationApi(params, 'dummy'); + verificationApi = new VerificationDomainApi(params, 'dummy'); verificationApi.getSinchClient(); expect(verificationApi.client).toBeDefined(); expect(verificationApi.client?.apiClientOptions.projectId).toBeUndefined(); @@ -23,13 +23,13 @@ describe('Verification API', () => { it('should update the base path', () => { const newPath = 'https://new.base.path'; - verificationApi = new VerificationApi(params, 'dummy'); + verificationApi = new VerificationDomainApi(params, 'dummy'); verificationApi.setBasePath(newPath); expect(verificationApi.client?.apiClientOptions.basePath).toBe('https://new.base.path'); }); it('should update the credentials', () => { - verificationApi = new VerificationApi(params, 'dummy'); + verificationApi = new VerificationDomainApi(params, 'dummy'); verificationApi.setApplication({ applicationKey: 'NEW_APPLICATION_KEY', applicationSecret: 'NEW_APPLICATION_SECRET', diff --git a/packages/voice/src/rest/v1/applications/applications-api.ts b/packages/voice/src/rest/v1/applications/applications-api.ts index d1a8cefe..32cbc8de 100644 --- a/packages/voice/src/rest/v1/applications/applications-api.ts +++ b/packages/voice/src/rest/v1/applications/applications-api.ts @@ -10,7 +10,7 @@ import { RequestBody, SinchClientParameters, } from '@sinch/sdk-client'; -import { VoiceApi } from '../voice-api'; +import { VoiceDomainApi } from '../voice-domain-api'; export interface QueryNumberRequestData { /** The phone number you want to query. */ @@ -37,7 +37,7 @@ export interface AssignNumbersRequestData { 'assignNumbersRequestBody'?: AssignNumbers; } -export class ApplicationsApi extends VoiceApi { +export class ApplicationsApi extends VoiceDomainApi { /** * Initialize your interface diff --git a/packages/voice/src/rest/v1/callouts/callouts-api.ts b/packages/voice/src/rest/v1/callouts/callouts-api.ts index fe782d34..45b3da0c 100644 --- a/packages/voice/src/rest/v1/callouts/callouts-api.ts +++ b/packages/voice/src/rest/v1/callouts/callouts-api.ts @@ -8,7 +8,7 @@ import { RequestBody, SinchClientParameters, } from '@sinch/sdk-client'; -import { VoiceApi } from '../voice-api'; +import { VoiceDomainApi } from '../voice-domain-api'; export interface TtsCalloutRequestData { 'ttsCalloutRequestBody': { @@ -37,7 +37,7 @@ export interface CustomCalloutRequestData { } } -export class CalloutsApi extends VoiceApi { +export class CalloutsApi extends VoiceDomainApi { /** * Initialize your interface diff --git a/packages/voice/src/rest/v1/calls/calls-api.ts b/packages/voice/src/rest/v1/calls/calls-api.ts index 4404f20a..9f1a059e 100644 --- a/packages/voice/src/rest/v1/calls/calls-api.ts +++ b/packages/voice/src/rest/v1/calls/calls-api.ts @@ -6,7 +6,7 @@ import { RequestBody, SinchClientParameters, } from '@sinch/sdk-client'; -import { VoiceApi } from '../voice-api'; +import { VoiceDomainApi } from '../voice-domain-api'; export type CallLegEnum = 'caller' | 'callee' | 'both'; export interface GetCallResultRequestData { @@ -28,7 +28,7 @@ export interface UpdateCallRequestData { 'svamlRequestBody'?: SVAMLRequestBody; } -export class CallsApi extends VoiceApi { +export class CallsApi extends VoiceDomainApi { /** * Initialize your interface diff --git a/packages/voice/src/rest/v1/conferences/conferences-api.ts b/packages/voice/src/rest/v1/conferences/conferences-api.ts index c4a21a73..9861c02a 100644 --- a/packages/voice/src/rest/v1/conferences/conferences-api.ts +++ b/packages/voice/src/rest/v1/conferences/conferences-api.ts @@ -6,7 +6,7 @@ import { RequestBody, SinchClientParameters, } from '@sinch/sdk-client'; -import { VoiceApi } from '../voice-api'; +import { VoiceDomainApi } from '../voice-domain-api'; export interface GetConferenceInfoRequestData { /** The unique identifier of the conference. The user sets this value. */ @@ -31,7 +31,7 @@ export interface ManageParticipantRequestData { 'manageParticipantRequestBody'?: ManageConferenceParticipantRequest; } -export class ConferencesApi extends VoiceApi { +export class ConferencesApi extends VoiceDomainApi { /** * Initialize your interface diff --git a/packages/voice/src/rest/v1/index.ts b/packages/voice/src/rest/v1/index.ts index e8d69728..43812f03 100644 --- a/packages/voice/src/rest/v1/index.ts +++ b/packages/voice/src/rest/v1/index.ts @@ -4,4 +4,4 @@ export * from './callouts'; export * from './calls'; export * from './conferences'; export * from './enums'; -export * from './voice'; +export * from './voice-service'; diff --git a/packages/voice/src/rest/v1/voice-api.ts b/packages/voice/src/rest/v1/voice-domain-api.ts similarity index 98% rename from packages/voice/src/rest/v1/voice-api.ts rename to packages/voice/src/rest/v1/voice-domain-api.ts index 842ecc8e..62e4e7dd 100644 --- a/packages/voice/src/rest/v1/voice-api.ts +++ b/packages/voice/src/rest/v1/voice-domain-api.ts @@ -8,7 +8,7 @@ import { XTimestampRequest, } from '@sinch/sdk-client'; -export class VoiceApi implements Api { +export class VoiceDomainApi implements Api { public readonly apiName: string; public client?: ApiClient; private sinchClientParameters: SinchClientParameters; diff --git a/packages/voice/src/rest/v1/voice.ts b/packages/voice/src/rest/v1/voice-service.ts similarity index 90% rename from packages/voice/src/rest/v1/voice.ts rename to packages/voice/src/rest/v1/voice-service.ts index 681a4233..e5c16234 100644 --- a/packages/voice/src/rest/v1/voice.ts +++ b/packages/voice/src/rest/v1/voice-service.ts @@ -1,16 +1,10 @@ -/** - * Domain: calling - * - * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. - * - */ import { SinchClientParameters, VoiceRegion } from '@sinch/sdk-client'; import { ApplicationsApi } from './applications'; import { ConferencesApi } from './conferences'; import { CallsApi } from './calls'; import { CalloutsApi } from './callouts'; -export class Voice { +export class VoiceService { public readonly applications: ApplicationsApi; public readonly conferences: ConferencesApi; public readonly calls: CallsApi;