@groundbrick/sms-service 1.1.3 → 1.1.4
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/dist/SmsService.d.ts +11 -0
- package/dist/SmsService.d.ts.map +1 -0
- package/dist/SmsService.js +29 -0
- package/dist/SmsService.js.map +1 -0
- package/dist/SmsServiceFactory.d.ts +5 -0
- package/dist/SmsServiceFactory.d.ts.map +1 -0
- package/dist/SmsServiceFactory.js +21 -0
- package/dist/SmsServiceFactory.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/ISmsProvider.d.ts +72 -0
- package/dist/interfaces/ISmsProvider.d.ts.map +1 -0
- package/dist/interfaces/ISmsProvider.js +9 -0
- package/dist/interfaces/ISmsProvider.js.map +1 -0
- package/dist/providers/GatewayApiSmsProvider.d.ts +25 -0
- package/dist/providers/GatewayApiSmsProvider.d.ts.map +1 -0
- package/dist/providers/GatewayApiSmsProvider.js +207 -0
- package/dist/providers/GatewayApiSmsProvider.js.map +1 -0
- package/dist/providers/MockSmsProvider.d.ts +39 -0
- package/dist/providers/MockSmsProvider.d.ts.map +1 -0
- package/dist/providers/MockSmsProvider.js +104 -0
- package/dist/providers/MockSmsProvider.js.map +1 -0
- package/dist/providers/SweegoSmsProvider.d.ts +22 -0
- package/dist/providers/SweegoSmsProvider.d.ts.map +1 -0
- package/dist/providers/SweegoSmsProvider.js +157 -0
- package/dist/providers/SweegoSmsProvider.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/index.js.map +1 -0
- package/package.json +6 -7
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SmsConfig, SmsMessage, SmsResult, DeliveryReport, WebhookValidationResult } from './interfaces/ISmsProvider.js';
|
|
2
|
+
export declare class SmsService {
|
|
3
|
+
private static instance;
|
|
4
|
+
private provider;
|
|
5
|
+
private constructor();
|
|
6
|
+
static getInstance(config?: SmsConfig): SmsService;
|
|
7
|
+
send(message: SmsMessage): Promise<SmsResult>;
|
|
8
|
+
getDeliveryReport(messageId: string): Promise<DeliveryReport | null>;
|
|
9
|
+
validateWebhook(payload: any, signature?: string): WebhookValidationResult;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=SmsService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmsService.d.ts","sourceRoot":"","sources":["../src/SmsService.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAGvI,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAe;IAE/B,OAAO;WAKO,WAAW,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,UAAU;IAWnD,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAI7C,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAI1E,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,uBAAuB;CAG3E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SmsServiceFactory } from './SmsServiceFactory.js';
|
|
2
|
+
export class SmsService {
|
|
3
|
+
static instance;
|
|
4
|
+
provider;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.provider = SmsServiceFactory.create(config);
|
|
7
|
+
console.log(`📱 SMS Service initialized with provider: ${config.provider}`);
|
|
8
|
+
}
|
|
9
|
+
static getInstance(config) {
|
|
10
|
+
if (!SmsService.instance) {
|
|
11
|
+
if (!config) {
|
|
12
|
+
throw new Error('Config is required on first initialization');
|
|
13
|
+
}
|
|
14
|
+
SmsService.instance = new SmsService(config);
|
|
15
|
+
}
|
|
16
|
+
return SmsService.instance;
|
|
17
|
+
}
|
|
18
|
+
// Proxy methods to the provider
|
|
19
|
+
async send(message) {
|
|
20
|
+
return this.provider.send(message);
|
|
21
|
+
}
|
|
22
|
+
async getDeliveryReport(messageId) {
|
|
23
|
+
return this.provider.getDeliveryReport(messageId);
|
|
24
|
+
}
|
|
25
|
+
validateWebhook(payload, signature) {
|
|
26
|
+
return this.provider.validateWebhook(payload, signature);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=SmsService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmsService.js","sourceRoot":"","sources":["../src/SmsService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,OAAO,UAAU;IACb,MAAM,CAAC,QAAQ,CAAa;IAC5B,QAAQ,CAAe;IAE/B,YAAoB,MAAiB;QACnC,IAAI,CAAC,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,6CAA6C,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9E,CAAC;IAEM,MAAM,CAAC,WAAW,CAAC,MAAkB;QAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,CAAC;YACD,UAAU,CAAC,QAAQ,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,UAAU,CAAC,QAAQ,CAAC;IAC7B,CAAC;IAED,gCAAgC;IAChC,KAAK,CAAC,IAAI,CAAC,OAAmB;QAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,SAAiB;QACvC,OAAO,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,eAAe,CAAC,OAAY,EAAE,SAAkB;QAC9C,OAAO,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC3D,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmsServiceFactory.d.ts","sourceRoot":"","sources":["../src/SmsServiceFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAA4B,MAAM,8BAA8B,CAAC;AAKjG,qBAAa,iBAAiB;IAC5B,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,YAAY;CAmB/C"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { GatewayApiSmsProvider } from './providers/GatewayApiSmsProvider.js';
|
|
2
|
+
import { SweegoSmsProvider } from './providers/SweegoSmsProvider.js';
|
|
3
|
+
import { MockSmsProvider } from './providers/MockSmsProvider.js';
|
|
4
|
+
export class SmsServiceFactory {
|
|
5
|
+
static create(config) {
|
|
6
|
+
switch (config.provider) {
|
|
7
|
+
case 'gatewayapi':
|
|
8
|
+
return new GatewayApiSmsProvider(config.config);
|
|
9
|
+
case 'sweego':
|
|
10
|
+
return new SweegoSmsProvider(config.config);
|
|
11
|
+
case 'mock':
|
|
12
|
+
return new MockSmsProvider(config.config);
|
|
13
|
+
// Future providers can be added here:
|
|
14
|
+
// case 'twilio':
|
|
15
|
+
// return new TwilioSmsProvider(config.config as any);
|
|
16
|
+
default:
|
|
17
|
+
throw new Error(`Provider ${config.provider} not supported`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=SmsServiceFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmsServiceFactory.js","sourceRoot":"","sources":["../src/SmsServiceFactory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEjE,MAAM,OAAO,iBAAiB;IAC5B,MAAM,CAAC,MAAM,CAAC,MAAiB;QAC7B,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;YACxB,KAAK,YAAY;gBACf,OAAO,IAAI,qBAAqB,CAAC,MAAM,CAAC,MAAa,CAAC,CAAC;YAEzD,KAAK,QAAQ;gBACX,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,MAAsB,CAAC,CAAC;YAE9D,KAAK,MAAM;gBACT,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,MAAoB,CAAC,CAAC;YAE1D,sCAAsC;YACtC,iBAAiB;YACjB,wDAAwD;YAExD;gBACE,MAAM,IAAI,KAAK,CAAC,YAAY,MAAM,CAAC,QAAQ,gBAAgB,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface ISmsProvider {
|
|
2
|
+
send(message: SmsMessage): Promise<SmsResult>;
|
|
3
|
+
getDeliveryReport(messageId: string): Promise<DeliveryReport | null>;
|
|
4
|
+
validateWebhook(payload: any, signature?: string): WebhookValidationResult;
|
|
5
|
+
}
|
|
6
|
+
export interface SmsMessage {
|
|
7
|
+
recipient: string;
|
|
8
|
+
message: string;
|
|
9
|
+
sender?: string;
|
|
10
|
+
metadata?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
export interface SmsResult {
|
|
13
|
+
success: boolean;
|
|
14
|
+
messageId?: string;
|
|
15
|
+
status: SmsStatus;
|
|
16
|
+
timestamp: Date;
|
|
17
|
+
error?: string;
|
|
18
|
+
providerResponse?: any;
|
|
19
|
+
}
|
|
20
|
+
export declare enum SmsStatus {
|
|
21
|
+
PENDING = "pending",
|
|
22
|
+
SENT = "sent",
|
|
23
|
+
DELIVERED = "delivered",
|
|
24
|
+
FAILED = "failed",
|
|
25
|
+
UNDELIVERED = "undelivered"
|
|
26
|
+
}
|
|
27
|
+
export interface DeliveryReport {
|
|
28
|
+
messageId: string;
|
|
29
|
+
status: SmsStatus;
|
|
30
|
+
timestamp: Date;
|
|
31
|
+
error?: string;
|
|
32
|
+
providerData?: any;
|
|
33
|
+
}
|
|
34
|
+
export interface WebhookValidationResult {
|
|
35
|
+
isValid: boolean;
|
|
36
|
+
payload?: IncomingSms | DeliveryReport;
|
|
37
|
+
error?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface IncomingSms {
|
|
40
|
+
id: string;
|
|
41
|
+
sender: string;
|
|
42
|
+
message: string;
|
|
43
|
+
receivedAt: Date;
|
|
44
|
+
metadata?: Record<string, any>;
|
|
45
|
+
}
|
|
46
|
+
export type SmsProviderType = 'gatewayapi' | 'sweego' | 'twilio' | 'mock';
|
|
47
|
+
export interface SmsConfig {
|
|
48
|
+
provider: SmsProviderType;
|
|
49
|
+
config: GatewayApiConfig | SweegoConfig | TwilioConfig | MockConfig;
|
|
50
|
+
}
|
|
51
|
+
export interface GatewayApiConfig {
|
|
52
|
+
token: string;
|
|
53
|
+
baseUrl?: string;
|
|
54
|
+
webhookSecret?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface TwilioConfig {
|
|
57
|
+
accountSid: string;
|
|
58
|
+
authToken: string;
|
|
59
|
+
fromNumber: string;
|
|
60
|
+
}
|
|
61
|
+
export interface MockConfig {
|
|
62
|
+
simulateDelay?: number;
|
|
63
|
+
simulateFailures?: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface SweegoConfig {
|
|
66
|
+
apiKey: string;
|
|
67
|
+
region?: string;
|
|
68
|
+
campaignType?: string;
|
|
69
|
+
baseUrl?: string;
|
|
70
|
+
providerSlug?: string;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=ISmsProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ISmsProvider.d.ts","sourceRoot":"","sources":["../../src/interfaces/ISmsProvider.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9C,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACrE,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,uBAAuB,CAAC;CAC5E;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,GAAG,CAAC;CACxB;AAED,oBAAY,SAAS;IACnB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,WAAW,gBAAgB;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,GAAG,cAAc,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE1E,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,gBAAgB,GAAG,YAAY,GAAG,YAAY,GAAG,UAAU,CAAC;CACrE;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export var SmsStatus;
|
|
2
|
+
(function (SmsStatus) {
|
|
3
|
+
SmsStatus["PENDING"] = "pending";
|
|
4
|
+
SmsStatus["SENT"] = "sent";
|
|
5
|
+
SmsStatus["DELIVERED"] = "delivered";
|
|
6
|
+
SmsStatus["FAILED"] = "failed";
|
|
7
|
+
SmsStatus["UNDELIVERED"] = "undelivered";
|
|
8
|
+
})(SmsStatus || (SmsStatus = {}));
|
|
9
|
+
//# sourceMappingURL=ISmsProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ISmsProvider.js","sourceRoot":"","sources":["../../src/interfaces/ISmsProvider.ts"],"names":[],"mappings":"AAsBA,MAAM,CAAN,IAAY,SAMX;AAND,WAAY,SAAS;IACnB,gCAAmB,CAAA;IACnB,0BAAa,CAAA;IACb,oCAAuB,CAAA;IACvB,8BAAiB,CAAA;IACjB,wCAA2B,CAAA;AAC7B,CAAC,EANW,SAAS,KAAT,SAAS,QAMpB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ISmsProvider, SmsMessage, SmsResult, DeliveryReport, WebhookValidationResult, GatewayApiConfig } from '../interfaces/ISmsProvider.js';
|
|
2
|
+
export declare class GatewayApiSmsProvider implements ISmsProvider {
|
|
3
|
+
private token;
|
|
4
|
+
private baseUrl;
|
|
5
|
+
private webhookSecret?;
|
|
6
|
+
private static readonly GSM7_BASIC_CHARS;
|
|
7
|
+
private static readonly GSM7_EXTENDED_CHARS;
|
|
8
|
+
constructor(config: GatewayApiConfig);
|
|
9
|
+
send(message: SmsMessage): Promise<SmsResult>;
|
|
10
|
+
private encodeMessage;
|
|
11
|
+
private buildCallbackUrl;
|
|
12
|
+
private requiresUnicodeEncoding;
|
|
13
|
+
getDeliveryReport(messageId: string): Promise<DeliveryReport | null>;
|
|
14
|
+
validateWebhook(payload: any, signature?: string): WebhookValidationResult;
|
|
15
|
+
/**
|
|
16
|
+
* Normalize phone number to international format (remove spaces, dashes, etc.)
|
|
17
|
+
* Ensures it starts with + or country code
|
|
18
|
+
*/
|
|
19
|
+
private normalizePhoneNumber;
|
|
20
|
+
/**
|
|
21
|
+
* Map GatewayAPI status codes to our SmsStatus enum
|
|
22
|
+
*/
|
|
23
|
+
private mapGatewayApiStatus;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=GatewayApiSmsProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GatewayApiSmsProvider.d.ts","sourceRoot":"","sources":["../../src/providers/GatewayApiSmsProvider.ts"],"names":[],"mappings":"AACA,OAAO,EACH,YAAY,EACZ,UAAU,EACV,SAAS,EACT,cAAc,EACd,uBAAuB,EACvB,gBAAgB,EAGnB,MAAM,+BAA+B,CAAC;AAGvC,qBAAa,qBAAsB,YAAW,YAAY;IACtD,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAwI;IAChL,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAgB;gBAE/C,MAAM,EAAE,gBAAgB;IAM9B,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAgEnD,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,uBAAuB;IAezB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA6B1E,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,uBAAuB;IA8D1E;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAgB5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAa9B"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { SmsStatus } from '../interfaces/ISmsProvider.js';
|
|
2
|
+
import jwt from 'jsonwebtoken';
|
|
3
|
+
export class GatewayApiSmsProvider {
|
|
4
|
+
token;
|
|
5
|
+
baseUrl;
|
|
6
|
+
webhookSecret;
|
|
7
|
+
static GSM7_BASIC_CHARS = "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";
|
|
8
|
+
static GSM7_EXTENDED_CHARS = "^{}\\[~]|€";
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.token = config.token;
|
|
11
|
+
this.baseUrl = config.baseUrl || 'https://gatewayapi.com';
|
|
12
|
+
this.webhookSecret = config.webhookSecret;
|
|
13
|
+
}
|
|
14
|
+
async send(message) {
|
|
15
|
+
try {
|
|
16
|
+
// Encode token as Base64 for Basic Auth
|
|
17
|
+
const authHeader = `Basic ${Buffer.from(this.token + ':').toString('base64')}`;
|
|
18
|
+
const requiresUnicode = this.requiresUnicodeEncoding(message.message);
|
|
19
|
+
// Build request body according to GatewayAPI docs
|
|
20
|
+
const requestBody = {
|
|
21
|
+
message: this.encodeMessage(message.message),
|
|
22
|
+
recipients: [
|
|
23
|
+
{ msisdn: this.normalizePhoneNumber(message.recipient) }
|
|
24
|
+
],
|
|
25
|
+
sender: message.sender,
|
|
26
|
+
userref: message.metadata?.reference,
|
|
27
|
+
callback_url: this.buildCallbackUrl(message.metadata?.callbackUrl)
|
|
28
|
+
};
|
|
29
|
+
if (requiresUnicode) {
|
|
30
|
+
requestBody.encoding = 'UCS2';
|
|
31
|
+
}
|
|
32
|
+
const response = await fetch(`${this.baseUrl}/rest/mtsms`, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: {
|
|
35
|
+
'Authorization': authHeader,
|
|
36
|
+
'Content-Type': 'application/json'
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify(requestBody)
|
|
39
|
+
});
|
|
40
|
+
const responseData = await response.json();
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
status: SmsStatus.FAILED,
|
|
45
|
+
timestamp: new Date(),
|
|
46
|
+
error: responseData.message || `HTTP ${response.status}`,
|
|
47
|
+
providerResponse: responseData
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// GatewayAPI returns an array of message IDs
|
|
51
|
+
const messageId = responseData.ids?.[0]?.toString();
|
|
52
|
+
return {
|
|
53
|
+
success: true,
|
|
54
|
+
messageId,
|
|
55
|
+
status: SmsStatus.SENT,
|
|
56
|
+
timestamp: new Date(),
|
|
57
|
+
providerResponse: responseData
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
status: SmsStatus.FAILED,
|
|
64
|
+
timestamp: new Date(),
|
|
65
|
+
error: error instanceof Error ? error.message : String(error)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
encodeMessage(text) {
|
|
70
|
+
return Buffer.from(text ?? '', 'utf8').toString('utf8');
|
|
71
|
+
}
|
|
72
|
+
buildCallbackUrl(callbackUrl) {
|
|
73
|
+
if (!callbackUrl) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
// Avoid duplicating schemes if caller already provided one
|
|
77
|
+
if (callbackUrl.startsWith('http://') || callbackUrl.startsWith('https://')) {
|
|
78
|
+
return callbackUrl;
|
|
79
|
+
}
|
|
80
|
+
return `https://${callbackUrl}`;
|
|
81
|
+
}
|
|
82
|
+
requiresUnicodeEncoding(text) {
|
|
83
|
+
if (!text) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
for (const char of text) {
|
|
87
|
+
if (!GatewayApiSmsProvider.GSM7_BASIC_CHARS.includes(char) &&
|
|
88
|
+
!GatewayApiSmsProvider.GSM7_EXTENDED_CHARS.includes(char)) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
async getDeliveryReport(messageId) {
|
|
95
|
+
try {
|
|
96
|
+
const authHeader = `Basic ${Buffer.from(this.token + ':').toString('base64')}`;
|
|
97
|
+
const response = await fetch(`${this.baseUrl}/rest/mtsms/${messageId}`, {
|
|
98
|
+
method: 'GET',
|
|
99
|
+
headers: {
|
|
100
|
+
'Authorization': authHeader
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const data = await response.json();
|
|
107
|
+
return {
|
|
108
|
+
messageId,
|
|
109
|
+
status: this.mapGatewayApiStatus(data.status),
|
|
110
|
+
timestamp: data.updated ? new Date(data.updated) : new Date(),
|
|
111
|
+
providerData: data
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
validateWebhook(payload, signature) {
|
|
119
|
+
try {
|
|
120
|
+
// If webhook secret is configured, validate the signature
|
|
121
|
+
if (this.webhookSecret && signature) {
|
|
122
|
+
// GatewayAPI uses a token-based authentication for webhooks
|
|
123
|
+
if (this.webhookSecret) {
|
|
124
|
+
if (!signature) {
|
|
125
|
+
return { isValid: false, error: 'Missing webhook signature' };
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
jwt.verify(signature, this.webhookSecret);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return { isValid: false, error: 'Invalid webhook signature' };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Check if this is a delivery report or incoming SMS
|
|
136
|
+
if (payload.status) {
|
|
137
|
+
// Delivery report
|
|
138
|
+
const deliveryReport = {
|
|
139
|
+
messageId: payload.id?.toString() || '',
|
|
140
|
+
status: this.mapGatewayApiStatus(payload.status),
|
|
141
|
+
timestamp: payload.time ? new Date(payload.time) : new Date(),
|
|
142
|
+
providerData: payload
|
|
143
|
+
};
|
|
144
|
+
return {
|
|
145
|
+
isValid: true,
|
|
146
|
+
payload: deliveryReport
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
else if (payload.message && payload.msisdn) {
|
|
150
|
+
// Incoming SMS
|
|
151
|
+
const incomingSms = {
|
|
152
|
+
id: payload.id?.toString() || '',
|
|
153
|
+
sender: payload.msisdn,
|
|
154
|
+
message: payload.message,
|
|
155
|
+
receivedAt: payload.senttime ? new Date(payload.senttime) : new Date(),
|
|
156
|
+
metadata: payload
|
|
157
|
+
};
|
|
158
|
+
return {
|
|
159
|
+
isValid: true,
|
|
160
|
+
payload: incomingSms
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
isValid: false,
|
|
165
|
+
error: 'Unknown webhook payload format'
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
return {
|
|
170
|
+
isValid: false,
|
|
171
|
+
error: error instanceof Error ? error.message : String(error)
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Normalize phone number to international format (remove spaces, dashes, etc.)
|
|
177
|
+
* Ensures it starts with + or country code
|
|
178
|
+
*/
|
|
179
|
+
normalizePhoneNumber(phone) {
|
|
180
|
+
// Remove every non-digit character to satisfy GatewayAPI requirement
|
|
181
|
+
let normalized = phone.replace(/\D/g, '');
|
|
182
|
+
if (!normalized) {
|
|
183
|
+
throw new Error('Invalid phone number');
|
|
184
|
+
}
|
|
185
|
+
// Ensure number contains a country code; default to Portugal (351) when missing
|
|
186
|
+
if (!normalized.match(/^(351|44|1|34|33)/)) {
|
|
187
|
+
normalized = `351${normalized}`;
|
|
188
|
+
}
|
|
189
|
+
return normalized;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Map GatewayAPI status codes to our SmsStatus enum
|
|
193
|
+
*/
|
|
194
|
+
mapGatewayApiStatus(status) {
|
|
195
|
+
const statusMap = {
|
|
196
|
+
'SCHEDULED': SmsStatus.PENDING,
|
|
197
|
+
'SENT': SmsStatus.SENT,
|
|
198
|
+
'DELIVERED': SmsStatus.DELIVERED,
|
|
199
|
+
'REJECTED': SmsStatus.FAILED,
|
|
200
|
+
'FAILED': SmsStatus.FAILED,
|
|
201
|
+
'EXPIRED': SmsStatus.UNDELIVERED,
|
|
202
|
+
'UNDELIVERABLE': SmsStatus.UNDELIVERED
|
|
203
|
+
};
|
|
204
|
+
return statusMap[status?.toUpperCase()] || SmsStatus.PENDING;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=GatewayApiSmsProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GatewayApiSmsProvider.js","sourceRoot":"","sources":["../../src/providers/GatewayApiSmsProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ISmsProvider, SmsMessage, SmsResult, DeliveryReport, WebhookValidationResult, MockConfig, SmsStatus } from '../interfaces/ISmsProvider.js';
|
|
2
|
+
interface SentSms {
|
|
3
|
+
id: string;
|
|
4
|
+
message: SmsMessage;
|
|
5
|
+
sentAt: Date;
|
|
6
|
+
status: SmsStatus;
|
|
7
|
+
}
|
|
8
|
+
export declare class MockSmsProvider implements ISmsProvider {
|
|
9
|
+
private simulateDelay;
|
|
10
|
+
private simulateFailures;
|
|
11
|
+
private sentMessages;
|
|
12
|
+
private messageIdCounter;
|
|
13
|
+
constructor(config: MockConfig);
|
|
14
|
+
send(message: SmsMessage): Promise<SmsResult>;
|
|
15
|
+
getDeliveryReport(messageId: string): Promise<DeliveryReport | null>;
|
|
16
|
+
validateWebhook(_payload: any, _signature?: string): WebhookValidationResult;
|
|
17
|
+
/**
|
|
18
|
+
* Get all sent SMS messages (useful for testing)
|
|
19
|
+
*/
|
|
20
|
+
getSentMessages(): SentSms[];
|
|
21
|
+
/**
|
|
22
|
+
* Clear all sent SMS messages (useful for testing)
|
|
23
|
+
*/
|
|
24
|
+
clearSentMessages(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Get a specific sent SMS by ID (useful for testing)
|
|
27
|
+
*/
|
|
28
|
+
getSentMessage(messageId: string): SentSms | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Log SMS to console (metadata only, no content for privacy)
|
|
31
|
+
*/
|
|
32
|
+
private logSms;
|
|
33
|
+
/**
|
|
34
|
+
* Simple delay helper
|
|
35
|
+
*/
|
|
36
|
+
private delay;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=MockSmsProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockSmsProvider.d.ts","sourceRoot":"","sources":["../../src/providers/MockSmsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EACZ,UAAU,EACV,SAAS,EACT,cAAc,EACd,uBAAuB,EACvB,UAAU,EACV,SAAS,EACZ,MAAM,+BAA+B,CAAC;AAEvC,UAAU,OAAO;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACrB;AAED,qBAAa,eAAgB,YAAW,YAAY;IAChD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,gBAAgB,CAAU;IAClC,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,gBAAgB,CAAK;gBAEjB,MAAM,EAAE,UAAU;IAKxB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAyC7C,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAe1E,eAAe,CACX,QAAQ,EAAE,GAAG,EACb,UAAU,CAAC,EAAE,MAAM,GACpB,uBAAuB;IAQ1B;;OAEG;IACH,eAAe,IAAI,OAAO,EAAE;IAI5B;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAKzB;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAItD;;OAEG;IACH,OAAO,CAAC,MAAM;IAcd;;OAEG;IACH,OAAO,CAAC,KAAK;CAGhB"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { SmsStatus } from '../interfaces/ISmsProvider.js';
|
|
2
|
+
export class MockSmsProvider {
|
|
3
|
+
simulateDelay;
|
|
4
|
+
simulateFailures;
|
|
5
|
+
sentMessages = new Map();
|
|
6
|
+
messageIdCounter = 1;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.simulateDelay = config.simulateDelay || 0;
|
|
9
|
+
this.simulateFailures = config.simulateFailures || false;
|
|
10
|
+
}
|
|
11
|
+
async send(message) {
|
|
12
|
+
// Simulate network delay
|
|
13
|
+
if (this.simulateDelay > 0) {
|
|
14
|
+
await this.delay(this.simulateDelay);
|
|
15
|
+
}
|
|
16
|
+
// Simulate random failures (10% chance)
|
|
17
|
+
if (this.simulateFailures && Math.random() < 0.1) {
|
|
18
|
+
return {
|
|
19
|
+
success: false,
|
|
20
|
+
status: SmsStatus.FAILED,
|
|
21
|
+
timestamp: new Date(),
|
|
22
|
+
error: 'Simulated failure'
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
// Generate message ID
|
|
26
|
+
const messageId = `mock-sms-${this.messageIdCounter++}-${Date.now()}`;
|
|
27
|
+
// Store sent SMS
|
|
28
|
+
const sentSms = {
|
|
29
|
+
id: messageId,
|
|
30
|
+
message,
|
|
31
|
+
sentAt: new Date(),
|
|
32
|
+
status: SmsStatus.DELIVERED
|
|
33
|
+
};
|
|
34
|
+
this.sentMessages.set(messageId, sentSms);
|
|
35
|
+
// Log SMS to console
|
|
36
|
+
this.logSms(messageId, message);
|
|
37
|
+
return {
|
|
38
|
+
success: true,
|
|
39
|
+
messageId,
|
|
40
|
+
status: SmsStatus.DELIVERED,
|
|
41
|
+
timestamp: new Date(),
|
|
42
|
+
providerResponse: { mock: true, stored: true }
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async getDeliveryReport(messageId) {
|
|
46
|
+
const sentSms = this.sentMessages.get(messageId);
|
|
47
|
+
if (!sentSms) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
messageId,
|
|
52
|
+
status: sentSms.status,
|
|
53
|
+
timestamp: sentSms.sentAt,
|
|
54
|
+
providerData: { mock: true }
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
validateWebhook(_payload, _signature) {
|
|
58
|
+
// Mock provider doesn't validate webhooks
|
|
59
|
+
return {
|
|
60
|
+
isValid: false,
|
|
61
|
+
error: 'Mock provider does not support webhooks'
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get all sent SMS messages (useful for testing)
|
|
66
|
+
*/
|
|
67
|
+
getSentMessages() {
|
|
68
|
+
return Array.from(this.sentMessages.values());
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Clear all sent SMS messages (useful for testing)
|
|
72
|
+
*/
|
|
73
|
+
clearSentMessages() {
|
|
74
|
+
this.sentMessages.clear();
|
|
75
|
+
this.messageIdCounter = 1;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get a specific sent SMS by ID (useful for testing)
|
|
79
|
+
*/
|
|
80
|
+
getSentMessage(messageId) {
|
|
81
|
+
return this.sentMessages.get(messageId);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Log SMS to console (metadata only, no content for privacy)
|
|
85
|
+
*/
|
|
86
|
+
logSms(messageId, message) {
|
|
87
|
+
const timestamp = new Date().toISOString();
|
|
88
|
+
const messageLength = message.message.length;
|
|
89
|
+
console.log(`📱 [MOCK SMS] ${timestamp} | ID: ${messageId} | To: ${message.recipient} | From: ${message.sender || 'N/A'} | Length: ${messageLength} chars`);
|
|
90
|
+
if (message.metadata && Object.keys(message.metadata).length > 0) {
|
|
91
|
+
const metaStr = Object.entries(message.metadata)
|
|
92
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
93
|
+
.join(', ');
|
|
94
|
+
console.log(` └─ Metadata: ${metaStr}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Simple delay helper
|
|
99
|
+
*/
|
|
100
|
+
delay(ms) {
|
|
101
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=MockSmsProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockSmsProvider.js","sourceRoot":"","sources":["../../src/providers/MockSmsProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ISmsProvider, SmsMessage, SmsResult, DeliveryReport, WebhookValidationResult, SweegoConfig } from '../interfaces/ISmsProvider.js';
|
|
2
|
+
export declare class SweegoSmsProvider implements ISmsProvider {
|
|
3
|
+
private apiKey;
|
|
4
|
+
private baseUrl;
|
|
5
|
+
private region;
|
|
6
|
+
private campaignType;
|
|
7
|
+
private providerSlug;
|
|
8
|
+
constructor(config: SweegoConfig);
|
|
9
|
+
send(message: SmsMessage): Promise<SmsResult>;
|
|
10
|
+
getDeliveryReport(messageId: string): Promise<DeliveryReport | null>;
|
|
11
|
+
validateWebhook(payload: any, signature?: string): WebhookValidationResult;
|
|
12
|
+
/**
|
|
13
|
+
* Normalize phone number to international format
|
|
14
|
+
* Ensures it starts with + for Sweego
|
|
15
|
+
*/
|
|
16
|
+
private normalizePhoneNumber;
|
|
17
|
+
/**
|
|
18
|
+
* Map Sweego status codes to our SmsStatus enum
|
|
19
|
+
*/
|
|
20
|
+
private mapSweegoStatus;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SweegoSmsProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SweegoSmsProvider.d.ts","sourceRoot":"","sources":["../../src/providers/SweegoSmsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EACZ,UAAU,EACV,SAAS,EACT,cAAc,EACd,uBAAuB,EACvB,YAAY,EAEf,MAAM,+BAA+B,CAAC;AAEvC,qBAAa,iBAAkB,YAAW,YAAY;IAClD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,YAAY;IAQ1B,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAyD7C,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA8B1E,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,uBAAuB;IAgC1E;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;OAEG;IACH,OAAO,CAAC,eAAe;CAa1B"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { SmsStatus } from '../interfaces/ISmsProvider.js';
|
|
2
|
+
export class SweegoSmsProvider {
|
|
3
|
+
apiKey;
|
|
4
|
+
baseUrl;
|
|
5
|
+
region;
|
|
6
|
+
campaignType;
|
|
7
|
+
providerSlug;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.apiKey = config.apiKey;
|
|
10
|
+
this.baseUrl = config.baseUrl || 'https://api.sweego.io';
|
|
11
|
+
this.region = config.region || 'PT';
|
|
12
|
+
this.campaignType = config.campaignType || 'transac';
|
|
13
|
+
this.providerSlug = config.providerSlug || 'sweego';
|
|
14
|
+
}
|
|
15
|
+
async send(message) {
|
|
16
|
+
try {
|
|
17
|
+
// Build request body according to Sweego SMS API
|
|
18
|
+
// SMS uses 'num' field instead of 'email' for recipients
|
|
19
|
+
const requestBody = {
|
|
20
|
+
channel: 'sms',
|
|
21
|
+
provider: this.providerSlug,
|
|
22
|
+
recipients: [
|
|
23
|
+
{ num: this.normalizePhoneNumber(message.recipient), region: this.region }
|
|
24
|
+
],
|
|
25
|
+
'message-txt': message.message,
|
|
26
|
+
'campaign-type': this.campaignType
|
|
27
|
+
};
|
|
28
|
+
const response = await fetch(`${this.baseUrl}/send`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'Api-Key': this.apiKey,
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
'Accept': 'application/json'
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(requestBody)
|
|
36
|
+
});
|
|
37
|
+
const responseData = await response.json();
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
status: SmsStatus.FAILED,
|
|
42
|
+
timestamp: new Date(),
|
|
43
|
+
error: responseData.message || responseData.error || `HTTP ${response.status}`,
|
|
44
|
+
providerResponse: responseData
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Sweego returns message ID in the response
|
|
48
|
+
const messageId = responseData.id?.toString() || responseData.message_id?.toString();
|
|
49
|
+
return {
|
|
50
|
+
success: true,
|
|
51
|
+
messageId,
|
|
52
|
+
status: SmsStatus.SENT,
|
|
53
|
+
timestamp: new Date(),
|
|
54
|
+
providerResponse: responseData
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
status: SmsStatus.FAILED,
|
|
61
|
+
timestamp: new Date(),
|
|
62
|
+
error: error instanceof Error ? error.message : String(error)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async getDeliveryReport(messageId) {
|
|
67
|
+
// Sweego may have a different endpoint for delivery reports
|
|
68
|
+
// For now, return null as it's not critical for basic sending
|
|
69
|
+
try {
|
|
70
|
+
const response = await fetch(`${this.baseUrl}/messages/${messageId}`, {
|
|
71
|
+
method: 'GET',
|
|
72
|
+
headers: {
|
|
73
|
+
'Api-Key': this.apiKey,
|
|
74
|
+
'Accept': 'application/json'
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const data = await response.json();
|
|
81
|
+
return {
|
|
82
|
+
messageId,
|
|
83
|
+
status: this.mapSweegoStatus(data.status),
|
|
84
|
+
timestamp: data.updated_at ? new Date(data.updated_at) : new Date(),
|
|
85
|
+
providerData: data
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
validateWebhook(payload, signature) {
|
|
93
|
+
try {
|
|
94
|
+
// Sweego webhook validation
|
|
95
|
+
// For now, accept all payloads and parse them
|
|
96
|
+
if (payload.status) {
|
|
97
|
+
// Delivery report
|
|
98
|
+
const deliveryReport = {
|
|
99
|
+
messageId: payload.id?.toString() || payload.message_id?.toString() || '',
|
|
100
|
+
status: this.mapSweegoStatus(payload.status),
|
|
101
|
+
timestamp: payload.timestamp ? new Date(payload.timestamp) : new Date(),
|
|
102
|
+
providerData: payload
|
|
103
|
+
};
|
|
104
|
+
return {
|
|
105
|
+
isValid: true,
|
|
106
|
+
payload: deliveryReport
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
isValid: false,
|
|
111
|
+
error: 'Unknown webhook payload format'
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
return {
|
|
116
|
+
isValid: false,
|
|
117
|
+
error: error instanceof Error ? error.message : String(error)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Normalize phone number to international format
|
|
123
|
+
* Ensures it starts with + for Sweego
|
|
124
|
+
*/
|
|
125
|
+
normalizePhoneNumber(phone) {
|
|
126
|
+
// Remove spaces, dashes, parentheses
|
|
127
|
+
let normalized = phone.replace(/[\s\-\(\)]/g, '');
|
|
128
|
+
// If doesn't start with +, add it
|
|
129
|
+
if (!normalized.startsWith('+')) {
|
|
130
|
+
// If starts with country code without +, add +
|
|
131
|
+
if (normalized.match(/^(351|44|1|34|33)/)) {
|
|
132
|
+
normalized = `+${normalized}`;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// Default to Portugal
|
|
136
|
+
normalized = `+351${normalized}`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return normalized;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Map Sweego status codes to our SmsStatus enum
|
|
143
|
+
*/
|
|
144
|
+
mapSweegoStatus(status) {
|
|
145
|
+
const statusMap = {
|
|
146
|
+
'pending': SmsStatus.PENDING,
|
|
147
|
+
'sent': SmsStatus.SENT,
|
|
148
|
+
'delivered': SmsStatus.DELIVERED,
|
|
149
|
+
'failed': SmsStatus.FAILED,
|
|
150
|
+
'rejected': SmsStatus.FAILED,
|
|
151
|
+
'undelivered': SmsStatus.UNDELIVERED,
|
|
152
|
+
'expired': SmsStatus.UNDELIVERED
|
|
153
|
+
};
|
|
154
|
+
return statusMap[status?.toLowerCase()] || SmsStatus.PENDING;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=SweegoSmsProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SweegoSmsProvider.js","sourceRoot":"","sources":["../../src/providers/SweegoSmsProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@groundbrick/sms-service",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Serviço de SMS plugável com suporte a múltiplos provedores (GatewayAPI, Twilio, etc)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,13 +18,12 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "tsc
|
|
22
|
-
"
|
|
23
|
-
"clean": "rm -rf dist",
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"dev": "tsc --watch",
|
|
23
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
24
24
|
"prepublishOnly": "npm run clean && npm run build",
|
|
25
|
-
"lint": "eslint src
|
|
26
|
-
"
|
|
27
|
-
"prepare": "npm run build"
|
|
25
|
+
"lint": "eslint src/**/*.ts",
|
|
26
|
+
"lint:fix": "eslint src/**/*.ts --fix"
|
|
28
27
|
},
|
|
29
28
|
"keywords": [
|
|
30
29
|
"sms",
|