@qrvey/sms 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -0
- package/__tests__/__mocks__/SMSSender.mock.ts +10 -0
- package/coverageReader.sh +50 -0
- package/dist/cjs/errors/index.js +19 -0
- package/dist/cjs/errors/index.js.map +1 -0
- package/dist/cjs/errors/notProvidedCredentials.error.js +11 -0
- package/dist/cjs/errors/notProvidedCredentials.error.js.map +1 -0
- package/dist/cjs/errors/unknownProvider.error.js +11 -0
- package/dist/cjs/errors/unknownProvider.error.js.map +1 -0
- package/dist/cjs/index.js +6 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/interfaces/index.js +18 -0
- package/dist/cjs/interfaces/index.js.map +1 -0
- package/dist/cjs/interfaces/smsSender.interface.js +3 -0
- package/dist/cjs/interfaces/smsSender.interface.js.map +1 -0
- package/dist/cjs/services/clients/awsSmsSender.client.js +37 -0
- package/dist/cjs/services/clients/awsSmsSender.client.js.map +1 -0
- package/dist/cjs/services/clients/azureSmsSender.client.js +36 -0
- package/dist/cjs/services/clients/azureSmsSender.client.js.map +1 -0
- package/dist/cjs/services/clients/twilioSmsSender.client.js +41 -0
- package/dist/cjs/services/clients/twilioSmsSender.client.js.map +1 -0
- package/dist/cjs/services/clients/vonageSmsSender.client.js +34 -0
- package/dist/cjs/services/clients/vonageSmsSender.client.js.map +1 -0
- package/dist/cjs/services/index.js +18 -0
- package/dist/cjs/services/index.js.map +1 -0
- package/dist/cjs/services/smsSender.service.js +17 -0
- package/dist/cjs/services/smsSender.service.js.map +1 -0
- package/dist/cjs/services/smsSenderFactory.service.js +45 -0
- package/dist/cjs/services/smsSenderFactory.service.js.map +1 -0
- package/dist/cjs/types/index.js +19 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/cjs/types/sendResult.type.js +3 -0
- package/dist/cjs/types/sendResult.type.js.map +1 -0
- package/dist/cjs/types/smsProviderModule.type.js +3 -0
- package/dist/cjs/types/smsProviderModule.type.js.map +1 -0
- package/dist/cjs/utils/constants.js +9 -0
- package/dist/cjs/utils/constants.js.map +1 -0
- package/dist/esm/awsSmsSender.client-DGZ2JYIG.mjs +41 -0
- package/dist/esm/awsSmsSender.client-DGZ2JYIG.mjs.map +1 -0
- package/dist/esm/azureSmsSender.client-K6MPTIU7.mjs +36 -0
- package/dist/esm/azureSmsSender.client-K6MPTIU7.mjs.map +1 -0
- package/dist/esm/chunk-NCQDKWNI.mjs +26 -0
- package/dist/esm/chunk-NCQDKWNI.mjs.map +1 -0
- package/dist/esm/index.d.mts +20 -0
- package/dist/esm/index.mjs +36 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/twilioSmsSender.client-2Z4R25US.mjs +42 -0
- package/dist/esm/twilioSmsSender.client-2Z4R25US.mjs.map +1 -0
- package/dist/esm/vonageSmsSender.client-23U65FBQ.mjs +38 -0
- package/dist/esm/vonageSmsSender.client-23U65FBQ.mjs.map +1 -0
- package/dist/types/index.d.ts +20 -0
- package/jest.config.ts +15 -0
- package/package.json +80 -0
- package/src/errors/index.test.ts +13 -0
- package/src/errors/index.ts +2 -0
- package/src/errors/notProvidedCredentials.error.ts +6 -0
- package/src/errors/unknownProvider.error.ts +6 -0
- package/src/index.test.ts +7 -0
- package/src/index.ts +2 -0
- package/src/interfaces/index.ts +1 -0
- package/src/interfaces/smsSender.interface.ts +5 -0
- package/src/services/clients/awsSmsSender.client.test.ts +39 -0
- package/src/services/clients/awsSmsSender.client.ts +57 -0
- package/src/services/clients/azureSmsSender.client.test.ts +46 -0
- package/src/services/clients/azureSmsSender.client.ts +38 -0
- package/src/services/clients/index.test.ts +50 -0
- package/src/services/clients/index.ts +4 -0
- package/src/services/clients/twilioSmsSender.client.test.ts +48 -0
- package/src/services/clients/twilioSmsSender.client.ts +52 -0
- package/src/services/clients/voangeSmsSender.client.test.ts +48 -0
- package/src/services/clients/vonageSmsSender.client.ts +49 -0
- package/src/services/index.test.ts +12 -0
- package/src/services/index.ts +1 -0
- package/src/services/smsSender.service.ts +16 -0
- package/src/services/smsSenderFactory.service.test.ts +16 -0
- package/src/services/smsSenderFactory.service.ts +24 -0
- package/src/types/index.ts +2 -0
- package/src/types/sendResult.type.ts +9 -0
- package/src/types/smsProviderModule.type.ts +5 -0
- package/src/utils/constants.ts +6 -0
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +17 -0
- package/tsup.config.cjs.ts +9 -0
- package/tsup.config.esm.ts +10 -0
- package/tsup.config.types.ts +9 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { USERNAME, PASSWORD, FROM, NotProvidedCredentialsError } from './chunk-NCQDKWNI.mjs';
|
|
2
|
+
import { SmsClient } from '@azure/communication-sms';
|
|
3
|
+
|
|
4
|
+
var AzureSMSSenderClient = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
if (!(USERNAME && PASSWORD && FROM))
|
|
7
|
+
throw new NotProvidedCredentialsError();
|
|
8
|
+
const connectionString = `endpoint=https://${USERNAME}.communication.azure.com/;accesskey=${PASSWORD}`;
|
|
9
|
+
this.client = new SmsClient(connectionString);
|
|
10
|
+
}
|
|
11
|
+
async send(phones, message) {
|
|
12
|
+
const result = {
|
|
13
|
+
sent: [],
|
|
14
|
+
failed: []
|
|
15
|
+
};
|
|
16
|
+
const smsResults = await this.client.send({
|
|
17
|
+
from: FROM,
|
|
18
|
+
to: phones,
|
|
19
|
+
message
|
|
20
|
+
});
|
|
21
|
+
smsResults.forEach((smsResult) => {
|
|
22
|
+
if (smsResult.errorMessage)
|
|
23
|
+
result.failed.push({
|
|
24
|
+
phone: smsResult.to,
|
|
25
|
+
error: smsResult.errorMessage
|
|
26
|
+
});
|
|
27
|
+
else
|
|
28
|
+
result.sent.push({ phone: smsResult.to });
|
|
29
|
+
});
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { AzureSMSSenderClient as default };
|
|
35
|
+
//# sourceMappingURL=out.js.map
|
|
36
|
+
//# sourceMappingURL=azureSmsSender.client-K6MPTIU7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/clients/azureSmsSender.client.ts"],"names":[],"mappings":";;;;;;;;AAIA,SAAS,iBAAiB;AAE1B,IAAqB,uBAArB,MAAgE;AAAA,EAE5D,cAAc;AACV,QAAI,EAAE,YAAY,YAAY;AAC1B,YAAM,IAAI,4BAA4B;AAC1C,UAAM,mBAAmB,oBAAoB,QAAQ,uCAAuC,QAAQ;AACpG,SAAK,SAAS,IAAI,UAAU,gBAAgB;AAAA,EAChD;AAAA,EAEA,MAAa,KAAK,QAAkB,SAAsC;AACtE,UAAM,SAAqB;AAAA,MACvB,MAAM,CAAC;AAAA,MACP,QAAQ,CAAC;AAAA,IACb;AACA,UAAM,aAAa,MAAM,KAAK,OAAO,KAAK;AAAA,MACtC,MAAM;AAAA,MACN,IAAI;AAAA,MACJ;AAAA,IACJ,CAAC;AAED,eAAW,QAAQ,CAAC,cAAc;AAC9B,UAAI,UAAU;AACV,eAAO,OAAO,KAAK;AAAA,UACf,OAAO,UAAU;AAAA,UACjB,OAAO,UAAU;AAAA,QACrB,CAAC;AAAA;AACA,eAAO,KAAK,KAAK,EAAE,OAAO,UAAU,GAAG,CAAC;AAAA,IACjD,CAAC;AAED,WAAO;AAAA,EACX;AACJ","sourcesContent":["import { NotProvidedCredentialsError } from '../../errors';\nimport { ISMSSender } from '../../interfaces';\nimport { SendResult } from '../../types';\nimport { USERNAME, PASSWORD, FROM } from '../../utils/constants';\nimport { SmsClient } from '@azure/communication-sms';\n\nexport default class AzureSMSSenderClient implements ISMSSender {\n client: SmsClient;\n constructor() {\n if (!(USERNAME && PASSWORD && FROM))\n throw new NotProvidedCredentialsError();\n const connectionString = `endpoint=https://${USERNAME}.communication.azure.com/;accesskey=${PASSWORD}`;\n this.client = new SmsClient(connectionString);\n }\n\n public async send(phones: string[], message: string): Promise<SendResult> {\n const result: SendResult = {\n sent: [],\n failed: [],\n };\n const smsResults = await this.client.send({\n from: FROM as string,\n to: phones,\n message: message,\n });\n\n smsResults.forEach((smsResult) => {\n if (smsResult.errorMessage)\n result.failed.push({\n phone: smsResult.to,\n error: smsResult.errorMessage,\n });\n else result.sent.push({ phone: smsResult.to });\n });\n\n return result;\n }\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/errors/notProvidedCredentials.error.ts
|
|
2
|
+
var NotProvidedCredentialsError = class extends Error {
|
|
3
|
+
constructor() {
|
|
4
|
+
super("SMS sender credentials not provided.");
|
|
5
|
+
this.name = "NotProvidedCredentialsError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// src/errors/unknownProvider.error.ts
|
|
10
|
+
var UnknownProviderError = class extends Error {
|
|
11
|
+
constructor() {
|
|
12
|
+
super("Unknown provider. Set PROVIDER env variable");
|
|
13
|
+
this.name = "UnknownProviderError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/utils/constants.ts
|
|
18
|
+
var SMS_PROVIDER = process.env.SMS_PROVIDER;
|
|
19
|
+
var USERNAME = process.env.SMS_PROVIDER_USERNAME;
|
|
20
|
+
var PASSWORD = process.env.SMS_PROVIDER_PASSWORD;
|
|
21
|
+
var FROM = process.env.SMS_PROVIDER_FROM_NUMBER;
|
|
22
|
+
var REGION = process.env.SMS_PROVIDER_REGION;
|
|
23
|
+
|
|
24
|
+
export { FROM, NotProvidedCredentialsError, PASSWORD, REGION, SMS_PROVIDER, USERNAME, UnknownProviderError };
|
|
25
|
+
//# sourceMappingURL=out.js.map
|
|
26
|
+
//# sourceMappingURL=chunk-NCQDKWNI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/errors/notProvidedCredentials.error.ts","../../src/errors/unknownProvider.error.ts","../../src/utils/constants.ts"],"names":[],"mappings":";AAAO,IAAM,8BAAN,cAA0C,MAAM;AAAA,EACnD,cAAc;AACV,UAAM,sCAAsC;AAC5C,SAAK,OAAO;AAAA,EAChB;AACJ;;;ACLO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC5C,cAAc;AACV,UAAM,6CAA6C;AACnD,SAAK,OAAO;AAAA,EAChB;AACJ;;;ACLO,IAAM,eAAe,QAAQ,IAAI;AAEjC,IAAM,WAAW,QAAQ,IAAI;AAC7B,IAAM,WAAW,QAAQ,IAAI;AAC7B,IAAM,OAAO,QAAQ,IAAI;AACzB,IAAM,SAAS,QAAQ,IAAI","sourcesContent":["export class NotProvidedCredentialsError extends Error {\n constructor() {\n super('SMS sender credentials not provided.');\n this.name = 'NotProvidedCredentialsError';\n }\n}\n","export class UnknownProviderError extends Error {\n constructor() {\n super('Unknown provider. Set PROVIDER env variable');\n this.name = 'UnknownProviderError';\n }\n}\n","export const SMS_PROVIDER = process.env.SMS_PROVIDER;\n\nexport const USERNAME = process.env.SMS_PROVIDER_USERNAME;\nexport const PASSWORD = process.env.SMS_PROVIDER_PASSWORD;\nexport const FROM = process.env.SMS_PROVIDER_FROM_NUMBER;\nexport const REGION = process.env.SMS_PROVIDER_REGION;\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type SendResult = {
|
|
2
|
+
sent: SendMessageResult[];
|
|
3
|
+
failed: SendMessageResult[];
|
|
4
|
+
};
|
|
5
|
+
type SendMessageResult = {
|
|
6
|
+
phone: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
declare class SMSSenderService {
|
|
11
|
+
/**
|
|
12
|
+
* Send a message to one or more phones.
|
|
13
|
+
* @param phones - phone numbers to send to
|
|
14
|
+
* @param message - message to send
|
|
15
|
+
* @returns {Promise<SendResult>} Send result.
|
|
16
|
+
*/
|
|
17
|
+
send: (phones: string[], message: string) => Promise<SendResult>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { SMSSenderService, SendResult };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { SMS_PROVIDER, UnknownProviderError } from './chunk-NCQDKWNI.mjs';
|
|
2
|
+
|
|
3
|
+
// src/services/smsSenderFactory.service.ts
|
|
4
|
+
var SMSSenderFactory = class {
|
|
5
|
+
static async getSMSSender() {
|
|
6
|
+
var _a;
|
|
7
|
+
const provider = (_a = SMS_PROVIDER) == null ? void 0 : _a.toLowerCase();
|
|
8
|
+
if (!provider)
|
|
9
|
+
throw new UnknownProviderError();
|
|
10
|
+
const { default: SMSSender } = await this.providerModules[provider]();
|
|
11
|
+
return new SMSSender();
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
SMSSenderFactory.providerModules = {
|
|
15
|
+
twilio: () => import('./twilioSmsSender.client-2Z4R25US.mjs'),
|
|
16
|
+
aws: () => import('./awsSmsSender.client-DGZ2JYIG.mjs'),
|
|
17
|
+
azure: () => import('./azureSmsSender.client-K6MPTIU7.mjs'),
|
|
18
|
+
vonage: () => import('./vonageSmsSender.client-23U65FBQ.mjs')
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/services/smsSender.service.ts
|
|
22
|
+
var SMSSenderService = class {
|
|
23
|
+
constructor() {
|
|
24
|
+
/**
|
|
25
|
+
* Send a message to one or more phones.
|
|
26
|
+
* @param phones - phone numbers to send to
|
|
27
|
+
* @param message - message to send
|
|
28
|
+
* @returns {Promise<SendResult>} Send result.
|
|
29
|
+
*/
|
|
30
|
+
this.send = async (phones, message) => (await SMSSenderFactory.getSMSSender()).send(phones, message);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { SMSSenderService };
|
|
35
|
+
//# sourceMappingURL=out.js.map
|
|
36
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/smsSenderFactory.service.ts","../../src/services/smsSender.service.ts"],"names":[],"mappings":";;;;;;AAKO,IAAM,mBAAN,MAAuB;AAAA,EAW1B,aAAa,eAAoC;AAhBrD;AAiBQ,UAAM,YAAW,yCAAc;AAC/B,QAAI,CAAC;AAAU,YAAM,IAAI,qBAAqB;AAE9C,UAAM,EAAE,SAAS,UAAU,IAAI,MAAM,KAAK,gBAAgB,QAAQ,EAAE;AACpE,WAAO,IAAI,UAAU;AAAA,EACzB;AACJ;AAlBa,iBACM,kBAGX;AAAA,EACA,QAAQ,MAAM,OAAO,uCAAkC;AAAA,EACvD,KAAK,MAAM,OAAO,oCAA+B;AAAA,EACjD,OAAO,MAAM,OAAO,sCAAiC;AAAA,EACrD,QAAQ,MAAM,OAAO,uCAAkC;AAC3D;;;ACXG,IAAM,mBAAN,MAAuB;AAAA,EAAvB;AAOH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAO,OAAO,OACV,QACA,aAEC,MAAM,iBAAiB,aAAa,GAAG,KAAK,QAAQ,OAAO;AAAA;AACpE","sourcesContent":["import { UnknownProviderError } from '../errors';\nimport { ISMSSender } from '../interfaces';\nimport { SMSProviderModule } from '../types';\nimport { SMS_PROVIDER } from '../utils/constants';\n\nexport class SMSSenderFactory {\n private static providerModules: Record<\n string,\n () => Promise<SMSProviderModule>\n > = {\n twilio: () => import('./clients/twilioSmsSender.client'),\n aws: () => import('./clients/awsSmsSender.client'),\n azure: () => import('./clients/azureSmsSender.client'),\n vonage: () => import('./clients/vonageSmsSender.client'),\n };\n\n static async getSMSSender(): Promise<ISMSSender> {\n const provider = SMS_PROVIDER?.toLowerCase();\n if (!provider) throw new UnknownProviderError();\n\n const { default: SMSSender } = await this.providerModules[provider]();\n return new SMSSender();\n }\n}\n","import { SendResult } from '../types';\nimport { SMSSenderFactory } from './smsSenderFactory.service';\n\nexport class SMSSenderService {\n /**\n * Send a message to one or more phones.\n * @param phones - phone numbers to send to\n * @param message - message to send\n * @returns {Promise<SendResult>} Send result.\n */\n public send = async (\n phones: string[],\n message: string,\n ): Promise<SendResult> =>\n (await SMSSenderFactory.getSMSSender()).send(phones, message);\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { FROM, USERNAME, PASSWORD, NotProvidedCredentialsError } from './chunk-NCQDKWNI.mjs';
|
|
2
|
+
import { Twilio } from 'twilio';
|
|
3
|
+
|
|
4
|
+
var TwilioSMSSenderClient = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._send = (phone, message) => this.client.messages.create({
|
|
7
|
+
from: FROM,
|
|
8
|
+
to: phone,
|
|
9
|
+
body: message
|
|
10
|
+
});
|
|
11
|
+
if (USERNAME && PASSWORD)
|
|
12
|
+
this.client = new Twilio(USERNAME, PASSWORD);
|
|
13
|
+
else
|
|
14
|
+
throw new NotProvidedCredentialsError();
|
|
15
|
+
}
|
|
16
|
+
async send(phones = [], message) {
|
|
17
|
+
const sentMessages = await Promise.all(
|
|
18
|
+
phones.map((phone) => this._send(phone, message))
|
|
19
|
+
);
|
|
20
|
+
const result = {
|
|
21
|
+
sent: [],
|
|
22
|
+
failed: []
|
|
23
|
+
};
|
|
24
|
+
sentMessages.forEach((message2) => {
|
|
25
|
+
if (message2.errorMessage) {
|
|
26
|
+
result.failed.push({
|
|
27
|
+
phone: message2.to,
|
|
28
|
+
error: message2.errorMessage
|
|
29
|
+
});
|
|
30
|
+
} else {
|
|
31
|
+
result.sent.push({
|
|
32
|
+
phone: message2.to
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { TwilioSMSSenderClient as default };
|
|
41
|
+
//# sourceMappingURL=out.js.map
|
|
42
|
+
//# sourceMappingURL=twilioSmsSender.client-2Z4R25US.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/clients/twilioSmsSender.client.ts"],"names":["message"],"mappings":";;;;;;;;AACA,SAAS,cAAc;AAMvB,IAAqB,wBAArB,MAAiE;AAAA,EAE7D,cAAc;AAiCd,SAAQ,QAAQ,CACZ,OACA,YAEA,KAAK,OAAO,SAAS,OAAO;AAAA,MACxB,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,MAAM;AAAA,IACV,CAAC;AAxCD,QAAI,YAAY;AAAU,WAAK,SAAS,IAAI,OAAO,UAAU,QAAQ;AAAA;AAChE,YAAM,IAAI,4BAA4B;AAAA,EAC/C;AAAA,EAEA,MAAa,KACT,SAAmB,CAAC,GACpB,SACmB;AACnB,UAAM,eAAe,MAAM,QAAQ;AAAA,MAC/B,OAAO,IAAI,CAAC,UAAU,KAAK,MAAM,OAAO,OAAO,CAAC;AAAA,IACpD;AAEA,UAAM,SAAqB;AAAA,MACvB,MAAM,CAAC;AAAA,MACP,QAAQ,CAAC;AAAA,IACb;AACA,iBAAa,QAAQ,CAACA,aAAY;AAC9B,UAAIA,SAAQ,cAAc;AACtB,eAAO,OAAO,KAAK;AAAA,UACf,OAAOA,SAAQ;AAAA,UACf,OAAOA,SAAQ;AAAA,QACnB,CAAC;AAAA,MACL,OAAO;AACH,eAAO,KAAK,KAAK;AAAA,UACb,OAAOA,SAAQ;AAAA,QACnB,CAAC;AAAA,MACL;AAAA,IACJ,CAAC;AAED,WAAO;AAAA,EACX;AAWJ","sourcesContent":["import { ISMSSender } from '../../interfaces/smsSender.interface';\nimport { Twilio } from 'twilio';\nimport { USERNAME, PASSWORD, FROM } from '../../utils/constants';\nimport { MessageInstance } from 'twilio/lib/rest/api/v2010/account/message';\nimport { SendResult } from '../../types/sendResult.type';\nimport { NotProvidedCredentialsError } from '../../errors';\n\nexport default class TwilioSMSSenderClient implements ISMSSender {\n private client: Twilio;\n constructor() {\n if (USERNAME && PASSWORD) this.client = new Twilio(USERNAME, PASSWORD);\n else throw new NotProvidedCredentialsError();\n }\n\n public async send(\n phones: string[] = [],\n message: string,\n ): Promise<SendResult> {\n const sentMessages = await Promise.all(\n phones.map((phone) => this._send(phone, message)),\n );\n\n const result: SendResult = {\n sent: [],\n failed: [],\n };\n sentMessages.forEach((message) => {\n if (message.errorMessage) {\n result.failed.push({\n phone: message.to,\n error: message.errorMessage,\n });\n } else {\n result.sent.push({\n phone: message.to,\n });\n }\n });\n\n return result;\n }\n\n private _send = (\n phone: string,\n message: string,\n ): Promise<MessageInstance> =>\n this.client.messages.create({\n from: FROM,\n to: phone,\n body: message,\n });\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { FROM, USERNAME, PASSWORD, NotProvidedCredentialsError } from './chunk-NCQDKWNI.mjs';
|
|
2
|
+
import { Vonage } from '@vonage/server-sdk';
|
|
3
|
+
import { Auth } from '@vonage/auth';
|
|
4
|
+
|
|
5
|
+
var VonageSMSSenderClient = class {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.send = async (phones, message) => {
|
|
8
|
+
const result = {
|
|
9
|
+
sent: [],
|
|
10
|
+
failed: []
|
|
11
|
+
};
|
|
12
|
+
await Promise.all(
|
|
13
|
+
phones.map(
|
|
14
|
+
(phone) => this._send(phone, message).then(() => result.sent.push({ phone })).catch(
|
|
15
|
+
(error) => result.failed.push({ phone, error: error.message })
|
|
16
|
+
)
|
|
17
|
+
)
|
|
18
|
+
);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
this._send = (phone, message) => this.client.sms.send({
|
|
22
|
+
to: phone,
|
|
23
|
+
text: message,
|
|
24
|
+
from: FROM
|
|
25
|
+
});
|
|
26
|
+
if (!(USERNAME && PASSWORD && FROM))
|
|
27
|
+
throw new NotProvidedCredentialsError();
|
|
28
|
+
const vonageAuth = new Auth({
|
|
29
|
+
apiKey: USERNAME,
|
|
30
|
+
apiSecret: PASSWORD
|
|
31
|
+
});
|
|
32
|
+
this.client = new Vonage(vonageAuth);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { VonageSMSSenderClient as default };
|
|
37
|
+
//# sourceMappingURL=out.js.map
|
|
38
|
+
//# sourceMappingURL=vonageSmsSender.client-23U65FBQ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/clients/vonageSmsSender.client.ts"],"names":[],"mappings":";;;;;;;;AAEA,SAAS,cAAc;AACvB,SAAS,YAAY;AAKrB,IAAqB,wBAArB,MAAiE;AAAA,EAE7D,cAAc;AAUd,SAAO,OAAO,OACV,QACA,YACsB;AACtB,YAAM,SAAqB;AAAA,QACvB,MAAM,CAAC;AAAA,QACP,QAAQ,CAAC;AAAA,MACb;AAEA,YAAM,QAAQ;AAAA,QACV,OAAO;AAAA,UAAI,CAAC,UACR,KAAK,MAAM,OAAO,OAAO,EACpB,KAAK,MAAM,OAAO,KAAK,KAAK,EAAE,MAAM,CAAC,CAAC,EACtC;AAAA,YAAM,CAAC,UACJ,OAAO,OAAO,KAAK,EAAE,OAAO,OAAO,MAAM,QAAQ,CAAC;AAAA,UACtD;AAAA,QACR;AAAA,MACJ;AAEA,aAAO;AAAA,IACX;AAEA,SAAQ,QAAQ,CAAC,OAAe,YAC5B,KAAK,OAAO,IAAI,KAAK;AAAA,MACjB,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,MAAM;AAAA,IACV,CAAC;AApCD,QAAI,EAAE,YAAY,YAAY;AAC1B,YAAM,IAAI,4BAA4B;AAC1C,UAAM,aAAa,IAAI,KAAK;AAAA,MACxB,QAAQ;AAAA,MACR,WAAW;AAAA,IACf,CAAC;AACD,SAAK,SAAS,IAAI,OAAO,UAAU;AAAA,EACvC;AA8BJ","sourcesContent":["import { ISMSSender } from '../../interfaces';\nimport { SendResult } from '../../types';\nimport { Vonage } from '@vonage/server-sdk';\nimport { Auth } from '@vonage/auth';\nimport { USERNAME, PASSWORD, FROM } from '../../utils/constants';\nimport { NotProvidedCredentialsError } from '../../errors';\nimport { SMSMessages } from '@vonage/sms/dist/lib/types/SMSMessages';\n\nexport default class VonageSMSSenderClient implements ISMSSender {\n private client: Vonage;\n constructor() {\n if (!(USERNAME && PASSWORD && FROM))\n throw new NotProvidedCredentialsError();\n const vonageAuth = new Auth({\n apiKey: USERNAME,\n apiSecret: PASSWORD,\n });\n this.client = new Vonage(vonageAuth);\n }\n\n public send = async (\n phones: string[],\n message: string,\n ): Promise<SendResult> => {\n const result: SendResult = {\n sent: [],\n failed: [],\n };\n\n await Promise.all(\n phones.map((phone) =>\n this._send(phone, message)\n .then(() => result.sent.push({ phone }))\n .catch((error) =>\n result.failed.push({ phone, error: error.message }),\n ),\n ),\n );\n\n return result;\n };\n\n private _send = (phone: string, message: string): Promise<SMSMessages> =>\n this.client.sms.send({\n to: phone,\n text: message,\n from: FROM as string,\n });\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type SendResult = {
|
|
2
|
+
sent: SendMessageResult[];
|
|
3
|
+
failed: SendMessageResult[];
|
|
4
|
+
};
|
|
5
|
+
type SendMessageResult = {
|
|
6
|
+
phone: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
declare class SMSSenderService {
|
|
11
|
+
/**
|
|
12
|
+
* Send a message to one or more phones.
|
|
13
|
+
* @param phones - phone numbers to send to
|
|
14
|
+
* @param message - message to send
|
|
15
|
+
* @returns {Promise<SendResult>} Send result.
|
|
16
|
+
*/
|
|
17
|
+
send: (phones: string[], message: string) => Promise<SendResult>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { SMSSenderService, SendResult };
|
package/jest.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
preset: 'ts-jest',
|
|
3
|
+
testEnvironment: 'node',
|
|
4
|
+
collectCoverageFrom: [
|
|
5
|
+
'src/**/*.ts',
|
|
6
|
+
'!src/**/*.test.ts',
|
|
7
|
+
'!src/**/*.spec.ts',
|
|
8
|
+
'!src/types/**/*',
|
|
9
|
+
'!src/interfaces/**/*',
|
|
10
|
+
],
|
|
11
|
+
testPathIgnorePatterns: [
|
|
12
|
+
'<rootDir>/node_modules/',
|
|
13
|
+
'<rootDir>/__tests__/__mocks__/',
|
|
14
|
+
],
|
|
15
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qrvey/sms",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"types": "dist/types/index.d.ts",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/esm/index.mjs",
|
|
9
|
+
"require": "./dist/cjs/index.js",
|
|
10
|
+
"default": "./dist/cjs/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "jest",
|
|
15
|
+
"test:cov": "jest --coverage && chmod +x ./coverageReader.sh && sh ./coverageReader.sh",
|
|
16
|
+
"build:clean": "rm -rf dist",
|
|
17
|
+
"build:compile:original": "tsc -b ./tsconfig.cjs.json ./tsconfig.esm.json ./tsconfig.types.json",
|
|
18
|
+
"build:compile:cjs:original": "tsup --config ./tsup.config.cjs.ts",
|
|
19
|
+
"build:compile:cjs": "tsc -b ./tsconfig.cjs.json",
|
|
20
|
+
"build:compile:esm": "tsup --config ./tsup.config.esm.ts",
|
|
21
|
+
"build:compile:types": "tsup --config ./tsup.config.types.ts",
|
|
22
|
+
"build:compile": "yarn build:compile:cjs && yarn build:compile:esm && yarn build:compile:types",
|
|
23
|
+
"build": "yarn test:cov && yarn build:clean && yarn build:compile",
|
|
24
|
+
"prepare-publish": "yarn install && yarn build",
|
|
25
|
+
"publish-package": "yarn prepare-publish && npm publish"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"sms",
|
|
29
|
+
"client",
|
|
30
|
+
"qrvey"
|
|
31
|
+
],
|
|
32
|
+
"author": "Qrvey",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"description": "",
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@aws-sdk/client-sns": "3.682.0",
|
|
37
|
+
"@azure/communication-sms": "1.2.0-beta.1",
|
|
38
|
+
"@types/jest": "29.5.5",
|
|
39
|
+
"@types/twilio": "3.19.3",
|
|
40
|
+
"@vonage/auth": "1.12.0",
|
|
41
|
+
"@vonage/server-sdk": "3.19.1",
|
|
42
|
+
"auto-version-js": "0.3.10",
|
|
43
|
+
"eslint-config-custom": "*",
|
|
44
|
+
"jest": "29.7.0",
|
|
45
|
+
"ts-jest": "29.1.1",
|
|
46
|
+
"tsc": "2.0.4",
|
|
47
|
+
"tsconfig": "*",
|
|
48
|
+
"tsup": "7.2.0",
|
|
49
|
+
"twilio": "5.3.5",
|
|
50
|
+
"typescript": "5.2.2"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@aws-sdk/client-sns": "3.682.0",
|
|
54
|
+
"@azure/communication-sms": "1.2.0-beta.1",
|
|
55
|
+
"@vonage/auth": "1.12.0",
|
|
56
|
+
"@vonage/server-sdk": "3.19.1",
|
|
57
|
+
"twilio": "5.3.5"
|
|
58
|
+
},
|
|
59
|
+
"peerDependenciesMeta": {
|
|
60
|
+
"@aws-sdk/client-sns": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@azure/communication-sms": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"@vonage/auth": {
|
|
67
|
+
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"@vonage/server-sdk": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"twilio": {
|
|
73
|
+
"optional": true
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"publishConfig": {
|
|
77
|
+
"access": "public",
|
|
78
|
+
"registry": "https://registry.npmjs.org"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { UnknownProviderError, NotProvidedCredentialsError } from './index';
|
|
2
|
+
|
|
3
|
+
describe('Error tests.', () => {
|
|
4
|
+
test('UnknownProviderError should be defined.', () => {
|
|
5
|
+
expect(UnknownProviderError).toBeDefined();
|
|
6
|
+
expect(new UnknownProviderError()).toBeInstanceOf(Error);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test('NotProvidedCredentialsError should be defined.', () => {
|
|
10
|
+
expect(NotProvidedCredentialsError).toBeDefined();
|
|
11
|
+
expect(new NotProvidedCredentialsError()).toBeInstanceOf(Error);
|
|
12
|
+
});
|
|
13
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './smsSender.interface';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import { SNSClient, PublishCommandOutput } from '@aws-sdk/client-sns';
|
|
3
|
+
import AwsSMSSenderClient from './awsSmsSender.client';
|
|
4
|
+
|
|
5
|
+
jest.mock('@aws-sdk/client-sns', () => {
|
|
6
|
+
const actualModule = jest.requireActual('@aws-sdk/client-sns');
|
|
7
|
+
class SNSClient {
|
|
8
|
+
send(
|
|
9
|
+
phones: string[] = [],
|
|
10
|
+
message: string,
|
|
11
|
+
): Promise<PublishCommandOutput> {
|
|
12
|
+
return Promise.resolve({} as PublishCommandOutput);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
...actualModule,
|
|
17
|
+
SNSClient,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
jest.mock('../../utils/constants', () => ({
|
|
22
|
+
REGION: 'us-east-1',
|
|
23
|
+
USERNAME: 'qrvey',
|
|
24
|
+
PASSWORD: '123456',
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
describe('AwsSMSSender tests.', () => {
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
jest.clearAllMocks();
|
|
30
|
+
jest.resetAllMocks();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('Should call send method.', async () => {
|
|
34
|
+
const smsSender = new AwsSMSSenderClient();
|
|
35
|
+
const clientSend = jest.spyOn(SNSClient.prototype, 'send');
|
|
36
|
+
await smsSender.send(['+1234567890', '+9876543210'], 'Hello world');
|
|
37
|
+
expect(clientSend).toHaveBeenCalledTimes(2);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { NotProvidedCredentialsError } from '../../errors';
|
|
2
|
+
import { ISMSSender } from '../../interfaces';
|
|
3
|
+
import { SendResult } from '../../types';
|
|
4
|
+
import { PASSWORD, REGION, USERNAME } from '../../utils/constants';
|
|
5
|
+
import {
|
|
6
|
+
PublishCommand,
|
|
7
|
+
PublishCommandOutput,
|
|
8
|
+
SNSClient,
|
|
9
|
+
} from '@aws-sdk/client-sns';
|
|
10
|
+
|
|
11
|
+
export default class AwsSMSSenderClient implements ISMSSender {
|
|
12
|
+
private client: SNSClient;
|
|
13
|
+
constructor() {
|
|
14
|
+
if (!(USERNAME && PASSWORD)) throw new NotProvidedCredentialsError();
|
|
15
|
+
this.client = new SNSClient({
|
|
16
|
+
region: REGION,
|
|
17
|
+
credentials: {
|
|
18
|
+
accessKeyId: USERNAME,
|
|
19
|
+
secretAccessKey: PASSWORD,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async send(
|
|
25
|
+
phones: string[] = [],
|
|
26
|
+
message: string,
|
|
27
|
+
): Promise<SendResult> {
|
|
28
|
+
const result: SendResult = {
|
|
29
|
+
sent: [],
|
|
30
|
+
failed: [],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
await Promise.all(
|
|
34
|
+
phones.map((phone) =>
|
|
35
|
+
this._send(phone, message)
|
|
36
|
+
.then(() => result.sent.push({ phone }))
|
|
37
|
+
.catch((error) =>
|
|
38
|
+
result.failed.push({ phone, error: error.message }),
|
|
39
|
+
),
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private _send = async (
|
|
47
|
+
phone: string,
|
|
48
|
+
message: string,
|
|
49
|
+
): Promise<PublishCommandOutput> => {
|
|
50
|
+
const command = new PublishCommand({
|
|
51
|
+
Message: message,
|
|
52
|
+
PhoneNumber: phone,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return await this.client.send(command);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import { SmsClient, SmsSendResult } from '@azure/communication-sms';
|
|
3
|
+
import AzureSMSSenderClient from './azureSmsSender.client';
|
|
4
|
+
|
|
5
|
+
jest.mock('@azure/communication-sms', () => {
|
|
6
|
+
const actualModule = jest.requireActual('@azure/communication-sms');
|
|
7
|
+
class SmsClient {
|
|
8
|
+
send({
|
|
9
|
+
from,
|
|
10
|
+
to,
|
|
11
|
+
message,
|
|
12
|
+
}: {
|
|
13
|
+
from: string;
|
|
14
|
+
to: string[];
|
|
15
|
+
message: string;
|
|
16
|
+
}): Promise<SmsSendResult[]> {
|
|
17
|
+
return Promise.resolve(
|
|
18
|
+
to.map((phone) => ({ to: phone })) as SmsSendResult[],
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
...actualModule,
|
|
24
|
+
SmsClient,
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
jest.mock('../../utils/constants', () => ({
|
|
29
|
+
FROM: '+123456789',
|
|
30
|
+
USERNAME: 'qrvey',
|
|
31
|
+
PASSWORD: '123456',
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
describe('AzureSMSSender tests.', () => {
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
jest.clearAllMocks();
|
|
37
|
+
jest.resetAllMocks();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('Should call send method.', async () => {
|
|
41
|
+
const smsSender = new AzureSMSSenderClient();
|
|
42
|
+
const clientSend = jest.spyOn(SmsClient.prototype, 'send');
|
|
43
|
+
await smsSender.send(['+1234567890', '+9876543210'], 'Hello world');
|
|
44
|
+
expect(clientSend).toHaveBeenCalledTimes(1);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { NotProvidedCredentialsError } from '../../errors';
|
|
2
|
+
import { ISMSSender } from '../../interfaces';
|
|
3
|
+
import { SendResult } from '../../types';
|
|
4
|
+
import { USERNAME, PASSWORD, FROM } from '../../utils/constants';
|
|
5
|
+
import { SmsClient } from '@azure/communication-sms';
|
|
6
|
+
|
|
7
|
+
export default class AzureSMSSenderClient implements ISMSSender {
|
|
8
|
+
client: SmsClient;
|
|
9
|
+
constructor() {
|
|
10
|
+
if (!(USERNAME && PASSWORD && FROM))
|
|
11
|
+
throw new NotProvidedCredentialsError();
|
|
12
|
+
const connectionString = `endpoint=https://${USERNAME}.communication.azure.com/;accesskey=${PASSWORD}`;
|
|
13
|
+
this.client = new SmsClient(connectionString);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public async send(phones: string[], message: string): Promise<SendResult> {
|
|
17
|
+
const result: SendResult = {
|
|
18
|
+
sent: [],
|
|
19
|
+
failed: [],
|
|
20
|
+
};
|
|
21
|
+
const smsResults = await this.client.send({
|
|
22
|
+
from: FROM as string,
|
|
23
|
+
to: phones,
|
|
24
|
+
message: message,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
smsResults.forEach((smsResult) => {
|
|
28
|
+
if (smsResult.errorMessage)
|
|
29
|
+
result.failed.push({
|
|
30
|
+
phone: smsResult.to,
|
|
31
|
+
error: smsResult.errorMessage,
|
|
32
|
+
});
|
|
33
|
+
else result.sent.push({ phone: smsResult.to });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { NotProvidedCredentialsError } from '../../errors';
|
|
2
|
+
import {
|
|
3
|
+
AwsSMSSenderClient,
|
|
4
|
+
AzureSMSSenderClient,
|
|
5
|
+
TwilioSMSSenderClient,
|
|
6
|
+
VonageSMSSenderClient,
|
|
7
|
+
} from './index';
|
|
8
|
+
import { SMSSender } from '../../../__tests__/__mocks__/SMSSender.mock';
|
|
9
|
+
|
|
10
|
+
describe('Client tests.', () => {
|
|
11
|
+
test('AwsSMSSender should be defined.', () => {
|
|
12
|
+
expect(AwsSMSSenderClient.default).toBeDefined();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('AzureSMSSender should be defined.', () => {
|
|
16
|
+
expect(AzureSMSSenderClient.default).toBeDefined();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('TwilioSMSSender should be defined.', () => {
|
|
20
|
+
expect(TwilioSMSSenderClient.default).toBeDefined();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('VonageSMSSender should be defined.', () => {
|
|
24
|
+
expect(VonageSMSSenderClient.default).toBeDefined();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('SMSSender must implement ISMSSender interface.', async () => {
|
|
28
|
+
const smsSender = new SMSSender();
|
|
29
|
+
const results = await smsSender.send(['+1234567890'], 'Hello world');
|
|
30
|
+
expect('send' in smsSender).toBe(true);
|
|
31
|
+
expect(smsSender.send).toBeInstanceOf(Function);
|
|
32
|
+
|
|
33
|
+
expect(results.sent).toBeInstanceOf(Array);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('Should return NotProvidedCredentialsError.', () => {
|
|
37
|
+
expect(() => new AwsSMSSenderClient.default()).toThrow(
|
|
38
|
+
new NotProvidedCredentialsError(),
|
|
39
|
+
);
|
|
40
|
+
expect(() => new TwilioSMSSenderClient.default()).toThrow(
|
|
41
|
+
new NotProvidedCredentialsError(),
|
|
42
|
+
);
|
|
43
|
+
expect(() => new VonageSMSSenderClient.default()).toThrow(
|
|
44
|
+
new NotProvidedCredentialsError(),
|
|
45
|
+
);
|
|
46
|
+
expect(() => new AzureSMSSenderClient.default()).toThrow(
|
|
47
|
+
new NotProvidedCredentialsError(),
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
});
|