@smart-pay-chain/otp 2.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.
- package/LICENSE +22 -0
- package/README.md +581 -0
- package/dist/errors.d.ts +101 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +161 -0
- package/dist/http-client.d.ts +33 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +136 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/otp-client.d.ts +184 -0
- package/dist/otp-client.d.ts.map +1 -0
- package/dist/otp-client.js +314 -0
- package/dist/types.d.ts +275 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +72 -0
- package/package.json +69 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OtpClient = void 0;
|
|
4
|
+
const http_client_1 = require("./http-client");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
/**
|
|
7
|
+
* Main OTP client for interacting with the OTP verification service
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const client = new OtpClient({ apiKey: 'your-api-key' });
|
|
12
|
+
*
|
|
13
|
+
* // Send an OTP
|
|
14
|
+
* const result = await client.sendOtp({
|
|
15
|
+
* phoneNumber: '+995555123456',
|
|
16
|
+
* channel: OtpChannel.SMS,
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Verify the OTP
|
|
20
|
+
* const verification = await client.verifyOtp({
|
|
21
|
+
* requestId: result.requestId,
|
|
22
|
+
* code: '123456',
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
class OtpClient {
|
|
27
|
+
/**
|
|
28
|
+
* Create a new OTP client
|
|
29
|
+
*
|
|
30
|
+
* @param config - Configuration options
|
|
31
|
+
*/
|
|
32
|
+
constructor(config) {
|
|
33
|
+
this.serverConfig = null;
|
|
34
|
+
this.serverConfigFetchedAt = null;
|
|
35
|
+
this.CONFIG_CACHE_TTL = 3600000; // 1 hour in milliseconds
|
|
36
|
+
if (!config.apiKey) {
|
|
37
|
+
throw new Error('API key is required');
|
|
38
|
+
}
|
|
39
|
+
this.http = new http_client_1.HttpClient(config);
|
|
40
|
+
// Auto-fetch configuration if requested
|
|
41
|
+
if (config.autoConfig) {
|
|
42
|
+
this.getConfig().catch((error) => {
|
|
43
|
+
// Silent fail for auto-config, log warning
|
|
44
|
+
console.warn('Failed to auto-fetch SDK configuration:', error.message);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Send an OTP to a phone number
|
|
50
|
+
*
|
|
51
|
+
* @param options - Options for sending the OTP
|
|
52
|
+
* @returns Promise resolving to the OTP request details
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const result = await client.sendOtp({
|
|
57
|
+
* phoneNumber: '+995555123456',
|
|
58
|
+
* channel: OtpChannel.SMS,
|
|
59
|
+
* ttl: 300,
|
|
60
|
+
* length: 6,
|
|
61
|
+
* metadata: { userId: '12345' }
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* console.log(result.requestId); // Save this for verification
|
|
65
|
+
* console.log(result.expiresAt);
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
async sendOtp(options) {
|
|
69
|
+
this.validatePhoneNumber(options.phoneNumber);
|
|
70
|
+
const body = {
|
|
71
|
+
phoneNumber: options.phoneNumber,
|
|
72
|
+
channel: options.channel || types_1.OtpChannel.SMS,
|
|
73
|
+
ttl: options.ttl || 300,
|
|
74
|
+
length: options.length || 6,
|
|
75
|
+
metadata: options.metadata,
|
|
76
|
+
};
|
|
77
|
+
const headers = {};
|
|
78
|
+
// Auto-generate idempotency key if not provided
|
|
79
|
+
headers['X-Idempotency-Key'] = options.idempotencyKey || this.generateIdempotencyKey();
|
|
80
|
+
const response = await this.http.post('/api/v1/otp/send', body, {
|
|
81
|
+
headers,
|
|
82
|
+
});
|
|
83
|
+
// Convert string date to Date object
|
|
84
|
+
return {
|
|
85
|
+
...response,
|
|
86
|
+
expiresAt: new Date(response.expiresAt),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Verify an OTP code
|
|
91
|
+
*
|
|
92
|
+
* @param options - Options for verifying the OTP
|
|
93
|
+
* @returns Promise resolving to the verification result
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* const result = await client.verifyOtp({
|
|
98
|
+
* requestId: 'req_123456',
|
|
99
|
+
* code: '123456',
|
|
100
|
+
* ipAddress: '192.168.1.1',
|
|
101
|
+
* userAgent: 'Mozilla/5.0...'
|
|
102
|
+
* });
|
|
103
|
+
*
|
|
104
|
+
* if (result.success) {
|
|
105
|
+
* console.log('OTP verified successfully!');
|
|
106
|
+
* }
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
async verifyOtp(options) {
|
|
110
|
+
if (!options.requestId) {
|
|
111
|
+
throw new Error('Request ID is required');
|
|
112
|
+
}
|
|
113
|
+
if (!options.code || options.code.length < 4 || options.code.length > 8) {
|
|
114
|
+
throw new Error('Code must be between 4 and 8 characters');
|
|
115
|
+
}
|
|
116
|
+
const body = {
|
|
117
|
+
requestId: options.requestId,
|
|
118
|
+
code: options.code,
|
|
119
|
+
ipAddress: options.ipAddress,
|
|
120
|
+
userAgent: options.userAgent,
|
|
121
|
+
};
|
|
122
|
+
return await this.http.post('/api/v1/otp/verify', body);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Resend an OTP (generates a new code for the same phone number)
|
|
126
|
+
*
|
|
127
|
+
* @param options - Options for resending the OTP
|
|
128
|
+
* @returns Promise resolving to the new OTP request details
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const result = await client.resendOtp({
|
|
133
|
+
* requestId: 'req_123456'
|
|
134
|
+
* });
|
|
135
|
+
*
|
|
136
|
+
* console.log('New OTP sent:', result.requestId);
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
async resendOtp(options) {
|
|
140
|
+
if (!options.requestId) {
|
|
141
|
+
throw new Error('Request ID is required');
|
|
142
|
+
}
|
|
143
|
+
// Auto-generate idempotency key for resend operations
|
|
144
|
+
const headers = {
|
|
145
|
+
'X-Idempotency-Key': this.generateIdempotencyKey(),
|
|
146
|
+
};
|
|
147
|
+
const response = await this.http.post(`/api/v1/otp/${options.requestId}/resend`, undefined, { headers });
|
|
148
|
+
// Convert string date to Date object
|
|
149
|
+
return {
|
|
150
|
+
...response,
|
|
151
|
+
expiresAt: new Date(response.expiresAt),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get OTP status (authenticated endpoint)
|
|
156
|
+
*
|
|
157
|
+
* @param requestId - The request ID from sendOtp()
|
|
158
|
+
* @returns Promise resolving to the OTP status
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const status = await client.getStatus('req_123456');
|
|
163
|
+
* console.log(status.status); // 'PENDING' | 'SENT' | 'VERIFIED' | 'EXPIRED' | 'FAILED'
|
|
164
|
+
* console.log(status.attempts); // Number of verification attempts
|
|
165
|
+
* console.log(status.isExpired); // Whether OTP is expired
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
async getStatus(requestId) {
|
|
169
|
+
if (!requestId) {
|
|
170
|
+
throw new Error('Request ID is required');
|
|
171
|
+
}
|
|
172
|
+
const response = await this.http.get(`/api/v1/otp/${requestId}`);
|
|
173
|
+
// Convert string dates to Date objects
|
|
174
|
+
return {
|
|
175
|
+
...response,
|
|
176
|
+
expiresAt: new Date(response.expiresAt),
|
|
177
|
+
verifiedAt: response.verifiedAt ? new Date(response.verifiedAt) : null,
|
|
178
|
+
createdAt: new Date(response.createdAt),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get OTP status with code (public endpoint for testing/development)
|
|
183
|
+
*
|
|
184
|
+
* ⚠️ WARNING: This endpoint returns the actual OTP code and should ONLY be used
|
|
185
|
+
* in development/testing environments! Never use in production client code.
|
|
186
|
+
*
|
|
187
|
+
* This method polls for up to 30 seconds waiting for SMS delivery.
|
|
188
|
+
*
|
|
189
|
+
* @param requestId - The request ID from sendOtp()
|
|
190
|
+
* @returns Promise resolving to the OTP status with code
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* // For automated testing only!
|
|
195
|
+
* const status = await client.getStatusWithCode('req_123456');
|
|
196
|
+
* console.log(status.otpCode); // The actual OTP code
|
|
197
|
+
* console.log(status.smsProvider); // Which provider was used
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
async getStatusWithCode(requestId) {
|
|
201
|
+
if (!requestId) {
|
|
202
|
+
throw new Error('Request ID is required');
|
|
203
|
+
}
|
|
204
|
+
const response = await this.http.get(`/api/v1/otp/${requestId}/status`);
|
|
205
|
+
// Convert string dates to Date objects
|
|
206
|
+
return {
|
|
207
|
+
...response,
|
|
208
|
+
expiresAt: new Date(response.expiresAt),
|
|
209
|
+
verifiedAt: response.verifiedAt ? new Date(response.verifiedAt) : null,
|
|
210
|
+
createdAt: new Date(response.createdAt),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get SDK configuration from server
|
|
215
|
+
*
|
|
216
|
+
* Fetches and caches configuration from the server. The configuration includes
|
|
217
|
+
* rate limits, supported features, test mode status, and more. Results are
|
|
218
|
+
* cached for 1 hour.
|
|
219
|
+
*
|
|
220
|
+
* @param forceRefresh - Force refresh the cached configuration
|
|
221
|
+
* @returns Promise resolving to the SDK configuration
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const config = await client.getConfig();
|
|
226
|
+
* console.log(config.features.testMode); // Check if test mode is enabled
|
|
227
|
+
* console.log(config.otpConfig.length); // Default OTP length
|
|
228
|
+
* console.log(config.rateLimits); // Rate limit information
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
async getConfig(forceRefresh = false) {
|
|
232
|
+
// Return cached config if valid
|
|
233
|
+
if (!forceRefresh &&
|
|
234
|
+
this.serverConfig &&
|
|
235
|
+
this.serverConfigFetchedAt &&
|
|
236
|
+
Date.now() - this.serverConfigFetchedAt < this.CONFIG_CACHE_TTL) {
|
|
237
|
+
return this.serverConfig;
|
|
238
|
+
}
|
|
239
|
+
// Fetch new configuration
|
|
240
|
+
const config = await this.http.get('/api/v1/sdk/config');
|
|
241
|
+
// Cache the configuration
|
|
242
|
+
this.serverConfig = config;
|
|
243
|
+
this.serverConfigFetchedAt = Date.now();
|
|
244
|
+
// Log warning if test mode is enabled
|
|
245
|
+
if (config.features.testMode) {
|
|
246
|
+
console.warn('⚠️ Test mode is enabled on the server. Use test phone numbers for testing:', config.testMode?.testPhoneNumbers);
|
|
247
|
+
}
|
|
248
|
+
return config;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Test connectivity to the OTP service
|
|
252
|
+
*
|
|
253
|
+
* @returns Promise resolving to true if connection is successful
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* const isConnected = await client.testConnection();
|
|
258
|
+
* if (isConnected) {
|
|
259
|
+
* console.log('✓ Connected to OTP service');
|
|
260
|
+
* }
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
async testConnection() {
|
|
264
|
+
try {
|
|
265
|
+
await this.http.get('/api/v1/sdk/test');
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Check if server is in test mode
|
|
274
|
+
*
|
|
275
|
+
* @returns Promise resolving to true if test mode is enabled
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```typescript
|
|
279
|
+
* const testMode = await client.isTestMode();
|
|
280
|
+
* if (testMode) {
|
|
281
|
+
* console.log('Server is in test mode - use test phone numbers');
|
|
282
|
+
* }
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
async isTestMode() {
|
|
286
|
+
try {
|
|
287
|
+
const config = await this.getConfig();
|
|
288
|
+
return config.features.testMode || false;
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Generate a unique idempotency key
|
|
296
|
+
*
|
|
297
|
+
* @returns A unique idempotency key in the format `{timestamp}-{random}`
|
|
298
|
+
*/
|
|
299
|
+
generateIdempotencyKey() {
|
|
300
|
+
const timestamp = Date.now();
|
|
301
|
+
const random = Math.random().toString(36).substring(2, 15);
|
|
302
|
+
return `${timestamp}-${random}`;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Validate phone number format (E.164)
|
|
306
|
+
*/
|
|
307
|
+
validatePhoneNumber(phoneNumber) {
|
|
308
|
+
const e164Regex = /^\+[1-9]\d{1,14}$/;
|
|
309
|
+
if (!e164Regex.test(phoneNumber)) {
|
|
310
|
+
throw new Error('Invalid phone number format. Must be in E.164 format (e.g., +995555123456)');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
exports.OtpClient = OtpClient;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTP Channel types
|
|
3
|
+
*/
|
|
4
|
+
export declare enum OtpChannel {
|
|
5
|
+
SMS = "SMS",
|
|
6
|
+
WHATSAPP = "WHATSAPP",
|
|
7
|
+
VOICE = "VOICE"
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Error codes returned by the API
|
|
11
|
+
*/
|
|
12
|
+
export declare enum ErrorCode {
|
|
13
|
+
AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED",
|
|
14
|
+
INVALID_API_KEY = "INVALID_API_KEY",
|
|
15
|
+
API_KEY_REVOKED = "API_KEY_REVOKED",
|
|
16
|
+
INVALID_PHONE_NUMBER = "INVALID_PHONE_NUMBER",
|
|
17
|
+
PHONE_NUMBER_BLOCKED = "PHONE_NUMBER_BLOCKED",
|
|
18
|
+
OTP_EXPIRED = "OTP_EXPIRED",
|
|
19
|
+
OTP_MAX_ATTEMPTS = "OTP_MAX_ATTEMPTS",
|
|
20
|
+
INVALID_OTP_CODE = "INVALID_OTP_CODE",
|
|
21
|
+
OTP_NOT_FOUND = "OTP_NOT_FOUND",
|
|
22
|
+
OTP_ALREADY_VERIFIED = "OTP_ALREADY_VERIFIED",
|
|
23
|
+
RATE_LIMIT_EXCEEDED = "RATE_LIMIT_EXCEEDED",
|
|
24
|
+
INSUFFICIENT_BALANCE = "INSUFFICIENT_BALANCE",
|
|
25
|
+
PAYMENT_REQUIRED = "PAYMENT_REQUIRED",
|
|
26
|
+
NO_BRAND_CONFIGURED = "NO_BRAND_CONFIGURED",
|
|
27
|
+
BRAND_NOT_AUTHORIZED = "BRAND_NOT_AUTHORIZED",
|
|
28
|
+
BRAND_PENDING_APPROVAL = "BRAND_PENDING_APPROVAL",
|
|
29
|
+
BRAND_CREATION_FAILED = "BRAND_CREATION_FAILED",
|
|
30
|
+
SMS_SEND_FAILED = "SMS_SEND_FAILED",
|
|
31
|
+
PROVIDER_UNAVAILABLE = "PROVIDER_UNAVAILABLE",
|
|
32
|
+
VALIDATION_ERROR = "VALIDATION_ERROR",
|
|
33
|
+
MISSING_REQUIRED_FIELD = "MISSING_REQUIRED_FIELD",
|
|
34
|
+
INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR",
|
|
35
|
+
SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
|
|
36
|
+
IDEMPOTENCY_KEY_CONFLICT = "IDEMPOTENCY_KEY_CONFLICT"
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* SDK Platform types
|
|
40
|
+
*/
|
|
41
|
+
export type SdkPlatform = 'node' | 'browser' | 'react-native' | 'unknown';
|
|
42
|
+
/**
|
|
43
|
+
* SDK Language types
|
|
44
|
+
*/
|
|
45
|
+
export type SdkLanguage = 'typescript' | 'javascript';
|
|
46
|
+
/**
|
|
47
|
+
* Configuration options for the OTP client
|
|
48
|
+
*/
|
|
49
|
+
export interface OtpClientConfig {
|
|
50
|
+
/** Your API key for authentication */
|
|
51
|
+
apiKey: string;
|
|
52
|
+
/** Base URL of the OTP service (default: https://otp.smartpaychain.com) */
|
|
53
|
+
baseUrl?: string;
|
|
54
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
55
|
+
timeout?: number;
|
|
56
|
+
/** Maximum number of retry attempts for failed requests (default: 3) */
|
|
57
|
+
maxRetries?: number;
|
|
58
|
+
/** Custom headers to include in all requests */
|
|
59
|
+
headers?: Record<string, string>;
|
|
60
|
+
/** SDK platform (auto-detected if not provided) */
|
|
61
|
+
platform?: SdkPlatform;
|
|
62
|
+
/** SDK language (auto-detected if not provided) */
|
|
63
|
+
language?: SdkLanguage;
|
|
64
|
+
/** Auto-fetch configuration from server on initialization (default: false) */
|
|
65
|
+
autoConfig?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Options for sending an OTP
|
|
69
|
+
*/
|
|
70
|
+
export interface SendOtpOptions {
|
|
71
|
+
/** Phone number in E.164 format (e.g., +995555123456) */
|
|
72
|
+
phoneNumber: string;
|
|
73
|
+
/** Delivery channel (default: SMS) */
|
|
74
|
+
channel?: OtpChannel;
|
|
75
|
+
/** Time-to-live in seconds (60-600, default: 300) */
|
|
76
|
+
ttl?: number;
|
|
77
|
+
/** OTP code length (4-8 digits, default: 6) */
|
|
78
|
+
length?: number;
|
|
79
|
+
/** Custom metadata to attach to the OTP request */
|
|
80
|
+
metadata?: Record<string, any>;
|
|
81
|
+
/** Idempotency key to prevent duplicate requests */
|
|
82
|
+
idempotencyKey?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Response from sending an OTP
|
|
86
|
+
*/
|
|
87
|
+
export interface SendOtpResponse {
|
|
88
|
+
/** Unique request ID for this OTP */
|
|
89
|
+
requestId: string;
|
|
90
|
+
/** When the OTP will expire */
|
|
91
|
+
expiresAt: Date;
|
|
92
|
+
/** Current status of the OTP request */
|
|
93
|
+
status: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Options for verifying an OTP
|
|
97
|
+
*/
|
|
98
|
+
export interface VerifyOtpOptions {
|
|
99
|
+
/** The request ID from sendOtp() */
|
|
100
|
+
requestId: string;
|
|
101
|
+
/** The OTP code to verify */
|
|
102
|
+
code: string;
|
|
103
|
+
/** IP address of the user verifying (optional but recommended) */
|
|
104
|
+
ipAddress?: string;
|
|
105
|
+
/** User agent of the user verifying (optional) */
|
|
106
|
+
userAgent?: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Response from verifying an OTP
|
|
110
|
+
*/
|
|
111
|
+
export interface VerifyOtpResponse {
|
|
112
|
+
/** Whether verification was successful */
|
|
113
|
+
success: boolean;
|
|
114
|
+
/** Message describing the result */
|
|
115
|
+
message: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Options for resending an OTP
|
|
119
|
+
*/
|
|
120
|
+
export interface ResendOtpOptions {
|
|
121
|
+
/** The request ID from the original sendOtp() call */
|
|
122
|
+
requestId: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Error response from the API
|
|
126
|
+
*/
|
|
127
|
+
export interface ApiErrorResponse {
|
|
128
|
+
success: false;
|
|
129
|
+
error: {
|
|
130
|
+
code: ErrorCode;
|
|
131
|
+
message: string;
|
|
132
|
+
statusCode: number;
|
|
133
|
+
retryable: boolean;
|
|
134
|
+
details?: Record<string, any>;
|
|
135
|
+
};
|
|
136
|
+
meta: {
|
|
137
|
+
requestId: string;
|
|
138
|
+
timestamp: string;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Success response wrapper
|
|
143
|
+
*/
|
|
144
|
+
export interface ApiSuccessResponse<T> {
|
|
145
|
+
success: true;
|
|
146
|
+
data: T;
|
|
147
|
+
meta?: {
|
|
148
|
+
requestId?: string;
|
|
149
|
+
timestamp?: string;
|
|
150
|
+
rateLimit?: {
|
|
151
|
+
limit: number;
|
|
152
|
+
remaining: number;
|
|
153
|
+
reset: number;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* OTP Status response (authenticated endpoint)
|
|
159
|
+
*/
|
|
160
|
+
export interface OtpStatus {
|
|
161
|
+
/** Request ID */
|
|
162
|
+
id: string;
|
|
163
|
+
/** Phone number (masked) */
|
|
164
|
+
phoneNumber: string;
|
|
165
|
+
/** Delivery channel */
|
|
166
|
+
channel: OtpChannel;
|
|
167
|
+
/** Current status */
|
|
168
|
+
status: 'PENDING' | 'SENT' | 'VERIFIED' | 'EXPIRED' | 'FAILED';
|
|
169
|
+
/** Number of verification attempts */
|
|
170
|
+
attempts: number;
|
|
171
|
+
/** Maximum allowed attempts */
|
|
172
|
+
maxAttempts: number;
|
|
173
|
+
/** When the OTP expires */
|
|
174
|
+
expiresAt: Date;
|
|
175
|
+
/** When the OTP was verified (if verified) */
|
|
176
|
+
verifiedAt: Date | null;
|
|
177
|
+
/** When the OTP was created */
|
|
178
|
+
createdAt: Date;
|
|
179
|
+
/** Whether the OTP is expired */
|
|
180
|
+
isExpired: boolean;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* OTP Status with code response (public endpoint for testing/development)
|
|
184
|
+
* WARNING: Only use this endpoint in development/testing!
|
|
185
|
+
*/
|
|
186
|
+
export interface OtpStatusWithCode extends OtpStatus {
|
|
187
|
+
/** The actual OTP code (for testing only!) */
|
|
188
|
+
otpCode: string;
|
|
189
|
+
/** SMS provider used */
|
|
190
|
+
smsProvider: string | null;
|
|
191
|
+
/** SMS message ID from provider */
|
|
192
|
+
smsMessageId: string | null;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* SDK Configuration from server
|
|
196
|
+
*/
|
|
197
|
+
export interface SdkConfiguration {
|
|
198
|
+
/** API version */
|
|
199
|
+
version: string;
|
|
200
|
+
/** OTP configuration */
|
|
201
|
+
otpConfig: {
|
|
202
|
+
/** Default OTP length */
|
|
203
|
+
length: number;
|
|
204
|
+
/** Default TTL in seconds */
|
|
205
|
+
ttl: number;
|
|
206
|
+
/** Maximum verification attempts */
|
|
207
|
+
maxAttempts: number;
|
|
208
|
+
};
|
|
209
|
+
/** Rate limits */
|
|
210
|
+
rateLimits: {
|
|
211
|
+
perPhone: {
|
|
212
|
+
limit: number;
|
|
213
|
+
window: string;
|
|
214
|
+
};
|
|
215
|
+
perAccount: {
|
|
216
|
+
limit: number;
|
|
217
|
+
window: string;
|
|
218
|
+
};
|
|
219
|
+
perIP: {
|
|
220
|
+
limit: number;
|
|
221
|
+
window: string;
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
/** Supported countries */
|
|
225
|
+
supportedCountries: string[];
|
|
226
|
+
/** Pricing information */
|
|
227
|
+
pricing: {
|
|
228
|
+
currency: string;
|
|
229
|
+
regions: Record<string, any>;
|
|
230
|
+
defaultPrice: number;
|
|
231
|
+
};
|
|
232
|
+
/** Supported features */
|
|
233
|
+
features: {
|
|
234
|
+
georgianLanguage: boolean;
|
|
235
|
+
customBranding: boolean;
|
|
236
|
+
webhooks: boolean;
|
|
237
|
+
idempotency: boolean;
|
|
238
|
+
testMode: boolean;
|
|
239
|
+
longPolling: boolean;
|
|
240
|
+
batchOperations: boolean;
|
|
241
|
+
};
|
|
242
|
+
/** API endpoints */
|
|
243
|
+
endpoints: {
|
|
244
|
+
base: string;
|
|
245
|
+
docs: string;
|
|
246
|
+
status: string;
|
|
247
|
+
};
|
|
248
|
+
/** Test mode information (if enabled) */
|
|
249
|
+
testMode?: {
|
|
250
|
+
enabled: boolean;
|
|
251
|
+
testPhoneNumbers: string[];
|
|
252
|
+
fixedOtpCode: string;
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Test phone numbers for testing/development
|
|
257
|
+
* Only work when server is in test mode
|
|
258
|
+
*/
|
|
259
|
+
export declare const TEST_PHONE_NUMBERS: Readonly<{
|
|
260
|
+
/** Always succeeds */
|
|
261
|
+
SUCCESS: "+15005550006";
|
|
262
|
+
/** Always fails with SMS send error */
|
|
263
|
+
SMS_FAIL: "+15005550007";
|
|
264
|
+
/** Always fails with rate limit exceeded */
|
|
265
|
+
RATE_LIMIT: "+15005550008";
|
|
266
|
+
/** Always fails with insufficient balance */
|
|
267
|
+
INSUFFICIENT_BALANCE: "+15005550009";
|
|
268
|
+
/** Always fails with brand not authorized */
|
|
269
|
+
BRAND_NOT_AUTH: "+15005550010";
|
|
270
|
+
}>;
|
|
271
|
+
/**
|
|
272
|
+
* Fixed OTP code for test mode
|
|
273
|
+
*/
|
|
274
|
+
export declare const TEST_OTP_CODE = "123456";
|
|
275
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TEST_OTP_CODE = exports.TEST_PHONE_NUMBERS = exports.ErrorCode = exports.OtpChannel = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* OTP Channel types
|
|
6
|
+
*/
|
|
7
|
+
var OtpChannel;
|
|
8
|
+
(function (OtpChannel) {
|
|
9
|
+
OtpChannel["SMS"] = "SMS";
|
|
10
|
+
OtpChannel["WHATSAPP"] = "WHATSAPP";
|
|
11
|
+
OtpChannel["VOICE"] = "VOICE";
|
|
12
|
+
})(OtpChannel || (exports.OtpChannel = OtpChannel = {}));
|
|
13
|
+
/**
|
|
14
|
+
* Error codes returned by the API
|
|
15
|
+
*/
|
|
16
|
+
var ErrorCode;
|
|
17
|
+
(function (ErrorCode) {
|
|
18
|
+
// Authentication & Authorization
|
|
19
|
+
ErrorCode["AUTHENTICATION_FAILED"] = "AUTHENTICATION_FAILED";
|
|
20
|
+
ErrorCode["INVALID_API_KEY"] = "INVALID_API_KEY";
|
|
21
|
+
ErrorCode["API_KEY_REVOKED"] = "API_KEY_REVOKED";
|
|
22
|
+
// Phone Number
|
|
23
|
+
ErrorCode["INVALID_PHONE_NUMBER"] = "INVALID_PHONE_NUMBER";
|
|
24
|
+
ErrorCode["PHONE_NUMBER_BLOCKED"] = "PHONE_NUMBER_BLOCKED";
|
|
25
|
+
// OTP
|
|
26
|
+
ErrorCode["OTP_EXPIRED"] = "OTP_EXPIRED";
|
|
27
|
+
ErrorCode["OTP_MAX_ATTEMPTS"] = "OTP_MAX_ATTEMPTS";
|
|
28
|
+
ErrorCode["INVALID_OTP_CODE"] = "INVALID_OTP_CODE";
|
|
29
|
+
ErrorCode["OTP_NOT_FOUND"] = "OTP_NOT_FOUND";
|
|
30
|
+
ErrorCode["OTP_ALREADY_VERIFIED"] = "OTP_ALREADY_VERIFIED";
|
|
31
|
+
// Rate Limiting
|
|
32
|
+
ErrorCode["RATE_LIMIT_EXCEEDED"] = "RATE_LIMIT_EXCEEDED";
|
|
33
|
+
// Billing
|
|
34
|
+
ErrorCode["INSUFFICIENT_BALANCE"] = "INSUFFICIENT_BALANCE";
|
|
35
|
+
ErrorCode["PAYMENT_REQUIRED"] = "PAYMENT_REQUIRED";
|
|
36
|
+
// Brand
|
|
37
|
+
ErrorCode["NO_BRAND_CONFIGURED"] = "NO_BRAND_CONFIGURED";
|
|
38
|
+
ErrorCode["BRAND_NOT_AUTHORIZED"] = "BRAND_NOT_AUTHORIZED";
|
|
39
|
+
ErrorCode["BRAND_PENDING_APPROVAL"] = "BRAND_PENDING_APPROVAL";
|
|
40
|
+
ErrorCode["BRAND_CREATION_FAILED"] = "BRAND_CREATION_FAILED";
|
|
41
|
+
// SMS Provider
|
|
42
|
+
ErrorCode["SMS_SEND_FAILED"] = "SMS_SEND_FAILED";
|
|
43
|
+
ErrorCode["PROVIDER_UNAVAILABLE"] = "PROVIDER_UNAVAILABLE";
|
|
44
|
+
// Validation
|
|
45
|
+
ErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
46
|
+
ErrorCode["MISSING_REQUIRED_FIELD"] = "MISSING_REQUIRED_FIELD";
|
|
47
|
+
// Server
|
|
48
|
+
ErrorCode["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
|
|
49
|
+
ErrorCode["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
|
|
50
|
+
// Idempotency
|
|
51
|
+
ErrorCode["IDEMPOTENCY_KEY_CONFLICT"] = "IDEMPOTENCY_KEY_CONFLICT";
|
|
52
|
+
})(ErrorCode || (exports.ErrorCode = ErrorCode = {}));
|
|
53
|
+
/**
|
|
54
|
+
* Test phone numbers for testing/development
|
|
55
|
+
* Only work when server is in test mode
|
|
56
|
+
*/
|
|
57
|
+
exports.TEST_PHONE_NUMBERS = Object.freeze({
|
|
58
|
+
/** Always succeeds */
|
|
59
|
+
SUCCESS: '+15005550006',
|
|
60
|
+
/** Always fails with SMS send error */
|
|
61
|
+
SMS_FAIL: '+15005550007',
|
|
62
|
+
/** Always fails with rate limit exceeded */
|
|
63
|
+
RATE_LIMIT: '+15005550008',
|
|
64
|
+
/** Always fails with insufficient balance */
|
|
65
|
+
INSUFFICIENT_BALANCE: '+15005550009',
|
|
66
|
+
/** Always fails with brand not authorized */
|
|
67
|
+
BRAND_NOT_AUTH: '+15005550010',
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Fixed OTP code for test mode
|
|
71
|
+
*/
|
|
72
|
+
exports.TEST_OTP_CODE = '123456';
|