@narcisbodea/smstunnel-sdk 1.1.9 → 1.2.2
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.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +4 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.js +40 -3
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +40 -3
- package/dist/react/index.mjs.map +1 -1
- package/dist/server/index.d.mts +2 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +2 -0
- package/dist/server/index.mjs.map +1 -1
- package/dist/vue/index.d.mts +3 -0
- package/dist/vue/index.d.ts +3 -0
- package/dist/vue/index.js +10 -2
- package/dist/vue/index.js.map +1 -1
- package/dist/vue/index.mjs +10 -2
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -27,6 +27,7 @@ interface SendSmsResult {
|
|
|
27
27
|
interface CreateTokenResult {
|
|
28
28
|
success: boolean;
|
|
29
29
|
token?: string;
|
|
30
|
+
pairingCode?: string;
|
|
30
31
|
qrData?: string;
|
|
31
32
|
expiresAt?: string;
|
|
32
33
|
pollUrl?: string;
|
|
@@ -69,6 +70,8 @@ interface SmsTunnelLabels {
|
|
|
69
70
|
sendTestButton: string;
|
|
70
71
|
smsSentSuccess: string;
|
|
71
72
|
smsError: string;
|
|
73
|
+
pairingCodeLabel: string;
|
|
74
|
+
pairingCodeCopied: string;
|
|
72
75
|
}
|
|
73
76
|
declare const EN_LABELS: SmsTunnelLabels;
|
|
74
77
|
declare const RO_LABELS: SmsTunnelLabels;
|
|
@@ -95,6 +98,7 @@ interface SmsTunnelStatusResponse {
|
|
|
95
98
|
interface CreateTokenResponse {
|
|
96
99
|
success: boolean;
|
|
97
100
|
token?: string;
|
|
101
|
+
pairingCode?: string;
|
|
98
102
|
qrData?: string;
|
|
99
103
|
expiresAt?: string;
|
|
100
104
|
pollUrl?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ interface SendSmsResult {
|
|
|
27
27
|
interface CreateTokenResult {
|
|
28
28
|
success: boolean;
|
|
29
29
|
token?: string;
|
|
30
|
+
pairingCode?: string;
|
|
30
31
|
qrData?: string;
|
|
31
32
|
expiresAt?: string;
|
|
32
33
|
pollUrl?: string;
|
|
@@ -69,6 +70,8 @@ interface SmsTunnelLabels {
|
|
|
69
70
|
sendTestButton: string;
|
|
70
71
|
smsSentSuccess: string;
|
|
71
72
|
smsError: string;
|
|
73
|
+
pairingCodeLabel: string;
|
|
74
|
+
pairingCodeCopied: string;
|
|
72
75
|
}
|
|
73
76
|
declare const EN_LABELS: SmsTunnelLabels;
|
|
74
77
|
declare const RO_LABELS: SmsTunnelLabels;
|
|
@@ -95,6 +98,7 @@ interface SmsTunnelStatusResponse {
|
|
|
95
98
|
interface CreateTokenResponse {
|
|
96
99
|
success: boolean;
|
|
97
100
|
token?: string;
|
|
101
|
+
pairingCode?: string;
|
|
98
102
|
qrData?: string;
|
|
99
103
|
expiresAt?: string;
|
|
100
104
|
pollUrl?: string;
|
package/dist/index.js
CHANGED
|
@@ -49,7 +49,9 @@ var EN_LABELS = {
|
|
|
49
49
|
testMessagePlaceholder: "Message",
|
|
50
50
|
sendTestButton: "Send",
|
|
51
51
|
smsSentSuccess: "SMS sent successfully!",
|
|
52
|
-
smsError: "Error"
|
|
52
|
+
smsError: "Error",
|
|
53
|
+
pairingCodeLabel: "Or enter this code in the app:",
|
|
54
|
+
pairingCodeCopied: "Code copied!"
|
|
53
55
|
};
|
|
54
56
|
var RO_LABELS = {
|
|
55
57
|
title: "Configurare SMS (SMSTunnel)",
|
|
@@ -73,7 +75,9 @@ var RO_LABELS = {
|
|
|
73
75
|
testMessagePlaceholder: "Mesaj",
|
|
74
76
|
sendTestButton: "Trimite",
|
|
75
77
|
smsSentSuccess: "SMS trimis cu succes!",
|
|
76
|
-
smsError: "Eroare"
|
|
78
|
+
smsError: "Eroare",
|
|
79
|
+
pairingCodeLabel: "Sau introdu acest cod in aplicatie:",
|
|
80
|
+
pairingCodeCopied: "Cod copiat!"
|
|
77
81
|
};
|
|
78
82
|
|
|
79
83
|
// src/client.ts
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/shared/labels.ts","../src/client.ts"],"sourcesContent":["// Common types shared between server and all frontends\r\nexport type {\r\n SmsTunnelConfig,\r\n SmsTunnelStorageAdapter,\r\n SmsTunnelStatus,\r\n SendSmsResult,\r\n CreateTokenResult,\r\n PairingStatusResult,\r\n PairingCallbackBody,\r\n} from './server/smstunnel.interfaces';\r\n\r\n// Shared labels (i18n)\r\nexport type { SmsTunnelLabels } from './shared/labels';\r\nexport { EN_LABELS, RO_LABELS } from './shared/labels';\r\n\r\n// Framework-agnostic client (Angular, Svelte, Astro, Solid, Vanilla JS)\r\nexport { SmsTunnelClient } from './client';\r\nexport type {\r\n SmsTunnelClientOptions,\r\n SmsTunnelStatusResponse,\r\n CreateTokenResponse,\r\n PairingStatusResponse,\r\n SendSmsResponse,\r\n SmsStatusResponse,\r\n SendBulkSmsRequest,\r\n SendBulkSmsResponse,\r\n Send2faRequest,\r\n ReceivedSmsResponse,\r\n DevicesResponse,\r\n AccountUsageResponse,\r\n PairingInfo,\r\n PairingEventCallback,\r\n DeviceE2EStatusResponse,\r\n DevicePublicKeyResponse,\r\n VerifyDeviceKeyResponse,\r\n} from './client';\r\n","export interface SmsTunnelLabels {\r\n title: string;\r\n description: string;\r\n serverUrlLabel: string;\r\n serverUrlPlaceholder: string;\r\n saveButton: string;\r\n pairedStatus: string;\r\n deviceLabel: string;\r\n unpairButton: string;\r\n unpairConfirm: string;\r\n notPairedStatus: string;\r\n notPairedDescription: string;\r\n connectButton: string;\r\n scanQrPrompt: string;\r\n waitingForPairing: string;\r\n cancelButton: string;\r\n qrExpired: string;\r\n testSmsTitle: string;\r\n testPhonePlaceholder: string;\r\n testMessagePlaceholder: string;\r\n sendTestButton: string;\r\n smsSentSuccess: string;\r\n smsError: string;\r\n}\r\n\r\nexport const EN_LABELS: SmsTunnelLabels = {\r\n title: 'SMS Configuration (SMSTunnel)',\r\n description: 'Connect an Android phone with the SMSTunnel app to send SMS directly from the application.',\r\n serverUrlLabel: 'SMSTunnel Server',\r\n serverUrlPlaceholder: 'https://smstunnel.io',\r\n saveButton: 'Save',\r\n pairedStatus: 'Connected',\r\n deviceLabel: 'Device',\r\n unpairButton: 'Disconnect',\r\n unpairConfirm: 'Are you sure you want to disconnect the SMS device?',\r\n notPairedStatus: 'Not connected',\r\n notPairedDescription: 'Scan the QR code with the SMSTunnel app on your Android phone.',\r\n connectButton: 'Connect phone',\r\n scanQrPrompt: 'Scan this QR code with the SMSTunnel app on your phone:',\r\n waitingForPairing: 'Waiting for connection...',\r\n cancelButton: 'Cancel',\r\n qrExpired: 'QR code has expired. Generate a new one.',\r\n testSmsTitle: 'Send test SMS',\r\n testPhonePlaceholder: 'Phone number (e.g., +1234567890)',\r\n testMessagePlaceholder: 'Message',\r\n sendTestButton: 'Send',\r\n smsSentSuccess: 'SMS sent successfully!',\r\n smsError: 'Error',\r\n};\r\n\r\nexport const RO_LABELS: SmsTunnelLabels = {\r\n title: 'Configurare SMS (SMSTunnel)',\r\n description: 'Conecteaza un telefon Android cu aplicatia SMSTunnel pentru a trimite SMS-uri direct din aplicatie.',\r\n serverUrlLabel: 'Server SMSTunnel',\r\n serverUrlPlaceholder: 'https://smstunnel.io',\r\n saveButton: 'Salveaza',\r\n pairedStatus: 'Conectat',\r\n deviceLabel: 'Dispozitiv',\r\n unpairButton: 'Deconecteaza',\r\n unpairConfirm: 'Sigur doresti sa deconectezi dispozitivul SMS?',\r\n notPairedStatus: 'Neconectat',\r\n notPairedDescription: 'Scaneaza codul QR cu aplicatia SMSTunnel de pe telefonul Android.',\r\n connectButton: 'Conecteaza telefon',\r\n scanQrPrompt: 'Scaneaza acest cod QR cu aplicatia SMSTunnel de pe telefon:',\r\n waitingForPairing: 'Se asteapta conectarea...',\r\n cancelButton: 'Anuleaza',\r\n qrExpired: 'Codul QR a expirat. Genereaza unul nou.',\r\n testSmsTitle: 'Trimite SMS de test',\r\n testPhonePlaceholder: 'Nr. telefon (ex: 0741234567)',\r\n testMessagePlaceholder: 'Mesaj',\r\n sendTestButton: 'Trimite',\r\n smsSentSuccess: 'SMS trimis cu succes!',\r\n smsError: 'Eroare',\r\n};\r\n","/**\r\n * Framework-agnostic SMSTunnel client.\r\n *\r\n * Works with Angular, Svelte, Astro, Solid, Vanilla JS, or any framework.\r\n * For React use `smstunnel-sdk/react`, for Vue use `smstunnel-sdk/vue`.\r\n */\r\nexport interface SmsTunnelClientOptions {\r\n apiBaseUrl: string;\r\n /** Return the current JWT/auth token. SDK adds Authorization: Bearer header automatically. */\r\n getToken?: () => string | null;\r\n /** Full control over auth headers. Takes precedence over getToken. */\r\n getAuthHeaders?: () => Record<string, string>;\r\n pollInterval?: number;\r\n}\r\n\r\n// --- Status ---\r\n\r\nexport interface SmsTunnelStatusResponse {\r\n paired: boolean;\r\n serverUrl?: string;\r\n deviceName?: string;\r\n}\r\n\r\n// --- Pairing ---\r\n\r\nexport interface CreateTokenResponse {\r\n success: boolean;\r\n token?: string;\r\n qrData?: string;\r\n expiresAt?: string;\r\n pollUrl?: string;\r\n error?: string;\r\n}\r\n\r\nexport interface PairingStatusResponse {\r\n status: 'pending' | 'completed' | 'expired' | 'error';\r\n source?: string;\r\n displayName?: string;\r\n pairedDeviceId?: string;\r\n pairingId?: string;\r\n error?: string;\r\n}\r\n\r\n// --- SMS ---\r\n\r\nexport interface SendSmsResponse {\r\n success: boolean;\r\n messageId?: string;\r\n queued?: boolean;\r\n data?: {\r\n messageId: string;\r\n branded: boolean;\r\n queued: boolean;\r\n remaining: number;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface SmsStatusResponse {\r\n success: boolean;\r\n data?: {\r\n messageId: string;\r\n status: 'sent' | 'pending' | 'failed' | 'delivered';\r\n recipient: string;\r\n sentAt?: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface SendBulkSmsRequest {\r\n messages: Array<{ to: string; message: string }>;\r\n}\r\n\r\nexport interface SendBulkSmsResponse {\r\n success: boolean;\r\n results?: Array<{ to: string; messageId?: string; error?: string }>;\r\n error?: string;\r\n}\r\n\r\nexport interface Send2faRequest {\r\n to: string;\r\n code: string;\r\n template?: string;\r\n}\r\n\r\nexport interface ReceivedSmsResponse {\r\n success: boolean;\r\n data?: Array<{\r\n from: string;\r\n message: string;\r\n receivedAt: string;\r\n }>;\r\n error?: string;\r\n}\r\n\r\n// --- Devices ---\r\n\r\nexport interface DevicesResponse {\r\n success: boolean;\r\n data?: Array<{\r\n id: string;\r\n clientId: string;\r\n name: string;\r\n brand?: string;\r\n model?: string;\r\n connected?: boolean;\r\n }>;\r\n error?: string;\r\n}\r\n\r\n// --- Account ---\r\n\r\nexport interface AccountUsageResponse {\r\n success: boolean;\r\n data?: {\r\n messagesSent: number;\r\n messagesReceived: number;\r\n messagesSentToday: number;\r\n messagesSentMonth: number;\r\n dailyLimit?: number;\r\n monthlyLimit?: number;\r\n };\r\n error?: string;\r\n}\r\n\r\n// --- E2E Encryption ---\r\n\r\nexport interface DeviceE2EStatusResponse {\r\n success: boolean;\r\n data?: {\r\n encryptionEnabled: boolean;\r\n hasPublicKey: boolean;\r\n publicKeyFingerprint?: string;\r\n keyCreatedAt?: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface DevicePublicKeyResponse {\r\n success: boolean;\r\n data?: {\r\n deviceId: string;\r\n deviceName: string;\r\n publicKey: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface VerifyDeviceKeyResponse {\r\n valid: boolean;\r\n currentFingerprint?: string;\r\n needsRePairing: boolean;\r\n}\r\n\r\n// --- Pairings list ---\r\n\r\nexport interface PairingInfo {\r\n _id: string;\r\n deviceId: string;\r\n type: string;\r\n name: string;\r\n status: 'active' | 'paused' | 'revoked';\r\n messagesSent: number;\r\n createdAt: string;\r\n source: string;\r\n}\r\n\r\n// --- Callback ---\r\n\r\nexport type PairingEventCallback = (event: 'completed' | 'expired' | 'error', data?: any) => void;\r\n\r\nexport class SmsTunnelClient {\r\n private readonly baseUrl: string;\r\n private readonly prefix = 'smstunnel';\r\n private readonly pollInterval: number;\r\n private readonly getAuthHeaders: () => Record<string, string>;\r\n private pollTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\n constructor(options: SmsTunnelClientOptions) {\r\n this.baseUrl = options.apiBaseUrl.replace(/\\/$/, '');\r\n this.pollInterval = options.pollInterval || 3000;\r\n\r\n if (options.getAuthHeaders) {\r\n this.getAuthHeaders = options.getAuthHeaders;\r\n } else if (options.getToken) {\r\n const getToken = options.getToken;\r\n this.getAuthHeaders = (): Record<string, string> => {\r\n const token = getToken();\r\n if (token) return { Authorization: `Bearer ${token}` };\r\n return {};\r\n };\r\n } else {\r\n this.getAuthHeaders = () => ({});\r\n }\r\n }\r\n\r\n // ─── Pairing ───────────────────────────────────────\r\n\r\n /** Get current pairing status */\r\n async getStatus(): Promise<SmsTunnelStatusResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/status`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Create a pairing token (generates QR data) */\r\n async createToken(): Promise<CreateTokenResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/create-token`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Check pairing status for a token (no auth needed) */\r\n async getPairingStatus(token: string): Promise<PairingStatusResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/pairing-status/${token}`,\r\n );\r\n return res.json();\r\n }\r\n\r\n /**\r\n * Start polling for pairing completion.\r\n * Returns a cleanup function to stop polling.\r\n */\r\n startPolling(token: string, callback: PairingEventCallback): () => void {\r\n this.stopPolling();\r\n\r\n this.pollTimer = setInterval(async () => {\r\n try {\r\n const data = await this.getPairingStatus(token);\r\n if (data.status === 'completed') {\r\n this.stopPolling();\r\n callback('completed', data);\r\n } else if (data.status === 'expired') {\r\n this.stopPolling();\r\n callback('expired', data);\r\n }\r\n } catch (err) {\r\n // ignore polling errors\r\n }\r\n }, this.pollInterval);\r\n\r\n return () => this.stopPolling();\r\n }\r\n\r\n /** Stop polling */\r\n stopPolling(): void {\r\n if (this.pollTimer) {\r\n clearInterval(this.pollTimer);\r\n this.pollTimer = null;\r\n }\r\n }\r\n\r\n /** Unpair the connected device */\r\n async unpair(): Promise<{ success: boolean }> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/unpair`, {\r\n method: 'POST',\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** List active pairings (proxied through backend) */\r\n async getPairings(): Promise<PairingInfo[]> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/pairings`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── SMS ───────────────────────────────────────────\r\n\r\n /** Send a single SMS */\r\n async sendSms(to: string, message: string): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ to, message }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send a 2FA SMS */\r\n async send2fa(to: string, code: string, template?: string): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-2fa`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ to, code, template }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send bulk SMS */\r\n async sendBulk(messages: Array<{ to: string; message: string }>): Promise<SendBulkSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-bulk`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ messages }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get SMS delivery status */\r\n async getSmsStatus(messageId: string): Promise<SmsStatusResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/sms-status/${messageId}`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get received SMS (inbox) */\r\n async getReceivedSms(): Promise<ReceivedSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/received`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── Devices & Account ─────────────────────────────\r\n\r\n /** List paired devices */\r\n async getDevices(): Promise<DevicesResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/devices`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get account usage stats */\r\n async getUsage(): Promise<AccountUsageResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/usage`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── E2E Encryption ────────────────────────────────\r\n\r\n /** Get E2E encryption status for a device */\r\n async getDeviceE2EStatus(deviceId: string): Promise<DeviceE2EStatusResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/e2e-status/${deviceId}`,\r\n { headers: this.getAuthHeaders() },\r\n );\r\n return res.json();\r\n }\r\n\r\n /** Get device public key for E2E encryption */\r\n async getDevicePublicKey(deviceId: string): Promise<DevicePublicKeyResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/public-key/${deviceId}`,\r\n { headers: this.getAuthHeaders() },\r\n );\r\n return res.json();\r\n }\r\n\r\n /** Verify that a stored fingerprint matches the current device key */\r\n async verifyDeviceKey(\r\n deviceId: string,\r\n fingerprint: string,\r\n ): Promise<VerifyDeviceKeyResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/verify-key`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ deviceId, fingerprint }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send an encrypted SMS (payload already encrypted with device public key) */\r\n async sendEncryptedSms(\r\n encryptedPayload: string,\r\n deviceId: string,\r\n is2FA: boolean = false,\r\n ): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-encrypted`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ encryptedPayload, deviceId, is2FA }),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── Config ────────────────────────────────────────\r\n\r\n /** Update server URL configuration */\r\n async updateServerUrl(serverUrl: string): Promise<{ success: boolean }> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/update-config`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ serverUrl }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Destroy - cleanup polling */\r\n destroy(): void {\r\n this.stopPolling();\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/shared/labels.ts","../src/client.ts"],"sourcesContent":["// Common types shared between server and all frontends\r\nexport type {\r\n SmsTunnelConfig,\r\n SmsTunnelStorageAdapter,\r\n SmsTunnelStatus,\r\n SendSmsResult,\r\n CreateTokenResult,\r\n PairingStatusResult,\r\n PairingCallbackBody,\r\n} from './server/smstunnel.interfaces';\r\n\r\n// Shared labels (i18n)\r\nexport type { SmsTunnelLabels } from './shared/labels';\r\nexport { EN_LABELS, RO_LABELS } from './shared/labels';\r\n\r\n// Framework-agnostic client (Angular, Svelte, Astro, Solid, Vanilla JS)\r\nexport { SmsTunnelClient } from './client';\r\nexport type {\r\n SmsTunnelClientOptions,\r\n SmsTunnelStatusResponse,\r\n CreateTokenResponse,\r\n PairingStatusResponse,\r\n SendSmsResponse,\r\n SmsStatusResponse,\r\n SendBulkSmsRequest,\r\n SendBulkSmsResponse,\r\n Send2faRequest,\r\n ReceivedSmsResponse,\r\n DevicesResponse,\r\n AccountUsageResponse,\r\n PairingInfo,\r\n PairingEventCallback,\r\n DeviceE2EStatusResponse,\r\n DevicePublicKeyResponse,\r\n VerifyDeviceKeyResponse,\r\n} from './client';\r\n","export interface SmsTunnelLabels {\r\n title: string;\r\n description: string;\r\n serverUrlLabel: string;\r\n serverUrlPlaceholder: string;\r\n saveButton: string;\r\n pairedStatus: string;\r\n deviceLabel: string;\r\n unpairButton: string;\r\n unpairConfirm: string;\r\n notPairedStatus: string;\r\n notPairedDescription: string;\r\n connectButton: string;\r\n scanQrPrompt: string;\r\n waitingForPairing: string;\r\n cancelButton: string;\r\n qrExpired: string;\r\n testSmsTitle: string;\r\n testPhonePlaceholder: string;\r\n testMessagePlaceholder: string;\r\n sendTestButton: string;\r\n smsSentSuccess: string;\r\n smsError: string;\r\n pairingCodeLabel: string;\r\n pairingCodeCopied: string;\r\n}\r\n\r\nexport const EN_LABELS: SmsTunnelLabels = {\r\n title: 'SMS Configuration (SMSTunnel)',\r\n description: 'Connect an Android phone with the SMSTunnel app to send SMS directly from the application.',\r\n serverUrlLabel: 'SMSTunnel Server',\r\n serverUrlPlaceholder: 'https://smstunnel.io',\r\n saveButton: 'Save',\r\n pairedStatus: 'Connected',\r\n deviceLabel: 'Device',\r\n unpairButton: 'Disconnect',\r\n unpairConfirm: 'Are you sure you want to disconnect the SMS device?',\r\n notPairedStatus: 'Not connected',\r\n notPairedDescription: 'Scan the QR code with the SMSTunnel app on your Android phone.',\r\n connectButton: 'Connect phone',\r\n scanQrPrompt: 'Scan this QR code with the SMSTunnel app on your phone:',\r\n waitingForPairing: 'Waiting for connection...',\r\n cancelButton: 'Cancel',\r\n qrExpired: 'QR code has expired. Generate a new one.',\r\n testSmsTitle: 'Send test SMS',\r\n testPhonePlaceholder: 'Phone number (e.g., +1234567890)',\r\n testMessagePlaceholder: 'Message',\r\n sendTestButton: 'Send',\r\n smsSentSuccess: 'SMS sent successfully!',\r\n smsError: 'Error',\r\n pairingCodeLabel: 'Or enter this code in the app:',\r\n pairingCodeCopied: 'Code copied!',\r\n};\r\n\r\nexport const RO_LABELS: SmsTunnelLabels = {\r\n title: 'Configurare SMS (SMSTunnel)',\r\n description: 'Conecteaza un telefon Android cu aplicatia SMSTunnel pentru a trimite SMS-uri direct din aplicatie.',\r\n serverUrlLabel: 'Server SMSTunnel',\r\n serverUrlPlaceholder: 'https://smstunnel.io',\r\n saveButton: 'Salveaza',\r\n pairedStatus: 'Conectat',\r\n deviceLabel: 'Dispozitiv',\r\n unpairButton: 'Deconecteaza',\r\n unpairConfirm: 'Sigur doresti sa deconectezi dispozitivul SMS?',\r\n notPairedStatus: 'Neconectat',\r\n notPairedDescription: 'Scaneaza codul QR cu aplicatia SMSTunnel de pe telefonul Android.',\r\n connectButton: 'Conecteaza telefon',\r\n scanQrPrompt: 'Scaneaza acest cod QR cu aplicatia SMSTunnel de pe telefon:',\r\n waitingForPairing: 'Se asteapta conectarea...',\r\n cancelButton: 'Anuleaza',\r\n qrExpired: 'Codul QR a expirat. Genereaza unul nou.',\r\n testSmsTitle: 'Trimite SMS de test',\r\n testPhonePlaceholder: 'Nr. telefon (ex: 0741234567)',\r\n testMessagePlaceholder: 'Mesaj',\r\n sendTestButton: 'Trimite',\r\n smsSentSuccess: 'SMS trimis cu succes!',\r\n smsError: 'Eroare',\r\n pairingCodeLabel: 'Sau introdu acest cod in aplicatie:',\r\n pairingCodeCopied: 'Cod copiat!',\r\n};\r\n","/**\r\n * Framework-agnostic SMSTunnel client.\r\n *\r\n * Works with Angular, Svelte, Astro, Solid, Vanilla JS, or any framework.\r\n * For React use `smstunnel-sdk/react`, for Vue use `smstunnel-sdk/vue`.\r\n */\r\nexport interface SmsTunnelClientOptions {\r\n apiBaseUrl: string;\r\n /** Return the current JWT/auth token. SDK adds Authorization: Bearer header automatically. */\r\n getToken?: () => string | null;\r\n /** Full control over auth headers. Takes precedence over getToken. */\r\n getAuthHeaders?: () => Record<string, string>;\r\n pollInterval?: number;\r\n}\r\n\r\n// --- Status ---\r\n\r\nexport interface SmsTunnelStatusResponse {\r\n paired: boolean;\r\n serverUrl?: string;\r\n deviceName?: string;\r\n}\r\n\r\n// --- Pairing ---\r\n\r\nexport interface CreateTokenResponse {\r\n success: boolean;\r\n token?: string;\r\n pairingCode?: string;\r\n qrData?: string;\r\n expiresAt?: string;\r\n pollUrl?: string;\r\n error?: string;\r\n}\r\n\r\nexport interface PairingStatusResponse {\r\n status: 'pending' | 'completed' | 'expired' | 'error';\r\n source?: string;\r\n displayName?: string;\r\n pairedDeviceId?: string;\r\n pairingId?: string;\r\n error?: string;\r\n}\r\n\r\n// --- SMS ---\r\n\r\nexport interface SendSmsResponse {\r\n success: boolean;\r\n messageId?: string;\r\n queued?: boolean;\r\n data?: {\r\n messageId: string;\r\n branded: boolean;\r\n queued: boolean;\r\n remaining: number;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface SmsStatusResponse {\r\n success: boolean;\r\n data?: {\r\n messageId: string;\r\n status: 'sent' | 'pending' | 'failed' | 'delivered';\r\n recipient: string;\r\n sentAt?: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface SendBulkSmsRequest {\r\n messages: Array<{ to: string; message: string }>;\r\n}\r\n\r\nexport interface SendBulkSmsResponse {\r\n success: boolean;\r\n results?: Array<{ to: string; messageId?: string; error?: string }>;\r\n error?: string;\r\n}\r\n\r\nexport interface Send2faRequest {\r\n to: string;\r\n code: string;\r\n template?: string;\r\n}\r\n\r\nexport interface ReceivedSmsResponse {\r\n success: boolean;\r\n data?: Array<{\r\n from: string;\r\n message: string;\r\n receivedAt: string;\r\n }>;\r\n error?: string;\r\n}\r\n\r\n// --- Devices ---\r\n\r\nexport interface DevicesResponse {\r\n success: boolean;\r\n data?: Array<{\r\n id: string;\r\n clientId: string;\r\n name: string;\r\n brand?: string;\r\n model?: string;\r\n connected?: boolean;\r\n }>;\r\n error?: string;\r\n}\r\n\r\n// --- Account ---\r\n\r\nexport interface AccountUsageResponse {\r\n success: boolean;\r\n data?: {\r\n messagesSent: number;\r\n messagesReceived: number;\r\n messagesSentToday: number;\r\n messagesSentMonth: number;\r\n dailyLimit?: number;\r\n monthlyLimit?: number;\r\n };\r\n error?: string;\r\n}\r\n\r\n// --- E2E Encryption ---\r\n\r\nexport interface DeviceE2EStatusResponse {\r\n success: boolean;\r\n data?: {\r\n encryptionEnabled: boolean;\r\n hasPublicKey: boolean;\r\n publicKeyFingerprint?: string;\r\n keyCreatedAt?: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface DevicePublicKeyResponse {\r\n success: boolean;\r\n data?: {\r\n deviceId: string;\r\n deviceName: string;\r\n publicKey: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface VerifyDeviceKeyResponse {\r\n valid: boolean;\r\n currentFingerprint?: string;\r\n needsRePairing: boolean;\r\n}\r\n\r\n// --- Pairings list ---\r\n\r\nexport interface PairingInfo {\r\n _id: string;\r\n deviceId: string;\r\n type: string;\r\n name: string;\r\n status: 'active' | 'paused' | 'revoked';\r\n messagesSent: number;\r\n createdAt: string;\r\n source: string;\r\n}\r\n\r\n// --- Callback ---\r\n\r\nexport type PairingEventCallback = (event: 'completed' | 'expired' | 'error', data?: any) => void;\r\n\r\nexport class SmsTunnelClient {\r\n private readonly baseUrl: string;\r\n private readonly prefix = 'smstunnel';\r\n private readonly pollInterval: number;\r\n private readonly getAuthHeaders: () => Record<string, string>;\r\n private pollTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\n constructor(options: SmsTunnelClientOptions) {\r\n this.baseUrl = options.apiBaseUrl.replace(/\\/$/, '');\r\n this.pollInterval = options.pollInterval || 3000;\r\n\r\n if (options.getAuthHeaders) {\r\n this.getAuthHeaders = options.getAuthHeaders;\r\n } else if (options.getToken) {\r\n const getToken = options.getToken;\r\n this.getAuthHeaders = (): Record<string, string> => {\r\n const token = getToken();\r\n if (token) return { Authorization: `Bearer ${token}` };\r\n return {};\r\n };\r\n } else {\r\n this.getAuthHeaders = () => ({});\r\n }\r\n }\r\n\r\n // ─── Pairing ───────────────────────────────────────\r\n\r\n /** Get current pairing status */\r\n async getStatus(): Promise<SmsTunnelStatusResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/status`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Create a pairing token (generates QR data) */\r\n async createToken(): Promise<CreateTokenResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/create-token`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Check pairing status for a token (no auth needed) */\r\n async getPairingStatus(token: string): Promise<PairingStatusResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/pairing-status/${token}`,\r\n );\r\n return res.json();\r\n }\r\n\r\n /**\r\n * Start polling for pairing completion.\r\n * Returns a cleanup function to stop polling.\r\n */\r\n startPolling(token: string, callback: PairingEventCallback): () => void {\r\n this.stopPolling();\r\n\r\n this.pollTimer = setInterval(async () => {\r\n try {\r\n const data = await this.getPairingStatus(token);\r\n if (data.status === 'completed') {\r\n this.stopPolling();\r\n callback('completed', data);\r\n } else if (data.status === 'expired') {\r\n this.stopPolling();\r\n callback('expired', data);\r\n }\r\n } catch (err) {\r\n // ignore polling errors\r\n }\r\n }, this.pollInterval);\r\n\r\n return () => this.stopPolling();\r\n }\r\n\r\n /** Stop polling */\r\n stopPolling(): void {\r\n if (this.pollTimer) {\r\n clearInterval(this.pollTimer);\r\n this.pollTimer = null;\r\n }\r\n }\r\n\r\n /** Unpair the connected device */\r\n async unpair(): Promise<{ success: boolean }> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/unpair`, {\r\n method: 'POST',\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** List active pairings (proxied through backend) */\r\n async getPairings(): Promise<PairingInfo[]> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/pairings`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── SMS ───────────────────────────────────────────\r\n\r\n /** Send a single SMS */\r\n async sendSms(to: string, message: string): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ to, message }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send a 2FA SMS */\r\n async send2fa(to: string, code: string, template?: string): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-2fa`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ to, code, template }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send bulk SMS */\r\n async sendBulk(messages: Array<{ to: string; message: string }>): Promise<SendBulkSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-bulk`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ messages }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get SMS delivery status */\r\n async getSmsStatus(messageId: string): Promise<SmsStatusResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/sms-status/${messageId}`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get received SMS (inbox) */\r\n async getReceivedSms(): Promise<ReceivedSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/received`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── Devices & Account ─────────────────────────────\r\n\r\n /** List paired devices */\r\n async getDevices(): Promise<DevicesResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/devices`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get account usage stats */\r\n async getUsage(): Promise<AccountUsageResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/usage`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── E2E Encryption ────────────────────────────────\r\n\r\n /** Get E2E encryption status for a device */\r\n async getDeviceE2EStatus(deviceId: string): Promise<DeviceE2EStatusResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/e2e-status/${deviceId}`,\r\n { headers: this.getAuthHeaders() },\r\n );\r\n return res.json();\r\n }\r\n\r\n /** Get device public key for E2E encryption */\r\n async getDevicePublicKey(deviceId: string): Promise<DevicePublicKeyResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/public-key/${deviceId}`,\r\n { headers: this.getAuthHeaders() },\r\n );\r\n return res.json();\r\n }\r\n\r\n /** Verify that a stored fingerprint matches the current device key */\r\n async verifyDeviceKey(\r\n deviceId: string,\r\n fingerprint: string,\r\n ): Promise<VerifyDeviceKeyResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/verify-key`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ deviceId, fingerprint }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send an encrypted SMS (payload already encrypted with device public key) */\r\n async sendEncryptedSms(\r\n encryptedPayload: string,\r\n deviceId: string,\r\n is2FA: boolean = false,\r\n ): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-encrypted`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ encryptedPayload, deviceId, is2FA }),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── Config ────────────────────────────────────────\r\n\r\n /** Update server URL configuration */\r\n async updateServerUrl(serverUrl: string): Promise<{ success: boolean }> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/update-config`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ serverUrl }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Destroy - cleanup polling */\r\n destroy(): void {\r\n this.stopPolling();\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -21,7 +21,9 @@ var EN_LABELS = {
|
|
|
21
21
|
testMessagePlaceholder: "Message",
|
|
22
22
|
sendTestButton: "Send",
|
|
23
23
|
smsSentSuccess: "SMS sent successfully!",
|
|
24
|
-
smsError: "Error"
|
|
24
|
+
smsError: "Error",
|
|
25
|
+
pairingCodeLabel: "Or enter this code in the app:",
|
|
26
|
+
pairingCodeCopied: "Code copied!"
|
|
25
27
|
};
|
|
26
28
|
var RO_LABELS = {
|
|
27
29
|
title: "Configurare SMS (SMSTunnel)",
|
|
@@ -45,7 +47,9 @@ var RO_LABELS = {
|
|
|
45
47
|
testMessagePlaceholder: "Mesaj",
|
|
46
48
|
sendTestButton: "Trimite",
|
|
47
49
|
smsSentSuccess: "SMS trimis cu succes!",
|
|
48
|
-
smsError: "Eroare"
|
|
50
|
+
smsError: "Eroare",
|
|
51
|
+
pairingCodeLabel: "Sau introdu acest cod in aplicatie:",
|
|
52
|
+
pairingCodeCopied: "Cod copiat!"
|
|
49
53
|
};
|
|
50
54
|
|
|
51
55
|
// src/client.ts
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/labels.ts","../src/client.ts"],"sourcesContent":["export interface SmsTunnelLabels {\r\n title: string;\r\n description: string;\r\n serverUrlLabel: string;\r\n serverUrlPlaceholder: string;\r\n saveButton: string;\r\n pairedStatus: string;\r\n deviceLabel: string;\r\n unpairButton: string;\r\n unpairConfirm: string;\r\n notPairedStatus: string;\r\n notPairedDescription: string;\r\n connectButton: string;\r\n scanQrPrompt: string;\r\n waitingForPairing: string;\r\n cancelButton: string;\r\n qrExpired: string;\r\n testSmsTitle: string;\r\n testPhonePlaceholder: string;\r\n testMessagePlaceholder: string;\r\n sendTestButton: string;\r\n smsSentSuccess: string;\r\n smsError: string;\r\n}\r\n\r\nexport const EN_LABELS: SmsTunnelLabels = {\r\n title: 'SMS Configuration (SMSTunnel)',\r\n description: 'Connect an Android phone with the SMSTunnel app to send SMS directly from the application.',\r\n serverUrlLabel: 'SMSTunnel Server',\r\n serverUrlPlaceholder: 'https://smstunnel.io',\r\n saveButton: 'Save',\r\n pairedStatus: 'Connected',\r\n deviceLabel: 'Device',\r\n unpairButton: 'Disconnect',\r\n unpairConfirm: 'Are you sure you want to disconnect the SMS device?',\r\n notPairedStatus: 'Not connected',\r\n notPairedDescription: 'Scan the QR code with the SMSTunnel app on your Android phone.',\r\n connectButton: 'Connect phone',\r\n scanQrPrompt: 'Scan this QR code with the SMSTunnel app on your phone:',\r\n waitingForPairing: 'Waiting for connection...',\r\n cancelButton: 'Cancel',\r\n qrExpired: 'QR code has expired. Generate a new one.',\r\n testSmsTitle: 'Send test SMS',\r\n testPhonePlaceholder: 'Phone number (e.g., +1234567890)',\r\n testMessagePlaceholder: 'Message',\r\n sendTestButton: 'Send',\r\n smsSentSuccess: 'SMS sent successfully!',\r\n smsError: 'Error',\r\n};\r\n\r\nexport const RO_LABELS: SmsTunnelLabels = {\r\n title: 'Configurare SMS (SMSTunnel)',\r\n description: 'Conecteaza un telefon Android cu aplicatia SMSTunnel pentru a trimite SMS-uri direct din aplicatie.',\r\n serverUrlLabel: 'Server SMSTunnel',\r\n serverUrlPlaceholder: 'https://smstunnel.io',\r\n saveButton: 'Salveaza',\r\n pairedStatus: 'Conectat',\r\n deviceLabel: 'Dispozitiv',\r\n unpairButton: 'Deconecteaza',\r\n unpairConfirm: 'Sigur doresti sa deconectezi dispozitivul SMS?',\r\n notPairedStatus: 'Neconectat',\r\n notPairedDescription: 'Scaneaza codul QR cu aplicatia SMSTunnel de pe telefonul Android.',\r\n connectButton: 'Conecteaza telefon',\r\n scanQrPrompt: 'Scaneaza acest cod QR cu aplicatia SMSTunnel de pe telefon:',\r\n waitingForPairing: 'Se asteapta conectarea...',\r\n cancelButton: 'Anuleaza',\r\n qrExpired: 'Codul QR a expirat. Genereaza unul nou.',\r\n testSmsTitle: 'Trimite SMS de test',\r\n testPhonePlaceholder: 'Nr. telefon (ex: 0741234567)',\r\n testMessagePlaceholder: 'Mesaj',\r\n sendTestButton: 'Trimite',\r\n smsSentSuccess: 'SMS trimis cu succes!',\r\n smsError: 'Eroare',\r\n};\r\n","/**\r\n * Framework-agnostic SMSTunnel client.\r\n *\r\n * Works with Angular, Svelte, Astro, Solid, Vanilla JS, or any framework.\r\n * For React use `smstunnel-sdk/react`, for Vue use `smstunnel-sdk/vue`.\r\n */\r\nexport interface SmsTunnelClientOptions {\r\n apiBaseUrl: string;\r\n /** Return the current JWT/auth token. SDK adds Authorization: Bearer header automatically. */\r\n getToken?: () => string | null;\r\n /** Full control over auth headers. Takes precedence over getToken. */\r\n getAuthHeaders?: () => Record<string, string>;\r\n pollInterval?: number;\r\n}\r\n\r\n// --- Status ---\r\n\r\nexport interface SmsTunnelStatusResponse {\r\n paired: boolean;\r\n serverUrl?: string;\r\n deviceName?: string;\r\n}\r\n\r\n// --- Pairing ---\r\n\r\nexport interface CreateTokenResponse {\r\n success: boolean;\r\n token?: string;\r\n qrData?: string;\r\n expiresAt?: string;\r\n pollUrl?: string;\r\n error?: string;\r\n}\r\n\r\nexport interface PairingStatusResponse {\r\n status: 'pending' | 'completed' | 'expired' | 'error';\r\n source?: string;\r\n displayName?: string;\r\n pairedDeviceId?: string;\r\n pairingId?: string;\r\n error?: string;\r\n}\r\n\r\n// --- SMS ---\r\n\r\nexport interface SendSmsResponse {\r\n success: boolean;\r\n messageId?: string;\r\n queued?: boolean;\r\n data?: {\r\n messageId: string;\r\n branded: boolean;\r\n queued: boolean;\r\n remaining: number;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface SmsStatusResponse {\r\n success: boolean;\r\n data?: {\r\n messageId: string;\r\n status: 'sent' | 'pending' | 'failed' | 'delivered';\r\n recipient: string;\r\n sentAt?: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface SendBulkSmsRequest {\r\n messages: Array<{ to: string; message: string }>;\r\n}\r\n\r\nexport interface SendBulkSmsResponse {\r\n success: boolean;\r\n results?: Array<{ to: string; messageId?: string; error?: string }>;\r\n error?: string;\r\n}\r\n\r\nexport interface Send2faRequest {\r\n to: string;\r\n code: string;\r\n template?: string;\r\n}\r\n\r\nexport interface ReceivedSmsResponse {\r\n success: boolean;\r\n data?: Array<{\r\n from: string;\r\n message: string;\r\n receivedAt: string;\r\n }>;\r\n error?: string;\r\n}\r\n\r\n// --- Devices ---\r\n\r\nexport interface DevicesResponse {\r\n success: boolean;\r\n data?: Array<{\r\n id: string;\r\n clientId: string;\r\n name: string;\r\n brand?: string;\r\n model?: string;\r\n connected?: boolean;\r\n }>;\r\n error?: string;\r\n}\r\n\r\n// --- Account ---\r\n\r\nexport interface AccountUsageResponse {\r\n success: boolean;\r\n data?: {\r\n messagesSent: number;\r\n messagesReceived: number;\r\n messagesSentToday: number;\r\n messagesSentMonth: number;\r\n dailyLimit?: number;\r\n monthlyLimit?: number;\r\n };\r\n error?: string;\r\n}\r\n\r\n// --- E2E Encryption ---\r\n\r\nexport interface DeviceE2EStatusResponse {\r\n success: boolean;\r\n data?: {\r\n encryptionEnabled: boolean;\r\n hasPublicKey: boolean;\r\n publicKeyFingerprint?: string;\r\n keyCreatedAt?: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface DevicePublicKeyResponse {\r\n success: boolean;\r\n data?: {\r\n deviceId: string;\r\n deviceName: string;\r\n publicKey: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface VerifyDeviceKeyResponse {\r\n valid: boolean;\r\n currentFingerprint?: string;\r\n needsRePairing: boolean;\r\n}\r\n\r\n// --- Pairings list ---\r\n\r\nexport interface PairingInfo {\r\n _id: string;\r\n deviceId: string;\r\n type: string;\r\n name: string;\r\n status: 'active' | 'paused' | 'revoked';\r\n messagesSent: number;\r\n createdAt: string;\r\n source: string;\r\n}\r\n\r\n// --- Callback ---\r\n\r\nexport type PairingEventCallback = (event: 'completed' | 'expired' | 'error', data?: any) => void;\r\n\r\nexport class SmsTunnelClient {\r\n private readonly baseUrl: string;\r\n private readonly prefix = 'smstunnel';\r\n private readonly pollInterval: number;\r\n private readonly getAuthHeaders: () => Record<string, string>;\r\n private pollTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\n constructor(options: SmsTunnelClientOptions) {\r\n this.baseUrl = options.apiBaseUrl.replace(/\\/$/, '');\r\n this.pollInterval = options.pollInterval || 3000;\r\n\r\n if (options.getAuthHeaders) {\r\n this.getAuthHeaders = options.getAuthHeaders;\r\n } else if (options.getToken) {\r\n const getToken = options.getToken;\r\n this.getAuthHeaders = (): Record<string, string> => {\r\n const token = getToken();\r\n if (token) return { Authorization: `Bearer ${token}` };\r\n return {};\r\n };\r\n } else {\r\n this.getAuthHeaders = () => ({});\r\n }\r\n }\r\n\r\n // ─── Pairing ───────────────────────────────────────\r\n\r\n /** Get current pairing status */\r\n async getStatus(): Promise<SmsTunnelStatusResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/status`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Create a pairing token (generates QR data) */\r\n async createToken(): Promise<CreateTokenResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/create-token`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Check pairing status for a token (no auth needed) */\r\n async getPairingStatus(token: string): Promise<PairingStatusResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/pairing-status/${token}`,\r\n );\r\n return res.json();\r\n }\r\n\r\n /**\r\n * Start polling for pairing completion.\r\n * Returns a cleanup function to stop polling.\r\n */\r\n startPolling(token: string, callback: PairingEventCallback): () => void {\r\n this.stopPolling();\r\n\r\n this.pollTimer = setInterval(async () => {\r\n try {\r\n const data = await this.getPairingStatus(token);\r\n if (data.status === 'completed') {\r\n this.stopPolling();\r\n callback('completed', data);\r\n } else if (data.status === 'expired') {\r\n this.stopPolling();\r\n callback('expired', data);\r\n }\r\n } catch (err) {\r\n // ignore polling errors\r\n }\r\n }, this.pollInterval);\r\n\r\n return () => this.stopPolling();\r\n }\r\n\r\n /** Stop polling */\r\n stopPolling(): void {\r\n if (this.pollTimer) {\r\n clearInterval(this.pollTimer);\r\n this.pollTimer = null;\r\n }\r\n }\r\n\r\n /** Unpair the connected device */\r\n async unpair(): Promise<{ success: boolean }> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/unpair`, {\r\n method: 'POST',\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** List active pairings (proxied through backend) */\r\n async getPairings(): Promise<PairingInfo[]> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/pairings`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── SMS ───────────────────────────────────────────\r\n\r\n /** Send a single SMS */\r\n async sendSms(to: string, message: string): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ to, message }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send a 2FA SMS */\r\n async send2fa(to: string, code: string, template?: string): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-2fa`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ to, code, template }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send bulk SMS */\r\n async sendBulk(messages: Array<{ to: string; message: string }>): Promise<SendBulkSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-bulk`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ messages }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get SMS delivery status */\r\n async getSmsStatus(messageId: string): Promise<SmsStatusResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/sms-status/${messageId}`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get received SMS (inbox) */\r\n async getReceivedSms(): Promise<ReceivedSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/received`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── Devices & Account ─────────────────────────────\r\n\r\n /** List paired devices */\r\n async getDevices(): Promise<DevicesResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/devices`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get account usage stats */\r\n async getUsage(): Promise<AccountUsageResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/usage`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── E2E Encryption ────────────────────────────────\r\n\r\n /** Get E2E encryption status for a device */\r\n async getDeviceE2EStatus(deviceId: string): Promise<DeviceE2EStatusResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/e2e-status/${deviceId}`,\r\n { headers: this.getAuthHeaders() },\r\n );\r\n return res.json();\r\n }\r\n\r\n /** Get device public key for E2E encryption */\r\n async getDevicePublicKey(deviceId: string): Promise<DevicePublicKeyResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/public-key/${deviceId}`,\r\n { headers: this.getAuthHeaders() },\r\n );\r\n return res.json();\r\n }\r\n\r\n /** Verify that a stored fingerprint matches the current device key */\r\n async verifyDeviceKey(\r\n deviceId: string,\r\n fingerprint: string,\r\n ): Promise<VerifyDeviceKeyResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/verify-key`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ deviceId, fingerprint }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send an encrypted SMS (payload already encrypted with device public key) */\r\n async sendEncryptedSms(\r\n encryptedPayload: string,\r\n deviceId: string,\r\n is2FA: boolean = false,\r\n ): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-encrypted`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ encryptedPayload, deviceId, is2FA }),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── Config ────────────────────────────────────────\r\n\r\n /** Update server URL configuration */\r\n async updateServerUrl(serverUrl: string): Promise<{ success: boolean }> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/update-config`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ serverUrl }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Destroy - cleanup polling */\r\n destroy(): void {\r\n this.stopPolling();\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/shared/labels.ts","../src/client.ts"],"sourcesContent":["export interface SmsTunnelLabels {\r\n title: string;\r\n description: string;\r\n serverUrlLabel: string;\r\n serverUrlPlaceholder: string;\r\n saveButton: string;\r\n pairedStatus: string;\r\n deviceLabel: string;\r\n unpairButton: string;\r\n unpairConfirm: string;\r\n notPairedStatus: string;\r\n notPairedDescription: string;\r\n connectButton: string;\r\n scanQrPrompt: string;\r\n waitingForPairing: string;\r\n cancelButton: string;\r\n qrExpired: string;\r\n testSmsTitle: string;\r\n testPhonePlaceholder: string;\r\n testMessagePlaceholder: string;\r\n sendTestButton: string;\r\n smsSentSuccess: string;\r\n smsError: string;\r\n pairingCodeLabel: string;\r\n pairingCodeCopied: string;\r\n}\r\n\r\nexport const EN_LABELS: SmsTunnelLabels = {\r\n title: 'SMS Configuration (SMSTunnel)',\r\n description: 'Connect an Android phone with the SMSTunnel app to send SMS directly from the application.',\r\n serverUrlLabel: 'SMSTunnel Server',\r\n serverUrlPlaceholder: 'https://smstunnel.io',\r\n saveButton: 'Save',\r\n pairedStatus: 'Connected',\r\n deviceLabel: 'Device',\r\n unpairButton: 'Disconnect',\r\n unpairConfirm: 'Are you sure you want to disconnect the SMS device?',\r\n notPairedStatus: 'Not connected',\r\n notPairedDescription: 'Scan the QR code with the SMSTunnel app on your Android phone.',\r\n connectButton: 'Connect phone',\r\n scanQrPrompt: 'Scan this QR code with the SMSTunnel app on your phone:',\r\n waitingForPairing: 'Waiting for connection...',\r\n cancelButton: 'Cancel',\r\n qrExpired: 'QR code has expired. Generate a new one.',\r\n testSmsTitle: 'Send test SMS',\r\n testPhonePlaceholder: 'Phone number (e.g., +1234567890)',\r\n testMessagePlaceholder: 'Message',\r\n sendTestButton: 'Send',\r\n smsSentSuccess: 'SMS sent successfully!',\r\n smsError: 'Error',\r\n pairingCodeLabel: 'Or enter this code in the app:',\r\n pairingCodeCopied: 'Code copied!',\r\n};\r\n\r\nexport const RO_LABELS: SmsTunnelLabels = {\r\n title: 'Configurare SMS (SMSTunnel)',\r\n description: 'Conecteaza un telefon Android cu aplicatia SMSTunnel pentru a trimite SMS-uri direct din aplicatie.',\r\n serverUrlLabel: 'Server SMSTunnel',\r\n serverUrlPlaceholder: 'https://smstunnel.io',\r\n saveButton: 'Salveaza',\r\n pairedStatus: 'Conectat',\r\n deviceLabel: 'Dispozitiv',\r\n unpairButton: 'Deconecteaza',\r\n unpairConfirm: 'Sigur doresti sa deconectezi dispozitivul SMS?',\r\n notPairedStatus: 'Neconectat',\r\n notPairedDescription: 'Scaneaza codul QR cu aplicatia SMSTunnel de pe telefonul Android.',\r\n connectButton: 'Conecteaza telefon',\r\n scanQrPrompt: 'Scaneaza acest cod QR cu aplicatia SMSTunnel de pe telefon:',\r\n waitingForPairing: 'Se asteapta conectarea...',\r\n cancelButton: 'Anuleaza',\r\n qrExpired: 'Codul QR a expirat. Genereaza unul nou.',\r\n testSmsTitle: 'Trimite SMS de test',\r\n testPhonePlaceholder: 'Nr. telefon (ex: 0741234567)',\r\n testMessagePlaceholder: 'Mesaj',\r\n sendTestButton: 'Trimite',\r\n smsSentSuccess: 'SMS trimis cu succes!',\r\n smsError: 'Eroare',\r\n pairingCodeLabel: 'Sau introdu acest cod in aplicatie:',\r\n pairingCodeCopied: 'Cod copiat!',\r\n};\r\n","/**\r\n * Framework-agnostic SMSTunnel client.\r\n *\r\n * Works with Angular, Svelte, Astro, Solid, Vanilla JS, or any framework.\r\n * For React use `smstunnel-sdk/react`, for Vue use `smstunnel-sdk/vue`.\r\n */\r\nexport interface SmsTunnelClientOptions {\r\n apiBaseUrl: string;\r\n /** Return the current JWT/auth token. SDK adds Authorization: Bearer header automatically. */\r\n getToken?: () => string | null;\r\n /** Full control over auth headers. Takes precedence over getToken. */\r\n getAuthHeaders?: () => Record<string, string>;\r\n pollInterval?: number;\r\n}\r\n\r\n// --- Status ---\r\n\r\nexport interface SmsTunnelStatusResponse {\r\n paired: boolean;\r\n serverUrl?: string;\r\n deviceName?: string;\r\n}\r\n\r\n// --- Pairing ---\r\n\r\nexport interface CreateTokenResponse {\r\n success: boolean;\r\n token?: string;\r\n pairingCode?: string;\r\n qrData?: string;\r\n expiresAt?: string;\r\n pollUrl?: string;\r\n error?: string;\r\n}\r\n\r\nexport interface PairingStatusResponse {\r\n status: 'pending' | 'completed' | 'expired' | 'error';\r\n source?: string;\r\n displayName?: string;\r\n pairedDeviceId?: string;\r\n pairingId?: string;\r\n error?: string;\r\n}\r\n\r\n// --- SMS ---\r\n\r\nexport interface SendSmsResponse {\r\n success: boolean;\r\n messageId?: string;\r\n queued?: boolean;\r\n data?: {\r\n messageId: string;\r\n branded: boolean;\r\n queued: boolean;\r\n remaining: number;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface SmsStatusResponse {\r\n success: boolean;\r\n data?: {\r\n messageId: string;\r\n status: 'sent' | 'pending' | 'failed' | 'delivered';\r\n recipient: string;\r\n sentAt?: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface SendBulkSmsRequest {\r\n messages: Array<{ to: string; message: string }>;\r\n}\r\n\r\nexport interface SendBulkSmsResponse {\r\n success: boolean;\r\n results?: Array<{ to: string; messageId?: string; error?: string }>;\r\n error?: string;\r\n}\r\n\r\nexport interface Send2faRequest {\r\n to: string;\r\n code: string;\r\n template?: string;\r\n}\r\n\r\nexport interface ReceivedSmsResponse {\r\n success: boolean;\r\n data?: Array<{\r\n from: string;\r\n message: string;\r\n receivedAt: string;\r\n }>;\r\n error?: string;\r\n}\r\n\r\n// --- Devices ---\r\n\r\nexport interface DevicesResponse {\r\n success: boolean;\r\n data?: Array<{\r\n id: string;\r\n clientId: string;\r\n name: string;\r\n brand?: string;\r\n model?: string;\r\n connected?: boolean;\r\n }>;\r\n error?: string;\r\n}\r\n\r\n// --- Account ---\r\n\r\nexport interface AccountUsageResponse {\r\n success: boolean;\r\n data?: {\r\n messagesSent: number;\r\n messagesReceived: number;\r\n messagesSentToday: number;\r\n messagesSentMonth: number;\r\n dailyLimit?: number;\r\n monthlyLimit?: number;\r\n };\r\n error?: string;\r\n}\r\n\r\n// --- E2E Encryption ---\r\n\r\nexport interface DeviceE2EStatusResponse {\r\n success: boolean;\r\n data?: {\r\n encryptionEnabled: boolean;\r\n hasPublicKey: boolean;\r\n publicKeyFingerprint?: string;\r\n keyCreatedAt?: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface DevicePublicKeyResponse {\r\n success: boolean;\r\n data?: {\r\n deviceId: string;\r\n deviceName: string;\r\n publicKey: string;\r\n };\r\n error?: string;\r\n}\r\n\r\nexport interface VerifyDeviceKeyResponse {\r\n valid: boolean;\r\n currentFingerprint?: string;\r\n needsRePairing: boolean;\r\n}\r\n\r\n// --- Pairings list ---\r\n\r\nexport interface PairingInfo {\r\n _id: string;\r\n deviceId: string;\r\n type: string;\r\n name: string;\r\n status: 'active' | 'paused' | 'revoked';\r\n messagesSent: number;\r\n createdAt: string;\r\n source: string;\r\n}\r\n\r\n// --- Callback ---\r\n\r\nexport type PairingEventCallback = (event: 'completed' | 'expired' | 'error', data?: any) => void;\r\n\r\nexport class SmsTunnelClient {\r\n private readonly baseUrl: string;\r\n private readonly prefix = 'smstunnel';\r\n private readonly pollInterval: number;\r\n private readonly getAuthHeaders: () => Record<string, string>;\r\n private pollTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\n constructor(options: SmsTunnelClientOptions) {\r\n this.baseUrl = options.apiBaseUrl.replace(/\\/$/, '');\r\n this.pollInterval = options.pollInterval || 3000;\r\n\r\n if (options.getAuthHeaders) {\r\n this.getAuthHeaders = options.getAuthHeaders;\r\n } else if (options.getToken) {\r\n const getToken = options.getToken;\r\n this.getAuthHeaders = (): Record<string, string> => {\r\n const token = getToken();\r\n if (token) return { Authorization: `Bearer ${token}` };\r\n return {};\r\n };\r\n } else {\r\n this.getAuthHeaders = () => ({});\r\n }\r\n }\r\n\r\n // ─── Pairing ───────────────────────────────────────\r\n\r\n /** Get current pairing status */\r\n async getStatus(): Promise<SmsTunnelStatusResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/status`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Create a pairing token (generates QR data) */\r\n async createToken(): Promise<CreateTokenResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/create-token`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Check pairing status for a token (no auth needed) */\r\n async getPairingStatus(token: string): Promise<PairingStatusResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/pairing-status/${token}`,\r\n );\r\n return res.json();\r\n }\r\n\r\n /**\r\n * Start polling for pairing completion.\r\n * Returns a cleanup function to stop polling.\r\n */\r\n startPolling(token: string, callback: PairingEventCallback): () => void {\r\n this.stopPolling();\r\n\r\n this.pollTimer = setInterval(async () => {\r\n try {\r\n const data = await this.getPairingStatus(token);\r\n if (data.status === 'completed') {\r\n this.stopPolling();\r\n callback('completed', data);\r\n } else if (data.status === 'expired') {\r\n this.stopPolling();\r\n callback('expired', data);\r\n }\r\n } catch (err) {\r\n // ignore polling errors\r\n }\r\n }, this.pollInterval);\r\n\r\n return () => this.stopPolling();\r\n }\r\n\r\n /** Stop polling */\r\n stopPolling(): void {\r\n if (this.pollTimer) {\r\n clearInterval(this.pollTimer);\r\n this.pollTimer = null;\r\n }\r\n }\r\n\r\n /** Unpair the connected device */\r\n async unpair(): Promise<{ success: boolean }> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/unpair`, {\r\n method: 'POST',\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** List active pairings (proxied through backend) */\r\n async getPairings(): Promise<PairingInfo[]> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/pairings`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── SMS ───────────────────────────────────────────\r\n\r\n /** Send a single SMS */\r\n async sendSms(to: string, message: string): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ to, message }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send a 2FA SMS */\r\n async send2fa(to: string, code: string, template?: string): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-2fa`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ to, code, template }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send bulk SMS */\r\n async sendBulk(messages: Array<{ to: string; message: string }>): Promise<SendBulkSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-bulk`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ messages }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get SMS delivery status */\r\n async getSmsStatus(messageId: string): Promise<SmsStatusResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/sms-status/${messageId}`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get received SMS (inbox) */\r\n async getReceivedSms(): Promise<ReceivedSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/received`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── Devices & Account ─────────────────────────────\r\n\r\n /** List paired devices */\r\n async getDevices(): Promise<DevicesResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/devices`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Get account usage stats */\r\n async getUsage(): Promise<AccountUsageResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/usage`, {\r\n headers: this.getAuthHeaders(),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── E2E Encryption ────────────────────────────────\r\n\r\n /** Get E2E encryption status for a device */\r\n async getDeviceE2EStatus(deviceId: string): Promise<DeviceE2EStatusResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/e2e-status/${deviceId}`,\r\n { headers: this.getAuthHeaders() },\r\n );\r\n return res.json();\r\n }\r\n\r\n /** Get device public key for E2E encryption */\r\n async getDevicePublicKey(deviceId: string): Promise<DevicePublicKeyResponse> {\r\n const res = await fetch(\r\n `${this.baseUrl}/${this.prefix}/public-key/${deviceId}`,\r\n { headers: this.getAuthHeaders() },\r\n );\r\n return res.json();\r\n }\r\n\r\n /** Verify that a stored fingerprint matches the current device key */\r\n async verifyDeviceKey(\r\n deviceId: string,\r\n fingerprint: string,\r\n ): Promise<VerifyDeviceKeyResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/verify-key`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ deviceId, fingerprint }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Send an encrypted SMS (payload already encrypted with device public key) */\r\n async sendEncryptedSms(\r\n encryptedPayload: string,\r\n deviceId: string,\r\n is2FA: boolean = false,\r\n ): Promise<SendSmsResponse> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/send-encrypted`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ encryptedPayload, deviceId, is2FA }),\r\n });\r\n return res.json();\r\n }\r\n\r\n // ─── Config ────────────────────────────────────────\r\n\r\n /** Update server URL configuration */\r\n async updateServerUrl(serverUrl: string): Promise<{ success: boolean }> {\r\n const res = await fetch(`${this.baseUrl}/${this.prefix}/update-config`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...this.getAuthHeaders(),\r\n },\r\n body: JSON.stringify({ serverUrl }),\r\n });\r\n return res.json();\r\n }\r\n\r\n /** Destroy - cleanup polling */\r\n destroy(): void {\r\n this.stopPolling();\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/react/index.d.mts
CHANGED
|
@@ -23,6 +23,8 @@ interface SmsTunnelLabels {
|
|
|
23
23
|
sendTestButton: string;
|
|
24
24
|
smsSentSuccess: string;
|
|
25
25
|
smsError: string;
|
|
26
|
+
pairingCodeLabel: string;
|
|
27
|
+
pairingCodeCopied: string;
|
|
26
28
|
}
|
|
27
29
|
declare const EN_LABELS: SmsTunnelLabels;
|
|
28
30
|
declare const RO_LABELS: SmsTunnelLabels;
|
|
@@ -57,6 +59,7 @@ interface SmsTunnelState {
|
|
|
57
59
|
deviceName: string;
|
|
58
60
|
showQr: boolean;
|
|
59
61
|
qrData: string;
|
|
62
|
+
pairingCode: string;
|
|
60
63
|
generating: boolean;
|
|
61
64
|
polling: boolean;
|
|
62
65
|
error: string;
|
|
@@ -93,6 +96,7 @@ declare function useSmsTunnel(options: UseSmsTunnelOptions): {
|
|
|
93
96
|
deviceName: string;
|
|
94
97
|
showQr: boolean;
|
|
95
98
|
qrData: string;
|
|
99
|
+
pairingCode: string;
|
|
96
100
|
generating: boolean;
|
|
97
101
|
polling: boolean;
|
|
98
102
|
error: string;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ interface SmsTunnelLabels {
|
|
|
23
23
|
sendTestButton: string;
|
|
24
24
|
smsSentSuccess: string;
|
|
25
25
|
smsError: string;
|
|
26
|
+
pairingCodeLabel: string;
|
|
27
|
+
pairingCodeCopied: string;
|
|
26
28
|
}
|
|
27
29
|
declare const EN_LABELS: SmsTunnelLabels;
|
|
28
30
|
declare const RO_LABELS: SmsTunnelLabels;
|
|
@@ -57,6 +59,7 @@ interface SmsTunnelState {
|
|
|
57
59
|
deviceName: string;
|
|
58
60
|
showQr: boolean;
|
|
59
61
|
qrData: string;
|
|
62
|
+
pairingCode: string;
|
|
60
63
|
generating: boolean;
|
|
61
64
|
polling: boolean;
|
|
62
65
|
error: string;
|
|
@@ -93,6 +96,7 @@ declare function useSmsTunnel(options: UseSmsTunnelOptions): {
|
|
|
93
96
|
deviceName: string;
|
|
94
97
|
showQr: boolean;
|
|
95
98
|
qrData: string;
|
|
99
|
+
pairingCode: string;
|
|
96
100
|
generating: boolean;
|
|
97
101
|
polling: boolean;
|
|
98
102
|
error: string;
|
package/dist/react/index.js
CHANGED
|
@@ -52,6 +52,7 @@ function useSmsTunnel(options) {
|
|
|
52
52
|
deviceName: "",
|
|
53
53
|
showQr: false,
|
|
54
54
|
qrData: "",
|
|
55
|
+
pairingCode: "",
|
|
55
56
|
generating: false,
|
|
56
57
|
polling: false,
|
|
57
58
|
error: ""
|
|
@@ -137,6 +138,7 @@ function useSmsTunnel(options) {
|
|
|
137
138
|
setState((prev) => ({
|
|
138
139
|
...prev,
|
|
139
140
|
qrData: data.qrData,
|
|
141
|
+
pairingCode: data.pairingCode || "",
|
|
140
142
|
showQr: true,
|
|
141
143
|
polling: true,
|
|
142
144
|
generating: false
|
|
@@ -156,7 +158,8 @@ function useSmsTunnel(options) {
|
|
|
156
158
|
...prev,
|
|
157
159
|
showQr: false,
|
|
158
160
|
polling: false,
|
|
159
|
-
qrData: ""
|
|
161
|
+
qrData: "",
|
|
162
|
+
pairingCode: ""
|
|
160
163
|
}));
|
|
161
164
|
}, []);
|
|
162
165
|
const unpair = (0, import_react.useCallback)(async () => {
|
|
@@ -340,7 +343,9 @@ var EN_LABELS = {
|
|
|
340
343
|
testMessagePlaceholder: "Message",
|
|
341
344
|
sendTestButton: "Send",
|
|
342
345
|
smsSentSuccess: "SMS sent successfully!",
|
|
343
|
-
smsError: "Error"
|
|
346
|
+
smsError: "Error",
|
|
347
|
+
pairingCodeLabel: "Or enter this code in the app:",
|
|
348
|
+
pairingCodeCopied: "Code copied!"
|
|
344
349
|
};
|
|
345
350
|
var RO_LABELS = {
|
|
346
351
|
title: "Configurare SMS (SMSTunnel)",
|
|
@@ -364,7 +369,9 @@ var RO_LABELS = {
|
|
|
364
369
|
testMessagePlaceholder: "Mesaj",
|
|
365
370
|
sendTestButton: "Trimite",
|
|
366
371
|
smsSentSuccess: "SMS trimis cu succes!",
|
|
367
|
-
smsError: "Eroare"
|
|
372
|
+
smsError: "Eroare",
|
|
373
|
+
pairingCodeLabel: "Sau introdu acest cod in aplicatie:",
|
|
374
|
+
pairingCodeCopied: "Cod copiat!"
|
|
368
375
|
};
|
|
369
376
|
|
|
370
377
|
// src/react/SmsTunnelPairing.tsx
|
|
@@ -700,6 +707,36 @@ function SmsTunnelPairing({
|
|
|
700
707
|
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.qrContainer, children: [
|
|
701
708
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: "13px", color: "#4b5563", marginBottom: "12px" }, children: labels.scanQrPrompt }),
|
|
702
709
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.qrFrame, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(QrCodeCanvas, { value: tunnel.qrData, size: qrSize }) }),
|
|
710
|
+
tunnel.pairingCode && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: {
|
|
711
|
+
marginTop: "12px",
|
|
712
|
+
marginBottom: "12px",
|
|
713
|
+
padding: "12px",
|
|
714
|
+
backgroundColor: "#f9fafb",
|
|
715
|
+
borderRadius: "8px",
|
|
716
|
+
border: "1px solid #e5e7eb",
|
|
717
|
+
textAlign: "center"
|
|
718
|
+
}, children: [
|
|
719
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: "12px", color: "#6b7280", marginBottom: "6px" }, children: labels.pairingCodeLabel }),
|
|
720
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
721
|
+
"div",
|
|
722
|
+
{
|
|
723
|
+
style: {
|
|
724
|
+
fontSize: "28px",
|
|
725
|
+
fontWeight: 700,
|
|
726
|
+
fontFamily: "monospace",
|
|
727
|
+
letterSpacing: "0.3em",
|
|
728
|
+
color: "#111827",
|
|
729
|
+
cursor: "pointer",
|
|
730
|
+
userSelect: "all"
|
|
731
|
+
},
|
|
732
|
+
onClick: () => {
|
|
733
|
+
navigator.clipboard?.writeText(tunnel.pairingCode);
|
|
734
|
+
},
|
|
735
|
+
title: "Click to copy",
|
|
736
|
+
children: tunnel.pairingCode
|
|
737
|
+
}
|
|
738
|
+
)
|
|
739
|
+
] }),
|
|
703
740
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
704
741
|
"div",
|
|
705
742
|
{
|