@narcisbodea/smstunnel-sdk 1.0.0

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,493 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __decorateClass = (decorators, target, key, kind) => {
20
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
21
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
22
+ if (decorator = decorators[i])
23
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
24
+ if (kind && result) __defProp(target, key, result);
25
+ return result;
26
+ };
27
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
28
+
29
+ // src/server/index.ts
30
+ var server_exports = {};
31
+ __export(server_exports, {
32
+ SMSTUNNEL_DEFAULT_PREFIX: () => SMSTUNNEL_DEFAULT_PREFIX,
33
+ SMSTUNNEL_OPTIONS: () => SMSTUNNEL_OPTIONS,
34
+ SMSTUNNEL_PUBLIC_PATHS: () => SMSTUNNEL_PUBLIC_PATHS,
35
+ SmsTunnelController: () => SmsTunnelController,
36
+ SmsTunnelModule: () => SmsTunnelModule,
37
+ SmsTunnelService: () => SmsTunnelService,
38
+ getSmsTunnelPublicPaths: () => getSmsTunnelPublicPaths
39
+ });
40
+ module.exports = __toCommonJS(server_exports);
41
+
42
+ // src/server/smstunnel.module.ts
43
+ var import_common3 = require("@nestjs/common");
44
+
45
+ // src/server/smstunnel.service.ts
46
+ var import_common = require("@nestjs/common");
47
+
48
+ // src/server/smstunnel.constants.ts
49
+ var SMSTUNNEL_OPTIONS = "SMSTUNNEL_OPTIONS";
50
+ var SMSTUNNEL_DEFAULT_PREFIX = "smstunnel";
51
+ var SMSTUNNEL_PUBLIC_PATHS = [
52
+ "/smstunnel/pairing-status/",
53
+ "/smstunnel/callback",
54
+ "/wp-json/smstunnel/v1/setup-callback"
55
+ ];
56
+ function getSmsTunnelPublicPaths(prefix) {
57
+ return [
58
+ `/${prefix}/pairing-status/`,
59
+ `/${prefix}/callback`,
60
+ "/wp-json/smstunnel/v1/setup-callback"
61
+ ];
62
+ }
63
+
64
+ // src/server/smstunnel.service.ts
65
+ var SmsTunnelService = class {
66
+ constructor(options) {
67
+ this.options = options;
68
+ this.logger = new import_common.Logger(SmsTunnelService.name);
69
+ }
70
+ /**
71
+ * Get current pairing status.
72
+ */
73
+ async getStatus() {
74
+ const config = await this.options.storage.getConfig();
75
+ return {
76
+ paired: !!config.apiKey,
77
+ serverUrl: config.serverUrl,
78
+ deviceName: config.deviceName
79
+ };
80
+ }
81
+ /**
82
+ * Create a pairing token on SMSTunnel server.
83
+ */
84
+ async createPairingToken() {
85
+ const config = await this.options.storage.getConfig();
86
+ if (!config.serverUrl) {
87
+ return { success: false, error: "SMSTunnel server URL is not configured." };
88
+ }
89
+ const serverUrl = config.serverUrl.replace(/\/$/, "");
90
+ const prefix = this.options.routePrefix || "smstunnel";
91
+ const callbackUrl = `${this.options.callbackBaseUrl.replace(/\/$/, "")}/${prefix}/callback`;
92
+ try {
93
+ const res = await fetch(`${serverUrl}/api/v1/pairing/public-create`, {
94
+ method: "POST",
95
+ headers: { "Content-Type": "application/json" },
96
+ body: JSON.stringify({
97
+ source: "api",
98
+ displayName: this.options.displayName || "App",
99
+ displayUrl: this.options.displayUrl || this.options.callbackBaseUrl,
100
+ context: { callbackUrl }
101
+ })
102
+ });
103
+ if (!res.ok) {
104
+ const errText = await res.text();
105
+ this.logger.warn(`SMSTunnel create token failed: ${res.status} ${errText}`);
106
+ return { success: false, error: `SMSTunnel returned error: ${res.status}` };
107
+ }
108
+ const data = await res.json();
109
+ await this.options.storage.updateConfig({ siteToken: data.token });
110
+ this.logger.log(`Pairing token created: ${data.token?.substring(0, 12)}...`);
111
+ return {
112
+ success: true,
113
+ token: data.token,
114
+ qrData: data.qrData,
115
+ expiresAt: data.expiresAt,
116
+ pollUrl: data.pollUrl || `${serverUrl}/api/v1/pairing/${data.token}`
117
+ };
118
+ } catch (err) {
119
+ this.logger.error(`SMSTunnel create token error: ${err.message}`);
120
+ return { success: false, error: `Could not connect to SMSTunnel: ${err.message}` };
121
+ }
122
+ }
123
+ /**
124
+ * Check pairing status by polling SMSTunnel.
125
+ */
126
+ async getPairingStatus(token) {
127
+ const config = await this.options.storage.getConfig();
128
+ if (!config.serverUrl) {
129
+ return { status: "error", error: "SMSTunnel server URL not configured" };
130
+ }
131
+ const serverUrl = config.serverUrl.replace(/\/$/, "");
132
+ try {
133
+ const res = await fetch(`${serverUrl}/api/v1/pairing/${token}`);
134
+ if (!res.ok) {
135
+ return { status: "expired" };
136
+ }
137
+ return await res.json();
138
+ } catch {
139
+ return { status: "error", error: "Could not contact SMSTunnel" };
140
+ }
141
+ }
142
+ /**
143
+ * Handle callback from SMSTunnel after pairing completes.
144
+ */
145
+ async handlePairingCallback(body) {
146
+ if (body.event !== "pairing_completed") {
147
+ this.logger.warn(`Unknown callback event: ${body.event}`);
148
+ return false;
149
+ }
150
+ const config = await this.options.storage.getConfig();
151
+ if (config.siteToken && config.siteToken !== body.token) {
152
+ this.logger.warn(
153
+ `Callback token mismatch: expected ${config.siteToken?.substring(0, 8)}, got ${body.token?.substring(0, 8)}`
154
+ );
155
+ return false;
156
+ }
157
+ await this.options.storage.updateConfig({
158
+ apiKey: body.apiKey,
159
+ deviceName: body.deviceName || "Android Phone"
160
+ });
161
+ this.logger.log(
162
+ `SMSTunnel paired! Device: ${body.deviceName}, API key: ${body.apiKey?.substring(0, 12)}...`
163
+ );
164
+ return true;
165
+ }
166
+ /**
167
+ * Handle legacy WordPress-compatible callback.
168
+ */
169
+ async handleLegacyCallback(siteToken, apiKey, deviceName) {
170
+ const config = await this.options.storage.getConfig();
171
+ if (config.siteToken !== siteToken) {
172
+ this.logger.warn("Legacy callback: site_token mismatch");
173
+ return false;
174
+ }
175
+ const update = { apiKey };
176
+ if (deviceName) update.deviceName = deviceName;
177
+ await this.options.storage.updateConfig(update);
178
+ this.logger.log(`SMSTunnel paired (legacy). Device: ${deviceName || "unknown"}`);
179
+ return true;
180
+ }
181
+ /**
182
+ * Send SMS via SMSTunnel API.
183
+ */
184
+ async sendSms(to, message) {
185
+ const config = await this.options.storage.getConfig();
186
+ if (!config.apiKey) {
187
+ return {
188
+ success: false,
189
+ error: "SMSTunnel is not configured. Pair a device first."
190
+ };
191
+ }
192
+ if (!config.serverUrl) {
193
+ return {
194
+ success: false,
195
+ error: "SMSTunnel server URL is not configured."
196
+ };
197
+ }
198
+ const serverUrl = config.serverUrl.replace(/\/$/, "");
199
+ try {
200
+ const res = await fetch(`${serverUrl}/api/v1/sms/send`, {
201
+ method: "POST",
202
+ headers: {
203
+ "Content-Type": "application/json",
204
+ "X-API-Key": config.apiKey
205
+ },
206
+ body: JSON.stringify({ to, message })
207
+ });
208
+ const data = await res.json();
209
+ if (data.success) {
210
+ this.logger.log(`SMS sent via SMSTunnel: ${data.messageId} -> ${to}`);
211
+ return { success: true, messageId: data.messageId };
212
+ }
213
+ return {
214
+ success: false,
215
+ error: data.error || data.message || "SMSTunnel returned an error"
216
+ };
217
+ } catch (err) {
218
+ this.logger.error(`SMS send error: ${err.message}`);
219
+ return { success: false, error: `Could not send SMS: ${err.message}` };
220
+ }
221
+ }
222
+ /**
223
+ * Unpair - clear saved API key and device info.
224
+ */
225
+ async unpair() {
226
+ await this.options.storage.clearConfig();
227
+ this.logger.log("SMSTunnel unpaired");
228
+ }
229
+ /**
230
+ * Update server URL in config.
231
+ */
232
+ async updateServerUrl(serverUrl) {
233
+ await this.options.storage.updateConfig({
234
+ serverUrl: serverUrl.replace(/\/$/, "")
235
+ });
236
+ }
237
+ // ─── Extended SMS endpoints ────────────────────────
238
+ /**
239
+ * Send 2FA SMS via SMSTunnel API.
240
+ */
241
+ async send2fa(to, code, template) {
242
+ return this.apiPost("/api/v1/sms/send-2fa", { to, code, template });
243
+ }
244
+ /**
245
+ * Send bulk SMS via SMSTunnel API.
246
+ */
247
+ async sendBulk(messages) {
248
+ return this.apiPost("/api/v1/sms/send-bulk", { messages });
249
+ }
250
+ /**
251
+ * Get SMS delivery status.
252
+ */
253
+ async getSmsStatus(messageId) {
254
+ return this.apiGet(`/api/v1/sms/status/${messageId}`);
255
+ }
256
+ /**
257
+ * Get received SMS (inbox).
258
+ */
259
+ async getReceivedSms() {
260
+ return this.apiGet("/api/v1/sms/received");
261
+ }
262
+ // ─── Devices & Account ─────────────────────────────
263
+ /**
264
+ * List paired devices.
265
+ */
266
+ async getDevices() {
267
+ return this.apiGet("/api/v1/devices");
268
+ }
269
+ /**
270
+ * Get account usage stats.
271
+ */
272
+ async getUsage() {
273
+ return this.apiGet("/api/v1/account/usage");
274
+ }
275
+ // ─── Internal helpers ──────────────────────────────
276
+ /** Make an authenticated GET request to SMSTunnel */
277
+ async apiGet(path) {
278
+ const config = await this.options.storage.getConfig();
279
+ if (!config.apiKey || !config.serverUrl) {
280
+ return { success: false, error: "SMSTunnel is not configured." };
281
+ }
282
+ const serverUrl = config.serverUrl.replace(/\/$/, "");
283
+ try {
284
+ const res = await fetch(`${serverUrl}${path}`, {
285
+ headers: { "X-API-Key": config.apiKey }
286
+ });
287
+ return await res.json();
288
+ } catch (err) {
289
+ return { success: false, error: err.message };
290
+ }
291
+ }
292
+ /** Make an authenticated POST request to SMSTunnel */
293
+ async apiPost(path, body) {
294
+ const config = await this.options.storage.getConfig();
295
+ if (!config.apiKey || !config.serverUrl) {
296
+ return { success: false, error: "SMSTunnel is not configured." };
297
+ }
298
+ const serverUrl = config.serverUrl.replace(/\/$/, "");
299
+ try {
300
+ const res = await fetch(`${serverUrl}${path}`, {
301
+ method: "POST",
302
+ headers: {
303
+ "Content-Type": "application/json",
304
+ "X-API-Key": config.apiKey
305
+ },
306
+ body: JSON.stringify(body)
307
+ });
308
+ return await res.json();
309
+ } catch (err) {
310
+ return { success: false, error: err.message };
311
+ }
312
+ }
313
+ };
314
+ SmsTunnelService = __decorateClass([
315
+ (0, import_common.Injectable)(),
316
+ __decorateParam(0, (0, import_common.Inject)(SMSTUNNEL_OPTIONS))
317
+ ], SmsTunnelService);
318
+
319
+ // src/server/smstunnel.controller.ts
320
+ var import_common2 = require("@nestjs/common");
321
+ function SmsTunnelPublic() {
322
+ return (target, key, descriptor) => {
323
+ Reflect.defineMetadata("isPublic", true, descriptor.value);
324
+ return descriptor;
325
+ };
326
+ }
327
+ var SmsTunnelController = class {
328
+ constructor(smsTunnelService, options) {
329
+ this.smsTunnelService = smsTunnelService;
330
+ this.options = options;
331
+ this.logger = new import_common2.Logger(SmsTunnelController.name);
332
+ this.prefix = options.routePrefix || "smstunnel";
333
+ }
334
+ async getStatus() {
335
+ return this.smsTunnelService.getStatus();
336
+ }
337
+ async createToken() {
338
+ return this.smsTunnelService.createPairingToken();
339
+ }
340
+ async pairingStatus(token) {
341
+ return this.smsTunnelService.getPairingStatus(token);
342
+ }
343
+ async pairingCallback(body) {
344
+ this.logger.log(
345
+ `SMSTunnel callback: event=${body.event}, token=${body.token?.substring(0, 8)}...`
346
+ );
347
+ const success = await this.smsTunnelService.handlePairingCallback(body);
348
+ return { success };
349
+ }
350
+ async setupCallbackWp(body) {
351
+ this.logger.log(`SMSTunnel legacy callback. Status: ${body.status || "unknown"}`);
352
+ const success = await this.smsTunnelService.handleLegacyCallback(
353
+ body.site_token,
354
+ body.api_key,
355
+ body.device_name
356
+ );
357
+ return { success };
358
+ }
359
+ async unpair() {
360
+ await this.smsTunnelService.unpair();
361
+ return { success: true };
362
+ }
363
+ async sendSms(body) {
364
+ return this.smsTunnelService.sendSms(body.to, body.message);
365
+ }
366
+ async updateConfig(body) {
367
+ await this.smsTunnelService.updateServerUrl(body.serverUrl);
368
+ return { success: true };
369
+ }
370
+ async send2fa(body) {
371
+ return this.smsTunnelService.send2fa(body.to, body.code, body.template);
372
+ }
373
+ async sendBulk(body) {
374
+ return this.smsTunnelService.sendBulk(body.messages);
375
+ }
376
+ async smsStatus(messageId) {
377
+ return this.smsTunnelService.getSmsStatus(messageId);
378
+ }
379
+ async receivedSms() {
380
+ return this.smsTunnelService.getReceivedSms();
381
+ }
382
+ async devices() {
383
+ return this.smsTunnelService.getDevices();
384
+ }
385
+ async usage() {
386
+ return this.smsTunnelService.getUsage();
387
+ }
388
+ };
389
+ __decorateClass([
390
+ (0, import_common2.Get)("smstunnel/status")
391
+ ], SmsTunnelController.prototype, "getStatus", 1);
392
+ __decorateClass([
393
+ (0, import_common2.Post)("smstunnel/create-token")
394
+ ], SmsTunnelController.prototype, "createToken", 1);
395
+ __decorateClass([
396
+ SmsTunnelPublic(),
397
+ (0, import_common2.Get)("smstunnel/pairing-status/:token"),
398
+ __decorateParam(0, (0, import_common2.Param)("token"))
399
+ ], SmsTunnelController.prototype, "pairingStatus", 1);
400
+ __decorateClass([
401
+ SmsTunnelPublic(),
402
+ (0, import_common2.Post)("smstunnel/callback"),
403
+ __decorateParam(0, (0, import_common2.Body)())
404
+ ], SmsTunnelController.prototype, "pairingCallback", 1);
405
+ __decorateClass([
406
+ SmsTunnelPublic(),
407
+ (0, import_common2.Post)("wp-json/smstunnel/v1/setup-callback"),
408
+ __decorateParam(0, (0, import_common2.Body)())
409
+ ], SmsTunnelController.prototype, "setupCallbackWp", 1);
410
+ __decorateClass([
411
+ (0, import_common2.Post)("smstunnel/unpair")
412
+ ], SmsTunnelController.prototype, "unpair", 1);
413
+ __decorateClass([
414
+ (0, import_common2.Post)("smstunnel/send"),
415
+ __decorateParam(0, (0, import_common2.Body)())
416
+ ], SmsTunnelController.prototype, "sendSms", 1);
417
+ __decorateClass([
418
+ (0, import_common2.Post)("smstunnel/update-config"),
419
+ __decorateParam(0, (0, import_common2.Body)())
420
+ ], SmsTunnelController.prototype, "updateConfig", 1);
421
+ __decorateClass([
422
+ (0, import_common2.Post)("smstunnel/send-2fa"),
423
+ __decorateParam(0, (0, import_common2.Body)())
424
+ ], SmsTunnelController.prototype, "send2fa", 1);
425
+ __decorateClass([
426
+ (0, import_common2.Post)("smstunnel/send-bulk"),
427
+ __decorateParam(0, (0, import_common2.Body)())
428
+ ], SmsTunnelController.prototype, "sendBulk", 1);
429
+ __decorateClass([
430
+ (0, import_common2.Get)("smstunnel/sms-status/:messageId"),
431
+ __decorateParam(0, (0, import_common2.Param)("messageId"))
432
+ ], SmsTunnelController.prototype, "smsStatus", 1);
433
+ __decorateClass([
434
+ (0, import_common2.Get)("smstunnel/received")
435
+ ], SmsTunnelController.prototype, "receivedSms", 1);
436
+ __decorateClass([
437
+ (0, import_common2.Get)("smstunnel/devices")
438
+ ], SmsTunnelController.prototype, "devices", 1);
439
+ __decorateClass([
440
+ (0, import_common2.Get)("smstunnel/usage")
441
+ ], SmsTunnelController.prototype, "usage", 1);
442
+ SmsTunnelController = __decorateClass([
443
+ (0, import_common2.Controller)(),
444
+ __decorateParam(1, (0, import_common2.Inject)(SMSTUNNEL_OPTIONS))
445
+ ], SmsTunnelController);
446
+
447
+ // src/server/smstunnel.module.ts
448
+ var SmsTunnelModule = class {
449
+ static forRoot(options) {
450
+ const optionsProvider = {
451
+ provide: SMSTUNNEL_OPTIONS,
452
+ useValue: options
453
+ };
454
+ const controllers = [SmsTunnelController];
455
+ if (!options.enableLegacyCallback) {
456
+ }
457
+ return {
458
+ module: SmsTunnelModule,
459
+ controllers,
460
+ providers: [optionsProvider, SmsTunnelService],
461
+ exports: [SmsTunnelService],
462
+ global: false
463
+ };
464
+ }
465
+ static forRootAsync(asyncOptions) {
466
+ const optionsProvider = {
467
+ provide: SMSTUNNEL_OPTIONS,
468
+ useFactory: asyncOptions.useFactory,
469
+ inject: asyncOptions.inject || []
470
+ };
471
+ return {
472
+ module: SmsTunnelModule,
473
+ controllers: [SmsTunnelController],
474
+ providers: [optionsProvider, SmsTunnelService],
475
+ exports: [SmsTunnelService],
476
+ global: false
477
+ };
478
+ }
479
+ };
480
+ SmsTunnelModule = __decorateClass([
481
+ (0, import_common3.Module)({})
482
+ ], SmsTunnelModule);
483
+ // Annotate the CommonJS export names for ESM import in node:
484
+ 0 && (module.exports = {
485
+ SMSTUNNEL_DEFAULT_PREFIX,
486
+ SMSTUNNEL_OPTIONS,
487
+ SMSTUNNEL_PUBLIC_PATHS,
488
+ SmsTunnelController,
489
+ SmsTunnelModule,
490
+ SmsTunnelService,
491
+ getSmsTunnelPublicPaths
492
+ });
493
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/server/index.ts","../../src/server/smstunnel.module.ts","../../src/server/smstunnel.service.ts","../../src/server/smstunnel.constants.ts","../../src/server/smstunnel.controller.ts"],"sourcesContent":["export { SmsTunnelModule } from './smstunnel.module';\r\nexport { SmsTunnelService } from './smstunnel.service';\r\nexport { SmsTunnelController } from './smstunnel.controller';\r\nexport {\r\n SMSTUNNEL_OPTIONS,\r\n SMSTUNNEL_PUBLIC_PATHS,\r\n SMSTUNNEL_DEFAULT_PREFIX,\r\n getSmsTunnelPublicPaths,\r\n} from './smstunnel.constants';\r\nexport type {\r\n SmsTunnelConfig,\r\n SmsTunnelStorageAdapter,\r\n SmsTunnelModuleOptions,\r\n SmsTunnelModuleAsyncOptions,\r\n SmsTunnelStatus,\r\n SendSmsResult,\r\n CreateTokenResult,\r\n PairingStatusResult,\r\n PairingCallbackBody,\r\n LegacyCallbackBody,\r\n} from './smstunnel.interfaces';\r\n","import { DynamicModule, Module, Provider } from '@nestjs/common';\r\nimport { SmsTunnelService } from './smstunnel.service';\r\nimport { SmsTunnelController } from './smstunnel.controller';\r\nimport { SMSTUNNEL_OPTIONS } from './smstunnel.constants';\r\nimport type {\r\n SmsTunnelModuleOptions,\r\n SmsTunnelModuleAsyncOptions,\r\n} from './smstunnel.interfaces';\r\n\r\n@Module({})\r\nexport class SmsTunnelModule {\r\n static forRoot(options: SmsTunnelModuleOptions): DynamicModule {\r\n const optionsProvider: Provider = {\r\n provide: SMSTUNNEL_OPTIONS,\r\n useValue: options,\r\n };\r\n\r\n const controllers = [SmsTunnelController];\r\n if (!options.enableLegacyCallback) {\r\n // Legacy callback is always registered but won't match\r\n // if the consumer doesn't enable it - no-op\r\n }\r\n\r\n return {\r\n module: SmsTunnelModule,\r\n controllers,\r\n providers: [optionsProvider, SmsTunnelService],\r\n exports: [SmsTunnelService],\r\n global: false,\r\n };\r\n }\r\n\r\n static forRootAsync(asyncOptions: SmsTunnelModuleAsyncOptions): DynamicModule {\r\n const optionsProvider: Provider = {\r\n provide: SMSTUNNEL_OPTIONS,\r\n useFactory: asyncOptions.useFactory,\r\n inject: asyncOptions.inject || [],\r\n };\r\n\r\n return {\r\n module: SmsTunnelModule,\r\n controllers: [SmsTunnelController],\r\n providers: [optionsProvider, SmsTunnelService],\r\n exports: [SmsTunnelService],\r\n global: false,\r\n };\r\n }\r\n}\r\n","import { Inject, Injectable, Logger } from '@nestjs/common';\r\nimport { SMSTUNNEL_OPTIONS } from './smstunnel.constants';\r\nimport type {\r\n SmsTunnelModuleOptions,\r\n SmsTunnelStatus,\r\n SendSmsResult,\r\n CreateTokenResult,\r\n PairingStatusResult,\r\n PairingCallbackBody,\r\n} from './smstunnel.interfaces';\r\n\r\n@Injectable()\r\nexport class SmsTunnelService {\r\n private readonly logger = new Logger(SmsTunnelService.name);\r\n\r\n constructor(\r\n @Inject(SMSTUNNEL_OPTIONS)\r\n private readonly options: SmsTunnelModuleOptions,\r\n ) {}\r\n\r\n /**\r\n * Get current pairing status.\r\n */\r\n async getStatus(): Promise<SmsTunnelStatus> {\r\n const config = await this.options.storage.getConfig();\r\n return {\r\n paired: !!config.apiKey,\r\n serverUrl: config.serverUrl,\r\n deviceName: config.deviceName,\r\n };\r\n }\r\n\r\n /**\r\n * Create a pairing token on SMSTunnel server.\r\n */\r\n async createPairingToken(): Promise<CreateTokenResult> {\r\n const config = await this.options.storage.getConfig();\r\n if (!config.serverUrl) {\r\n return { success: false, error: 'SMSTunnel server URL is not configured.' };\r\n }\r\n\r\n const serverUrl = config.serverUrl.replace(/\\/$/, '');\r\n const prefix = this.options.routePrefix || 'smstunnel';\r\n const callbackUrl = `${this.options.callbackBaseUrl.replace(/\\/$/, '')}/${prefix}/callback`;\r\n\r\n try {\r\n const res = await fetch(`${serverUrl}/api/v1/pairing/public-create`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n source: 'api',\r\n displayName: this.options.displayName || 'App',\r\n displayUrl: this.options.displayUrl || this.options.callbackBaseUrl,\r\n context: { callbackUrl },\r\n }),\r\n });\r\n\r\n if (!res.ok) {\r\n const errText = await res.text();\r\n this.logger.warn(`SMSTunnel create token failed: ${res.status} ${errText}`);\r\n return { success: false, error: `SMSTunnel returned error: ${res.status}` };\r\n }\r\n\r\n const data: any = await res.json();\r\n\r\n await this.options.storage.updateConfig({ siteToken: data.token });\r\n\r\n this.logger.log(`Pairing token created: ${data.token?.substring(0, 12)}...`);\r\n\r\n return {\r\n success: true,\r\n token: data.token,\r\n qrData: data.qrData,\r\n expiresAt: data.expiresAt,\r\n pollUrl: data.pollUrl || `${serverUrl}/api/v1/pairing/${data.token}`,\r\n };\r\n } catch (err: any) {\r\n this.logger.error(`SMSTunnel create token error: ${err.message}`);\r\n return { success: false, error: `Could not connect to SMSTunnel: ${err.message}` };\r\n }\r\n }\r\n\r\n /**\r\n * Check pairing status by polling SMSTunnel.\r\n */\r\n async getPairingStatus(token: string): Promise<PairingStatusResult> {\r\n const config = await this.options.storage.getConfig();\r\n if (!config.serverUrl) {\r\n return { status: 'error', error: 'SMSTunnel server URL not configured' };\r\n }\r\n\r\n const serverUrl = config.serverUrl.replace(/\\/$/, '');\r\n\r\n try {\r\n const res = await fetch(`${serverUrl}/api/v1/pairing/${token}`);\r\n if (!res.ok) {\r\n return { status: 'expired' };\r\n }\r\n return (await res.json()) as PairingStatusResult;\r\n } catch {\r\n return { status: 'error', error: 'Could not contact SMSTunnel' };\r\n }\r\n }\r\n\r\n /**\r\n * Handle callback from SMSTunnel after pairing completes.\r\n */\r\n async handlePairingCallback(body: PairingCallbackBody): Promise<boolean> {\r\n if (body.event !== 'pairing_completed') {\r\n this.logger.warn(`Unknown callback event: ${body.event}`);\r\n return false;\r\n }\r\n\r\n const config = await this.options.storage.getConfig();\r\n\r\n if (config.siteToken && config.siteToken !== body.token) {\r\n this.logger.warn(\r\n `Callback token mismatch: expected ${config.siteToken?.substring(0, 8)}, got ${body.token?.substring(0, 8)}`,\r\n );\r\n return false;\r\n }\r\n\r\n await this.options.storage.updateConfig({\r\n apiKey: body.apiKey,\r\n deviceName: body.deviceName || 'Android Phone',\r\n });\r\n\r\n this.logger.log(\r\n `SMSTunnel paired! Device: ${body.deviceName}, API key: ${body.apiKey?.substring(0, 12)}...`,\r\n );\r\n return true;\r\n }\r\n\r\n /**\r\n * Handle legacy WordPress-compatible callback.\r\n */\r\n async handleLegacyCallback(\r\n siteToken: string,\r\n apiKey: string,\r\n deviceName?: string,\r\n ): Promise<boolean> {\r\n const config = await this.options.storage.getConfig();\r\n\r\n if (config.siteToken !== siteToken) {\r\n this.logger.warn('Legacy callback: site_token mismatch');\r\n return false;\r\n }\r\n\r\n const update: Partial<{ apiKey: string; deviceName: string }> = { apiKey };\r\n if (deviceName) update.deviceName = deviceName;\r\n\r\n await this.options.storage.updateConfig(update);\r\n this.logger.log(`SMSTunnel paired (legacy). Device: ${deviceName || 'unknown'}`);\r\n return true;\r\n }\r\n\r\n /**\r\n * Send SMS via SMSTunnel API.\r\n */\r\n async sendSms(to: string, message: string): Promise<SendSmsResult> {\r\n const config = await this.options.storage.getConfig();\r\n\r\n if (!config.apiKey) {\r\n return {\r\n success: false,\r\n error: 'SMSTunnel is not configured. Pair a device first.',\r\n };\r\n }\r\n\r\n if (!config.serverUrl) {\r\n return {\r\n success: false,\r\n error: 'SMSTunnel server URL is not configured.',\r\n };\r\n }\r\n\r\n const serverUrl = config.serverUrl.replace(/\\/$/, '');\r\n\r\n try {\r\n const res = await fetch(`${serverUrl}/api/v1/sms/send`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-API-Key': config.apiKey,\r\n },\r\n body: JSON.stringify({ to, message }),\r\n });\r\n\r\n const data: any = await res.json();\r\n\r\n if (data.success) {\r\n this.logger.log(`SMS sent via SMSTunnel: ${data.messageId} -> ${to}`);\r\n return { success: true, messageId: data.messageId };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: data.error || data.message || 'SMSTunnel returned an error',\r\n };\r\n } catch (err: any) {\r\n this.logger.error(`SMS send error: ${err.message}`);\r\n return { success: false, error: `Could not send SMS: ${err.message}` };\r\n }\r\n }\r\n\r\n /**\r\n * Unpair - clear saved API key and device info.\r\n */\r\n async unpair(): Promise<void> {\r\n await this.options.storage.clearConfig();\r\n this.logger.log('SMSTunnel unpaired');\r\n }\r\n\r\n /**\r\n * Update server URL in config.\r\n */\r\n async updateServerUrl(serverUrl: string): Promise<void> {\r\n await this.options.storage.updateConfig({\r\n serverUrl: serverUrl.replace(/\\/$/, ''),\r\n });\r\n }\r\n\r\n // ─── Extended SMS endpoints ────────────────────────\r\n\r\n /**\r\n * Send 2FA SMS via SMSTunnel API.\r\n */\r\n async send2fa(to: string, code: string, template?: string): Promise<SendSmsResult> {\r\n return this.apiPost('/api/v1/sms/send-2fa', { to, code, template });\r\n }\r\n\r\n /**\r\n * Send bulk SMS via SMSTunnel API.\r\n */\r\n async sendBulk(\r\n messages: Array<{ to: string; message: string }>,\r\n ): Promise<{ success: boolean; results?: any[]; error?: string }> {\r\n return this.apiPost('/api/v1/sms/send-bulk', { messages });\r\n }\r\n\r\n /**\r\n * Get SMS delivery status.\r\n */\r\n async getSmsStatus(messageId: string): Promise<any> {\r\n return this.apiGet(`/api/v1/sms/status/${messageId}`);\r\n }\r\n\r\n /**\r\n * Get received SMS (inbox).\r\n */\r\n async getReceivedSms(): Promise<any> {\r\n return this.apiGet('/api/v1/sms/received');\r\n }\r\n\r\n // ─── Devices & Account ─────────────────────────────\r\n\r\n /**\r\n * List paired devices.\r\n */\r\n async getDevices(): Promise<any> {\r\n return this.apiGet('/api/v1/devices');\r\n }\r\n\r\n /**\r\n * Get account usage stats.\r\n */\r\n async getUsage(): Promise<any> {\r\n return this.apiGet('/api/v1/account/usage');\r\n }\r\n\r\n // ─── Internal helpers ──────────────────────────────\r\n\r\n /** Make an authenticated GET request to SMSTunnel */\r\n private async apiGet(path: string): Promise<any> {\r\n const config = await this.options.storage.getConfig();\r\n if (!config.apiKey || !config.serverUrl) {\r\n return { success: false, error: 'SMSTunnel is not configured.' };\r\n }\r\n const serverUrl = config.serverUrl.replace(/\\/$/, '');\r\n try {\r\n const res = await fetch(`${serverUrl}${path}`, {\r\n headers: { 'X-API-Key': config.apiKey },\r\n });\r\n return await res.json();\r\n } catch (err: any) {\r\n return { success: false, error: err.message };\r\n }\r\n }\r\n\r\n /** Make an authenticated POST request to SMSTunnel */\r\n private async apiPost(path: string, body: any): Promise<any> {\r\n const config = await this.options.storage.getConfig();\r\n if (!config.apiKey || !config.serverUrl) {\r\n return { success: false, error: 'SMSTunnel is not configured.' };\r\n }\r\n const serverUrl = config.serverUrl.replace(/\\/$/, '');\r\n try {\r\n const res = await fetch(`${serverUrl}${path}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-API-Key': config.apiKey,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n return await res.json();\r\n } catch (err: any) {\r\n return { success: false, error: err.message };\r\n }\r\n }\r\n}\r\n","export const SMSTUNNEL_OPTIONS = 'SMSTUNNEL_OPTIONS';\r\n\r\nexport const SMSTUNNEL_DEFAULT_PREFIX = 'smstunnel';\r\n\r\n/**\r\n * Public paths that should be excluded from auth guards.\r\n * Use with your global guard to skip auth on callback/polling routes.\r\n *\r\n * Example (NestJS):\r\n * if (SMSTUNNEL_PUBLIC_PATHS.some(p => request.url.includes(p))) return true;\r\n */\r\nexport const SMSTUNNEL_PUBLIC_PATHS = [\r\n '/smstunnel/pairing-status/',\r\n '/smstunnel/callback',\r\n '/wp-json/smstunnel/v1/setup-callback',\r\n];\r\n\r\n/**\r\n * Returns public paths with a custom prefix.\r\n */\r\nexport function getSmsTunnelPublicPaths(prefix: string): string[] {\r\n return [\r\n `/${prefix}/pairing-status/`,\r\n `/${prefix}/callback`,\r\n '/wp-json/smstunnel/v1/setup-callback',\r\n ];\r\n}\r\n","import {\r\n Controller,\r\n Post,\r\n Get,\r\n Body,\r\n Param,\r\n Inject,\r\n Logger,\r\n} from '@nestjs/common';\r\nimport { SmsTunnelService } from './smstunnel.service';\r\nimport { SMSTUNNEL_OPTIONS } from './smstunnel.constants';\r\nimport type {\r\n SmsTunnelModuleOptions,\r\n PairingCallbackBody,\r\n LegacyCallbackBody,\r\n} from './smstunnel.interfaces';\r\n\r\n/**\r\n * Decorator to mark routes as public (no auth).\r\n * If you have your own @Public() decorator, the module re-exports\r\n * SMSTUNNEL_PUBLIC_PATHS so you can exclude them in your guard.\r\n */\r\nfunction SmsTunnelPublic() {\r\n // We use Reflect metadata so consumers can detect public routes\r\n return (target: any, key: string, descriptor: PropertyDescriptor) => {\r\n Reflect.defineMetadata('isPublic', true, descriptor.value);\r\n return descriptor;\r\n };\r\n}\r\n\r\n@Controller()\r\nexport class SmsTunnelController {\r\n private readonly logger = new Logger(SmsTunnelController.name);\r\n private readonly prefix: string;\r\n\r\n constructor(\r\n private readonly smsTunnelService: SmsTunnelService,\r\n @Inject(SMSTUNNEL_OPTIONS)\r\n private readonly options: SmsTunnelModuleOptions,\r\n ) {\r\n this.prefix = options.routePrefix || 'smstunnel';\r\n }\r\n\r\n /**\r\n * Get current pairing status.\r\n * Route: GET /{prefix}/status\r\n */\r\n @Get('smstunnel/status')\r\n async getStatus() {\r\n return this.smsTunnelService.getStatus();\r\n }\r\n\r\n /**\r\n * Create a pairing token on SMSTunnel.\r\n * Route: POST /{prefix}/create-token\r\n */\r\n @Post('smstunnel/create-token')\r\n async createToken() {\r\n return this.smsTunnelService.createPairingToken();\r\n }\r\n\r\n /**\r\n * Proxy polling to SMSTunnel (avoids CORS issues).\r\n * This should be public (no auth) - just proxying SMSTunnel's endpoint.\r\n * Route: GET /{prefix}/pairing-status/:token\r\n */\r\n @SmsTunnelPublic()\r\n @Get('smstunnel/pairing-status/:token')\r\n async pairingStatus(@Param('token') token: string) {\r\n return this.smsTunnelService.getPairingStatus(token);\r\n }\r\n\r\n /**\r\n * Callback from SMSTunnel after pairing completes.\r\n * Route: POST /{prefix}/callback\r\n */\r\n @SmsTunnelPublic()\r\n @Post('smstunnel/callback')\r\n async pairingCallback(@Body() body: PairingCallbackBody) {\r\n this.logger.log(\r\n `SMSTunnel callback: event=${body.event}, token=${body.token?.substring(0, 8)}...`,\r\n );\r\n const success = await this.smsTunnelService.handlePairingCallback(body);\r\n return { success };\r\n }\r\n\r\n /**\r\n * WordPress-compatible legacy callback.\r\n * Route: POST /wp-json/smstunnel/v1/setup-callback\r\n */\r\n @SmsTunnelPublic()\r\n @Post('wp-json/smstunnel/v1/setup-callback')\r\n async setupCallbackWp(@Body() body: LegacyCallbackBody) {\r\n this.logger.log(`SMSTunnel legacy callback. Status: ${body.status || 'unknown'}`);\r\n const success = await this.smsTunnelService.handleLegacyCallback(\r\n body.site_token,\r\n body.api_key,\r\n body.device_name,\r\n );\r\n return { success };\r\n }\r\n\r\n /**\r\n * Unpair the connected device.\r\n * Route: POST /{prefix}/unpair\r\n */\r\n @Post('smstunnel/unpair')\r\n async unpair() {\r\n await this.smsTunnelService.unpair();\r\n return { success: true };\r\n }\r\n\r\n /**\r\n * Send an SMS via SMSTunnel.\r\n * Route: POST /{prefix}/send\r\n */\r\n @Post('smstunnel/send')\r\n async sendSms(@Body() body: { to: string; message: string }) {\r\n return this.smsTunnelService.sendSms(body.to, body.message);\r\n }\r\n\r\n /**\r\n * Update server URL configuration.\r\n * Route: POST /{prefix}/update-config\r\n */\r\n @Post('smstunnel/update-config')\r\n async updateConfig(@Body() body: { serverUrl: string }) {\r\n await this.smsTunnelService.updateServerUrl(body.serverUrl);\r\n return { success: true };\r\n }\r\n\r\n // ─── Extended SMS endpoints ────────────────────────\r\n\r\n /**\r\n * Send a 2FA SMS.\r\n * Route: POST /{prefix}/send-2fa\r\n */\r\n @Post('smstunnel/send-2fa')\r\n async send2fa(@Body() body: { to: string; code: string; template?: string }) {\r\n return this.smsTunnelService.send2fa(body.to, body.code, body.template);\r\n }\r\n\r\n /**\r\n * Send bulk SMS.\r\n * Route: POST /{prefix}/send-bulk\r\n */\r\n @Post('smstunnel/send-bulk')\r\n async sendBulk(@Body() body: { messages: Array<{ to: string; message: string }> }) {\r\n return this.smsTunnelService.sendBulk(body.messages);\r\n }\r\n\r\n /**\r\n * Get SMS delivery status.\r\n * Route: GET /{prefix}/sms-status/:messageId\r\n */\r\n @Get('smstunnel/sms-status/:messageId')\r\n async smsStatus(@Param('messageId') messageId: string) {\r\n return this.smsTunnelService.getSmsStatus(messageId);\r\n }\r\n\r\n /**\r\n * Get received SMS (inbox).\r\n * Route: GET /{prefix}/received\r\n */\r\n @Get('smstunnel/received')\r\n async receivedSms() {\r\n return this.smsTunnelService.getReceivedSms();\r\n }\r\n\r\n // ─── Devices & Account ─────────────────────────────\r\n\r\n /**\r\n * List paired devices.\r\n * Route: GET /{prefix}/devices\r\n */\r\n @Get('smstunnel/devices')\r\n async devices() {\r\n return this.smsTunnelService.getDevices();\r\n }\r\n\r\n /**\r\n * Get account usage stats.\r\n * Route: GET /{prefix}/usage\r\n */\r\n @Get('smstunnel/usage')\r\n async usage() {\r\n return this.smsTunnelService.getUsage();\r\n }\r\n}\r\n"],"mappings":"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","names":["import_common","import_common"]}