@narcisbodea/smstunnel-sdk 1.1.3 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -63
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,74 @@
|
|
|
1
|
-
# smstunnel-sdk
|
|
1
|
+
# @narcisbodea/smstunnel-sdk
|
|
2
2
|
|
|
3
|
-
SMSTunnel SDK - NestJS + React + Vue + framework-agnostic client for SMS pairing.
|
|
3
|
+
SMSTunnel SDK - Node.js + NestJS + React + Vue + Angular + framework-agnostic client for SMS pairing & E2E encryption.
|
|
4
4
|
|
|
5
5
|
| Import path | Scope |
|
|
6
6
|
|---|---|
|
|
7
|
-
|
|
|
8
|
-
|
|
|
9
|
-
|
|
|
10
|
-
|
|
|
7
|
+
| `@narcisbodea/smstunnel-sdk` | `SmsTunnelClient` class + types + labels (Svelte, Astro, Solid, Vanilla JS) |
|
|
8
|
+
| `@narcisbodea/smstunnel-sdk/server` | NestJS module (backend proxy) |
|
|
9
|
+
| `@narcisbodea/smstunnel-sdk/react` | React components + hook (Next.js, Remix, Gatsby) |
|
|
10
|
+
| `@narcisbodea/smstunnel-sdk/vue` | Vue 3 components + composable (Nuxt) |
|
|
11
|
+
| `@narcisbodea/smstunnel-sdk/angular` | Angular 17+ injectable service |
|
|
12
|
+
| `@narcisbodea/smstunnel-sdk/node` | Standalone Node.js client (no framework, API key auth) |
|
|
11
13
|
|
|
12
14
|
## Install
|
|
13
15
|
|
|
14
16
|
```bash
|
|
15
|
-
npm install smstunnel-sdk
|
|
17
|
+
npm install @narcisbodea/smstunnel-sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Node.js (Standalone)
|
|
23
|
+
|
|
24
|
+
Works without NestJS or any framework. Uses native `fetch` (Node 18+), zero external dependencies.
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { SmsTunnelNodeClient } from '@narcisbodea/smstunnel-sdk/node';
|
|
28
|
+
|
|
29
|
+
const client = new SmsTunnelNodeClient({
|
|
30
|
+
apiKey: 'sk_live_xxx',
|
|
31
|
+
serverUrl: 'https://smstunnel.io',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Send SMS
|
|
35
|
+
const result = await client.sendSms('+40721123456', 'Hello!');
|
|
36
|
+
|
|
37
|
+
// Send 2FA
|
|
38
|
+
await client.send2FaSms('+40721123456', 'Your code is 123456');
|
|
39
|
+
|
|
40
|
+
// Send bulk SMS
|
|
41
|
+
await client.sendBulkSms(['+40721111111', '+40722222222'], 'Bulk message');
|
|
42
|
+
|
|
43
|
+
// Get message status
|
|
44
|
+
const status = await client.getMessageStatus('msg-id');
|
|
45
|
+
|
|
46
|
+
// Get received SMS (inbox)
|
|
47
|
+
const inbox = await client.getReceivedSms({ limit: 20, page: 1 });
|
|
48
|
+
|
|
49
|
+
// List devices
|
|
50
|
+
const devices = await client.getDevices();
|
|
51
|
+
|
|
52
|
+
// E2E Encryption
|
|
53
|
+
const e2eStatus = await client.getDeviceE2EStatus('device-id');
|
|
54
|
+
const publicKey = await client.getDevicePublicKey('device-id');
|
|
55
|
+
const verification = await client.verifyDeviceKey('device-id', 'stored-fingerprint');
|
|
56
|
+
await client.sendEncryptedSms('encrypted-payload', 'device-id', {
|
|
57
|
+
is2FA: false,
|
|
58
|
+
expectedFingerprint: 'a1b2c3d4',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Unified Pairing v2
|
|
62
|
+
const pairing = await client.createPairingToken({
|
|
63
|
+
source: 'api',
|
|
64
|
+
displayName: 'My App',
|
|
65
|
+
});
|
|
66
|
+
const pairingStatus = await client.getPairingTokenStatus(pairing.data.token);
|
|
67
|
+
|
|
68
|
+
// E2E Pairing (with public key exchange)
|
|
69
|
+
const e2ePairing = await client.createE2EPairing({ siteName: 'My App' });
|
|
70
|
+
const e2eResult = await client.pollE2EPairing(e2ePairing.data.token);
|
|
71
|
+
// e2eResult.data.publicKey contains the device's RSA public key
|
|
16
72
|
```
|
|
17
73
|
|
|
18
74
|
---
|
|
@@ -26,7 +82,7 @@ The SDK is database-agnostic. You provide a simple adapter with 3 methods:
|
|
|
26
82
|
#### MongoDB (Mongoose)
|
|
27
83
|
|
|
28
84
|
```typescript
|
|
29
|
-
import { SmsTunnelStorageAdapter, SmsTunnelConfig } from 'smstunnel-sdk/server';
|
|
85
|
+
import { SmsTunnelStorageAdapter, SmsTunnelConfig } from '@narcisbodea/smstunnel-sdk/server';
|
|
30
86
|
import { Model } from 'mongoose';
|
|
31
87
|
|
|
32
88
|
export class MongoSmsTunnelStorage implements SmsTunnelStorageAdapter {
|
|
@@ -62,7 +118,7 @@ export class MongoSmsTunnelStorage implements SmsTunnelStorageAdapter {
|
|
|
62
118
|
#### Prisma (PostgreSQL)
|
|
63
119
|
|
|
64
120
|
```typescript
|
|
65
|
-
import { SmsTunnelStorageAdapter, SmsTunnelConfig } from 'smstunnel-sdk/server';
|
|
121
|
+
import { SmsTunnelStorageAdapter, SmsTunnelConfig } from '@narcisbodea/smstunnel-sdk/server';
|
|
66
122
|
import { PrismaClient } from '@prisma/client';
|
|
67
123
|
|
|
68
124
|
export class PrismaSmsTunnelStorage implements SmsTunnelStorageAdapter {
|
|
@@ -93,7 +149,7 @@ export class PrismaSmsTunnelStorage implements SmsTunnelStorageAdapter {
|
|
|
93
149
|
#### JSON File
|
|
94
150
|
|
|
95
151
|
```typescript
|
|
96
|
-
import { SmsTunnelStorageAdapter, SmsTunnelConfig } from 'smstunnel-sdk/server';
|
|
152
|
+
import { SmsTunnelStorageAdapter, SmsTunnelConfig } from '@narcisbodea/smstunnel-sdk/server';
|
|
97
153
|
import { readFile, writeFile } from 'fs/promises';
|
|
98
154
|
|
|
99
155
|
export class JsonFileStorage implements SmsTunnelStorageAdapter {
|
|
@@ -118,7 +174,7 @@ export class JsonFileStorage implements SmsTunnelStorageAdapter {
|
|
|
118
174
|
### 2. Register the Module
|
|
119
175
|
|
|
120
176
|
```typescript
|
|
121
|
-
import { SmsTunnelModule } from 'smstunnel-sdk/server';
|
|
177
|
+
import { SmsTunnelModule } from '@narcisbodea/smstunnel-sdk/server';
|
|
122
178
|
|
|
123
179
|
@Module({
|
|
124
180
|
imports: [
|
|
@@ -147,7 +203,7 @@ SmsTunnelModule.forRootAsync({
|
|
|
147
203
|
|
|
148
204
|
### Multi-Tenant (Enterprise/SaaS) Mode
|
|
149
205
|
|
|
150
|
-
For **multi-tenant applications** (SaaS platforms, CRMs, ERPs) where each tenant needs their own SMS device
|
|
206
|
+
For **multi-tenant applications** (SaaS platforms, CRMs, ERPs) where each tenant needs their own SMS device:
|
|
151
207
|
|
|
152
208
|
```typescript
|
|
153
209
|
SmsTunnelModule.forRootAsync({
|
|
@@ -155,7 +211,6 @@ SmsTunnelModule.forRootAsync({
|
|
|
155
211
|
storage: new MongoSmsTunnelStorage(settingsModel),
|
|
156
212
|
callbackBaseUrl: process.env.CALLBACK_URL,
|
|
157
213
|
displayName: 'My SaaS App',
|
|
158
|
-
// Multi-tenant mode
|
|
159
214
|
enterpriseApiKey: process.env.SMSTUNNEL_ENTERPRISE_API_KEY,
|
|
160
215
|
externalId: tenantService.getCurrentTenantId(),
|
|
161
216
|
}),
|
|
@@ -163,12 +218,10 @@ SmsTunnelModule.forRootAsync({
|
|
|
163
218
|
})
|
|
164
219
|
```
|
|
165
220
|
|
|
166
|
-
When `enterpriseApiKey` is set, `createPairingToken()` automatically uses `POST /api/v1/saas/activate` to create isolated sub-accounts per tenant. The callback flow and SMS sending remain the same — the SDK handles the routing transparently.
|
|
167
|
-
|
|
168
221
|
### 3. Auth Guard Integration
|
|
169
222
|
|
|
170
223
|
```typescript
|
|
171
|
-
import { SMSTUNNEL_PUBLIC_PATHS } from 'smstunnel-sdk/server';
|
|
224
|
+
import { SMSTUNNEL_PUBLIC_PATHS } from '@narcisbodea/smstunnel-sdk/server';
|
|
172
225
|
|
|
173
226
|
// In your JwtAuthGuard:
|
|
174
227
|
if (SMSTUNNEL_PUBLIC_PATHS.some(p => request.url.includes(p))) return true;
|
|
@@ -185,6 +238,11 @@ if (SMSTUNNEL_PUBLIC_PATHS.some(p => request.url.includes(p))) return true;
|
|
|
185
238
|
| `POST /smstunnel/unpair` | unpair | Yes | Disconnect device |
|
|
186
239
|
| `POST /smstunnel/send` | sendSms | Yes | Send SMS |
|
|
187
240
|
| `POST /smstunnel/update-config` | updateConfig | Yes | Set server URL |
|
|
241
|
+
| `GET /smstunnel/e2e-status/:deviceId` | getDeviceE2EStatus | Yes | E2E encryption status |
|
|
242
|
+
| `GET /smstunnel/public-key/:deviceId` | getDevicePublicKey | Yes | Get device public key |
|
|
243
|
+
| `POST /smstunnel/verify-key` | verifyDeviceKey | Yes | Verify key fingerprint |
|
|
244
|
+
| `POST /smstunnel/send-encrypted` | sendEncryptedSms | Yes | Send encrypted SMS |
|
|
245
|
+
| `GET /smstunnel/pairings` | getPairings | Yes | List active pairings |
|
|
188
246
|
|
|
189
247
|
---
|
|
190
248
|
|
|
@@ -195,7 +253,7 @@ Works with: **React, Next.js, Remix, Gatsby**
|
|
|
195
253
|
### Plug and Play Component
|
|
196
254
|
|
|
197
255
|
```tsx
|
|
198
|
-
import { SmsTunnelPairing, RO_LABELS } from 'smstunnel-sdk/react';
|
|
256
|
+
import { SmsTunnelPairing, RO_LABELS } from '@narcisbodea/smstunnel-sdk/react';
|
|
199
257
|
|
|
200
258
|
function SettingsPage() {
|
|
201
259
|
return (
|
|
@@ -220,7 +278,7 @@ Add `'use client'` in your page/component:
|
|
|
220
278
|
|
|
221
279
|
```tsx
|
|
222
280
|
'use client';
|
|
223
|
-
import { SmsTunnelPairing, RO_LABELS } from 'smstunnel-sdk/react';
|
|
281
|
+
import { SmsTunnelPairing, RO_LABELS } from '@narcisbodea/smstunnel-sdk/react';
|
|
224
282
|
|
|
225
283
|
export default function SmsSettings() {
|
|
226
284
|
return <SmsTunnelPairing apiBaseUrl="/api" labels={RO_LABELS} />;
|
|
@@ -230,7 +288,7 @@ export default function SmsSettings() {
|
|
|
230
288
|
### Custom UI with Hook
|
|
231
289
|
|
|
232
290
|
```tsx
|
|
233
|
-
import { useSmsTunnel, QrCodeCanvas } from 'smstunnel-sdk/react';
|
|
291
|
+
import { useSmsTunnel, QrCodeCanvas } from '@narcisbodea/smstunnel-sdk/react';
|
|
234
292
|
|
|
235
293
|
function MySmsSettings() {
|
|
236
294
|
const tunnel = useSmsTunnel({
|
|
@@ -238,6 +296,12 @@ function MySmsSettings() {
|
|
|
238
296
|
getAuthHeaders: () => ({ Authorization: `Bearer ${token}` }),
|
|
239
297
|
});
|
|
240
298
|
|
|
299
|
+
// E2E Encryption
|
|
300
|
+
const e2eStatus = await tunnel.getDeviceE2EStatus('device-id');
|
|
301
|
+
const publicKey = await tunnel.getDevicePublicKey('device-id');
|
|
302
|
+
const keyValid = await tunnel.verifyDeviceKey('device-id', 'fingerprint');
|
|
303
|
+
await tunnel.sendEncryptedSms('payload', 'device-id');
|
|
304
|
+
|
|
241
305
|
if (tunnel.status === 'paired') {
|
|
242
306
|
return <div>Connected: {tunnel.deviceName}</div>;
|
|
243
307
|
}
|
|
@@ -269,7 +333,7 @@ Works with: **Vue 3, Nuxt 3**
|
|
|
269
333
|
|
|
270
334
|
```vue
|
|
271
335
|
<script setup>
|
|
272
|
-
import { SmsTunnelPairing, RO_LABELS } from 'smstunnel-sdk/vue';
|
|
336
|
+
import { SmsTunnelPairing, RO_LABELS } from '@narcisbodea/smstunnel-sdk/vue';
|
|
273
337
|
|
|
274
338
|
function onPaired(device) {
|
|
275
339
|
console.log('Paired:', device);
|
|
@@ -299,7 +363,7 @@ Wrap in `<ClientOnly>` since pairing uses browser APIs:
|
|
|
299
363
|
</template>
|
|
300
364
|
|
|
301
365
|
<script setup>
|
|
302
|
-
import { SmsTunnelPairing, RO_LABELS } from 'smstunnel-sdk/vue';
|
|
366
|
+
import { SmsTunnelPairing, RO_LABELS } from '@narcisbodea/smstunnel-sdk/vue';
|
|
303
367
|
</script>
|
|
304
368
|
```
|
|
305
369
|
|
|
@@ -307,12 +371,17 @@ import { SmsTunnelPairing, RO_LABELS } from 'smstunnel-sdk/vue';
|
|
|
307
371
|
|
|
308
372
|
```vue
|
|
309
373
|
<script setup>
|
|
310
|
-
import { useSmsTunnel, QrCodeCanvas } from 'smstunnel-sdk/vue';
|
|
374
|
+
import { useSmsTunnel, QrCodeCanvas } from '@narcisbodea/smstunnel-sdk/vue';
|
|
311
375
|
|
|
312
376
|
const tunnel = useSmsTunnel({
|
|
313
377
|
apiBaseUrl: '/api',
|
|
314
378
|
getAuthHeaders: () => ({ Authorization: `Bearer ${token}` }),
|
|
315
379
|
});
|
|
380
|
+
|
|
381
|
+
// E2E Encryption
|
|
382
|
+
const e2eStatus = await tunnel.getDeviceE2EStatus('device-id');
|
|
383
|
+
const publicKey = await tunnel.getDevicePublicKey('device-id');
|
|
384
|
+
await tunnel.sendEncryptedSms('payload', 'device-id');
|
|
316
385
|
</script>
|
|
317
386
|
|
|
318
387
|
<template>
|
|
@@ -336,46 +405,59 @@ const tunnel = useSmsTunnel({
|
|
|
336
405
|
|
|
337
406
|
## Angular
|
|
338
407
|
|
|
339
|
-
|
|
408
|
+
Works with: **Angular 17+** (standalone)
|
|
340
409
|
|
|
341
|
-
|
|
342
|
-
import { Injectable, OnDestroy } from '@angular/core';
|
|
343
|
-
import { SmsTunnelClient } from 'smstunnel-sdk';
|
|
410
|
+
### Setup
|
|
344
411
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
412
|
+
```typescript
|
|
413
|
+
// app.config.ts
|
|
414
|
+
import { provideSmsTunnel } from '@narcisbodea/smstunnel-sdk/angular';
|
|
415
|
+
|
|
416
|
+
export const appConfig: ApplicationConfig = {
|
|
417
|
+
providers: [
|
|
418
|
+
provideSmsTunnel({
|
|
419
|
+
apiBaseUrl: 'https://your-backend.com',
|
|
420
|
+
getAuthHeaders: () => ({
|
|
421
|
+
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
|
422
|
+
}),
|
|
351
423
|
}),
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
getStatus() { return this.client.getStatus(); }
|
|
355
|
-
createToken() { return this.client.createToken(); }
|
|
356
|
-
startPolling(token: string, cb: any) { return this.client.startPolling(token, cb); }
|
|
357
|
-
sendSms(to: string, msg: string) { return this.client.sendSms(to, msg); }
|
|
358
|
-
unpair() { return this.client.unpair(); }
|
|
359
|
-
updateServerUrl(url: string) { return this.client.updateServerUrl(url); }
|
|
360
|
-
|
|
361
|
-
ngOnDestroy() { this.client.destroy(); }
|
|
362
|
-
}
|
|
424
|
+
],
|
|
425
|
+
};
|
|
363
426
|
```
|
|
364
427
|
|
|
428
|
+
### Usage
|
|
429
|
+
|
|
365
430
|
```typescript
|
|
366
|
-
|
|
367
|
-
|
|
431
|
+
import { Component, inject } from '@angular/core';
|
|
432
|
+
import { SmsTunnelService } from '@narcisbodea/smstunnel-sdk/angular';
|
|
433
|
+
|
|
434
|
+
@Component({ /* ... */ })
|
|
368
435
|
export class SmsPairingComponent {
|
|
369
|
-
|
|
436
|
+
private sms = inject(SmsTunnelService);
|
|
370
437
|
|
|
371
438
|
async connect() {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
439
|
+
// Pairing
|
|
440
|
+
const status = await this.sms.getStatus();
|
|
441
|
+
const token = await this.sms.createToken();
|
|
442
|
+
const pairings = await this.sms.getPairings();
|
|
443
|
+
await this.sms.unpair();
|
|
444
|
+
|
|
445
|
+
// SMS
|
|
446
|
+
await this.sms.sendSms('+40721123456', 'Hello!');
|
|
447
|
+
await this.sms.send2fa('+40721123456', '123456');
|
|
448
|
+
await this.sms.sendBulk([{ to: '+40721111111', message: 'Hi' }]);
|
|
449
|
+
const msgStatus = await this.sms.getSmsStatus('msg-id');
|
|
450
|
+
const inbox = await this.sms.getReceivedSms();
|
|
451
|
+
|
|
452
|
+
// Devices
|
|
453
|
+
const devices = await this.sms.getDevices();
|
|
454
|
+
const usage = await this.sms.getUsage();
|
|
455
|
+
|
|
456
|
+
// E2E Encryption
|
|
457
|
+
const e2eStatus = await this.sms.getDeviceE2EStatus('device-id');
|
|
458
|
+
const publicKey = await this.sms.getDevicePublicKey('device-id');
|
|
459
|
+
const verification = await this.sms.verifyDeviceKey('device-id', 'fingerprint');
|
|
460
|
+
await this.sms.sendEncryptedSms('payload', 'device-id');
|
|
379
461
|
}
|
|
380
462
|
}
|
|
381
463
|
```
|
|
@@ -386,7 +468,7 @@ export class SmsPairingComponent {
|
|
|
386
468
|
|
|
387
469
|
```svelte
|
|
388
470
|
<script>
|
|
389
|
-
import { SmsTunnelClient } from 'smstunnel-sdk';
|
|
471
|
+
import { SmsTunnelClient } from '@narcisbodea/smstunnel-sdk';
|
|
390
472
|
import { onMount, onDestroy } from 'svelte';
|
|
391
473
|
|
|
392
474
|
let status = 'loading';
|
|
@@ -442,7 +524,7 @@ Astro supports React, Vue, and Svelte islands. Use any of the above:
|
|
|
442
524
|
// pages/settings.astro
|
|
443
525
|
---
|
|
444
526
|
<script>
|
|
445
|
-
import { SmsTunnelPairing, RO_LABELS } from 'smstunnel-sdk/react';
|
|
527
|
+
import { SmsTunnelPairing, RO_LABELS } from '@narcisbodea/smstunnel-sdk/react';
|
|
446
528
|
</script>
|
|
447
529
|
|
|
448
530
|
<SmsTunnelPairing client:only="react" apiBaseUrl="/api" labels={RO_LABELS} />
|
|
@@ -456,10 +538,35 @@ Or with Vue:
|
|
|
456
538
|
|
|
457
539
|
---
|
|
458
540
|
|
|
541
|
+
## E2E Encryption
|
|
542
|
+
|
|
543
|
+
All SDKs support end-to-end encryption using RSA-2048. The device holds the private key, the server stores the public key.
|
|
544
|
+
|
|
545
|
+
### Flow
|
|
546
|
+
|
|
547
|
+
1. Check if device has E2E enabled: `getDeviceE2EStatus(deviceId)`
|
|
548
|
+
2. Get the device's public key: `getDevicePublicKey(deviceId)`
|
|
549
|
+
3. Encrypt your message with the RSA public key (client-side)
|
|
550
|
+
4. Send encrypted: `sendEncryptedSms(encryptedPayload, deviceId)`
|
|
551
|
+
5. Device decrypts with its private key
|
|
552
|
+
|
|
553
|
+
### Key Verification
|
|
554
|
+
|
|
555
|
+
Store the `publicKeyFingerprint` locally after first pairing. Before sending, verify it hasn't changed:
|
|
556
|
+
|
|
557
|
+
```typescript
|
|
558
|
+
const result = await client.verifyDeviceKey('device-id', 'stored-fingerprint');
|
|
559
|
+
if (result.needsRePairing) {
|
|
560
|
+
// Device was reinstalled, key changed - need to re-pair
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
459
566
|
## SmsTunnelClient API (framework-agnostic)
|
|
460
567
|
|
|
461
568
|
```typescript
|
|
462
|
-
import { SmsTunnelClient } from 'smstunnel-sdk';
|
|
569
|
+
import { SmsTunnelClient } from '@narcisbodea/smstunnel-sdk';
|
|
463
570
|
|
|
464
571
|
const client = new SmsTunnelClient({
|
|
465
572
|
apiBaseUrl: '/api',
|
|
@@ -468,14 +575,24 @@ const client = new SmsTunnelClient({
|
|
|
468
575
|
pollInterval: 3000, // default
|
|
469
576
|
});
|
|
470
577
|
|
|
578
|
+
// Pairing
|
|
471
579
|
await client.getStatus(); // { paired, serverUrl, deviceName }
|
|
472
580
|
await client.createToken(); // { success, token, qrData, ... }
|
|
473
581
|
await client.getPairingStatus(token); // { status, displayName }
|
|
474
582
|
client.startPolling(token, (event) => ...); // returns cleanup fn
|
|
475
583
|
client.stopPolling();
|
|
476
584
|
await client.unpair();
|
|
585
|
+
|
|
586
|
+
// SMS
|
|
477
587
|
await client.sendSms('+40741234567', 'Hi');
|
|
478
588
|
await client.updateServerUrl('https://...');
|
|
589
|
+
|
|
590
|
+
// E2E Encryption
|
|
591
|
+
await client.getDeviceE2EStatus('device-id');
|
|
592
|
+
await client.getDevicePublicKey('device-id');
|
|
593
|
+
await client.verifyDeviceKey('device-id', 'fingerprint');
|
|
594
|
+
await client.sendEncryptedSms('payload', 'device-id');
|
|
595
|
+
|
|
479
596
|
client.destroy(); // cleanup
|
|
480
597
|
```
|
|
481
598
|
|
|
@@ -487,9 +604,9 @@ Built-in presets: `EN_LABELS` (default), `RO_LABELS`.
|
|
|
487
604
|
|
|
488
605
|
Available from any import path:
|
|
489
606
|
```typescript
|
|
490
|
-
import { EN_LABELS, RO_LABELS } from 'smstunnel-sdk';
|
|
491
|
-
import { EN_LABELS, RO_LABELS } from 'smstunnel-sdk/react';
|
|
492
|
-
import { EN_LABELS, RO_LABELS } from 'smstunnel-sdk/vue';
|
|
607
|
+
import { EN_LABELS, RO_LABELS } from '@narcisbodea/smstunnel-sdk';
|
|
608
|
+
import { EN_LABELS, RO_LABELS } from '@narcisbodea/smstunnel-sdk/react';
|
|
609
|
+
import { EN_LABELS, RO_LABELS } from '@narcisbodea/smstunnel-sdk/vue';
|
|
493
610
|
```
|
|
494
611
|
|
|
495
612
|
Custom labels: implement the `SmsTunnelLabels` interface.
|
|
@@ -500,10 +617,12 @@ Custom labels: implement the `SmsTunnelLabels` interface.
|
|
|
500
617
|
|
|
501
618
|
| Path | Exports |
|
|
502
619
|
|------|---------|
|
|
503
|
-
|
|
|
504
|
-
|
|
|
505
|
-
|
|
|
506
|
-
|
|
|
620
|
+
| `@narcisbodea/smstunnel-sdk` | `SmsTunnelClient`, `EN_LABELS`, `RO_LABELS`, types |
|
|
621
|
+
| `@narcisbodea/smstunnel-sdk/server` | `SmsTunnelModule`, `SmsTunnelService`, `SMSTUNNEL_PUBLIC_PATHS` |
|
|
622
|
+
| `@narcisbodea/smstunnel-sdk/react` | `SmsTunnelPairing`, `QrCodeCanvas`, `useSmsTunnel` |
|
|
623
|
+
| `@narcisbodea/smstunnel-sdk/vue` | `SmsTunnelPairing`, `QrCodeCanvas`, `useSmsTunnel` |
|
|
624
|
+
| `@narcisbodea/smstunnel-sdk/angular` | `SmsTunnelService`, `provideSmsTunnel`, `SMSTUNNEL_CONFIG` |
|
|
625
|
+
| `@narcisbodea/smstunnel-sdk/node` | `SmsTunnelNodeClient` |
|
|
507
626
|
|
|
508
627
|
## License
|
|
509
628
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narcisbodea/smstunnel-sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "SMSTunnel SDK - Node.js + NestJS + React + Vue + Angular + framework-agnostic client for SMS pairing & E2E encryption",
|
|
5
5
|
"author": "NARBOWEB SRL",
|
|
6
6
|
"license": "MIT",
|