@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.
package/dist/index.js ADDED
@@ -0,0 +1,457 @@
1
+ // src/types.ts
2
+ var SMSErrorCodes = {
3
+ INVALID_CONFIG: "SMS_INVALID_CONFIG",
4
+ SEND_FAILED: "SMS_SEND_FAILED",
5
+ INVALID_PHONE: "SMS_INVALID_PHONE",
6
+ RATE_LIMITED: "SMS_RATE_LIMITED",
7
+ INSUFFICIENT_BALANCE: "SMS_INSUFFICIENT_BALANCE",
8
+ PROVIDER_ERROR: "SMS_PROVIDER_ERROR"
9
+ };
10
+ var SMSError = class extends Error {
11
+ code;
12
+ cause;
13
+ constructor(message, code, cause) {
14
+ super(message);
15
+ this.name = "SMSError";
16
+ this.code = code;
17
+ this.cause = cause;
18
+ }
19
+ };
20
+
21
+ // src/providers/netgsm.ts
22
+ var NetGSMProvider = class {
23
+ /** Provider type identifier */
24
+ type = "netgsm";
25
+ username;
26
+ password;
27
+ from;
28
+ baseUrl;
29
+ /**
30
+ * Creates a new NetGSMProvider instance.
31
+ *
32
+ * @param config - The provider configuration including credentials and sender info
33
+ */
34
+ constructor(config) {
35
+ if (!config.username || !config.password) {
36
+ throw new SMSError(
37
+ "NetGSM requires username and password",
38
+ SMSErrorCodes.INVALID_CONFIG
39
+ );
40
+ }
41
+ if (!config.from) {
42
+ throw new SMSError(
43
+ "NetGSM requires a sender ID (from/header)",
44
+ SMSErrorCodes.INVALID_CONFIG
45
+ );
46
+ }
47
+ this.username = config.username;
48
+ this.password = config.password;
49
+ this.from = config.from;
50
+ this.baseUrl = config.providerUrl || "https://api.netgsm.com.tr/sms/send/otp";
51
+ }
52
+ /**
53
+ * Sends an SMS via the NetGSM API.
54
+ *
55
+ * @param options - The SMS options including recipient and message
56
+ * @returns A promise that resolves to the send result
57
+ */
58
+ async send(options) {
59
+ const from = options.from || this.from;
60
+ const to = this.sanitizePhoneNumber(options.to);
61
+ const xmlData = `<?xml version='1.0' encoding='iso-8859-9'?>
62
+ <mainbody>
63
+ <header>
64
+ <usercode>${this.escapeXml(this.username)}</usercode>
65
+ <password>${this.escapeXml(this.password)}</password>
66
+ <msgheader>${this.escapeXml(from)}</msgheader>
67
+ <encoding>TR</encoding>
68
+ </header>
69
+ <body>
70
+ <msg><![CDATA[${options.message}]]></msg>
71
+ <no>${to}</no>
72
+ </body>
73
+ </mainbody>`;
74
+ try {
75
+ const response = await fetch(this.baseUrl, {
76
+ method: "POST",
77
+ headers: {
78
+ "Content-Type": "application/xml"
79
+ },
80
+ body: xmlData
81
+ });
82
+ if (!response.ok) {
83
+ return {
84
+ success: false,
85
+ error: `HTTP ${response.status}: ${response.statusText}`
86
+ };
87
+ }
88
+ const responseText = await response.text();
89
+ const result = this.parseResponse(responseText);
90
+ if (result.success && result.code) {
91
+ const successResult = {
92
+ success: true,
93
+ messageId: result.code,
94
+ data: { raw: responseText }
95
+ };
96
+ return successResult;
97
+ }
98
+ const errorResult = {
99
+ success: false,
100
+ error: this.getErrorMessage(result.code),
101
+ data: { code: result.code, raw: responseText }
102
+ };
103
+ return errorResult;
104
+ } catch (err) {
105
+ throw new SMSError(
106
+ `NetGSM send failed: ${err instanceof Error ? err.message : "Unknown error"}`,
107
+ SMSErrorCodes.SEND_FAILED,
108
+ err
109
+ );
110
+ }
111
+ }
112
+ /**
113
+ * Sends multiple SMS messages sequentially.
114
+ *
115
+ * @param options - The batch SMS options
116
+ * @returns A promise that resolves to the batch result
117
+ */
118
+ async sendBatch(options) {
119
+ const results = [];
120
+ let successful = 0;
121
+ let failed = 0;
122
+ for (const sms of options.messages) {
123
+ try {
124
+ const result = await this.send(sms);
125
+ results.push(result);
126
+ if (result.success) {
127
+ successful++;
128
+ } else {
129
+ failed++;
130
+ if (options.stopOnError) break;
131
+ }
132
+ } catch (err) {
133
+ failed++;
134
+ results.push({
135
+ success: false,
136
+ error: err instanceof Error ? err.message : "Unknown error"
137
+ });
138
+ if (options.stopOnError) break;
139
+ }
140
+ }
141
+ return {
142
+ total: options.messages.length,
143
+ successful,
144
+ failed,
145
+ results
146
+ };
147
+ }
148
+ /**
149
+ * Verifies the NetGSM credentials by checking balance/credit.
150
+ *
151
+ * @returns A promise that resolves to true if credentials are valid
152
+ */
153
+ async verify() {
154
+ return !!(this.username && this.password && this.from);
155
+ }
156
+ /**
157
+ * Parse NetGSM XML response
158
+ * Success codes: "0", "00", or numeric job ID
159
+ */
160
+ parseResponse(xml) {
161
+ try {
162
+ const codeMatch = xml.match(/<code>(.*?)<\/code>/);
163
+ if (codeMatch && codeMatch[1]) {
164
+ const code = codeMatch[1].trim();
165
+ if (code === "00" || code === "0") {
166
+ return { success: true, code };
167
+ }
168
+ return { success: false, code };
169
+ }
170
+ const trimmed = xml.trim();
171
+ if (/^\d+$/.test(trimmed) && trimmed.length > 5) {
172
+ return { success: true, code: trimmed };
173
+ }
174
+ return { success: false };
175
+ } catch {
176
+ return { success: false };
177
+ }
178
+ }
179
+ /**
180
+ * Get human-readable error message for NetGSM error codes
181
+ */
182
+ getErrorMessage(code) {
183
+ const errorMessages = {
184
+ "20": "Mesaj metninde hata var",
185
+ "30": "Ge\xE7ersiz kullan\u0131c\u0131 ad\u0131 veya \u015Fifre",
186
+ "40": "Mesaj ba\u015Fl\u0131\u011F\u0131 sistemde tan\u0131ml\u0131 de\u011Fil",
187
+ "50": "Abone hesab\u0131 tan\u0131ml\u0131 de\u011Fil",
188
+ "51": "Abone hesab\u0131nda yeterli bakiye yok",
189
+ "60": "G\xF6nderilecek mesaj bulunamad\u0131",
190
+ "70": "Ge\xE7ersiz parametre hatas\u0131",
191
+ "80": "G\xF6nderim zamanlamas\u0131 hatal\u0131",
192
+ "85": "G\xF6nderim zamanlamas\u0131 \xE7ok ge\xE7"
193
+ };
194
+ return code ? errorMessages[code] || `NetGSM error code: ${code}` : "Unknown error";
195
+ }
196
+ /**
197
+ * Escape XML special characters
198
+ */
199
+ escapeXml(unsafe) {
200
+ return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
201
+ }
202
+ /**
203
+ * Sanitize phone number (remove spaces, dashes, parentheses)
204
+ */
205
+ sanitizePhoneNumber(phone) {
206
+ return phone.replace(/[\s\-\(\)\+]/g, "");
207
+ }
208
+ };
209
+ function createNetGSMProvider(config) {
210
+ return new NetGSMProvider(config);
211
+ }
212
+
213
+ // src/providers/console.ts
214
+ var ConsoleProvider = class {
215
+ /** Provider type identifier */
216
+ type = "console";
217
+ from;
218
+ delay;
219
+ /**
220
+ * Creates a new ConsoleProvider instance.
221
+ *
222
+ * @param config - The provider configuration
223
+ */
224
+ constructor(config) {
225
+ this.from = config.from || "CONSOLE";
226
+ this.delay = config.delay ?? 100;
227
+ }
228
+ /**
229
+ * Logs an SMS message to the console.
230
+ *
231
+ * @param options - The SMS options
232
+ * @returns A promise that resolves to a successful result
233
+ */
234
+ async send(options) {
235
+ if (this.delay > 0) {
236
+ await new Promise((resolve) => setTimeout(resolve, this.delay));
237
+ }
238
+ const from = options.from || this.from;
239
+ const messageId = `console-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
240
+ console.log("\n" + "\u2500".repeat(50));
241
+ console.log("\u{1F4F1} SMS (Console Provider)");
242
+ console.log("\u2500".repeat(50));
243
+ console.log(`To: ${options.to}`);
244
+ console.log(`From: ${from}`);
245
+ console.log(`Message: ${options.message}`);
246
+ if (options.tags) {
247
+ console.log(`Tags: ${JSON.stringify(options.tags)}`);
248
+ }
249
+ console.log(`ID: ${messageId}`);
250
+ console.log("\u2500".repeat(50) + "\n");
251
+ return {
252
+ success: true,
253
+ messageId,
254
+ data: { provider: "console", logged: true }
255
+ };
256
+ }
257
+ /**
258
+ * Logs multiple SMS messages to the console.
259
+ *
260
+ * @param options - The batch SMS options
261
+ * @returns A promise that resolves to the batch result
262
+ */
263
+ async sendBatch(options) {
264
+ const results = [];
265
+ for (const sms of options.messages) {
266
+ const result = await this.send(sms);
267
+ results.push(result);
268
+ }
269
+ return {
270
+ total: options.messages.length,
271
+ successful: options.messages.length,
272
+ failed: 0,
273
+ results
274
+ };
275
+ }
276
+ /**
277
+ * Always returns true for console provider.
278
+ */
279
+ async verify() {
280
+ return true;
281
+ }
282
+ };
283
+ function createConsoleProvider(config) {
284
+ return new ConsoleProvider(config || {});
285
+ }
286
+
287
+ // src/index.ts
288
+ var SMSService = class {
289
+ provider;
290
+ debug;
291
+ /**
292
+ * Creates a new SMSService instance.
293
+ *
294
+ * @param config - The SMS service configuration
295
+ */
296
+ constructor(config) {
297
+ this.debug = config.debug ?? false;
298
+ this.provider = this.createProvider(config);
299
+ }
300
+ createProvider(config) {
301
+ const providerConfig = {};
302
+ if (config.apiKey !== void 0) providerConfig.apiKey = config.apiKey;
303
+ if (config.username !== void 0) providerConfig.username = config.username;
304
+ if (config.password !== void 0) providerConfig.password = config.password;
305
+ if (config.from !== void 0) providerConfig.from = config.from;
306
+ if (config.options !== void 0) providerConfig.options = config.options;
307
+ if (config.providerUrl !== void 0) providerConfig.providerUrl = config.providerUrl;
308
+ switch (config.provider) {
309
+ case "netgsm":
310
+ return new NetGSMProvider(providerConfig);
311
+ case "console":
312
+ return new ConsoleProvider(providerConfig);
313
+ default:
314
+ throw new SMSError(
315
+ `Unknown SMS provider: ${config.provider}`,
316
+ SMSErrorCodes.INVALID_CONFIG
317
+ );
318
+ }
319
+ }
320
+ /**
321
+ * Gets the type of SMS provider being used.
322
+ */
323
+ get providerType() {
324
+ return this.provider.type;
325
+ }
326
+ /**
327
+ * Sends a single SMS message.
328
+ *
329
+ * @param options - The SMS options
330
+ * @returns A promise that resolves to the send result
331
+ */
332
+ async send(options) {
333
+ if (this.debug) {
334
+ console.log("[SMS] Sending:", {
335
+ to: options.to,
336
+ message: options.message.slice(0, 50) + (options.message.length > 50 ? "..." : ""),
337
+ provider: this.provider.type
338
+ });
339
+ }
340
+ const result = await this.provider.send(options);
341
+ if (this.debug) {
342
+ console.log("[SMS] Result:", result);
343
+ }
344
+ return result;
345
+ }
346
+ /**
347
+ * Sends multiple SMS messages in a batch.
348
+ *
349
+ * @param options - The batch SMS options
350
+ * @returns A promise that resolves to the batch result
351
+ */
352
+ async sendBatch(options) {
353
+ if (this.debug) {
354
+ console.log("[SMS] Sending batch:", {
355
+ count: options.messages.length,
356
+ provider: this.provider.type
357
+ });
358
+ }
359
+ if (this.provider.sendBatch) {
360
+ const result = await this.provider.sendBatch(options);
361
+ if (this.debug) {
362
+ console.log("[SMS] Batch result:", {
363
+ total: result.total,
364
+ successful: result.successful,
365
+ failed: result.failed
366
+ });
367
+ }
368
+ return result;
369
+ }
370
+ const results = [];
371
+ let successful = 0;
372
+ let failed = 0;
373
+ for (const sms of options.messages) {
374
+ try {
375
+ const result = await this.send(sms);
376
+ results.push(result);
377
+ if (result.success) {
378
+ successful++;
379
+ } else {
380
+ failed++;
381
+ if (options.stopOnError) break;
382
+ }
383
+ } catch (err) {
384
+ failed++;
385
+ results.push({
386
+ success: false,
387
+ error: err instanceof Error ? err.message : "Unknown error"
388
+ });
389
+ if (options.stopOnError) break;
390
+ }
391
+ }
392
+ return {
393
+ total: options.messages.length,
394
+ successful,
395
+ failed,
396
+ results
397
+ };
398
+ }
399
+ /**
400
+ * Verifies the provider configuration.
401
+ *
402
+ * @returns A promise that resolves to true if configuration is valid
403
+ */
404
+ async verify() {
405
+ if (this.provider.verify) {
406
+ return this.provider.verify();
407
+ }
408
+ return true;
409
+ }
410
+ /**
411
+ * Send OTP verification SMS
412
+ *
413
+ * @param phone - Recipient phone number
414
+ * @param code - OTP code
415
+ * @param expiresInMinutes - Code expiration time
416
+ */
417
+ async sendOTP(phone, code, expiresInMinutes = 10) {
418
+ const message = `Dogrulama kodunuz: ${code}. Bu kod ${expiresInMinutes} dakika gecerlidir.`;
419
+ return this.send({ to: phone, message });
420
+ }
421
+ /**
422
+ * Send welcome SMS
423
+ *
424
+ * @param phone - Recipient phone number
425
+ * @param name - User's display name
426
+ */
427
+ async sendWelcome(phone, name) {
428
+ const displayName = name || "Kullanici";
429
+ const message = `Merhaba ${displayName}! Hesabiniz basariyla olusturuldu.`;
430
+ return this.send({ to: phone, message });
431
+ }
432
+ };
433
+ function createSMSService(config) {
434
+ return new SMSService(config);
435
+ }
436
+ function createSMSProvider(type, config) {
437
+ switch (type) {
438
+ case "netgsm":
439
+ return new NetGSMProvider(config);
440
+ case "console":
441
+ return new ConsoleProvider(config);
442
+ default:
443
+ throw new SMSError(
444
+ `Unknown SMS provider: ${type}`,
445
+ SMSErrorCodes.INVALID_CONFIG
446
+ );
447
+ }
448
+ }
449
+ var index_default = {
450
+ SMSService,
451
+ createSMSService,
452
+ createSMSProvider
453
+ };
454
+
455
+ export { ConsoleProvider, NetGSMProvider, SMSError, SMSErrorCodes, SMSService, createConsoleProvider, createNetGSMProvider, createSMSProvider, createSMSService, index_default as default };
456
+ //# sourceMappingURL=index.js.map
457
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/providers/netgsm.ts","../src/providers/console.ts","../src/index.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","/**\n * @module\n * Edge-compatible SMS sending for Pars.\n *\n * Supports multiple providers:\n * - NetGSM (Turkey)\n * - Console (development)\n *\n * @example\n * ```typescript\n * import { createSMSService } from '@parsrun/sms';\n *\n * const sms = createSMSService({\n * provider: 'netgsm',\n * username: process.env.NETGSM_USERNAME,\n * password: process.env.NETGSM_PASSWORD,\n * from: 'MYSENDER',\n * });\n *\n * await sms.send({\n * to: '905551234567',\n * message: 'Your verification code is: 123456',\n * });\n * ```\n */\n\n// Re-export types\nexport * from \"./types.js\";\n\n// Re-export providers\nexport { NetGSMProvider, createNetGSMProvider } from \"./providers/netgsm.js\";\nexport { ConsoleProvider, createConsoleProvider } from \"./providers/console.js\";\n\nimport type {\n BatchSMSOptions,\n BatchSMSResult,\n SMSOptions,\n SMSProvider,\n SMSProviderConfig,\n SMSProviderType,\n SMSResult,\n SMSServiceConfig,\n} from \"./types.js\";\nimport { SMSError, SMSErrorCodes } from \"./types.js\";\nimport { NetGSMProvider } from \"./providers/netgsm.js\";\nimport { ConsoleProvider } from \"./providers/console.js\";\n\n/**\n * SMS Service\n *\n * High-level SMS service that provides a unified interface for sending SMS\n * through various providers (NetGSM, Twilio, or Console for development).\n *\n * @example\n * ```typescript\n * const service = new SMSService({\n * provider: 'netgsm',\n * username: 'your-username',\n * password: 'your-password',\n * from: 'MYSENDER',\n * });\n *\n * await service.send({\n * to: '905551234567',\n * message: 'Hello!',\n * });\n * ```\n */\nexport class SMSService {\n private provider: SMSProvider;\n private debug: boolean;\n\n /**\n * Creates a new SMSService instance.\n *\n * @param config - The SMS service configuration\n */\n constructor(config: SMSServiceConfig) {\n this.debug = config.debug ?? false;\n this.provider = this.createProvider(config);\n }\n\n private createProvider(config: SMSServiceConfig): SMSProvider {\n // Build config object conditionally to satisfy exactOptionalPropertyTypes\n const providerConfig: SMSProviderConfig & { providerUrl?: string } = {};\n if (config.apiKey !== undefined) providerConfig.apiKey = config.apiKey;\n if (config.username !== undefined) providerConfig.username = config.username;\n if (config.password !== undefined) providerConfig.password = config.password;\n if (config.from !== undefined) providerConfig.from = config.from;\n if (config.options !== undefined) providerConfig.options = config.options;\n if (config.providerUrl !== undefined) providerConfig.providerUrl = config.providerUrl;\n\n switch (config.provider) {\n case \"netgsm\":\n return new NetGSMProvider(providerConfig);\n case \"console\":\n return new ConsoleProvider(providerConfig);\n default:\n throw new SMSError(\n `Unknown SMS provider: ${config.provider}`,\n SMSErrorCodes.INVALID_CONFIG\n );\n }\n }\n\n /**\n * Gets the type of SMS provider being used.\n */\n get providerType(): SMSProviderType {\n return this.provider.type;\n }\n\n /**\n * Sends a single SMS message.\n *\n * @param options - The SMS options\n * @returns A promise that resolves to the send result\n */\n async send(options: SMSOptions): Promise<SMSResult> {\n if (this.debug) {\n console.log(\"[SMS] Sending:\", {\n to: options.to,\n message: options.message.slice(0, 50) + (options.message.length > 50 ? \"...\" : \"\"),\n provider: this.provider.type,\n });\n }\n\n const result = await this.provider.send(options);\n\n if (this.debug) {\n console.log(\"[SMS] Result:\", result);\n }\n\n return result;\n }\n\n /**\n * Sends multiple SMS messages in a batch.\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 if (this.debug) {\n console.log(\"[SMS] Sending batch:\", {\n count: options.messages.length,\n provider: this.provider.type,\n });\n }\n\n // Use provider's native batch if available\n if (this.provider.sendBatch) {\n const result = await this.provider.sendBatch(options);\n\n if (this.debug) {\n console.log(\"[SMS] Batch result:\", {\n total: result.total,\n successful: result.successful,\n failed: result.failed,\n });\n }\n\n return result;\n }\n\n // Fallback to sequential sending\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 provider configuration.\n *\n * @returns A promise that resolves to true if configuration is valid\n */\n async verify(): Promise<boolean> {\n if (this.provider.verify) {\n return this.provider.verify();\n }\n return true;\n }\n\n /**\n * Send OTP verification SMS\n *\n * @param phone - Recipient phone number\n * @param code - OTP code\n * @param expiresInMinutes - Code expiration time\n */\n async sendOTP(\n phone: string,\n code: string,\n expiresInMinutes = 10\n ): Promise<SMSResult> {\n const message = `Dogrulama kodunuz: ${code}. Bu kod ${expiresInMinutes} dakika gecerlidir.`;\n return this.send({ to: phone, message });\n }\n\n /**\n * Send welcome SMS\n *\n * @param phone - Recipient phone number\n * @param name - User's display name\n */\n async sendWelcome(phone: string, name?: string): Promise<SMSResult> {\n const displayName = name || \"Kullanici\";\n const message = `Merhaba ${displayName}! Hesabiniz basariyla olusturuldu.`;\n return this.send({ to: phone, message });\n }\n}\n\n/**\n * Create an SMS service\n *\n * @example\n * ```typescript\n * // With NetGSM\n * const sms = createSMSService({\n * provider: 'netgsm',\n * username: process.env.NETGSM_USERNAME,\n * password: process.env.NETGSM_PASSWORD,\n * from: 'MYSENDER',\n * });\n *\n * // For development\n * const sms = createSMSService({\n * provider: 'console',\n * from: 'TEST',\n * });\n * ```\n */\nexport function createSMSService(config: SMSServiceConfig): SMSService {\n return new SMSService(config);\n}\n\n/**\n * Creates an SMS provider instance directly.\n *\n * @param type - The type of SMS provider to create\n * @param config - The provider configuration\n * @returns A new SMS provider instance\n */\nexport function createSMSProvider(\n type: SMSProviderType,\n config: SMSProviderConfig & { providerUrl?: string }\n): SMSProvider {\n switch (type) {\n case \"netgsm\":\n return new NetGSMProvider(config);\n case \"console\":\n return new ConsoleProvider(config);\n default:\n throw new SMSError(\n `Unknown SMS provider: ${type}`,\n SMSErrorCodes.INVALID_CONFIG\n );\n }\n}\n\n// Default export\nexport default {\n SMSService,\n createSMSService,\n createSMSProvider,\n};\n"]}
@@ -0,0 +1,65 @@
1
+ import { SMSProvider, SMSProviderConfig, SMSOptions, SMSResult, BatchSMSOptions, BatchSMSResult } from '../types.js';
2
+
3
+ /**
4
+ * @parsrun/sms - Console Provider
5
+ * Development provider that logs SMS to console instead of sending
6
+ */
7
+
8
+ /**
9
+ * Console SMS Provider
10
+ * Logs SMS messages to console for development/testing
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const sms = new ConsoleProvider({ from: 'TEST' });
15
+ *
16
+ * await sms.send({
17
+ * to: '905551234567',
18
+ * message: 'Test message',
19
+ * });
20
+ * // Logs: [SMS] To: 905551234567, From: TEST, Message: Test message
21
+ * ```
22
+ */
23
+ declare class ConsoleProvider implements SMSProvider {
24
+ /** Provider type identifier */
25
+ readonly type: "console";
26
+ private from;
27
+ private delay;
28
+ /**
29
+ * Creates a new ConsoleProvider instance.
30
+ *
31
+ * @param config - The provider configuration
32
+ */
33
+ constructor(config: SMSProviderConfig & {
34
+ delay?: number;
35
+ });
36
+ /**
37
+ * Logs an SMS message to the console.
38
+ *
39
+ * @param options - The SMS options
40
+ * @returns A promise that resolves to a successful result
41
+ */
42
+ send(options: SMSOptions): Promise<SMSResult>;
43
+ /**
44
+ * Logs multiple SMS messages to the console.
45
+ *
46
+ * @param options - The batch SMS options
47
+ * @returns A promise that resolves to the batch result
48
+ */
49
+ sendBatch(options: BatchSMSOptions): Promise<BatchSMSResult>;
50
+ /**
51
+ * Always returns true for console provider.
52
+ */
53
+ verify(): Promise<boolean>;
54
+ }
55
+ /**
56
+ * Creates a Console provider instance.
57
+ *
58
+ * @param config - The provider configuration
59
+ * @returns A new ConsoleProvider instance
60
+ */
61
+ declare function createConsoleProvider(config?: SMSProviderConfig & {
62
+ delay?: number;
63
+ }): ConsoleProvider;
64
+
65
+ export { ConsoleProvider, createConsoleProvider };
@@ -0,0 +1,77 @@
1
+ // src/providers/console.ts
2
+ var ConsoleProvider = class {
3
+ /** Provider type identifier */
4
+ type = "console";
5
+ from;
6
+ delay;
7
+ /**
8
+ * Creates a new ConsoleProvider instance.
9
+ *
10
+ * @param config - The provider configuration
11
+ */
12
+ constructor(config) {
13
+ this.from = config.from || "CONSOLE";
14
+ this.delay = config.delay ?? 100;
15
+ }
16
+ /**
17
+ * Logs an SMS message to the console.
18
+ *
19
+ * @param options - The SMS options
20
+ * @returns A promise that resolves to a successful result
21
+ */
22
+ async send(options) {
23
+ if (this.delay > 0) {
24
+ await new Promise((resolve) => setTimeout(resolve, this.delay));
25
+ }
26
+ const from = options.from || this.from;
27
+ const messageId = `console-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
28
+ console.log("\n" + "\u2500".repeat(50));
29
+ console.log("\u{1F4F1} SMS (Console Provider)");
30
+ console.log("\u2500".repeat(50));
31
+ console.log(`To: ${options.to}`);
32
+ console.log(`From: ${from}`);
33
+ console.log(`Message: ${options.message}`);
34
+ if (options.tags) {
35
+ console.log(`Tags: ${JSON.stringify(options.tags)}`);
36
+ }
37
+ console.log(`ID: ${messageId}`);
38
+ console.log("\u2500".repeat(50) + "\n");
39
+ return {
40
+ success: true,
41
+ messageId,
42
+ data: { provider: "console", logged: true }
43
+ };
44
+ }
45
+ /**
46
+ * Logs multiple SMS messages to the console.
47
+ *
48
+ * @param options - The batch SMS options
49
+ * @returns A promise that resolves to the batch result
50
+ */
51
+ async sendBatch(options) {
52
+ const results = [];
53
+ for (const sms of options.messages) {
54
+ const result = await this.send(sms);
55
+ results.push(result);
56
+ }
57
+ return {
58
+ total: options.messages.length,
59
+ successful: options.messages.length,
60
+ failed: 0,
61
+ results
62
+ };
63
+ }
64
+ /**
65
+ * Always returns true for console provider.
66
+ */
67
+ async verify() {
68
+ return true;
69
+ }
70
+ };
71
+ function createConsoleProvider(config) {
72
+ return new ConsoleProvider(config || {});
73
+ }
74
+
75
+ export { ConsoleProvider, createConsoleProvider };
76
+ //# sourceMappingURL=console.js.map
77
+ //# sourceMappingURL=console.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/console.ts"],"names":[],"mappings":"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","file":"console.js","sourcesContent":["/**\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"]}