@parsrun/sms 0.2.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.
@@ -0,0 +1,3 @@
1
+ export { NetGSMProvider, createNetGSMProvider } from './netgsm.js';
2
+ export { ConsoleProvider, createConsoleProvider } from './console.js';
3
+ import '../types.js';
@@ -0,0 +1,284 @@
1
+ // src/types.ts
2
+ var SMSErrorCodes = {
3
+ INVALID_CONFIG: "SMS_INVALID_CONFIG",
4
+ SEND_FAILED: "SMS_SEND_FAILED"};
5
+ var SMSError = class extends Error {
6
+ code;
7
+ cause;
8
+ constructor(message, code, cause) {
9
+ super(message);
10
+ this.name = "SMSError";
11
+ this.code = code;
12
+ this.cause = cause;
13
+ }
14
+ };
15
+
16
+ // src/providers/netgsm.ts
17
+ var NetGSMProvider = class {
18
+ /** Provider type identifier */
19
+ type = "netgsm";
20
+ username;
21
+ password;
22
+ from;
23
+ baseUrl;
24
+ /**
25
+ * Creates a new NetGSMProvider instance.
26
+ *
27
+ * @param config - The provider configuration including credentials and sender info
28
+ */
29
+ constructor(config) {
30
+ if (!config.username || !config.password) {
31
+ throw new SMSError(
32
+ "NetGSM requires username and password",
33
+ SMSErrorCodes.INVALID_CONFIG
34
+ );
35
+ }
36
+ if (!config.from) {
37
+ throw new SMSError(
38
+ "NetGSM requires a sender ID (from/header)",
39
+ SMSErrorCodes.INVALID_CONFIG
40
+ );
41
+ }
42
+ this.username = config.username;
43
+ this.password = config.password;
44
+ this.from = config.from;
45
+ this.baseUrl = config.providerUrl || "https://api.netgsm.com.tr/sms/send/otp";
46
+ }
47
+ /**
48
+ * Sends an SMS via the NetGSM API.
49
+ *
50
+ * @param options - The SMS options including recipient and message
51
+ * @returns A promise that resolves to the send result
52
+ */
53
+ async send(options) {
54
+ const from = options.from || this.from;
55
+ const to = this.sanitizePhoneNumber(options.to);
56
+ const xmlData = `<?xml version='1.0' encoding='iso-8859-9'?>
57
+ <mainbody>
58
+ <header>
59
+ <usercode>${this.escapeXml(this.username)}</usercode>
60
+ <password>${this.escapeXml(this.password)}</password>
61
+ <msgheader>${this.escapeXml(from)}</msgheader>
62
+ <encoding>TR</encoding>
63
+ </header>
64
+ <body>
65
+ <msg><![CDATA[${options.message}]]></msg>
66
+ <no>${to}</no>
67
+ </body>
68
+ </mainbody>`;
69
+ try {
70
+ const response = await fetch(this.baseUrl, {
71
+ method: "POST",
72
+ headers: {
73
+ "Content-Type": "application/xml"
74
+ },
75
+ body: xmlData
76
+ });
77
+ if (!response.ok) {
78
+ return {
79
+ success: false,
80
+ error: `HTTP ${response.status}: ${response.statusText}`
81
+ };
82
+ }
83
+ const responseText = await response.text();
84
+ const result = this.parseResponse(responseText);
85
+ if (result.success && result.code) {
86
+ const successResult = {
87
+ success: true,
88
+ messageId: result.code,
89
+ data: { raw: responseText }
90
+ };
91
+ return successResult;
92
+ }
93
+ const errorResult = {
94
+ success: false,
95
+ error: this.getErrorMessage(result.code),
96
+ data: { code: result.code, raw: responseText }
97
+ };
98
+ return errorResult;
99
+ } catch (err) {
100
+ throw new SMSError(
101
+ `NetGSM send failed: ${err instanceof Error ? err.message : "Unknown error"}`,
102
+ SMSErrorCodes.SEND_FAILED,
103
+ err
104
+ );
105
+ }
106
+ }
107
+ /**
108
+ * Sends multiple SMS messages sequentially.
109
+ *
110
+ * @param options - The batch SMS options
111
+ * @returns A promise that resolves to the batch result
112
+ */
113
+ async sendBatch(options) {
114
+ const results = [];
115
+ let successful = 0;
116
+ let failed = 0;
117
+ for (const sms of options.messages) {
118
+ try {
119
+ const result = await this.send(sms);
120
+ results.push(result);
121
+ if (result.success) {
122
+ successful++;
123
+ } else {
124
+ failed++;
125
+ if (options.stopOnError) break;
126
+ }
127
+ } catch (err) {
128
+ failed++;
129
+ results.push({
130
+ success: false,
131
+ error: err instanceof Error ? err.message : "Unknown error"
132
+ });
133
+ if (options.stopOnError) break;
134
+ }
135
+ }
136
+ return {
137
+ total: options.messages.length,
138
+ successful,
139
+ failed,
140
+ results
141
+ };
142
+ }
143
+ /**
144
+ * Verifies the NetGSM credentials by checking balance/credit.
145
+ *
146
+ * @returns A promise that resolves to true if credentials are valid
147
+ */
148
+ async verify() {
149
+ return !!(this.username && this.password && this.from);
150
+ }
151
+ /**
152
+ * Parse NetGSM XML response
153
+ * Success codes: "0", "00", or numeric job ID
154
+ */
155
+ parseResponse(xml) {
156
+ try {
157
+ const codeMatch = xml.match(/<code>(.*?)<\/code>/);
158
+ if (codeMatch && codeMatch[1]) {
159
+ const code = codeMatch[1].trim();
160
+ if (code === "00" || code === "0") {
161
+ return { success: true, code };
162
+ }
163
+ return { success: false, code };
164
+ }
165
+ const trimmed = xml.trim();
166
+ if (/^\d+$/.test(trimmed) && trimmed.length > 5) {
167
+ return { success: true, code: trimmed };
168
+ }
169
+ return { success: false };
170
+ } catch {
171
+ return { success: false };
172
+ }
173
+ }
174
+ /**
175
+ * Get human-readable error message for NetGSM error codes
176
+ */
177
+ getErrorMessage(code) {
178
+ const errorMessages = {
179
+ "20": "Mesaj metninde hata var",
180
+ "30": "Ge\xE7ersiz kullan\u0131c\u0131 ad\u0131 veya \u015Fifre",
181
+ "40": "Mesaj ba\u015Fl\u0131\u011F\u0131 sistemde tan\u0131ml\u0131 de\u011Fil",
182
+ "50": "Abone hesab\u0131 tan\u0131ml\u0131 de\u011Fil",
183
+ "51": "Abone hesab\u0131nda yeterli bakiye yok",
184
+ "60": "G\xF6nderilecek mesaj bulunamad\u0131",
185
+ "70": "Ge\xE7ersiz parametre hatas\u0131",
186
+ "80": "G\xF6nderim zamanlamas\u0131 hatal\u0131",
187
+ "85": "G\xF6nderim zamanlamas\u0131 \xE7ok ge\xE7"
188
+ };
189
+ return code ? errorMessages[code] || `NetGSM error code: ${code}` : "Unknown error";
190
+ }
191
+ /**
192
+ * Escape XML special characters
193
+ */
194
+ escapeXml(unsafe) {
195
+ return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
196
+ }
197
+ /**
198
+ * Sanitize phone number (remove spaces, dashes, parentheses)
199
+ */
200
+ sanitizePhoneNumber(phone) {
201
+ return phone.replace(/[\s\-\(\)\+]/g, "");
202
+ }
203
+ };
204
+ function createNetGSMProvider(config) {
205
+ return new NetGSMProvider(config);
206
+ }
207
+
208
+ // src/providers/console.ts
209
+ var ConsoleProvider = class {
210
+ /** Provider type identifier */
211
+ type = "console";
212
+ from;
213
+ delay;
214
+ /**
215
+ * Creates a new ConsoleProvider instance.
216
+ *
217
+ * @param config - The provider configuration
218
+ */
219
+ constructor(config) {
220
+ this.from = config.from || "CONSOLE";
221
+ this.delay = config.delay ?? 100;
222
+ }
223
+ /**
224
+ * Logs an SMS message to the console.
225
+ *
226
+ * @param options - The SMS options
227
+ * @returns A promise that resolves to a successful result
228
+ */
229
+ async send(options) {
230
+ if (this.delay > 0) {
231
+ await new Promise((resolve) => setTimeout(resolve, this.delay));
232
+ }
233
+ const from = options.from || this.from;
234
+ const messageId = `console-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
235
+ console.log("\n" + "\u2500".repeat(50));
236
+ console.log("\u{1F4F1} SMS (Console Provider)");
237
+ console.log("\u2500".repeat(50));
238
+ console.log(`To: ${options.to}`);
239
+ console.log(`From: ${from}`);
240
+ console.log(`Message: ${options.message}`);
241
+ if (options.tags) {
242
+ console.log(`Tags: ${JSON.stringify(options.tags)}`);
243
+ }
244
+ console.log(`ID: ${messageId}`);
245
+ console.log("\u2500".repeat(50) + "\n");
246
+ return {
247
+ success: true,
248
+ messageId,
249
+ data: { provider: "console", logged: true }
250
+ };
251
+ }
252
+ /**
253
+ * Logs multiple SMS messages to the console.
254
+ *
255
+ * @param options - The batch SMS options
256
+ * @returns A promise that resolves to the batch result
257
+ */
258
+ async sendBatch(options) {
259
+ const results = [];
260
+ for (const sms of options.messages) {
261
+ const result = await this.send(sms);
262
+ results.push(result);
263
+ }
264
+ return {
265
+ total: options.messages.length,
266
+ successful: options.messages.length,
267
+ failed: 0,
268
+ results
269
+ };
270
+ }
271
+ /**
272
+ * Always returns true for console provider.
273
+ */
274
+ async verify() {
275
+ return true;
276
+ }
277
+ };
278
+ function createConsoleProvider(config) {
279
+ return new ConsoleProvider(config || {});
280
+ }
281
+
282
+ export { ConsoleProvider, NetGSMProvider, createConsoleProvider, createNetGSMProvider };
283
+ //# sourceMappingURL=index.js.map
284
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types.ts","../../src/providers/netgsm.ts","../../src/providers/console.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @parsrun/sms - Type definitions\n */\n\n/**\n * Supported SMS provider types\n */\nexport type SMSProviderType = \"netgsm\" | \"twilio\" | \"console\";\n\n/**\n * SMS send options\n */\nexport interface SMSOptions {\n /** Recipient phone number (international format recommended, e.g., 905xxxxxxxxx) */\n to: string;\n /** SMS message content */\n message: string;\n /** Optional sender ID override */\n from?: string;\n /** Optional metadata/tags */\n tags?: Record<string, string>;\n}\n\n/**\n * SMS send result\n */\nexport interface SMSResult {\n /** Whether the SMS was sent successfully */\n success: boolean;\n /** Provider-specific message ID */\n messageId?: string;\n /** Error message if send failed */\n error?: string;\n /** Raw provider response data */\n data?: unknown;\n}\n\n/**\n * Batch SMS options\n */\nexport interface BatchSMSOptions {\n /** Array of SMS messages to send */\n messages: SMSOptions[];\n /** Stop sending if an error occurs */\n stopOnError?: boolean;\n}\n\n/**\n * Batch SMS result\n */\nexport interface BatchSMSResult {\n /** Total number of messages attempted */\n total: number;\n /** Number of successfully sent messages */\n successful: number;\n /** Number of failed messages */\n failed: number;\n /** Individual results for each message */\n results: SMSResult[];\n}\n\n/**\n * SMS provider configuration\n */\nexport interface SMSProviderConfig {\n /** API key or authentication token */\n apiKey?: string;\n /** Provider username (for providers like NetGSM) */\n username?: string;\n /** Provider password (for providers like NetGSM) */\n password?: string;\n /** Default sender ID/header */\n from?: string;\n /** Provider-specific options */\n options?: Record<string, unknown>;\n}\n\n/**\n * SMS service configuration\n */\nexport interface SMSServiceConfig extends SMSProviderConfig {\n /** SMS provider type */\n provider: SMSProviderType;\n /** Provider API URL (for custom endpoints) */\n providerUrl?: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * SMS provider interface\n */\nexport interface SMSProvider {\n /** Provider type identifier */\n readonly type: SMSProviderType;\n\n /** Send a single SMS */\n send(options: SMSOptions): Promise<SMSResult>;\n\n /** Send multiple SMS messages (optional) */\n sendBatch?(options: BatchSMSOptions): Promise<BatchSMSResult>;\n\n /** Verify provider configuration (optional) */\n verify?(): Promise<boolean>;\n}\n\n/**\n * SMS error codes\n */\nexport const SMSErrorCodes = {\n INVALID_CONFIG: \"SMS_INVALID_CONFIG\",\n SEND_FAILED: \"SMS_SEND_FAILED\",\n INVALID_PHONE: \"SMS_INVALID_PHONE\",\n RATE_LIMITED: \"SMS_RATE_LIMITED\",\n INSUFFICIENT_BALANCE: \"SMS_INSUFFICIENT_BALANCE\",\n PROVIDER_ERROR: \"SMS_PROVIDER_ERROR\",\n} as const;\n\nexport type SMSErrorCode = (typeof SMSErrorCodes)[keyof typeof SMSErrorCodes];\n\n/**\n * SMS error class\n */\nexport class SMSError extends Error {\n code: SMSErrorCode;\n cause?: unknown;\n\n constructor(message: string, code: SMSErrorCode, cause?: unknown) {\n super(message);\n this.name = \"SMSError\";\n this.code = code;\n this.cause = cause;\n }\n}\n","/**\n * @parsrun/sms - NetGSM Provider\n * Edge-compatible NetGSM SMS provider using fetch API\n */\n\nimport type {\n BatchSMSOptions,\n BatchSMSResult,\n SMSOptions,\n SMSProvider,\n SMSProviderConfig,\n SMSResult,\n} from \"../types.js\";\nimport { SMSError, SMSErrorCodes } from \"../types.js\";\n\n/**\n * NetGSM SMS Provider\n * Uses fetch API for edge compatibility\n *\n * @example\n * ```typescript\n * const netgsm = new NetGSMProvider({\n * username: process.env.NETGSM_USERNAME,\n * password: process.env.NETGSM_PASSWORD,\n * from: 'MYSENDER',\n * });\n *\n * await netgsm.send({\n * to: '905551234567',\n * message: 'Hello from Pars!',\n * });\n * ```\n */\nexport class NetGSMProvider implements SMSProvider {\n /** Provider type identifier */\n readonly type = \"netgsm\" as const;\n\n private username: string;\n private password: string;\n private from: string;\n private baseUrl: string;\n\n /**\n * Creates a new NetGSMProvider instance.\n *\n * @param config - The provider configuration including credentials and sender info\n */\n constructor(config: SMSProviderConfig & { providerUrl?: string }) {\n if (!config.username || !config.password) {\n throw new SMSError(\n \"NetGSM requires username and password\",\n SMSErrorCodes.INVALID_CONFIG\n );\n }\n if (!config.from) {\n throw new SMSError(\n \"NetGSM requires a sender ID (from/header)\",\n SMSErrorCodes.INVALID_CONFIG\n );\n }\n\n this.username = config.username;\n this.password = config.password;\n this.from = config.from;\n this.baseUrl = config.providerUrl || \"https://api.netgsm.com.tr/sms/send/otp\";\n }\n\n /**\n * Sends an SMS via the NetGSM API.\n *\n * @param options - The SMS options including recipient and message\n * @returns A promise that resolves to the send result\n */\n async send(options: SMSOptions): Promise<SMSResult> {\n const from = options.from || this.from;\n const to = this.sanitizePhoneNumber(options.to);\n\n const xmlData = `<?xml version='1.0' encoding='iso-8859-9'?>\n<mainbody>\n <header>\n <usercode>${this.escapeXml(this.username)}</usercode>\n <password>${this.escapeXml(this.password)}</password>\n <msgheader>${this.escapeXml(from)}</msgheader>\n <encoding>TR</encoding>\n </header>\n <body>\n <msg><![CDATA[${options.message}]]></msg>\n <no>${to}</no>\n </body>\n</mainbody>`;\n\n try {\n const response = await fetch(this.baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/xml\",\n },\n body: xmlData,\n });\n\n if (!response.ok) {\n return {\n success: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n const responseText = await response.text();\n const result = this.parseResponse(responseText);\n\n if (result.success && result.code) {\n const successResult: SMSResult = {\n success: true,\n messageId: result.code,\n data: { raw: responseText },\n };\n return successResult;\n }\n\n const errorResult: SMSResult = {\n success: false,\n error: this.getErrorMessage(result.code),\n data: { code: result.code, raw: responseText },\n };\n return errorResult;\n } catch (err) {\n throw new SMSError(\n `NetGSM send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n SMSErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n /**\n * Sends multiple SMS messages sequentially.\n *\n * @param options - The batch SMS options\n * @returns A promise that resolves to the batch result\n */\n async sendBatch(options: BatchSMSOptions): Promise<BatchSMSResult> {\n const results: SMSResult[] = [];\n let successful = 0;\n let failed = 0;\n\n for (const sms of options.messages) {\n try {\n const result = await this.send(sms);\n results.push(result);\n\n if (result.success) {\n successful++;\n } else {\n failed++;\n if (options.stopOnError) break;\n }\n } catch (err) {\n failed++;\n results.push({\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n\n if (options.stopOnError) break;\n }\n }\n\n return {\n total: options.messages.length,\n successful,\n failed,\n results,\n };\n }\n\n /**\n * Verifies the NetGSM credentials by checking balance/credit.\n *\n * @returns A promise that resolves to true if credentials are valid\n */\n async verify(): Promise<boolean> {\n // NetGSM doesn't have a dedicated verify endpoint,\n // so we just return true if config is valid\n return !!(this.username && this.password && this.from);\n }\n\n /**\n * Parse NetGSM XML response\n * Success codes: \"0\", \"00\", or numeric job ID\n */\n private parseResponse(xml: string): { success: boolean; code?: string } {\n try {\n // Try to find <code> element\n const codeMatch = xml.match(/<code>(.*?)<\\/code>/);\n if (codeMatch && codeMatch[1]) {\n const code = codeMatch[1].trim();\n // NetGSM returns \"00\" or \"0\" for success\n if (code === \"00\" || code === \"0\") {\n return { success: true, code };\n }\n return { success: false, code };\n }\n\n // If no <code> element, check for numeric job ID (success)\n const trimmed = xml.trim();\n if (/^\\d+$/.test(trimmed) && trimmed.length > 5) {\n return { success: true, code: trimmed };\n }\n\n return { success: false };\n } catch {\n return { success: false };\n }\n }\n\n /**\n * Get human-readable error message for NetGSM error codes\n */\n private getErrorMessage(code?: string): string {\n const errorMessages: Record<string, string> = {\n \"20\": \"Mesaj metninde hata var\",\n \"30\": \"Geçersiz kullanıcı adı veya şifre\",\n \"40\": \"Mesaj başlığı sistemde tanımlı değil\",\n \"50\": \"Abone hesabı tanımlı değil\",\n \"51\": \"Abone hesabında yeterli bakiye yok\",\n \"60\": \"Gönderilecek mesaj bulunamadı\",\n \"70\": \"Geçersiz parametre hatası\",\n \"80\": \"Gönderim zamanlaması hatalı\",\n \"85\": \"Gönderim zamanlaması çok geç\",\n };\n\n return code ? errorMessages[code] || `NetGSM error code: ${code}` : \"Unknown error\";\n }\n\n /**\n * Escape XML special characters\n */\n private escapeXml(unsafe: string): string {\n return unsafe\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n }\n\n /**\n * Sanitize phone number (remove spaces, dashes, parentheses)\n */\n private sanitizePhoneNumber(phone: string): string {\n return phone.replace(/[\\s\\-\\(\\)\\+]/g, \"\");\n }\n}\n\n/**\n * Creates a NetGSM provider instance.\n *\n * @param config - The provider configuration\n * @returns A new NetGSMProvider instance\n */\nexport function createNetGSMProvider(\n config: SMSProviderConfig & { providerUrl?: string }\n): NetGSMProvider {\n return new NetGSMProvider(config);\n}\n","/**\n * @parsrun/sms - Console Provider\n * Development provider that logs SMS to console instead of sending\n */\n\nimport type {\n BatchSMSOptions,\n BatchSMSResult,\n SMSOptions,\n SMSProvider,\n SMSProviderConfig,\n SMSResult,\n} from \"../types.js\";\n\n/**\n * Console SMS Provider\n * Logs SMS messages to console for development/testing\n *\n * @example\n * ```typescript\n * const sms = new ConsoleProvider({ from: 'TEST' });\n *\n * await sms.send({\n * to: '905551234567',\n * message: 'Test message',\n * });\n * // Logs: [SMS] To: 905551234567, From: TEST, Message: Test message\n * ```\n */\nexport class ConsoleProvider implements SMSProvider {\n /** Provider type identifier */\n readonly type = \"console\" as const;\n\n private from: string;\n private delay: number;\n\n /**\n * Creates a new ConsoleProvider instance.\n *\n * @param config - The provider configuration\n */\n constructor(config: SMSProviderConfig & { delay?: number }) {\n this.from = config.from || \"CONSOLE\";\n this.delay = config.delay ?? 100; // Simulate network delay\n }\n\n /**\n * Logs an SMS message to the console.\n *\n * @param options - The SMS options\n * @returns A promise that resolves to a successful result\n */\n async send(options: SMSOptions): Promise<SMSResult> {\n // Simulate network delay\n if (this.delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, this.delay));\n }\n\n const from = options.from || this.from;\n const messageId = `console-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n\n console.log(\"\\n\" + \"─\".repeat(50));\n console.log(\"📱 SMS (Console Provider)\");\n console.log(\"─\".repeat(50));\n console.log(`To: ${options.to}`);\n console.log(`From: ${from}`);\n console.log(`Message: ${options.message}`);\n if (options.tags) {\n console.log(`Tags: ${JSON.stringify(options.tags)}`);\n }\n console.log(`ID: ${messageId}`);\n console.log(\"─\".repeat(50) + \"\\n\");\n\n return {\n success: true,\n messageId,\n data: { provider: \"console\", logged: true },\n };\n }\n\n /**\n * Logs multiple SMS messages to the console.\n *\n * @param options - The batch SMS options\n * @returns A promise that resolves to the batch result\n */\n async sendBatch(options: BatchSMSOptions): Promise<BatchSMSResult> {\n const results: SMSResult[] = [];\n\n for (const sms of options.messages) {\n const result = await this.send(sms);\n results.push(result);\n }\n\n return {\n total: options.messages.length,\n successful: options.messages.length,\n failed: 0,\n results,\n };\n }\n\n /**\n * Always returns true for console provider.\n */\n async verify(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Creates a Console provider instance.\n *\n * @param config - The provider configuration\n * @returns A new ConsoleProvider instance\n */\nexport function createConsoleProvider(\n config?: SMSProviderConfig & { delay?: number }\n): ConsoleProvider {\n return new ConsoleProvider(config || {});\n}\n"]}
@@ -0,0 +1,89 @@
1
+ import { SMSProvider, SMSProviderConfig, SMSOptions, SMSResult, BatchSMSOptions, BatchSMSResult } from '../types.js';
2
+
3
+ /**
4
+ * @parsrun/sms - NetGSM Provider
5
+ * Edge-compatible NetGSM SMS provider using fetch API
6
+ */
7
+
8
+ /**
9
+ * NetGSM SMS Provider
10
+ * Uses fetch API for edge compatibility
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const netgsm = new NetGSMProvider({
15
+ * username: process.env.NETGSM_USERNAME,
16
+ * password: process.env.NETGSM_PASSWORD,
17
+ * from: 'MYSENDER',
18
+ * });
19
+ *
20
+ * await netgsm.send({
21
+ * to: '905551234567',
22
+ * message: 'Hello from Pars!',
23
+ * });
24
+ * ```
25
+ */
26
+ declare class NetGSMProvider implements SMSProvider {
27
+ /** Provider type identifier */
28
+ readonly type: "netgsm";
29
+ private username;
30
+ private password;
31
+ private from;
32
+ private baseUrl;
33
+ /**
34
+ * Creates a new NetGSMProvider instance.
35
+ *
36
+ * @param config - The provider configuration including credentials and sender info
37
+ */
38
+ constructor(config: SMSProviderConfig & {
39
+ providerUrl?: string;
40
+ });
41
+ /**
42
+ * Sends an SMS via the NetGSM API.
43
+ *
44
+ * @param options - The SMS options including recipient and message
45
+ * @returns A promise that resolves to the send result
46
+ */
47
+ send(options: SMSOptions): Promise<SMSResult>;
48
+ /**
49
+ * Sends multiple SMS messages sequentially.
50
+ *
51
+ * @param options - The batch SMS options
52
+ * @returns A promise that resolves to the batch result
53
+ */
54
+ sendBatch(options: BatchSMSOptions): Promise<BatchSMSResult>;
55
+ /**
56
+ * Verifies the NetGSM credentials by checking balance/credit.
57
+ *
58
+ * @returns A promise that resolves to true if credentials are valid
59
+ */
60
+ verify(): Promise<boolean>;
61
+ /**
62
+ * Parse NetGSM XML response
63
+ * Success codes: "0", "00", or numeric job ID
64
+ */
65
+ private parseResponse;
66
+ /**
67
+ * Get human-readable error message for NetGSM error codes
68
+ */
69
+ private getErrorMessage;
70
+ /**
71
+ * Escape XML special characters
72
+ */
73
+ private escapeXml;
74
+ /**
75
+ * Sanitize phone number (remove spaces, dashes, parentheses)
76
+ */
77
+ private sanitizePhoneNumber;
78
+ }
79
+ /**
80
+ * Creates a NetGSM provider instance.
81
+ *
82
+ * @param config - The provider configuration
83
+ * @returns A new NetGSMProvider instance
84
+ */
85
+ declare function createNetGSMProvider(config: SMSProviderConfig & {
86
+ providerUrl?: string;
87
+ }): NetGSMProvider;
88
+
89
+ export { NetGSMProvider, createNetGSMProvider };
@@ -0,0 +1,210 @@
1
+ // src/types.ts
2
+ var SMSErrorCodes = {
3
+ INVALID_CONFIG: "SMS_INVALID_CONFIG",
4
+ SEND_FAILED: "SMS_SEND_FAILED"};
5
+ var SMSError = class extends Error {
6
+ code;
7
+ cause;
8
+ constructor(message, code, cause) {
9
+ super(message);
10
+ this.name = "SMSError";
11
+ this.code = code;
12
+ this.cause = cause;
13
+ }
14
+ };
15
+
16
+ // src/providers/netgsm.ts
17
+ var NetGSMProvider = class {
18
+ /** Provider type identifier */
19
+ type = "netgsm";
20
+ username;
21
+ password;
22
+ from;
23
+ baseUrl;
24
+ /**
25
+ * Creates a new NetGSMProvider instance.
26
+ *
27
+ * @param config - The provider configuration including credentials and sender info
28
+ */
29
+ constructor(config) {
30
+ if (!config.username || !config.password) {
31
+ throw new SMSError(
32
+ "NetGSM requires username and password",
33
+ SMSErrorCodes.INVALID_CONFIG
34
+ );
35
+ }
36
+ if (!config.from) {
37
+ throw new SMSError(
38
+ "NetGSM requires a sender ID (from/header)",
39
+ SMSErrorCodes.INVALID_CONFIG
40
+ );
41
+ }
42
+ this.username = config.username;
43
+ this.password = config.password;
44
+ this.from = config.from;
45
+ this.baseUrl = config.providerUrl || "https://api.netgsm.com.tr/sms/send/otp";
46
+ }
47
+ /**
48
+ * Sends an SMS via the NetGSM API.
49
+ *
50
+ * @param options - The SMS options including recipient and message
51
+ * @returns A promise that resolves to the send result
52
+ */
53
+ async send(options) {
54
+ const from = options.from || this.from;
55
+ const to = this.sanitizePhoneNumber(options.to);
56
+ const xmlData = `<?xml version='1.0' encoding='iso-8859-9'?>
57
+ <mainbody>
58
+ <header>
59
+ <usercode>${this.escapeXml(this.username)}</usercode>
60
+ <password>${this.escapeXml(this.password)}</password>
61
+ <msgheader>${this.escapeXml(from)}</msgheader>
62
+ <encoding>TR</encoding>
63
+ </header>
64
+ <body>
65
+ <msg><![CDATA[${options.message}]]></msg>
66
+ <no>${to}</no>
67
+ </body>
68
+ </mainbody>`;
69
+ try {
70
+ const response = await fetch(this.baseUrl, {
71
+ method: "POST",
72
+ headers: {
73
+ "Content-Type": "application/xml"
74
+ },
75
+ body: xmlData
76
+ });
77
+ if (!response.ok) {
78
+ return {
79
+ success: false,
80
+ error: `HTTP ${response.status}: ${response.statusText}`
81
+ };
82
+ }
83
+ const responseText = await response.text();
84
+ const result = this.parseResponse(responseText);
85
+ if (result.success && result.code) {
86
+ const successResult = {
87
+ success: true,
88
+ messageId: result.code,
89
+ data: { raw: responseText }
90
+ };
91
+ return successResult;
92
+ }
93
+ const errorResult = {
94
+ success: false,
95
+ error: this.getErrorMessage(result.code),
96
+ data: { code: result.code, raw: responseText }
97
+ };
98
+ return errorResult;
99
+ } catch (err) {
100
+ throw new SMSError(
101
+ `NetGSM send failed: ${err instanceof Error ? err.message : "Unknown error"}`,
102
+ SMSErrorCodes.SEND_FAILED,
103
+ err
104
+ );
105
+ }
106
+ }
107
+ /**
108
+ * Sends multiple SMS messages sequentially.
109
+ *
110
+ * @param options - The batch SMS options
111
+ * @returns A promise that resolves to the batch result
112
+ */
113
+ async sendBatch(options) {
114
+ const results = [];
115
+ let successful = 0;
116
+ let failed = 0;
117
+ for (const sms of options.messages) {
118
+ try {
119
+ const result = await this.send(sms);
120
+ results.push(result);
121
+ if (result.success) {
122
+ successful++;
123
+ } else {
124
+ failed++;
125
+ if (options.stopOnError) break;
126
+ }
127
+ } catch (err) {
128
+ failed++;
129
+ results.push({
130
+ success: false,
131
+ error: err instanceof Error ? err.message : "Unknown error"
132
+ });
133
+ if (options.stopOnError) break;
134
+ }
135
+ }
136
+ return {
137
+ total: options.messages.length,
138
+ successful,
139
+ failed,
140
+ results
141
+ };
142
+ }
143
+ /**
144
+ * Verifies the NetGSM credentials by checking balance/credit.
145
+ *
146
+ * @returns A promise that resolves to true if credentials are valid
147
+ */
148
+ async verify() {
149
+ return !!(this.username && this.password && this.from);
150
+ }
151
+ /**
152
+ * Parse NetGSM XML response
153
+ * Success codes: "0", "00", or numeric job ID
154
+ */
155
+ parseResponse(xml) {
156
+ try {
157
+ const codeMatch = xml.match(/<code>(.*?)<\/code>/);
158
+ if (codeMatch && codeMatch[1]) {
159
+ const code = codeMatch[1].trim();
160
+ if (code === "00" || code === "0") {
161
+ return { success: true, code };
162
+ }
163
+ return { success: false, code };
164
+ }
165
+ const trimmed = xml.trim();
166
+ if (/^\d+$/.test(trimmed) && trimmed.length > 5) {
167
+ return { success: true, code: trimmed };
168
+ }
169
+ return { success: false };
170
+ } catch {
171
+ return { success: false };
172
+ }
173
+ }
174
+ /**
175
+ * Get human-readable error message for NetGSM error codes
176
+ */
177
+ getErrorMessage(code) {
178
+ const errorMessages = {
179
+ "20": "Mesaj metninde hata var",
180
+ "30": "Ge\xE7ersiz kullan\u0131c\u0131 ad\u0131 veya \u015Fifre",
181
+ "40": "Mesaj ba\u015Fl\u0131\u011F\u0131 sistemde tan\u0131ml\u0131 de\u011Fil",
182
+ "50": "Abone hesab\u0131 tan\u0131ml\u0131 de\u011Fil",
183
+ "51": "Abone hesab\u0131nda yeterli bakiye yok",
184
+ "60": "G\xF6nderilecek mesaj bulunamad\u0131",
185
+ "70": "Ge\xE7ersiz parametre hatas\u0131",
186
+ "80": "G\xF6nderim zamanlamas\u0131 hatal\u0131",
187
+ "85": "G\xF6nderim zamanlamas\u0131 \xE7ok ge\xE7"
188
+ };
189
+ return code ? errorMessages[code] || `NetGSM error code: ${code}` : "Unknown error";
190
+ }
191
+ /**
192
+ * Escape XML special characters
193
+ */
194
+ escapeXml(unsafe) {
195
+ return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
196
+ }
197
+ /**
198
+ * Sanitize phone number (remove spaces, dashes, parentheses)
199
+ */
200
+ sanitizePhoneNumber(phone) {
201
+ return phone.replace(/[\s\-\(\)\+]/g, "");
202
+ }
203
+ };
204
+ function createNetGSMProvider(config) {
205
+ return new NetGSMProvider(config);
206
+ }
207
+
208
+ export { NetGSMProvider, createNetGSMProvider };
209
+ //# sourceMappingURL=netgsm.js.map
210
+ //# sourceMappingURL=netgsm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types.ts","../../src/providers/netgsm.ts"],"names":[],"mappings":"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","file":"netgsm.js","sourcesContent":["/**\n * @parsrun/sms - Type definitions\n */\n\n/**\n * Supported SMS provider types\n */\nexport type SMSProviderType = \"netgsm\" | \"twilio\" | \"console\";\n\n/**\n * SMS send options\n */\nexport interface SMSOptions {\n /** Recipient phone number (international format recommended, e.g., 905xxxxxxxxx) */\n to: string;\n /** SMS message content */\n message: string;\n /** Optional sender ID override */\n from?: string;\n /** Optional metadata/tags */\n tags?: Record<string, string>;\n}\n\n/**\n * SMS send result\n */\nexport interface SMSResult {\n /** Whether the SMS was sent successfully */\n success: boolean;\n /** Provider-specific message ID */\n messageId?: string;\n /** Error message if send failed */\n error?: string;\n /** Raw provider response data */\n data?: unknown;\n}\n\n/**\n * Batch SMS options\n */\nexport interface BatchSMSOptions {\n /** Array of SMS messages to send */\n messages: SMSOptions[];\n /** Stop sending if an error occurs */\n stopOnError?: boolean;\n}\n\n/**\n * Batch SMS result\n */\nexport interface BatchSMSResult {\n /** Total number of messages attempted */\n total: number;\n /** Number of successfully sent messages */\n successful: number;\n /** Number of failed messages */\n failed: number;\n /** Individual results for each message */\n results: SMSResult[];\n}\n\n/**\n * SMS provider configuration\n */\nexport interface SMSProviderConfig {\n /** API key or authentication token */\n apiKey?: string;\n /** Provider username (for providers like NetGSM) */\n username?: string;\n /** Provider password (for providers like NetGSM) */\n password?: string;\n /** Default sender ID/header */\n from?: string;\n /** Provider-specific options */\n options?: Record<string, unknown>;\n}\n\n/**\n * SMS service configuration\n */\nexport interface SMSServiceConfig extends SMSProviderConfig {\n /** SMS provider type */\n provider: SMSProviderType;\n /** Provider API URL (for custom endpoints) */\n providerUrl?: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * SMS provider interface\n */\nexport interface SMSProvider {\n /** Provider type identifier */\n readonly type: SMSProviderType;\n\n /** Send a single SMS */\n send(options: SMSOptions): Promise<SMSResult>;\n\n /** Send multiple SMS messages (optional) */\n sendBatch?(options: BatchSMSOptions): Promise<BatchSMSResult>;\n\n /** Verify provider configuration (optional) */\n verify?(): Promise<boolean>;\n}\n\n/**\n * SMS error codes\n */\nexport const SMSErrorCodes = {\n INVALID_CONFIG: \"SMS_INVALID_CONFIG\",\n SEND_FAILED: \"SMS_SEND_FAILED\",\n INVALID_PHONE: \"SMS_INVALID_PHONE\",\n RATE_LIMITED: \"SMS_RATE_LIMITED\",\n INSUFFICIENT_BALANCE: \"SMS_INSUFFICIENT_BALANCE\",\n PROVIDER_ERROR: \"SMS_PROVIDER_ERROR\",\n} as const;\n\nexport type SMSErrorCode = (typeof SMSErrorCodes)[keyof typeof SMSErrorCodes];\n\n/**\n * SMS error class\n */\nexport class SMSError extends Error {\n code: SMSErrorCode;\n cause?: unknown;\n\n constructor(message: string, code: SMSErrorCode, cause?: unknown) {\n super(message);\n this.name = \"SMSError\";\n this.code = code;\n this.cause = cause;\n }\n}\n","/**\n * @parsrun/sms - NetGSM Provider\n * Edge-compatible NetGSM SMS provider using fetch API\n */\n\nimport type {\n BatchSMSOptions,\n BatchSMSResult,\n SMSOptions,\n SMSProvider,\n SMSProviderConfig,\n SMSResult,\n} from \"../types.js\";\nimport { SMSError, SMSErrorCodes } from \"../types.js\";\n\n/**\n * NetGSM SMS Provider\n * Uses fetch API for edge compatibility\n *\n * @example\n * ```typescript\n * const netgsm = new NetGSMProvider({\n * username: process.env.NETGSM_USERNAME,\n * password: process.env.NETGSM_PASSWORD,\n * from: 'MYSENDER',\n * });\n *\n * await netgsm.send({\n * to: '905551234567',\n * message: 'Hello from Pars!',\n * });\n * ```\n */\nexport class NetGSMProvider implements SMSProvider {\n /** Provider type identifier */\n readonly type = \"netgsm\" as const;\n\n private username: string;\n private password: string;\n private from: string;\n private baseUrl: string;\n\n /**\n * Creates a new NetGSMProvider instance.\n *\n * @param config - The provider configuration including credentials and sender info\n */\n constructor(config: SMSProviderConfig & { providerUrl?: string }) {\n if (!config.username || !config.password) {\n throw new SMSError(\n \"NetGSM requires username and password\",\n SMSErrorCodes.INVALID_CONFIG\n );\n }\n if (!config.from) {\n throw new SMSError(\n \"NetGSM requires a sender ID (from/header)\",\n SMSErrorCodes.INVALID_CONFIG\n );\n }\n\n this.username = config.username;\n this.password = config.password;\n this.from = config.from;\n this.baseUrl = config.providerUrl || \"https://api.netgsm.com.tr/sms/send/otp\";\n }\n\n /**\n * Sends an SMS via the NetGSM API.\n *\n * @param options - The SMS options including recipient and message\n * @returns A promise that resolves to the send result\n */\n async send(options: SMSOptions): Promise<SMSResult> {\n const from = options.from || this.from;\n const to = this.sanitizePhoneNumber(options.to);\n\n const xmlData = `<?xml version='1.0' encoding='iso-8859-9'?>\n<mainbody>\n <header>\n <usercode>${this.escapeXml(this.username)}</usercode>\n <password>${this.escapeXml(this.password)}</password>\n <msgheader>${this.escapeXml(from)}</msgheader>\n <encoding>TR</encoding>\n </header>\n <body>\n <msg><![CDATA[${options.message}]]></msg>\n <no>${to}</no>\n </body>\n</mainbody>`;\n\n try {\n const response = await fetch(this.baseUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/xml\",\n },\n body: xmlData,\n });\n\n if (!response.ok) {\n return {\n success: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n const responseText = await response.text();\n const result = this.parseResponse(responseText);\n\n if (result.success && result.code) {\n const successResult: SMSResult = {\n success: true,\n messageId: result.code,\n data: { raw: responseText },\n };\n return successResult;\n }\n\n const errorResult: SMSResult = {\n success: false,\n error: this.getErrorMessage(result.code),\n data: { code: result.code, raw: responseText },\n };\n return errorResult;\n } catch (err) {\n throw new SMSError(\n `NetGSM send failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n SMSErrorCodes.SEND_FAILED,\n err\n );\n }\n }\n\n /**\n * Sends multiple SMS messages sequentially.\n *\n * @param options - The batch SMS options\n * @returns A promise that resolves to the batch result\n */\n async sendBatch(options: BatchSMSOptions): Promise<BatchSMSResult> {\n const results: SMSResult[] = [];\n let successful = 0;\n let failed = 0;\n\n for (const sms of options.messages) {\n try {\n const result = await this.send(sms);\n results.push(result);\n\n if (result.success) {\n successful++;\n } else {\n failed++;\n if (options.stopOnError) break;\n }\n } catch (err) {\n failed++;\n results.push({\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n\n if (options.stopOnError) break;\n }\n }\n\n return {\n total: options.messages.length,\n successful,\n failed,\n results,\n };\n }\n\n /**\n * Verifies the NetGSM credentials by checking balance/credit.\n *\n * @returns A promise that resolves to true if credentials are valid\n */\n async verify(): Promise<boolean> {\n // NetGSM doesn't have a dedicated verify endpoint,\n // so we just return true if config is valid\n return !!(this.username && this.password && this.from);\n }\n\n /**\n * Parse NetGSM XML response\n * Success codes: \"0\", \"00\", or numeric job ID\n */\n private parseResponse(xml: string): { success: boolean; code?: string } {\n try {\n // Try to find <code> element\n const codeMatch = xml.match(/<code>(.*?)<\\/code>/);\n if (codeMatch && codeMatch[1]) {\n const code = codeMatch[1].trim();\n // NetGSM returns \"00\" or \"0\" for success\n if (code === \"00\" || code === \"0\") {\n return { success: true, code };\n }\n return { success: false, code };\n }\n\n // If no <code> element, check for numeric job ID (success)\n const trimmed = xml.trim();\n if (/^\\d+$/.test(trimmed) && trimmed.length > 5) {\n return { success: true, code: trimmed };\n }\n\n return { success: false };\n } catch {\n return { success: false };\n }\n }\n\n /**\n * Get human-readable error message for NetGSM error codes\n */\n private getErrorMessage(code?: string): string {\n const errorMessages: Record<string, string> = {\n \"20\": \"Mesaj metninde hata var\",\n \"30\": \"Geçersiz kullanıcı adı veya şifre\",\n \"40\": \"Mesaj başlığı sistemde tanımlı değil\",\n \"50\": \"Abone hesabı tanımlı değil\",\n \"51\": \"Abone hesabında yeterli bakiye yok\",\n \"60\": \"Gönderilecek mesaj bulunamadı\",\n \"70\": \"Geçersiz parametre hatası\",\n \"80\": \"Gönderim zamanlaması hatalı\",\n \"85\": \"Gönderim zamanlaması çok geç\",\n };\n\n return code ? errorMessages[code] || `NetGSM error code: ${code}` : \"Unknown error\";\n }\n\n /**\n * Escape XML special characters\n */\n private escapeXml(unsafe: string): string {\n return unsafe\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n }\n\n /**\n * Sanitize phone number (remove spaces, dashes, parentheses)\n */\n private sanitizePhoneNumber(phone: string): string {\n return phone.replace(/[\\s\\-\\(\\)\\+]/g, \"\");\n }\n}\n\n/**\n * Creates a NetGSM provider instance.\n *\n * @param config - The provider configuration\n * @returns A new NetGSMProvider instance\n */\nexport function createNetGSMProvider(\n config: SMSProviderConfig & { providerUrl?: string }\n): NetGSMProvider {\n return new NetGSMProvider(config);\n}\n"]}