From 2ed277d8dfb208547ac5dc86ba6d12700ec91e3c Mon Sep 17 00:00:00 2001 From: Antoine SEIN <142824551+asein-sinch@users.noreply.github.com> Date: Wed, 14 Feb 2024 10:10:48 +0100 Subject: [PATCH] Conversation API support (#13) * DEVEXP-272: Conversation API - First commit * DEVEXP-274: Conversation API - Write tests (#14) * DEVEXP-276: Conversation API - Add example files (#15) * DEVEXP-288: Support Callback Events in Conversation API (#16) * Support multiple regions for the conversation API (#17) * DEVEXP-295: Refactor channel credentials interface (#18) * DEVEXP-290: Support Templates API v1 and v2 (#20) * Revive dates --- examples/simple-examples/.env.template | 20 +- examples/simple-examples/README.md | 196 +++++--- examples/simple-examples/package.json | 42 ++ examples/simple-examples/src/config.ts | 36 ++ .../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 | 50 +++ .../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 | 45 ++ .../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/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 +++ .../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 | 34 +- .../src/services/conversation.service.ts | 206 +++++++++ jest.config.ts | 5 + 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 | 29 ++ .../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-message.ts | 19 + .../models/v1/app-message-message/index.ts | 1 + .../src/models/v1/app-message/app-message.ts | 83 ++++ .../src/models/v1/app-message/index.ts | 1 + .../models/v1/app-response/app-response.ts | 73 +++ .../src/models/v1/app-response/index.ts | 7 + .../app-update-request/app-update-request.ts | 29 ++ .../src/models/v1/app-update-request/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 + .../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 + .../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 + .../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 | 17 + .../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 | 38 ++ .../src/models/v1/choice/index.ts | 8 + .../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 | 72 +++ .../src/models/v1/contact-language/index.ts | 1 + .../v1/contact-message/contact-message.ts | 53 +++ .../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 | 150 +++++++ .../conversation-channel-credential/index.ts | 20 + .../conversation-channel.ts | 29 ++ .../models/v1/conversation-channel/index.ts | 1 + .../conversation-message-injected.ts | 25 ++ .../v1/conversation-message-injected/index.ts | 1 + .../conversation-message.ts | 56 +++ .../models/v1/conversation-message/index.ts | 1 + .../models/v1/conversation/conversation.ts | 26 ++ .../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 | 20 + .../v1/create-conversation-request/index.ts | 1 + .../dispatch-retention-policy.ts | 12 + .../v1/dispatch-retention-policy/index.ts | 1 + packages/conversation/src/models/v1/enums.ts | 48 ++ .../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 + .../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 + packages/conversation/src/models/v1/helper.ts | 174 ++++++++ .../models/v1/identified-by/identified-by.ts | 13 + .../src/models/v1/identified-by/index.ts | 1 + packages/conversation/src/models/v1/index.ts | 89 ++++ .../src/models/v1/list-apps-response/index.ts | 1 + .../list-apps-response/list-apps-response.ts | 7 + .../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 + .../src/models/v1/list-section/index.ts | 1 + .../models/v1/list-section/list-section.ts | 13 + .../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/lookup-capability/index.ts | 1 + .../v1/lookup-capability/lookup-capability.ts | 11 + .../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 | 10 + .../capability-event/capability-event.ts | 44 ++ .../capability-event/index.ts | 1 + .../channel-event/channel-event.ts | 35 ++ .../channel-event/index.ts | 1 + .../contact-create-event.ts | 25 ++ .../contact-create-event/index.ts | 1 + .../contact-delete-event.ts | 25 ++ .../contact-delete-event/index.ts | 1 + .../contact-identities-duplication-event.ts | 36 ++ .../index.ts | 1 + .../contact-merge-event.ts | 33 ++ .../contact-merge-event/index.ts | 1 + .../contact-notification.ts | 7 + .../contact-notification/index.ts | 1 + .../contact-update-event.ts | 25 ++ .../contact-update-event/index.ts | 1 + .../conversation-delete-event.ts | 34 ++ .../conversation-delete-event/index.ts | 1 + .../conversation-event/conversation-event.ts | 5 + .../conversation-event/index.ts | 1 + .../conversation-start-event.ts | 34 ++ .../conversation-start-event/index.ts | 1 + .../conversation-stop-event.ts | 34 ++ .../conversation-stop-event/index.ts | 1 + .../conversation-webhook-event.ts | 42 ++ .../conversation-webhook-event/index.ts | 1 + .../event-delivery/event-delivery.ts | 42 ++ .../event-delivery/index.ts | 1 + .../event-inbound/event-inbound.ts | 107 +++++ .../event-inbound/index.ts | 8 + .../models/v1/mod-callback-events/index.ts | 23 + .../message-delivery-receipt-event/index.ts | 4 + .../message-delivery-receipt-event.ts | 47 ++ .../message-inbound-event-item/index.ts | 1 + .../message-inbound-event-item.ts | 29 ++ .../message-inbound-event/index.ts | 1 + .../message-inbound-event.ts | 25 ++ .../index.ts | 3 + ...ound-smart-conversation-redaction-event.ts | 25 ++ .../message-submit-event/index.ts | 1 + .../message-submit-event.ts | 45 ++ .../mod-callback-events/opt-in-event/index.ts | 1 + .../opt-in-event/opt-in-event.ts | 53 +++ .../opt-out-event/index.ts | 1 + .../opt-out-event/opt-out-event.ts | 53 +++ .../smart-conversations-event/index.ts | 17 + .../smart-conversations-event.ts | 176 ++++++++ .../unsupported-callback-event/index.ts | 1 + .../unsupported-callback-event.ts | 45 ++ .../applebc-credentials.ts | 14 + .../applebc-credentials/index.ts | 1 + .../basic-auth-credential.ts | 10 + .../basic-auth-credential/index.ts | 1 + .../src/models/v1/mod-credentials/index.ts | 12 + .../instagram-credentials/index.ts | 1 + .../instagram-credentials.ts | 10 + .../kakaotalk-credentials/index.ts | 1 + .../kakaotalk-credentials.ts | 10 + .../kakaotalkchat-credentials/index.ts | 1 + .../kakaotalkchat-credentials.ts | 10 + .../mod-credentials/line-credentials/index.ts | 1 + .../line-credentials/line-credentials.ts | 10 + .../mod-credentials/mms-credentials/index.ts | 1 + .../mms-credentials/mms-credentials.ts | 16 + .../mod-credentials/sms-credentials/index.ts | 1 + .../sms-credentials/sms-credentials.ts | 8 + .../static-bearer-credential/index.ts | 1 + .../static-bearer-credential.ts | 10 + .../static-token-credential/index.ts | 1 + .../static-token-credential.ts | 8 + .../telegram-credentials/index.ts | 1 + .../telegram-credentials.ts | 8 + .../wechat-credentials/index.ts | 1 + .../wechat-credentials/wechat-credentials.ts | 14 + .../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/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 | 37 ++ .../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 + .../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/template-variable/index.ts | 1 + .../v1/template-variable/template-variable.ts | 6 + .../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 + .../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/models/v1/webhook-trigger/index.ts | 1 + .../v1/webhook-trigger/webhook-trigger.ts | 42 ++ .../src/models/v1/webhook/index.ts | 1 + .../src/models/v1/webhook/webhook.ts | 24 + 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 | 184 ++++++++ .../conversation/src/rest/v1/app/index.ts | 2 + .../rest/v1/callbacks/callbacks-webhook.ts | 192 ++++++++ .../src/rest/v1/callbacks/index.ts | 1 + .../capability/capability-api.jest.fixture.ts | 11 + .../src/rest/v1/capability/capability-api.ts | 56 +++ .../src/rest/v1/capability/index.ts | 2 + .../v1/contact/contact-api.jest.fixture.ts | 37 ++ .../src/rest/v1/contact/contact-api.ts | 286 ++++++++++++ .../conversation/src/rest/v1/contact/index.ts | 2 + .../src/rest/v1/conversation-domain-api.ts | 113 +++++ .../src/rest/v1/conversation-service.ts | 56 +++ .../conversation-api.jest.fixture.ts | 36 ++ .../rest/v1/conversation/conversation-api.ts | 300 +++++++++++++ .../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 | 54 +++ .../conversation/src/rest/v1/events/index.ts | 2 + packages/conversation/src/rest/v1/index.ts | 13 + .../src/rest/v1/messages/index.ts | 2 + .../v1/messages/messages-api.jest.fixture.ts | 25 ++ .../src/rest/v1/messages/messages-api.ts | 214 +++++++++ .../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 +++++++++ .../src/rest/v1/transcoding/index.ts | 2 + .../transcoding-api.jest.fixture.ts | 11 + .../rest/v1/transcoding/transcoding-api.ts | 55 +++ .../src/rest/v1/webhooks/index.ts | 2 + .../v1/webhooks/webhooks-api.jest.fixture.ts | 28 ++ .../src/rest/v1/webhooks/webhooks-api.ts | 188 ++++++++ .../tests/models/v1/helper.test.ts | 420 ++++++++++++++++++ .../tests/rest/v1/app/app-api.test.ts | 282 ++++++++++++ .../rest/v1/capability/capability-api.test.ts | 53 +++ .../tests/rest/v1/contact/contact-api.test.ts | 215 +++++++++ .../rest/v1/conversation-domain-api.test.ts | 75 ++++ .../v1/conversation/conversation-api.test.ts | 202 +++++++++ .../tests/rest/v1/events/events-api.test.ts | 54 +++ .../rest/v1/messages/messages-api.test.ts | 241 ++++++++++ .../v1/templates-v1/templates-v1-api.test.ts | 247 ++++++++++ .../v1/templates-v2/templates-v2-api.test.ts | 365 +++++++++++++++ .../v1/transcoding/transcoding-api.test.ts | 54 +++ .../rest/v1/webhooks/webhooks-api.test.ts | 194 ++++++++ packages/conversation/tsconfig.build.json | 17 + packages/conversation/tsconfig.json | 11 + packages/conversation/tsconfig.tests.json | 17 + .../v1/active-number/active-number-api.ts | 4 +- .../available-number/available-number-api.ts | 4 +- .../available-regions-api.ts | 4 +- .../v1/callbacks-webhook/callbacks-webhook.ts | 2 +- .../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-client/src/api/api-errors.ts | 8 +- .../src/client/api-client-helpers.ts | 31 ++ .../client/api-client-pagination-helper.ts | 4 +- .../sdk-client/src/client/api-fetch-client.ts | 52 ++- .../sdk-client/src/domain/domain-interface.ts | 6 + .../src/utils/authorization.helper.ts | 45 ++ .../tests/client/api-client-helpers.test.ts | 47 ++ .../tests/utils/authorization.helper.test.ts | 71 ++- packages/sdk-core/package.json | 1 + packages/sdk-core/src/index.ts | 1 + packages/sdk-core/src/sinch-client.ts | 29 +- .../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 +- packages/voice/src/models/v1/enums.ts | 3 +- .../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 +- 398 files changed, 10744 insertions(+), 166 deletions(-) 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/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 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/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-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/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-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-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/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/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-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/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/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-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/helper.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/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-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-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/lookup-capability/index.ts create mode 100644 packages/conversation/src/models/v1/lookup-capability/lookup-capability.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/mod-callback-events/capability-event/capability-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/capability-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/channel-event/channel-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/channel-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-create-event/contact-create-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-create-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/contact-delete-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-identities-duplication-event/contact-identities-duplication-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-identities-duplication-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/contact-merge-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-notification/contact-notification.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-notification/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-update-event/contact-update-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/contact-update-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/conversation-delete-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-event/conversation-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/conversation-start-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/conversation-stop-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/conversation-webhook-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/event-delivery/event-delivery.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/event-delivery/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/event-inbound/event-inbound.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/event-inbound/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/message-delivery-receipt-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/message-inbound-event-item.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/message-inbound-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-inbound-smart-conversation-redaction-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-inbound-smart-conversation-redaction-event/message-inbound-smart-conversation-redaction-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-submit-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/message-submit-event/message-submit-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/opt-in-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/opt-in-event/opt-in-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/opt-out-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/opt-out-event/opt-out-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/smart-conversations-event.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/index.ts create mode 100644 packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/unsupported-callback-event.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/applebc-credentials/applebc-credentials.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/applebc-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/basic-auth-credential.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/instagram-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/instagram-credentials/instagram-credentials.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/kakaotalk-credentials.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/kakaotalkchat-credentials.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/line-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/line-credentials/line-credentials.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/mms-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/mms-credentials/mms-credentials.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/sms-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/sms-credentials/sms-credentials.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/static-bearer-credential.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/static-token-credential/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/static-token-credential/static-token-credential.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/telegram-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/telegram-credentials/telegram-credentials.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/wechat-credentials/index.ts create mode 100644 packages/conversation/src/models/v1/mod-credentials/wechat-credentials/wechat-credentials.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/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/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/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/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/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/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/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/callbacks/callbacks-webhook.ts create mode 100644 packages/conversation/src/rest/v1/callbacks/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-service.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/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/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/tests/models/v1/helper.test.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-domain-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/templates-v1/templates-v1-api.test.ts create mode 100644 packages/conversation/tests/rest/v1/templates-v2/templates-v2-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 create mode 100644 packages/conversation/tsconfig.build.json create mode 100644 packages/conversation/tsconfig.json create mode 100644 packages/conversation/tsconfig.tests.json 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%) create mode 100644 packages/sdk-client/tests/client/api-client-helpers.test.ts 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/examples/simple-examples/.env.template b/examples/simple-examples/.env.template index 897bf8a9..103f3c21 100644 --- a/examples/simple-examples/.env.template +++ b/examples/simple-examples/.env.template @@ -9,14 +9,32 @@ 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 NUMBER_CALLBACK_URL=URL to receive callbacks relative a number you own +# 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 diff --git a/examples/simple-examples/README.md b/examples/simple-examples/README.md index a157afcb..3516b29d 100644 --- a/examples/simple-examples/README.md +++ b/examples/simple-examples/README.md @@ -40,21 +40,35 @@ 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 NUMBER_CALLBACK_URL=URL to receive callbacks relative a number you own +# 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. @@ -78,59 +92,129 @@ 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` + `NUMBER_CALLBACK_URL` + `SINCH_SERVICE_PLAN_ID` + `SINCH_APPLICATION_KEY` | -| | | [./src/numbers/available/rentAny.ts](./src/numbers/available/rentAny.ts) | `NUMBER_CALLBACK_URL` + `SINCH_SERVICE_PLAN_ID` + `SINCH_APPLICATION_KEY` | -| | 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` + `SINCH_SERVICE_PLAN_ID` + `NUMBER_CALLBACK_URL` | -| | | [./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/sms/start-sms.ts](./src/verification/verifications/sms/start-sms.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_REFERENCE` | -| | | [./src/verification/verifications/sms/report-with-id_sms.ts](./src/verification/verifications/sms/report-with-id_sms.ts) | `VERIFICATION_ID` + `VERIFICATION_CODE` or `VERIFICATION_CLI` (flashCall) | -| | | [./src/verification/verifications/sms/report-with-identity_sms.ts](./src/verification/verifications/sms/report-with-identity_sms.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` + `NUMBER_CALLBACK_URL` + `SINCH_SERVICE_PLAN_ID` + `SINCH_APPLICATION_KEY` | +| | [./src/numbers/available/rentAny.ts](./src/numbers/available/rentAny.ts) | `NUMBER_CALLBACK_URL` + `SINCH_SERVICE_PLAN_ID` + `SINCH_APPLICATION_KEY` | +| 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` + `SINCH_SERVICE_PLAN_ID` + `NUMBER_CALLBACK_URL` | +| | [./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/sms/start-sms.ts](./src/verification/verifications/sms/start-sms.ts) | `VERIFICATION_IDENTITY` | +| | [./src/verification/verifications/sms/report-with-id_sms.ts](./src/verification/verifications/sms/report-with-id_sms.ts) | `VERIFICATION_ID` + `VERIFICATION_CODE` | +| | [./src/verification/verifications/sms/report-with-identity_sms.ts](./src/verification/verifications/sms/report-with-identity_sms.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_CODE` | +| | [./src/verification/verifications/flashcall/start-flashcall.ts](./src/verification/verifications/flashcall/start-flashcall.ts) | `VERIFICATION_IDENTITY` | +| | [./src/verification/verifications/flashcall/report-with-id_flashcall.ts](./src/verification/verifications/flashcall/report-with-id_flashcall.ts) | `VERIFICATION_ID` + `VERIFICATION_CLI` | +| | [./src/verification/verifications/flashcall/report-with-identity_flashcall.ts](./src/verification/verifications/flashcall/report-with-identity_flashcall.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_CLI` | +| | [./src/verification/verifications/callout/start-callout.ts](./src/verification/verifications/callout/start-callout.ts) | `VERIFICATION_IDENTITY` | +| | [./src/verification/verifications/callout/report-with-id_callout.ts](./src/verification/verifications/callout/report-with-id_callout.ts) | `VERIFICATION_ID` + `VERIFICATION_CODE` | +| | [./src/verification/verifications/callout/report-with-identity_callout.ts](./src/verification/verifications/callout/report-with-identity_callout.ts) | `VERIFICATION_IDENTITY` + `VERIFICATION_CODE` | +| 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 416cbf99..caa6181b 100644 --- a/examples/simple-examples/package.json +++ b/examples/simple-examples/package.json @@ -8,6 +8,48 @@ "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", + "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 9d2ae1c7..3e4c7b56 100644 --- a/examples/simple-examples/src/config.ts +++ b/examples/simple-examples/src/config.ts @@ -105,6 +105,42 @@ 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'); +}; + +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/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..b121ad58 --- /dev/null +++ b/examples/simple-examples/src/conversation/app/update.ts @@ -0,0 +1,50 @@ +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(); + 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/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..0b81d29a --- /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: ['MESSENGER'], + 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..5a34d5f8 --- /dev/null +++ b/examples/simple-examples/src/conversation/conversation/injectMessage.ts @@ -0,0 +1,45 @@ +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: { + 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/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/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 3c014d16..585b3ae5 100644 --- a/examples/webhooks/src/controller/app.controller.ts +++ b/examples/webhooks/src/controller/app.controller.ts @@ -1,18 +1,26 @@ import { Body, Controller, Post, Req, Res } from '@nestjs/common'; import { Request, Response } from 'express'; -import { NumbersService } from '../services/numbers.service'; import { + ConversationCallbackWebhooks, NumbersCallbackWebhooks, SmsCallbackWebhooks, VerificationCallbackWebhooks, VoiceCallbackWebhooks, } 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 Numbers API const SINCH_NUMBERS_CALLBACK_SECRET = process.env.SINCH_NUMBERS_CALLBACK_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 || ''; @@ -20,11 +28,34 @@ 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, private readonly voiceService: VoiceService) {} + @Post('/conversation') + public conversation(@Req() request: Request, @Res() res: Response) { + // 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 { + // 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) { + console.error(error); + res.status(500).send(); + } + } + @Post('/numbers') public numbers(@Req() request: Request, @Res() res: Response) { // Initialize the class that will be used to validate the request and parse it @@ -112,4 +143,5 @@ export class AppController { res.status(500).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..80e9c5a9 --- /dev/null +++ b/examples/webhooks/src/services/conversation.service.ts @@ -0,0 +1,206 @@ +import { Injectable } from '@nestjs/common'; +import { + SinchClient, + ConversationWebhookEventParsed, + ContactMessage, + SendMessageRequestData, + messageBuilder, +} from '@sinch/sdk-core'; + +@Injectable() +export class ConversationService { + + 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 messageBuilder.text({ + text: `Parrot mode 🦜: ${contactMessage.text_message.text}`, + }); + } + if ('media_message' in contactMessage) { + return messageBuilder.media({ + url: contactMessage.media_message.url, + }); + } + if ('fallback_message' in contactMessage) { + return messageBuilder.text({ + text: `Error: ${contactMessage.fallback_message.reason.code} (${contactMessage.fallback_message.reason.sub_code})\n${contactMessage.fallback_message.reason.description}` + }); + } + } + + 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'); + 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'); + 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/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/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..813b16c4 --- /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..6cab3293 --- /dev/null +++ b/packages/conversation/src/models/v1/app-create-request/app-create-request.ts @@ -0,0 +1,29 @@ +import { CallbackSettings } from '../callback-settings'; +import { ConversationChannelCredential } from '../conversation-channel-credential'; +import { DispatchRetentionPolicy } from '../dispatch-retention-policy'; +import { RetentionPolicy } from '../retention-policy'; +import { SmartConversation } from '../smart-conversation'; +import { ConversationMetadataReportView, ProcessingMode } from '../enums'; + +/** + * 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-message/app-message-message.ts b/packages/conversation/src/models/v1/app-message-message/app-message-message.ts new file mode 100644 index 00000000..880d2575 --- /dev/null +++ b/packages/conversation/src/models/v1/app-message-message/app-message-message.ts @@ -0,0 +1,19 @@ +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'; + +/** The content of the 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..71da85b2 --- /dev/null +++ b/packages/conversation/src/models/v1/app-message/app-message.ts @@ -0,0 +1,83 @@ +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 type AppMessage = + AppMessageCardMessage + | AppMessageChoiceMessage + | AppMessageLocationMessage + | AppMessageCarouselMessage + | AppMessageMediaMessage + | AppMessageTemplateMessage + | AppMessageTextMessage + | AppMessageListMessage; + +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?: { [key: string]: string; }; + /** @see AppMessageAdditionalProperties */ + additionalProperties?: AppMessageAdditionalProperties; + /** Identity of a sender */ + agent?: Agent | null; + /** */ + 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-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..9acaa02d --- /dev/null +++ b/packages/conversation/src/models/v1/app-response/app-response.ts @@ -0,0 +1,73 @@ +import { ConversationChannelCredential } from '../conversation-channel-credential'; +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 { CallbackSettings } from '../callback-settings'; +import { ConversationMetadataReportView, ProcessingMode } from '../enums'; + +/** + * 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; + + /** Message status persistence configuration. */ + persist_message_status?: PersistMessageStatus; + /** Message search configuration */ + message_search?: MessageSearch; + /** Additional callback configuration. */ + callback_settings?: CallbackSettings; + /** Fallback upon no positive delivery report configuration. */ + delivery_report_based_fallback?: DeliveryReportBasedFallback | null; + /** Message retry time configuration. */ + message_retry_settings?: MessageRetrySettings | null; +} + +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 new file mode 100644 index 00000000..bdc7716f --- /dev/null +++ b/packages/conversation/src/models/v1/app-response/index.ts @@ -0,0 +1,7 @@ +export type { + AppResponse, + DeliveryReportBasedFallback, + MessageRetrySettings, + MessageSearch, + PersistMessageStatus, +} 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..d698da3a --- /dev/null +++ b/packages/conversation/src/models/v1/app-update-request/app-update-request.ts @@ -0,0 +1,29 @@ +import { CallbackSettings } from '../callback-settings'; +import { ConversationChannelCredential } from '../conversation-channel-credential'; +import { DispatchRetentionPolicy } from '../dispatch-retention-policy'; +import { RetentionPolicy } from '../retention-policy'; +import { SmartConversation } from '../smart-conversation'; +import { ConversationMetadataReportView, ProcessingMode } from '../enums'; + +/** + * 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/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-message/card-message.ts b/packages/conversation/src/models/v1/card-message/card-message.ts new file mode 100644 index 00000000..3fa590f9 --- /dev/null +++ b/packages/conversation/src/models/v1/card-message/card-message.ts @@ -0,0 +1,26 @@ +import { MediaCarouselMessage } from '../media-carousel-message'; +import { Choice } from '../choice'; +import { CardHeight } from '../enums'; + +/** + * 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..807b3f1d --- /dev/null +++ b/packages/conversation/src/models/v1/carousel-message/carousel-message.ts @@ -0,0 +1,19 @@ +import { CardMessageItem } 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: 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/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-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/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 new file mode 100644 index 00000000..34c5dd46 --- /dev/null +++ b/packages/conversation/src/models/v1/choice-item/choice-item.ts @@ -0,0 +1,17 @@ +import { MediaMessageItem } from '../media-message'; + +export interface ChoiceItem { + choice: ChoiceItemItem; +} + +export interface ChoiceItemItem { + + /** Required parameter. Title for the choice item. */ + title: string; + /** Optional parameter. The description (or subtitle) of this choice item. */ + description?: string; + /** @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/choice-item/index.ts b/packages/conversation/src/models/v1/choice-item/index.ts new file mode 100644 index 00000000..9bb775aa --- /dev/null +++ b/packages/conversation/src/models/v1/choice-item/index.ts @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000..97e0457a --- /dev/null +++ b/packages/conversation/src/models/v1/choice-message/choice-message.ts @@ -0,0 +1,19 @@ +import { TextMessageItem } from '../text-message'; +import { Choice } from '../choice'; + +/** + * 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?: TextMessageItem; +} 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..e88f387a --- /dev/null +++ b/packages/conversation/src/models/v1/choice-message/index.ts @@ -0,0 +1 @@ +export type { ChoiceMessage, ChoiceMessageItem } 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..2493cd74 --- /dev/null +++ b/packages/conversation/src/models/v1/choice/choice.ts @@ -0,0 +1,38 @@ +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 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; +} + +export interface LocationMessageChoice extends ChoiceBase { + /** @see LocationMessage */ + 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 new file mode 100644 index 00000000..e5530fec --- /dev/null +++ b/packages/conversation/src/models/v1/choice/index.ts @@ -0,0 +1,8 @@ +export type { + Choice, + ChoiceBase, + CallMessageChoice, + LocationMessageChoice, + TextMessageChoice, + UrlMessageChoice, +} 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..c51375aa --- /dev/null +++ b/packages/conversation/src/models/v1/contact-language/contact-language.ts @@ -0,0 +1,72 @@ +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' + | 'UNSPECIFIED'; 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..5712ea93 --- /dev/null +++ b/packages/conversation/src/models/v1/contact-message/contact-message.ts @@ -0,0 +1,53 @@ +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 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; +} + +interface ContactMessageLocationMessage extends ContactMessageBase { + /** @see LocationMessageItem */ + location_message?: LocationMessageItem; +} + +interface ContactMessageMediaCardMessage extends ContactMessageBase { + /** @see MediaCardMessage */ + media_card_message?: MediaCardMessage; +} + +interface ContactMessageMediaMessage extends ContactMessageBase { + /** @see MediaMessageItem */ + media_message?: MediaMessageItem; +} + +interface ContactMessageTextMessage extends ContactMessageBase { + /** @see TextMessageItem */ + text_message?: TextMessageItem; +} + +interface ContactMessageBase { + /** @see ReplyTo */ + reply_to?: ReplyTo; +} 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..717129f5 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-channel-credential/conversation-channel-credential.ts @@ -0,0 +1,150 @@ +import { ConversationChannel } from '../conversation-channel'; +import { + AppleBcCredentials, + InstagramCredentials, + KakaoTalkChatCredentials, + KakaoTalkCredentials, + LineCredentials, + MMSCredentials, + SMSCredentials, + StaticBearerCredential, + StaticTokenCredential, + TelegramCredentials, + WeChatCredentials, +} from '../mod-credentials'; + +/** + * Enables access to the underlying messaging channel. + */ +export type ConversationChannelCredential = + ChannelCredentialsAppleBC + | ChannelCredentialsInstagram + | ChannelCredentialsKakaoTalk + | ChannelCredentialsKakaoTalkChat + | ChannelCredentialsLine + | ChannelCredentialsMessenger + | ChannelCredentialsMms + | ChannelCredentialsRcs + | ChannelCredentialsSms + | ChannelCredentialsTelegram + | ChannelCredentialsViber + | ChannelCredentialsViberBM + | ChannelCredentialsWeChat + | ChannelCredentialsWhatsApp; + +export interface ChannelCredentialsWhatsApp extends ConversationChannelCredentialBase { + channel: 'WHATSAPP'; + /** @see StaticBearerCredential */ + static_bearer: StaticBearerCredential; +} + +export interface ChannelCredentialsRcs extends ConversationChannelCredentialBase { + channel: 'RCS'; + /** @see 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; +} + +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; +} + +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; +} + +export interface ChannelCredentialsWeChat extends ConversationChannelCredentialBase { + channel: 'WECHAT'; + /** @see WeChatCredentials */ + wechat_credentials: WeChatCredentials; +} + +export interface ChannelCredentialsAppleBC extends ConversationChannelCredentialBase { + channel: 'APPLEBC'; + /** @see 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). + */ + 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 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 new file mode 100644 index 00000000..3a9afc37 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-channel-credential/index.ts @@ -0,0 +1,20 @@ +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/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..6f0fb682 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-channel/conversation-channel.ts @@ -0,0 +1,29 @@ +/** + * The identifier of the channel you want to include. Must be one of the enum values except 'CHANNEL_UNSPECIFIED'. + */ +export type ConversationChannel = + 'WHATSAPP' + | 'RCS' + | 'SMS' + | 'MESSENGER' + | 'VIBER' + | 'VIBERBM' + | 'MMS' + | 'INSTAGRAM' + | 'TELEGRAM' + | 'KAKAOTALK' + | 'KAKAOTALKCHAT' + | 'LINE' + | '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 new file mode 100644 index 00000000..18c63305 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-channel/index.ts @@ -0,0 +1 @@ +export type { ConversationChannel, TemplateChannel } from './conversation-channel'; 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..0fef2a76 --- /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 '../enums'; + +/** + * 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..4a582556 --- /dev/null +++ b/packages/conversation/src/models/v1/conversation-message/conversation-message.ts @@ -0,0 +1,56 @@ +import { AppMessage } from '../app-message'; +import { ChannelIdentity } from '../channel-identity'; +import { ContactMessage } from '../contact-message'; +import { ConversationDirection, ProcessingMode } from '../enums'; + +/** + * A message on a particular channel. + */ +export interface ConversationMessage { + + /** Output only. 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; + /** Output only. Flag for whether this message was injected. */ + injected?: boolean; + /** 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; + /** Output only. The processing mode. */ + processing_mode?: ProcessingMode; + /** 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/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/conversation.ts b/packages/conversation/src/models/v1/conversation/conversation.ts new file mode 100644 index 00000000..4bfde51d --- /dev/null +++ b/packages/conversation/src/models/v1/conversation/conversation.ts @@ -0,0 +1,26 @@ +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; + /** Up to 128 characters long */ + correlation_id?: string; +} 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..401f7d1a --- /dev/null +++ b/packages/conversation/src/models/v1/create-conversation-request/create-conversation-request.ts @@ -0,0 +1,20 @@ +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; + /** 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/dispatch-retention-policy.ts b/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts new file mode 100644 index 00000000..d64b23c6 --- /dev/null +++ b/packages/conversation/src/models/v1/dispatch-retention-policy/dispatch-retention-policy.ts @@ -0,0 +1,12 @@ +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). + */ +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..27013a18 --- /dev/null +++ b/packages/conversation/src/models/v1/enums.ts @@ -0,0 +1,48 @@ +export type { + PaymentStatusEnum as PaymentStatusUpdateEventPaymentStatusEnum, + PaymentTransactionStatusEnum as PaymentStatusUpdateEventPaymentTransactionStatusEnum, +} from './mod-callback-events/event-inbound/event-inbound'; +export type { + SentimentResult as MachineLearningSentimentEnum, + EvaluationEnum as OffensiveAnalysisEvaluationEnum, +} from './mod-callback-events/smart-conversations-event/smart-conversations-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/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-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..0baafd70 --- /dev/null +++ b/packages/conversation/src/models/v1/get-channel-profile-request/get-channel-profile-request.ts @@ -0,0 +1,12 @@ +import { Recipient } from '../recipient'; +import { GetChannelProfileConversationChannel } from '../enums'; + +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/helper.ts b/packages/conversation/src/models/v1/helper.ts new file mode 100644 index 00000000..ebdf48c5 --- /dev/null +++ b/packages/conversation/src/models/v1/helper.ts @@ -0,0 +1,174 @@ +import { TextMessage, TextMessageItem } from './text-message'; +import { CardMessage, CardMessageItem } from './card-message'; +import { CarouselMessage, CarouselMessageItem } from './carousel-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(messageBuilder.text(textMessageItem)); + }, + buildCardMessageContent: (cardMessageItem: CardMessageItem): string => { + return JSON.stringify(messageBuilder.card(cardMessageItem)); + }, + buildCarouselMessageContent: (carouselMessageItem: CarouselMessageItem): string => { + return JSON.stringify(messageBuilder.carousel(carouselMessageItem)); + }, + buildChoiceMessageContent: (choiceMessageItem: ChoiceMessageItem): string => { + return JSON.stringify(messageBuilder.choice(choiceMessageItem)); + }, + buildLocationMessageContent: (locationMessageItem: LocationMessageItem): string => { + return JSON.stringify(messageBuilder.location(locationMessageItem)); + }, + buildMediaMessageContent: (mediaMessageItem: MediaMessageItem): string => { + return JSON.stringify(messageBuilder.media(mediaMessageItem)); + }, + buildTemplateMessageContent: (templateMessageItem: TemplateMessageItem): string => { + return JSON.stringify(messageBuilder.template(templateMessageItem)); + }, + buildListMessageContent: (listMessageItem: ListMessageItem): string => { + return JSON.stringify(messageBuilder.list(listMessageItem)); + }, +}; + +export const templateV2Helper = { + // Template V2 + buildTextMessageContent: (textMessageItem: TextMessageItem): TextMessage => { + return messageBuilder.text(textMessageItem); + }, + buildCardMessageContent: (cardMessageItem: CardMessageItem): CardMessage => { + return messageBuilder.card(cardMessageItem); + }, + buildCarouselMessageContent: (carouselMessageItem: CarouselMessageItem): CarouselMessage => { + return messageBuilder.carousel(carouselMessageItem); + }, + buildChoiceMessageContent: (choiceMessageItem: ChoiceMessageItem): ChoiceMessage => { + return messageBuilder.choice(choiceMessageItem); + }, + buildLocationMessageContent: (locationMessageItem: LocationMessageItem): LocationMessage => { + return messageBuilder.location(locationMessageItem); + }, + buildMediaMessageContent: (mediaMessageItem: MediaMessageItem): MediaMessage => { + return messageBuilder.media(mediaMessageItem); + }, + buildTemplateMessageContent: (templateMessageItem: TemplateMessageItem): TemplateMessage => { + return messageBuilder.template(templateMessageItem); + }, + buildListMessageContent: (listMessageItem: ListMessageItem): ListMessage => { + return messageBuilder.list(listMessageItem); + }, + 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/identified-by/identified-by.ts b/packages/conversation/src/models/v1/identified-by/identified-by.ts new file mode 100644 index 00000000..8fdeefe2 --- /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 { + + /** 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/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..44718df9 --- /dev/null +++ b/packages/conversation/src/models/v1/index.ts @@ -0,0 +1,89 @@ +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-message'; +export * from './app-response'; +export * from './app-update-request'; +export * from './call-message'; +export * from './callback-settings'; +export * from './card-message'; +export * from './carousel-message'; +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'; +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-message'; +export * from './conversation-message-injected'; +export * from './coordinates'; +export * from './create-conversation-request'; +export * from './dispatch-retention-policy'; +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 './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 './media-card-message'; +export * from './media-carousel-message'; +export * from './media-message'; +export * from './merge-contact-request'; +export * from './product'; +export * from './error-detail'; +export * from './lookup-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 './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 './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 './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/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-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-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..00d0dcb8 --- /dev/null +++ b/packages/conversation/src/models/v1/list-section/list-section.ts @@ -0,0 +1,13 @@ +import { ChoiceItem } from '../choice-item'; +import { Product } from '../product'; + +/** + * Section for interactive whatsapp messages containing ListItem + */ +export interface ListSection { + + /** Optional parameter. Title for list section. */ + title?: string; + /** List of ListItems */ + items?: (ChoiceItem | Product)[]; +} 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/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/lookup-capability/lookup-capability.ts b/packages/conversation/src/models/v1/lookup-capability/lookup-capability.ts new file mode 100644 index 00000000..14dce31d --- /dev/null +++ b/packages/conversation/src/models/v1/lookup-capability/lookup-capability.ts @@ -0,0 +1,11 @@ +import { Recipient } from '../recipient'; + +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. */ + request_id?: 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..432ae693 --- /dev/null +++ b/packages/conversation/src/models/v1/merge-contact-request/merge-contact-request.ts @@ -0,0 +1,10 @@ +import { ConversationMergeStrategy } from '../enums'; + + +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/mod-callback-events/capability-event/capability-event.ts b/packages/conversation/src/models/v1/mod-callback-events/capability-event/capability-event.ts new file mode 100644 index 00000000..233d8420 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/capability-event/capability-event.ts @@ -0,0 +1,44 @@ +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?: '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; +} diff --git a/packages/conversation/src/models/v1/mod-callback-events/capability-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/capability-event/index.ts new file mode 100644 index 00000000..8a673538 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/capability-event/index.ts @@ -0,0 +1 @@ +export type { CapabilityEvent, CapabilityNotification } from './capability-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/channel-event/channel-event.ts b/packages/conversation/src/models/v1/mod-callback-events/channel-event/channel-event.ts new file mode 100644 index 00000000..a20eef6a --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/channel-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/channel-event/index.ts new file mode 100644 index 00000000..7dd22303 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/channel-event/index.ts @@ -0,0 +1 @@ +export type { ChannelEvent, ChannelEventNotification } from './channel-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/contact-create-event/contact-create-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-create-event/contact-create-event.ts new file mode 100644 index 00000000..e3d12a75 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/contact-create-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-create-event/index.ts new file mode 100644 index 00000000..799d65aa --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/contact-create-event/index.ts @@ -0,0 +1 @@ +export type { ContactCreateEvent } from './contact-create-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/contact-delete-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/contact-delete-event.ts new file mode 100644 index 00000000..ef4f9263 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/contact-delete-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/index.ts new file mode 100644 index 00000000..967b2119 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/contact-delete-event/index.ts @@ -0,0 +1 @@ +export type { ContactDeleteEvent } from './contact-delete-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/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 new file mode 100644 index 00000000..055f413f --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/contact-identities-duplication-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-identities-duplication-event/index.ts new file mode 100644 index 00000000..abbc9eb7 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/contact-merge-event/contact-merge-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/contact-merge-event.ts new file mode 100644 index 00000000..cc74b054 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/contact-merge-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/index.ts new file mode 100644 index 00000000..d1d8a4b8 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/contact-merge-event/index.ts @@ -0,0 +1 @@ +export type { ContactMergeEvent, ContactMergeNotification } from './contact-merge-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/contact-notification/contact-notification.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-notification/contact-notification.ts new file mode 100644 index 00000000..b80461e2 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/contact-notification/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-notification/index.ts new file mode 100644 index 00000000..bf81b51e --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/contact-notification/index.ts @@ -0,0 +1 @@ +export type { ContactNotification } from './contact-notification'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/contact-update-event/contact-update-event.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-update-event/contact-update-event.ts new file mode 100644 index 00000000..719f0169 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/contact-update-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/contact-update-event/index.ts new file mode 100644 index 00000000..e2d683b4 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/contact-update-event/index.ts @@ -0,0 +1 @@ +export type { ContactUpdateEvent } from './contact-update-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/conversation-delete-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/conversation-delete-event.ts new file mode 100644 index 00000000..4979d938 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/conversation-delete-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/index.ts new file mode 100644 index 00000000..e0e7ac2d --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-delete-event/index.ts @@ -0,0 +1 @@ +export type { ConversationDeleteEvent } from './conversation-delete-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/conversation-event/conversation-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-event/conversation-event.ts new file mode 100644 index 00000000..d6feeb32 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/conversation-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-event/index.ts new file mode 100644 index 00000000..782519a5 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-event/index.ts @@ -0,0 +1 @@ +export { ConversationEvent } from './conversation-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/conversation-start-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/conversation-start-event.ts new file mode 100644 index 00000000..395ede02 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/conversation-start-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/index.ts new file mode 100644 index 00000000..fecb24c8 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-start-event/index.ts @@ -0,0 +1 @@ +export type { ConversationStartEvent } from './conversation-start-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/conversation-stop-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/conversation-stop-event.ts new file mode 100644 index 00000000..f382b33c --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/conversation-stop-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/index.ts new file mode 100644 index 00000000..ec0f786c --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-stop-event/index.ts @@ -0,0 +1 @@ +export type { ConversationStopEvent } from './conversation-stop-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/conversation-webhook-event.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/conversation-webhook-event.ts new file mode 100644 index 00000000..15dea601 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/conversation-webhook-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/index.ts new file mode 100644 index 00000000..ee93ce03 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/conversation-webhook-event/index.ts @@ -0,0 +1 @@ +export type { ConversationWebhookEvent } from './conversation-webhook-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/event-delivery/event-delivery.ts b/packages/conversation/src/models/v1/mod-callback-events/event-delivery/event-delivery.ts new file mode 100644 index 00000000..67257cb2 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/event-delivery/event-delivery.ts @@ -0,0 +1,42 @@ +import { ChannelIdentity } from '../../channel-identity'; +import { Reason } from '../../reason'; +import { ConversationEvent } from '../conversation-event'; +import { DeliveryStatus, ProcessingMode } from '../../enums'; + +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/mod-callback-events/event-delivery/index.ts b/packages/conversation/src/models/v1/mod-callback-events/event-delivery/index.ts new file mode 100644 index 00000000..6845a076 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/event-delivery/index.ts @@ -0,0 +1 @@ +export type { EventDelivery, EventDeliveryReport } from './event-delivery'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/event-inbound/event-inbound.ts b/packages/conversation/src/models/v1/mod-callback-events/event-inbound/event-inbound.ts new file mode 100644 index 00000000..546238ee --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/event-inbound/event-inbound.ts @@ -0,0 +1,107 @@ +import { ChannelIdentity } from '../../channel-identity'; +import { ConversationEvent } from '../conversation-event'; +import { ProcessingMode } from '../../enums'; + +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?: 'TO_APP'; + /** @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 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?: '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; +} + +/** + * 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/mod-callback-events/event-inbound/index.ts b/packages/conversation/src/models/v1/mod-callback-events/event-inbound/index.ts new file mode 100644 index 00000000..5f7f4f04 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/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/mod-callback-events/message-delivery-receipt-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/index.ts new file mode 100644 index 00000000..2f535d06 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/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 new file mode 100644 index 00000000..cb82f2fc --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/message-delivery-receipt-event/message-delivery-receipt-event.ts @@ -0,0 +1,47 @@ +import { ChannelIdentity } from '../../channel-identity'; +import { Reason } from '../../reason'; +import { ConversationEvent } from '../conversation-event'; +import { DeliveryStatus, ProcessingMode } from '../../enums'; + +/** + * 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/mod-callback-events/message-inbound-event-item/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/index.ts new file mode 100644 index 00000000..a436afa0 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/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 new file mode 100644 index 00000000..a4897550 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event-item/message-inbound-event-item.ts @@ -0,0 +1,29 @@ +import { ChannelIdentity } from '../../channel-identity'; +import { ContactMessage } from '../../contact-message'; +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?: 'TO_APP'; + /** @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; +} diff --git a/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/index.ts new file mode 100644 index 00000000..7f7a277d --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/index.ts @@ -0,0 +1 @@ +export type { MessageInboundEvent } from './message-inbound-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/message-inbound-event.ts b/packages/conversation/src/models/v1/mod-callback-events/message-inbound-event/message-inbound-event.ts new file mode 100644 index 00000000..fc3b7342 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/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 new file mode 100644 index 00000000..f125b096 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/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 new file mode 100644 index 00000000..c54b9149 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/message-submit-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/message-submit-event/index.ts new file mode 100644 index 00000000..c03ff64c --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/message-submit-event/index.ts @@ -0,0 +1 @@ +export type { MessageSubmitEvent, MessageSubmitNotification } from './message-submit-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/message-submit-event/message-submit-event.ts b/packages/conversation/src/models/v1/mod-callback-events/message-submit-event/message-submit-event.ts new file mode 100644 index 00000000..f349d54e --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/message-submit-event/message-submit-event.ts @@ -0,0 +1,45 @@ +import { ChannelIdentity } from '../../channel-identity'; +import { ContactMessage } from '../../contact-message'; +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. + */ +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/mod-callback-events/opt-in-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/opt-in-event/index.ts new file mode 100644 index 00000000..f908d1a0 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/opt-in-event/opt-in-event.ts b/packages/conversation/src/models/v1/mod-callback-events/opt-in-event/opt-in-event.ts new file mode 100644 index 00000000..47f7a321 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/opt-in-event/opt-in-event.ts @@ -0,0 +1,53 @@ +import { ConversationChannel } from '../../conversation-channel'; +import { ConversationEvent } from '../conversation-event'; +import { ProcessingMode } from '../../enums'; + +/** + * 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?: 'OPT_IN_SUCCEEDED' | 'OPT_IN_FAILED' | 'OPT_IN_STATUS_UNSPECIFIED'; + /** @see OptInNotificationErrorDetails */ + error_details?:OptInNotificationErrorDetails; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; +} + +/** + * 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/mod-callback-events/opt-out-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/opt-out-event/index.ts new file mode 100644 index 00000000..b2b54504 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/opt-out-event/index.ts @@ -0,0 +1 @@ +export type { OptOutEvent } from './opt-out-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/opt-out-event/opt-out-event.ts b/packages/conversation/src/models/v1/mod-callback-events/opt-out-event/opt-out-event.ts new file mode 100644 index 00000000..b49bf771 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/opt-out-event/opt-out-event.ts @@ -0,0 +1,53 @@ +import { ConversationChannel } from '../../conversation-channel'; +import { ConversationEvent } from '../conversation-event'; +import { ProcessingMode } from '../../enums'; + +/** + * 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?: 'OPT_OUT_SUCCEEDED' | 'OPT_OUT_FAILED' | 'OPT_OUT_STATUS_UNSPECIFIED'; + /** @see OptOutNotificationErrorDetails */ + error_details?: OptOutNotificationErrorDetails; + /** @see ProcessingMode */ + processing_mode?: ProcessingMode; +} + +/** + * 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/mod-callback-events/smart-conversations-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/index.ts new file mode 100644 index 00000000..a1475c8f --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/smart-conversations-event/smart-conversations-event.ts b/packages/conversation/src/models/v1/mod-callback-events/smart-conversations-event/smart-conversations-event.ts new file mode 100644 index 00000000..4c4bfb48 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/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/mod-callback-events/unsupported-callback-event/index.ts b/packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/index.ts new file mode 100644 index 00000000..ebdb1d02 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/index.ts @@ -0,0 +1 @@ +export type { UnsupportedCallbackEvent, UnsupportedCallback } from './unsupported-callback-event'; diff --git a/packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/unsupported-callback-event.ts b/packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/unsupported-callback-event.ts new file mode 100644 index 00000000..0a602d0e --- /dev/null +++ b/packages/conversation/src/models/v1/mod-callback-events/unsupported-callback-event/unsupported-callback-event.ts @@ -0,0 +1,45 @@ +import { ConversationChannel } from '../../conversation-channel'; +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. + */ +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/mod-credentials/applebc-credentials/applebc-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/applebc-credentials/applebc-credentials.ts new file mode 100644 index 00000000..18efe1e1 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/mod-credentials/applebc-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/applebc-credentials/index.ts new file mode 100644 index 00000000..8e41cd71 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/applebc-credentials/index.ts @@ -0,0 +1 @@ +export type { AppleBcCredentials } from './applebc-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/basic-auth-credential.ts b/packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/basic-auth-credential.ts new file mode 100644 index 00000000..25348ff9 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/mod-credentials/basic-auth-credential/index.ts b/packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/index.ts new file mode 100644 index 00000000..4be43bf7 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/basic-auth-credential/index.ts @@ -0,0 +1 @@ +export type { BasicAuthCredential } from './basic-auth-credential'; 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/mod-credentials/instagram-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/instagram-credentials/index.ts new file mode 100644 index 00000000..f1016965 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/instagram-credentials/index.ts @@ -0,0 +1 @@ +export type { InstagramCredentials } from './instagram-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/instagram-credentials/instagram-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/instagram-credentials/instagram-credentials.ts new file mode 100644 index 00000000..545393f7 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/mod-credentials/kakaotalk-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/index.ts new file mode 100644 index 00000000..488353e3 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/index.ts @@ -0,0 +1 @@ +export type { KakaoTalkCredentials } from './kakaotalk-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/kakaotalk-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/kakaotalk-credentials.ts new file mode 100644 index 00000000..3efcd51e --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/kakaotalk-credentials/kakaotalk-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/mod-credentials/kakaotalkchat-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/index.ts new file mode 100644 index 00000000..e39631c0 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/index.ts @@ -0,0 +1 @@ +export type { KakaoTalkChatCredentials } from './kakaotalkchat-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/kakaotalkchat-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/kakaotalkchat-credentials/kakaotalkchat-credentials.ts new file mode 100644 index 00000000..3b5b32eb --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/mod-credentials/line-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/line-credentials/index.ts new file mode 100644 index 00000000..f9456018 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/line-credentials/index.ts @@ -0,0 +1 @@ +export type { LineCredentials } from './line-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/line-credentials/line-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/line-credentials/line-credentials.ts new file mode 100644 index 00000000..8b083c64 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/mod-credentials/mms-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/mms-credentials/index.ts new file mode 100644 index 00000000..52b425f6 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/mms-credentials/index.ts @@ -0,0 +1 @@ +export type { MMSCredentials } from './mms-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/mms-credentials/mms-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/mms-credentials/mms-credentials.ts new file mode 100644 index 00000000..1cd34b37 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/mms-credentials/mms-credentials.ts @@ -0,0 +1,16 @@ +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; + /** 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/mod-credentials/sms-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/sms-credentials/index.ts new file mode 100644 index 00000000..b57e808c --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/sms-credentials/index.ts @@ -0,0 +1 @@ +export type { SMSCredentials } from './sms-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/sms-credentials/sms-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/sms-credentials/sms-credentials.ts new file mode 100644 index 00000000..5de7cff8 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/src/models/v1/mod-credentials/static-bearer-credential/index.ts b/packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/index.ts new file mode 100644 index 00000000..a4ccb653 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/index.ts @@ -0,0 +1 @@ +export type { StaticBearerCredential } from './static-bearer-credential'; diff --git a/packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/static-bearer-credential.ts b/packages/conversation/src/models/v1/mod-credentials/static-bearer-credential/static-bearer-credential.ts new file mode 100644 index 00000000..d18037d9 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/mod-credentials/static-token-credential/index.ts b/packages/conversation/src/models/v1/mod-credentials/static-token-credential/index.ts new file mode 100644 index 00000000..ae5231c4 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/static-token-credential/index.ts @@ -0,0 +1 @@ +export type { StaticTokenCredential } from './static-token-credential'; diff --git a/packages/conversation/src/models/v1/mod-credentials/static-token-credential/static-token-credential.ts b/packages/conversation/src/models/v1/mod-credentials/static-token-credential/static-token-credential.ts new file mode 100644 index 00000000..03b258ad --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/mod-credentials/telegram-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/telegram-credentials/index.ts new file mode 100644 index 00000000..beaafac8 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/telegram-credentials/index.ts @@ -0,0 +1 @@ +export type { TelegramCredentials } from './telegram-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/telegram-credentials/telegram-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/telegram-credentials/telegram-credentials.ts new file mode 100644 index 00000000..916b3b27 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/mod-credentials/wechat-credentials/index.ts b/packages/conversation/src/models/v1/mod-credentials/wechat-credentials/index.ts new file mode 100644 index 00000000..0bf66303 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/wechat-credentials/index.ts @@ -0,0 +1 @@ +export type { WeChatCredentials } from './wechat-credentials'; diff --git a/packages/conversation/src/models/v1/mod-credentials/wechat-credentials/wechat-credentials.ts b/packages/conversation/src/models/v1/mod-credentials/wechat-credentials/wechat-credentials.ts new file mode 100644 index 00000000..a2e19961 --- /dev/null +++ b/packages/conversation/src/models/v1/mod-credentials/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/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/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..4e8f6494 --- /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 { Recipient } from '../recipient'; +import { MessageQueue } from '../enums'; + +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..545ee9f3 --- /dev/null +++ b/packages/conversation/src/models/v1/send-message-request/send-message-request.ts @@ -0,0 +1,37 @@ +import { ConversationChannel } from '../conversation-channel'; +import { Recipient } from '../recipient'; +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. + */ +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: 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. */ + 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/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/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/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..973955a7 --- /dev/null +++ b/packages/conversation/src/models/v1/transcode-message-request/transcode-message-request.ts @@ -0,0 +1,16 @@ +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 AppMessageMessage */ + app_message: AppMessageMessage; + /** 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/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/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..44aa0792 --- /dev/null +++ b/packages/conversation/src/models/v1/webhook-trigger/webhook-trigger.ts @@ -0,0 +1,42 @@ +/** + * - `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 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. + * - `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' + | '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' + | 'CHANNEL_EVENT' + | 'CAPABILITY'; 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..af60e63d --- /dev/null +++ b/packages/conversation/src/models/v1/webhook/webhook.ts @@ -0,0 +1,24 @@ +import { ClientCredentials } from '../client-credentials'; +import { WebhookTrigger } from '../webhook-trigger'; +import { WebhookTargetType } from '../enums'; + +/** + * 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/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..0ffad1b9 --- /dev/null +++ b/packages/conversation/src/rest/v1/app/app-api.ts @@ -0,0 +1,184 @@ +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); + + 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/callbacks/callbacks-webhook.ts b/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts new file mode 100644 index 00000000..de2ee88d --- /dev/null +++ b/packages/conversation/src/rest/v1/callbacks/callbacks-webhook.ts @@ -0,0 +1,192 @@ +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'; +import { CallbackProcessor, validateWebhookSignature } from '@sinch/sdk-client'; +import { IncomingHttpHeaders } from 'http'; + +interface WebhookTriggerEvent { + trigger: WebhookTrigger; +} +export type ConversationWebhookEventParsed = ConversationWebhookEvent & WebhookTriggerEvent; + +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/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/capability/capability-api.jest.fixture.ts b/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts new file mode 100644 index 00000000..d1277f14 --- /dev/null +++ b/packages/conversation/src/rest/v1/capability/capability-api.jest.fixture.ts @@ -0,0 +1,11 @@ +import { QueryCapabilityResponse } from '../../../models'; +import { CapabilityApi, LookupCapabilityRequestData } from './capability-api'; + +export class CapabilityApiFixture implements Partial> { + + /** + * Fixture associated to function lookup + */ + 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 new file mode 100644 index 00000000..768d323a --- /dev/null +++ b/packages/conversation/src/rest/v1/capability/capability-api.ts @@ -0,0 +1,56 @@ +import { + RequestBody, + SinchClientParameters, +} from '@sinch/sdk-client'; +import { + LookupCapability, + QueryCapabilityResponse, +} from '../../../models'; +import { ConversationDomainApi } from '../conversation-domain-api'; + +export interface LookupCapabilityRequestData { + /** The lookup capability request. */ + 'lookupCapabilityRequestBody': LookupCapability; +} + +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 { LookupCapabilityRequestData } data - The data to provide to the API call. + */ + public async lookup(data: LookupCapabilityRequestData): 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['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); + 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..5cb3ca3c --- /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 create + */ + public create: jest.Mock, [CreateContactRequestData]> = jest.fn(); + /** + * Fixture associated to function delete + */ + public delete: jest.Mock, [DeleteContactRequestData]> = jest.fn(); + /** + * Fixture associated to function getChannelProfile + */ + public getChannelProfile: jest.Mock, [GetChannelProfileRequestData]> = jest.fn(); + /** + * Fixture associated to function get + */ + public get: jest.Mock, [GetContactRequestData]> = jest.fn(); + /** + * Fixture associated to function list + */ + public list: jest.Mock, [ListContactsRequestData]> = jest.fn(); + /** + * Fixture associated to function mergeContact + */ + public mergeContact: jest.Mock, [MergeContactRequestData]> = jest.fn(); + /** + * Fixture associated to function update + */ + 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 new file mode 100644 index 00000000..45a65e2e --- /dev/null +++ b/packages/conversation/src/rest/v1/contact/contact-api.ts @@ -0,0 +1,286 @@ +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. */ + 'updateContactRequestBody': Contact; + /** The set of field mask paths. */ + 'update_mask'?: 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 create(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 delete(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 get(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 list(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 update(data: UpdateContactRequestData): 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['updateContactRequestBody'] + ? JSON.stringify(data['updateContactRequestBody']) + : '{}'; + 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..ff577b5a --- /dev/null +++ b/packages/conversation/src/rest/v1/conversation-domain-api.ts @@ -0,0 +1,113 @@ +import { + Api, + ApiClient, + ApiClientOptions, + ApiFetchClient, + ConversationRegion, + Oauth2TokenRequest, + Region, + SinchClientParameters, + 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) { + 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); + } + } + + /** + * 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 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 = this.buildBasePath(region); + } + 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, + }; + } + + 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-service.ts b/packages/conversation/src/rest/v1/conversation-service.ts new file mode 100644 index 00000000..391721d1 --- /dev/null +++ b/packages/conversation/src/rest/v1/conversation-service.ts @@ -0,0 +1,56 @@ +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'; +import { TemplatesV1Api } from './templates-v1'; +import { TemplatesV2Api } from './templates-v2'; + +export class ConversationService { + 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; + public readonly templatesV1: TemplatesV1Api; + public readonly templatesV2: TemplatesV2Api; + + + 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); + this.templatesV1 = new TemplatesV1Api(params); + this.templatesV2 = new TemplatesV2Api(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); + this.templatesV1.setBasePath(basePath); + this.templatesV2.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..f202929a --- /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 create + */ + public create: jest.Mock, [CreateConversationRequestData]> = jest.fn(); + /** + * Fixture associated to function delete + */ + public delete: jest.Mock, [DeleteConversationRequestData]> = jest.fn(); + /** + * Fixture associated to function get + */ + public get: jest.Mock, [GetConversationRequestData]> = jest.fn(); + /** + * Fixture associated to function injectMessage + */ + public injectMessage: jest.Mock, [InjectMessageRequestData]> = jest.fn(); + /** + * Fixture associated to function list + */ + public list: jest.Mock, [ListConversationsRequestData]> = jest.fn(); + /** + * Fixture associated to function stopActive + */ + public stopActive: jest.Mock, [StopActiveConversationRequestData]> = jest.fn(); + /** + * Fixture associated to function update + */ + 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 new file mode 100644 index 00000000..75a50ad4 --- /dev/null +++ b/packages/conversation/src/rest/v1/conversation/conversation-api.ts @@ -0,0 +1,300 @@ +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. */ + 'conversation_id': string; + /** Message to be injected. */ + 'injectMessageRequestBody': 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. */ + 'updateConversationRequestBody': Conversation; + /** The set of field mask paths. */ + 'update_mask'?: 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 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 + = 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 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 = ''; + 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 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 = ''; + 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['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); + + 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 list(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 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 = ''; + 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 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', + 'metadata_update_strategy', + ]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + 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 + = 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..6a6294f6 --- /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 send + */ + 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 new file mode 100644 index 00000000..fb49739e --- /dev/null +++ b/packages/conversation/src/rest/v1/events/events-api.ts @@ -0,0 +1,54 @@ +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 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']) : '{}'; + 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..d86bda6b --- /dev/null +++ b/packages/conversation/src/rest/v1/index.ts @@ -0,0 +1,13 @@ +export * from './app'; +export * from './callbacks'; +export * from './capability'; +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'; +export * from './conversation-service'; 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..f60793e7 --- /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 delete + */ + public delete: jest.Mock, [DeleteMessageRequestData]> = jest.fn(); + /** + * Fixture associated to function get + */ + public get: jest.Mock, [GetMessageRequestData]> = jest.fn(); + /** + * Fixture associated to function list + */ + public list: jest.Mock, [ListMessagesRequestData]> = jest.fn(); + /** + * Fixture associated to function send + */ + 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 new file mode 100644 index 00000000..3ab17e90 --- /dev/null +++ b/packages/conversation/src/rest/v1/messages/messages-api.ts @@ -0,0 +1,214 @@ +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 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 = ''; + 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 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 = ''; + 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 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, [ + '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 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']) : '{}'; + 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/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/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..48dd1951 --- /dev/null +++ b/packages/conversation/src/rest/v1/transcoding/transcoding-api.ts @@ -0,0 +1,55 @@ +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..39131f5f --- /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 create + */ + public create: jest.Mock, [CreateWebhookRequestData]> = jest.fn(); + /** + * Fixture associated to function delete + */ + public delete: jest.Mock, [DeleteWebhookRequestData]> = jest.fn(); + /** + * Fixture associated to function get + */ + public get: jest.Mock, [GetWebhookRequestData]> = jest.fn(); + /** + * Fixture associated to function list + */ + public list: jest.Mock, [ListWebhooksRequestData]> = jest.fn(); + /** + * Fixture associated to function update + */ + 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 new file mode 100644 index 00000000..f5726608 --- /dev/null +++ b/packages/conversation/src/rest/v1/webhooks/webhooks-api.ts @@ -0,0 +1,188 @@ +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 */ + 'webhookCreateRequestBody': 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 */ + 'webhookUpdateRequestBody': Webhook; + /** The set of field mask paths. */ + 'update_mask'?: 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 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['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); + 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 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 = ''; + 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 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 = ''; + 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 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 = ''; + 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 update(data: UpdateWebhookRequestData): 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['webhookUpdateRequestBody'] + ? JSON.stringify(data['webhookUpdateRequestBody']) + : '{}'; + 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/tests/models/v1/helper.test.ts b/packages/conversation/tests/models/v1/helper.test.ts new file mode 100644 index 00000000..50331272 --- /dev/null +++ b/packages/conversation/tests/models/v1/helper.test.ts @@ -0,0 +1,420 @@ +import { + CardMessage, CardMessageItem, + CarouselMessage, CarouselMessageItem, + ChoiceMessage, ChoiceMessageItem, + ListMessage, ListMessageItem, + LocationMessage, LocationMessageItem, + MediaMessage, MediaMessageItem, + TemplateMessage, TemplateMessageItem, + TextMessage, TextMessageItem, + V2TemplateTranslation, + MessageType, + templateV1Helper, + templateV2Helper, messageBuilder, +} 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'); + }); + }); + + 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); + }); + }); + +}); 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..0c98c15d --- /dev/null +++ b/packages/conversation/tests/rest/v1/app/app-api.test.ts @@ -0,0 +1,282 @@ +import { SinchClientParameters } from '@sinch/sdk-client'; +import { + AppResponse, + CreateAppRequestData, + DeleteAppRequestData, + GetAppRequestData, + ListAppsRequestData, + UpdateAppRequestData, + ChannelCredentialsAppleBC, + ChannelCredentialsInstagram, + ChannelCredentialsKakaoTalk, + ChannelCredentialsKakaoTalkChat, + ChannelCredentialsLine, + ChannelCredentialsMessenger, + ChannelCredentialsMms, + ChannelCredentialsRcs, + ChannelCredentialsSms, + ListAppsResponse, + AppApi, + AppApiFixture, + ChannelCredentialsTelegram, + ChannelCredentialsViber, + ChannelCredentialsViberBM, ChannelCredentialsWeChat, ChannelCredentialsWhatsApp, +} 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 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: [ + channelCredentialsAppleBC, + channelCredentialsInstagram, + channelCredentialsKakaoTalk, + channelCredentialsKakaoTalkChat, + channelCredentialsLine, + channelCredentialsMms, + channelCredentialsMessenger, + channelCredentialsRcs, + channelCredentialsSms, + // channelCredentialsSmsWithAppId, + channelCredentialsTelegram, + channelCredentialsViber, + channelCredentialsViberBM, + channelCredentialsWeChat, + channelCredetialsWhatsApp, + ], + }, + }; + 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-domain-api.test.ts b/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts new file mode 100644 index 00000000..4ee62a91 --- /dev/null +++ b/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts @@ -0,0 +1,75 @@ +import { ConversationDomainApi } from '../../../src/rest/v1/conversation-domain-api'; +import { Region, UnifiedCredentials } from '@sinch/sdk-client'; + +describe('Conversation API', () => { + let conversationApi: ConversationDomainApi; + 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 ConversationDomainApi(params, 'dummy'); + 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 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 ConversationDomainApi(params, 'dummy'); + const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation(() => {}); + 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 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/conversation/conversation-api.test.ts b/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts new file mode 100644 index 00000000..1ab7976b --- /dev/null +++ b/packages/conversation/tests/rest/v1/conversation/conversation-api.test.ts @@ -0,0 +1,202 @@ +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: { + 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..8d1ae6d7 --- /dev/null +++ b/packages/conversation/tests/rest/v1/messages/messages-api.test.ts @@ -0,0 +1,241 @@ +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: { + 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: { + 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/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); + }); + }); +}); 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); + }); + }); +}); 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/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-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/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-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-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 adfbdd82..c61a296b 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-client/src/client/api-fetch-client.ts b/packages/sdk-client/src/client/api-fetch-client.ts index 4d479177..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)), + data: responseData || [], + hasNextPage: hasMore(transformedResponse, buildPaginationContext(apiCallParameters)), nextPageValue: nextPage, nextPage: () => createNextPageMethod( this, buildPaginationContext(apiCallParameters), apiCallParameters.requestOptions, nextPage), 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 ab01d9ce..60e8ef1d 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'; /** * Generate authorization header for application-signed requests (Verification and Voice) @@ -35,6 +36,35 @@ 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: any, +): 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; +}; + /** * 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 @@ -122,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/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); + }); + +}); diff --git a/packages/sdk-client/tests/utils/authorization.helper.test.ts b/packages/sdk-client/tests/utils/authorization.helper.test.ts index 34f0cf5c..9c1538cb 100644 --- a/packages/sdk-client/tests/utils/authorization.helper.test.ts +++ b/packages/sdk-client/tests/utils/authorization.helper.test.ts @@ -1,8 +1,12 @@ import { calculateMD5, calculateSignature, + calculateWebhookSignature, + computeSignedData, generateAuthorizationHeader, - validateAuthenticationHeader, validateSignatureHeader, + validateAuthenticationHeader, + validateSignatureHeader, + validateWebhookSignature, } from '../../src'; describe('Authorization validation', () => { @@ -214,3 +218,68 @@ 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'; + const timestamp = 'timestamp'; + const signedData = computeSignedData(body, nonce, timestamp); + expect(signedData).toEqual('body.nonce.timestamp'); + }); + + it('should calculate the right signature', () => { + const signedData = computeSignedData(CONVERSATION_BODY, NONCE, TIMESTAMP); + const signature = calculateWebhookSignature(signedData, APP_SECRET); + + expect(signature).toEqual(VALID_SIGNATURE); + }); + + 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(); + }); + +}); 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..97c23c5d 100644 --- a/packages/sdk-core/src/sinch-client.ts +++ b/packages/sdk-core/src/sinch-client.ts @@ -1,16 +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'; /** Sinch Client to declare and initialize the supported APIs */ export class SinchClient { - 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. @@ -18,16 +20,19 @@ export class SinchClient { * @param {SinchClientParameters} params - The object containing the Sinch credentials. */ constructor(params: SinchClientParameters) { + // Initialize the "Conversation" API + 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/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/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;