sms-verification-api 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +20 -0
- package/DEPLOYMENT.md +151 -0
- package/README.md +475 -0
- package/docs/app/(home)/layout.tsx +7 -0
- package/docs/app/(home)/page.tsx +38 -0
- package/docs/app/docs/[[...slug]]/page.tsx +59 -0
- package/docs/app/docs/layout.tsx +12 -0
- package/docs/app/docs-og/[...slug]/route.ts +24 -0
- package/docs/app/globals.css +587 -0
- package/docs/app/layout.config.tsx +13 -0
- package/docs/app/layout.tsx +27 -0
- package/docs/app/logo.tsx +35 -0
- package/docs/content/docs/API_AUTHENTICATION.md +91 -0
- package/docs/content/docs/DEPLOYMENT.md +181 -0
- package/docs/content/docs/api/post.mdx +35 -0
- package/docs/content/docs/api/verify.mdx +34 -0
- package/docs/content/docs/meta.json +8 -0
- package/docs/content/docs/verify-legal-name.md +339 -0
- package/docs/lib/source.ts +14 -0
- package/docs/mdx-components.tsx +12 -0
- package/docs/next.config.mjs +51 -0
- package/docs/openapi.json +329 -0
- package/docs/package.json +37 -0
- package/docs/postcss.config.mjs +5 -0
- package/docs/scripts/generate-docs.mjs +23 -0
- package/docs/source.config.ts +5 -0
- package/docs/tsconfig.json +29 -0
- package/docs/worker.js +35 -0
- package/docs/wrangler.toml +26 -0
- package/examples/client.js +119 -0
- package/examples/demo.html +325 -0
- package/examples/libphonenumber-example.js +120 -0
- package/openapi.json +329 -0
- package/package.json +71 -0
- package/scripts/deploy.sh +63 -0
- package/src/identity-verification-server.ts +553 -0
- package/src/index.js +8 -0
- package/src/sns.js +236 -0
- package/src/verify-phone-server.js +448 -0
- package/src/verify-phone.ts +551 -0
- package/test/api.test.js +201 -0
- package/test/integration.test.js +152 -0
- package/test/metadata-test.js +73 -0
- package/test/server.test.js +143 -0
- package/test/setup.js +32 -0
- package/test/utils.test.js +186 -0
- package/test/verify.test.js +23 -0
- package/test/voip.test.js +112 -0
- package/vitest.config.js +10 -0
- package/wrangler.toml +27 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>SMS Verification API Demo</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
10
|
+
max-width: 800px;
|
|
11
|
+
margin: 0 auto;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
background-color: #f5f5f5;
|
|
14
|
+
}
|
|
15
|
+
.container {
|
|
16
|
+
background: white;
|
|
17
|
+
padding: 30px;
|
|
18
|
+
border-radius: 10px;
|
|
19
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
20
|
+
}
|
|
21
|
+
h1 {
|
|
22
|
+
color: #333;
|
|
23
|
+
text-align: center;
|
|
24
|
+
margin-bottom: 30px;
|
|
25
|
+
}
|
|
26
|
+
.form-group {
|
|
27
|
+
margin-bottom: 20px;
|
|
28
|
+
}
|
|
29
|
+
label {
|
|
30
|
+
display: block;
|
|
31
|
+
margin-bottom: 5px;
|
|
32
|
+
font-weight: 600;
|
|
33
|
+
color: #555;
|
|
34
|
+
}
|
|
35
|
+
input, textarea, select {
|
|
36
|
+
width: 100%;
|
|
37
|
+
padding: 10px;
|
|
38
|
+
border: 1px solid #ddd;
|
|
39
|
+
border-radius: 5px;
|
|
40
|
+
font-size: 16px;
|
|
41
|
+
box-sizing: border-box;
|
|
42
|
+
}
|
|
43
|
+
button {
|
|
44
|
+
background: #007bff;
|
|
45
|
+
color: white;
|
|
46
|
+
padding: 12px 24px;
|
|
47
|
+
border: none;
|
|
48
|
+
border-radius: 5px;
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
font-size: 16px;
|
|
51
|
+
margin-right: 10px;
|
|
52
|
+
}
|
|
53
|
+
button:hover {
|
|
54
|
+
background: #0056b3;
|
|
55
|
+
}
|
|
56
|
+
button:disabled {
|
|
57
|
+
background: #ccc;
|
|
58
|
+
cursor: not-allowed;
|
|
59
|
+
}
|
|
60
|
+
.result {
|
|
61
|
+
margin-top: 20px;
|
|
62
|
+
padding: 15px;
|
|
63
|
+
border-radius: 5px;
|
|
64
|
+
white-space: pre-wrap;
|
|
65
|
+
font-family: monospace;
|
|
66
|
+
font-size: 14px;
|
|
67
|
+
}
|
|
68
|
+
.success {
|
|
69
|
+
background: #d4edda;
|
|
70
|
+
border: 1px solid #c3e6cb;
|
|
71
|
+
color: #155724;
|
|
72
|
+
}
|
|
73
|
+
.error {
|
|
74
|
+
background: #f8d7da;
|
|
75
|
+
border: 1px solid #f5c6cb;
|
|
76
|
+
color: #721c24;
|
|
77
|
+
}
|
|
78
|
+
.info {
|
|
79
|
+
background: #d1ecf1;
|
|
80
|
+
border: 1px solid #bee5eb;
|
|
81
|
+
color: #0c5460;
|
|
82
|
+
}
|
|
83
|
+
.tabs {
|
|
84
|
+
display: flex;
|
|
85
|
+
margin-bottom: 20px;
|
|
86
|
+
}
|
|
87
|
+
.tab {
|
|
88
|
+
padding: 10px 20px;
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
border: 1px solid #ddd;
|
|
91
|
+
background: #f8f9fa;
|
|
92
|
+
border-bottom: none;
|
|
93
|
+
}
|
|
94
|
+
.tab.active {
|
|
95
|
+
background: white;
|
|
96
|
+
border-bottom: 1px solid white;
|
|
97
|
+
}
|
|
98
|
+
.tab-content {
|
|
99
|
+
display: none;
|
|
100
|
+
}
|
|
101
|
+
.tab-content.active {
|
|
102
|
+
display: block;
|
|
103
|
+
}
|
|
104
|
+
.checkbox-group {
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: 10px;
|
|
108
|
+
}
|
|
109
|
+
.checkbox-group input[type="checkbox"] {
|
|
110
|
+
width: auto;
|
|
111
|
+
}
|
|
112
|
+
</style>
|
|
113
|
+
</head>
|
|
114
|
+
<body>
|
|
115
|
+
<div class="container">
|
|
116
|
+
<h1>SMS Verification API Demo</h1>
|
|
117
|
+
|
|
118
|
+
<div class="tabs">
|
|
119
|
+
<div class="tab active" onclick="showTab('send')">Send Verification</div>
|
|
120
|
+
<div class="tab" onclick="showTab('verify')">Verify Code</div>
|
|
121
|
+
<div class="tab" onclick="showTab('sms')">Send SMS</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<!-- Send Verification Tab -->
|
|
125
|
+
<div id="send" class="tab-content active">
|
|
126
|
+
<div class="form-group">
|
|
127
|
+
<label for="sendPhone">Phone Number:</label>
|
|
128
|
+
<input type="tel" id="sendPhone" placeholder="+1234567890" value="+1234567890">
|
|
129
|
+
</div>
|
|
130
|
+
<div class="form-group">
|
|
131
|
+
<label for="sendCode">Verification Code (optional):</label>
|
|
132
|
+
<input type="text" id="sendCode" placeholder="Leave empty for auto-generated">
|
|
133
|
+
</div>
|
|
134
|
+
<div class="form-group">
|
|
135
|
+
<label for="sendSenderId">Sender ID:</label>
|
|
136
|
+
<input type="text" id="sendSenderId" placeholder="Verify" value="Verify">
|
|
137
|
+
</div>
|
|
138
|
+
<div class="form-group">
|
|
139
|
+
<label for="sendMessageTemplate">Message Template:</label>
|
|
140
|
+
<textarea id="sendMessageTemplate" rows="3" placeholder="Your verification code is: {code}">Your verification code is: {code}</textarea>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="form-group">
|
|
143
|
+
<label for="sendSmsType">SMS Type:</label>
|
|
144
|
+
<select id="sendSmsType">
|
|
145
|
+
<option value="Transactional">Transactional</option>
|
|
146
|
+
<option value="Promotional">Promotional</option>
|
|
147
|
+
</select>
|
|
148
|
+
</div>
|
|
149
|
+
<div class="form-group">
|
|
150
|
+
<div class="checkbox-group">
|
|
151
|
+
<input type="checkbox" id="blockVoip">
|
|
152
|
+
<label for="blockVoip">Block VoIP Numbers</label>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
<button onclick="sendVerification()">Send Verification Code</button>
|
|
156
|
+
<div id="sendResult" class="result" style="display: none;"></div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<!-- Verify Code Tab -->
|
|
160
|
+
<div id="verify" class="tab-content">
|
|
161
|
+
<div class="form-group">
|
|
162
|
+
<label for="verifyPhone">Phone Number:</label>
|
|
163
|
+
<input type="tel" id="verifyPhone" placeholder="+1234567890" value="+1234567890">
|
|
164
|
+
</div>
|
|
165
|
+
<div class="form-group">
|
|
166
|
+
<label for="verifyCode">Verification Code:</label>
|
|
167
|
+
<input type="text" id="verifyCode" placeholder="Enter the code you received">
|
|
168
|
+
</div>
|
|
169
|
+
<button onclick="verifyCode()">Verify Code</button>
|
|
170
|
+
<div id="verifyResult" class="result" style="display: none;"></div>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<!-- Send SMS Tab -->
|
|
174
|
+
<div id="sms" class="tab-content">
|
|
175
|
+
<div class="form-group">
|
|
176
|
+
<label for="smsPhone">Phone Number:</label>
|
|
177
|
+
<input type="tel" id="smsPhone" placeholder="+1234567890" value="+1234567890">
|
|
178
|
+
</div>
|
|
179
|
+
<div class="form-group">
|
|
180
|
+
<label for="smsMessage">Message:</label>
|
|
181
|
+
<textarea id="smsMessage" rows="4" placeholder="Enter your message here">Hello from the SMS API demo!</textarea>
|
|
182
|
+
</div>
|
|
183
|
+
<div class="form-group">
|
|
184
|
+
<label for="smsSenderId">Sender ID:</label>
|
|
185
|
+
<input type="text" id="smsSenderId" placeholder="Verify" value="Verify">
|
|
186
|
+
</div>
|
|
187
|
+
<div class="form-group">
|
|
188
|
+
<label for="smsType">SMS Type:</label>
|
|
189
|
+
<select id="smsType">
|
|
190
|
+
<option value="Transactional">Transactional</option>
|
|
191
|
+
<option value="Promotional">Promotional</option>
|
|
192
|
+
</select>
|
|
193
|
+
</div>
|
|
194
|
+
<button onclick="sendSMS()">Send SMS</button>
|
|
195
|
+
<div id="smsResult" class="result" style="display: none;"></div>
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<script>
|
|
200
|
+
// Configuration
|
|
201
|
+
const API_BASE_URL = 'http://localhost:8787'; // Change to your deployed URL
|
|
202
|
+
const API_KEY = 'sms_1234567890abcdef1234567890abcdef'; // Change to your API key
|
|
203
|
+
|
|
204
|
+
function showTab(tabName) {
|
|
205
|
+
// Hide all tab contents
|
|
206
|
+
document.querySelectorAll('.tab-content').forEach(content => {
|
|
207
|
+
content.classList.remove('active');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Remove active class from all tabs
|
|
211
|
+
document.querySelectorAll('.tab').forEach(tab => {
|
|
212
|
+
tab.classList.remove('active');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Show selected tab content
|
|
216
|
+
document.getElementById(tabName).classList.add('active');
|
|
217
|
+
|
|
218
|
+
// Add active class to clicked tab
|
|
219
|
+
event.target.classList.add('active');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function showResult(elementId, data, isSuccess = true) {
|
|
223
|
+
const element = document.getElementById(elementId);
|
|
224
|
+
element.style.display = 'block';
|
|
225
|
+
element.className = `result ${isSuccess ? 'success' : 'error'}`;
|
|
226
|
+
element.textContent = JSON.stringify(data, null, 2);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function sendVerification() {
|
|
230
|
+
const phoneNumber = document.getElementById('sendPhone').value;
|
|
231
|
+
const code = document.getElementById('sendCode').value;
|
|
232
|
+
const senderId = document.getElementById('sendSenderId').value;
|
|
233
|
+
const messageTemplate = document.getElementById('sendMessageTemplate').value;
|
|
234
|
+
const smsType = document.getElementById('sendSmsType').value;
|
|
235
|
+
const blockVoip = document.getElementById('blockVoip').checked;
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
const response = await fetch(`${API_BASE_URL}/api/send`, {
|
|
239
|
+
method: 'POST',
|
|
240
|
+
headers: {
|
|
241
|
+
'Content-Type': 'application/json',
|
|
242
|
+
'X-API-Key': API_KEY
|
|
243
|
+
},
|
|
244
|
+
body: JSON.stringify({
|
|
245
|
+
phoneNumber,
|
|
246
|
+
code: code || undefined,
|
|
247
|
+
senderId,
|
|
248
|
+
messageTemplate,
|
|
249
|
+
smsType,
|
|
250
|
+
blockVoip
|
|
251
|
+
})
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const result = await response.json();
|
|
255
|
+
showResult('sendResult', result, result.success);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
showResult('sendResult', { error: error.message }, false);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async function verifyCode() {
|
|
262
|
+
const phoneNumber = document.getElementById('verifyPhone').value;
|
|
263
|
+
const code = document.getElementById('verifyCode').value;
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
const response = await fetch(`${API_BASE_URL}/api/verify`, {
|
|
267
|
+
method: 'POST',
|
|
268
|
+
headers: {
|
|
269
|
+
'Content-Type': 'application/json',
|
|
270
|
+
'X-API-Key': API_KEY
|
|
271
|
+
},
|
|
272
|
+
body: JSON.stringify({
|
|
273
|
+
phoneNumber,
|
|
274
|
+
code
|
|
275
|
+
})
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const result = await response.json();
|
|
279
|
+
showResult('verifyResult', result, result.success);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
showResult('verifyResult', { error: error.message }, false);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function sendSMS() {
|
|
286
|
+
const phoneNumber = document.getElementById('smsPhone').value;
|
|
287
|
+
const message = document.getElementById('smsMessage').value;
|
|
288
|
+
const senderId = document.getElementById('smsSenderId').value;
|
|
289
|
+
const smsType = document.getElementById('smsType').value;
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const response = await fetch(`${API_BASE_URL}/api/sms`, {
|
|
293
|
+
method: 'POST',
|
|
294
|
+
headers: {
|
|
295
|
+
'Content-Type': 'application/json',
|
|
296
|
+
'X-API-Key': API_KEY
|
|
297
|
+
},
|
|
298
|
+
body: JSON.stringify({
|
|
299
|
+
phoneNumber,
|
|
300
|
+
message,
|
|
301
|
+
senderId,
|
|
302
|
+
smsType
|
|
303
|
+
})
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const result = await response.json();
|
|
307
|
+
showResult('smsResult', result, result.success);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
showResult('smsResult', { error: error.message }, false);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Check server health on page load
|
|
314
|
+
window.addEventListener('load', async () => {
|
|
315
|
+
try {
|
|
316
|
+
const response = await fetch(`${API_BASE_URL}/health`);
|
|
317
|
+
const health = await response.json();
|
|
318
|
+
console.log('Server health:', health);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
console.error('Server health check failed:', error);
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
</script>
|
|
324
|
+
</body>
|
|
325
|
+
</html>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import verifyPhone from '../src/verify-phone.js';
|
|
2
|
+
|
|
3
|
+
// Example 1: Using libphonenumber-js for VoIP detection with full metadata
|
|
4
|
+
async function exampleWithLibPhoneNumberVoipDetection() {
|
|
5
|
+
try {
|
|
6
|
+
const result = await verifyPhone({
|
|
7
|
+
phoneNumber: '+1-800-555-0123',
|
|
8
|
+
code: '123456',
|
|
9
|
+
blockVoip: true,
|
|
10
|
+
voipDetectionMethod: 'libphonenumber', // Use local analysis instead of external API
|
|
11
|
+
useLibPhoneNumber: true, // Also use libphonenumber-js for formatting/validation
|
|
12
|
+
metadataType: 'full', // Use full metadata (140KB) for better phone type detection
|
|
13
|
+
messageTemplate: 'Your verification code is: {code}. Valid for 10 minutes.'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
console.log('Result:', result);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error('Error:', error);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Example 2: Using libphonenumber-js for phone number formatting and validation only
|
|
23
|
+
async function exampleWithLibPhoneNumberFormatting() {
|
|
24
|
+
try {
|
|
25
|
+
const result = await verifyPhone({
|
|
26
|
+
phoneNumber: '555-123-4567', // US number without country code
|
|
27
|
+
code: '789012',
|
|
28
|
+
blockVoip: false, // Don't block VoIP numbers
|
|
29
|
+
useLibPhoneNumber: true, // Use libphonenumber-js for formatting/validation
|
|
30
|
+
senderId: 'MyApp',
|
|
31
|
+
smsType: 'Transactional'
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
console.log('Result:', result);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('Error:', error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Example 3: Traditional approach (external API for VoIP detection)
|
|
41
|
+
async function exampleWithExternalApi() {
|
|
42
|
+
try {
|
|
43
|
+
const result = await verifyPhone({
|
|
44
|
+
phoneNumber: '+44 20 7946 0958', // UK number
|
|
45
|
+
code: 'ABCDEF',
|
|
46
|
+
blockVoip: true,
|
|
47
|
+
voipDetectionMethod: 'api', // Use external API (default)
|
|
48
|
+
useLibPhoneNumber: false, // Use basic formatting/validation
|
|
49
|
+
messageTemplate: 'Welcome! Your code: {code}'
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
console.log('Result:', result);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('Error:', error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Example 4: International number with libphonenumber-js
|
|
59
|
+
async function exampleInternationalNumber() {
|
|
60
|
+
try {
|
|
61
|
+
const result = await verifyPhone({
|
|
62
|
+
phoneNumber: '49 30 12345678', // German number
|
|
63
|
+
code: 'GHIJKL',
|
|
64
|
+
blockVoip: true,
|
|
65
|
+
voipDetectionMethod: 'libphonenumber',
|
|
66
|
+
useLibPhoneNumber: true,
|
|
67
|
+
awsRegion: 'eu-west-1'
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
console.log('Result:', result);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Error:', error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Example 5: Comparing minimal vs full metadata
|
|
77
|
+
async function exampleMetadataComparison() {
|
|
78
|
+
try {
|
|
79
|
+
console.log('=== Testing with minimal metadata (75KB) ===');
|
|
80
|
+
const resultMinimal = await verifyPhone({
|
|
81
|
+
phoneNumber: '+1-800-555-0123',
|
|
82
|
+
code: 'MIN123',
|
|
83
|
+
blockVoip: true,
|
|
84
|
+
voipDetectionMethod: 'libphonenumber',
|
|
85
|
+
useLibPhoneNumber: true,
|
|
86
|
+
metadataType: 'minimal' // Uses pattern-based heuristics
|
|
87
|
+
});
|
|
88
|
+
console.log('Minimal metadata result:', resultMinimal);
|
|
89
|
+
|
|
90
|
+
console.log('\n=== Testing with full metadata (140KB) ===');
|
|
91
|
+
const resultFull = await verifyPhone({
|
|
92
|
+
phoneNumber: '+1-800-555-0123',
|
|
93
|
+
code: 'FULL456',
|
|
94
|
+
blockVoip: true,
|
|
95
|
+
voipDetectionMethod: 'libphonenumber',
|
|
96
|
+
useLibPhoneNumber: true,
|
|
97
|
+
metadataType: 'full' // Uses phone number type detection
|
|
98
|
+
});
|
|
99
|
+
console.log('Full metadata result:', resultFull);
|
|
100
|
+
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('Error:', error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Run examples
|
|
107
|
+
console.log('=== Example 1: VoIP Detection with libphonenumber-js ===');
|
|
108
|
+
await exampleWithLibPhoneNumberVoipDetection();
|
|
109
|
+
|
|
110
|
+
console.log('\n=== Example 2: Formatting with libphonenumber-js ===');
|
|
111
|
+
await exampleWithLibPhoneNumberFormatting();
|
|
112
|
+
|
|
113
|
+
console.log('\n=== Example 3: Traditional External API ===');
|
|
114
|
+
await exampleWithExternalApi();
|
|
115
|
+
|
|
116
|
+
console.log('\n=== Example 4: International Number ===');
|
|
117
|
+
await exampleInternationalNumber();
|
|
118
|
+
|
|
119
|
+
console.log('\n=== Example 5: Metadata Comparison ===');
|
|
120
|
+
await exampleMetadataComparison();
|