@glideidentity/web-client-sdk 4.4.8-beta.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.
Files changed (136) hide show
  1. package/README.md +938 -0
  2. package/dist/adapters/angular/client.service.d.ts +7 -0
  3. package/dist/adapters/angular/client.service.js +30 -0
  4. package/dist/adapters/angular/index.d.ts +3 -0
  5. package/dist/adapters/angular/index.js +18 -0
  6. package/dist/adapters/angular/phone-auth.service.d.ts +38 -0
  7. package/dist/adapters/angular/phone-auth.service.js +130 -0
  8. package/dist/adapters/react/index.d.ts +9 -0
  9. package/dist/adapters/react/index.js +28 -0
  10. package/dist/adapters/react/useClient.d.ts +26 -0
  11. package/dist/adapters/react/useClient.js +121 -0
  12. package/dist/adapters/react/usePhoneAuth.d.ts +23 -0
  13. package/dist/adapters/react/usePhoneAuth.js +95 -0
  14. package/dist/adapters/vanilla/client.d.ts +8 -0
  15. package/dist/adapters/vanilla/client.js +33 -0
  16. package/dist/adapters/vanilla/index.d.ts +3 -0
  17. package/dist/adapters/vanilla/index.js +18 -0
  18. package/dist/adapters/vanilla/phone-auth.d.ts +46 -0
  19. package/dist/adapters/vanilla/phone-auth.js +138 -0
  20. package/dist/adapters/vue/index.d.ts +10 -0
  21. package/dist/adapters/vue/index.js +36 -0
  22. package/dist/adapters/vue/useClient.d.ts +115 -0
  23. package/dist/adapters/vue/useClient.js +131 -0
  24. package/dist/adapters/vue/usePhoneAuth.d.ts +94 -0
  25. package/dist/adapters/vue/usePhoneAuth.js +103 -0
  26. package/dist/browser/web-client-sdk.min.js +2 -0
  27. package/dist/browser/web-client-sdk.min.js.LICENSE.txt +1 -0
  28. package/dist/browser.d.ts +7 -0
  29. package/dist/browser.js +31 -0
  30. package/dist/core/client.d.ts +22 -0
  31. package/dist/core/client.js +77 -0
  32. package/dist/core/logger.d.ts +130 -0
  33. package/dist/core/logger.js +370 -0
  34. package/dist/core/phone-auth/api-types.d.ts +525 -0
  35. package/dist/core/phone-auth/api-types.js +215 -0
  36. package/dist/core/phone-auth/client.d.ts +187 -0
  37. package/dist/core/phone-auth/client.js +1353 -0
  38. package/dist/core/phone-auth/error-utils.d.ts +110 -0
  39. package/dist/core/phone-auth/error-utils.js +350 -0
  40. package/dist/core/phone-auth/index.d.ts +7 -0
  41. package/dist/core/phone-auth/index.js +47 -0
  42. package/dist/core/phone-auth/status-types.d.ts +107 -0
  43. package/dist/core/phone-auth/status-types.js +31 -0
  44. package/dist/core/phone-auth/strategies/desktop.d.ts +113 -0
  45. package/dist/core/phone-auth/strategies/desktop.js +502 -0
  46. package/dist/core/phone-auth/strategies/index.d.ts +11 -0
  47. package/dist/core/phone-auth/strategies/index.js +15 -0
  48. package/dist/core/phone-auth/strategies/link.d.ts +81 -0
  49. package/dist/core/phone-auth/strategies/link.js +265 -0
  50. package/dist/core/phone-auth/strategies/ts43.d.ts +32 -0
  51. package/dist/core/phone-auth/strategies/ts43.js +146 -0
  52. package/dist/core/phone-auth/strategies/types.d.ts +18 -0
  53. package/dist/core/phone-auth/strategies/types.js +6 -0
  54. package/dist/core/phone-auth/type-guards.d.ts +125 -0
  55. package/dist/core/phone-auth/type-guards.js +160 -0
  56. package/dist/core/phone-auth/types.d.ts +232 -0
  57. package/dist/core/phone-auth/types.js +93 -0
  58. package/dist/core/phone-auth/ui/mobile-debug-console.d.ts +25 -0
  59. package/dist/core/phone-auth/ui/mobile-debug-console.js +288 -0
  60. package/dist/core/phone-auth/ui/modal.d.ts +84 -0
  61. package/dist/core/phone-auth/ui/modal.js +574 -0
  62. package/dist/core/phone-auth/validation-utils.d.ts +66 -0
  63. package/dist/core/phone-auth/validation-utils.js +182 -0
  64. package/dist/core/types.d.ts +62 -0
  65. package/dist/core/types.js +2 -0
  66. package/dist/core/version.d.ts +1 -0
  67. package/dist/core/version.js +5 -0
  68. package/dist/esm/adapters/angular/client.service.d.ts +7 -0
  69. package/dist/esm/adapters/angular/client.service.js +27 -0
  70. package/dist/esm/adapters/angular/index.d.ts +3 -0
  71. package/dist/esm/adapters/angular/index.js +4 -0
  72. package/dist/esm/adapters/angular/phone-auth.service.d.ts +38 -0
  73. package/dist/esm/adapters/angular/phone-auth.service.js +127 -0
  74. package/dist/esm/adapters/react/index.d.ts +9 -0
  75. package/dist/esm/adapters/react/index.js +8 -0
  76. package/dist/esm/adapters/react/useClient.d.ts +26 -0
  77. package/dist/esm/adapters/react/useClient.js +116 -0
  78. package/dist/esm/adapters/react/usePhoneAuth.d.ts +23 -0
  79. package/dist/esm/adapters/react/usePhoneAuth.js +92 -0
  80. package/dist/esm/adapters/vanilla/client.d.ts +8 -0
  81. package/dist/esm/adapters/vanilla/client.js +29 -0
  82. package/dist/esm/adapters/vanilla/index.d.ts +3 -0
  83. package/dist/esm/adapters/vanilla/index.js +4 -0
  84. package/dist/esm/adapters/vanilla/phone-auth.d.ts +46 -0
  85. package/dist/esm/adapters/vanilla/phone-auth.js +134 -0
  86. package/dist/esm/adapters/vue/index.d.ts +10 -0
  87. package/dist/esm/adapters/vue/index.js +11 -0
  88. package/dist/esm/adapters/vue/useClient.d.ts +115 -0
  89. package/dist/esm/adapters/vue/useClient.js +127 -0
  90. package/dist/esm/adapters/vue/usePhoneAuth.d.ts +94 -0
  91. package/dist/esm/adapters/vue/usePhoneAuth.js +100 -0
  92. package/dist/esm/browser.d.ts +7 -0
  93. package/dist/esm/browser.js +11 -0
  94. package/dist/esm/core/client.d.ts +22 -0
  95. package/dist/esm/core/client.js +70 -0
  96. package/dist/esm/core/logger.d.ts +130 -0
  97. package/dist/esm/core/logger.js +359 -0
  98. package/dist/esm/core/phone-auth/api-types.d.ts +525 -0
  99. package/dist/esm/core/phone-auth/api-types.js +203 -0
  100. package/dist/esm/core/phone-auth/client.d.ts +187 -0
  101. package/dist/esm/core/phone-auth/client.js +1316 -0
  102. package/dist/esm/core/phone-auth/error-utils.d.ts +110 -0
  103. package/dist/esm/core/phone-auth/error-utils.js +338 -0
  104. package/dist/esm/core/phone-auth/index.d.ts +7 -0
  105. package/dist/esm/core/phone-auth/index.js +6 -0
  106. package/dist/esm/core/phone-auth/status-types.d.ts +107 -0
  107. package/dist/esm/core/phone-auth/status-types.js +26 -0
  108. package/dist/esm/core/phone-auth/strategies/desktop.d.ts +113 -0
  109. package/dist/esm/core/phone-auth/strategies/desktop.js +496 -0
  110. package/dist/esm/core/phone-auth/strategies/index.d.ts +11 -0
  111. package/dist/esm/core/phone-auth/strategies/index.js +7 -0
  112. package/dist/esm/core/phone-auth/strategies/link.d.ts +81 -0
  113. package/dist/esm/core/phone-auth/strategies/link.js +261 -0
  114. package/dist/esm/core/phone-auth/strategies/ts43.d.ts +32 -0
  115. package/dist/esm/core/phone-auth/strategies/ts43.js +142 -0
  116. package/dist/esm/core/phone-auth/strategies/types.d.ts +18 -0
  117. package/dist/esm/core/phone-auth/strategies/types.js +5 -0
  118. package/dist/esm/core/phone-auth/type-guards.d.ts +125 -0
  119. package/dist/esm/core/phone-auth/type-guards.js +150 -0
  120. package/dist/esm/core/phone-auth/types.d.ts +232 -0
  121. package/dist/esm/core/phone-auth/types.js +76 -0
  122. package/dist/esm/core/phone-auth/ui/mobile-debug-console.d.ts +25 -0
  123. package/dist/esm/core/phone-auth/ui/mobile-debug-console.js +284 -0
  124. package/dist/esm/core/phone-auth/ui/modal.d.ts +84 -0
  125. package/dist/esm/core/phone-auth/ui/modal.js +570 -0
  126. package/dist/esm/core/phone-auth/validation-utils.d.ts +66 -0
  127. package/dist/esm/core/phone-auth/validation-utils.js +174 -0
  128. package/dist/esm/core/types.d.ts +62 -0
  129. package/dist/esm/core/types.js +1 -0
  130. package/dist/esm/core/version.d.ts +1 -0
  131. package/dist/esm/core/version.js +2 -0
  132. package/dist/esm/index.d.ts +12 -0
  133. package/dist/esm/index.js +15 -0
  134. package/dist/index.d.ts +12 -0
  135. package/dist/index.js +52 -0
  136. package/package.json +92 -0
@@ -0,0 +1,570 @@
1
+ /**
2
+ * Modal UI Component for Phone Authentication
3
+ *
4
+ * This file creates the UI components (modals, buttons) that are shown
5
+ * when the SDK is NOT in headless mode. Think of it like a popup window
6
+ * that handles the authentication flow for you.
7
+ */
8
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
9
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
10
+ return new (P || (P = Promise))(function (resolve, reject) {
11
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
12
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
13
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
14
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
15
+ });
16
+ };
17
+ /**
18
+ * Creates and manages a modal dialog for authentication
19
+ *
20
+ * @example
21
+ * const modal = new AuthModal({
22
+ * title: "Verify Your Phone",
23
+ * description: "Complete authentication to continue"
24
+ * });
25
+ * modal.show();
26
+ */
27
+ export class AuthModal {
28
+ constructor(options, callbacks) {
29
+ this.container = null;
30
+ this.backdrop = null;
31
+ this.isOpen = false;
32
+ this.options = options || {};
33
+ this.callbacks = callbacks || {};
34
+ // Bind escape key handler
35
+ this.handleEscapeKey = this.handleEscapeKey.bind(this);
36
+ }
37
+ handleEscapeKey(event) {
38
+ var _a, _b;
39
+ if (event.key === 'Escape' && this.isOpen) {
40
+ // Check if escape closing is enabled (default true)
41
+ if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.closeOnEscape) !== false) {
42
+ (_b = this.closeCallback) === null || _b === void 0 ? void 0 : _b.call(this); // Call the cancellation callback if set
43
+ this.close();
44
+ }
45
+ }
46
+ }
47
+ /**
48
+ * Shows the modal with a QR code for desktop authentication
49
+ * Supports both single QR code (legacy) and dual-platform QR codes (iOS + Android)
50
+ */
51
+ showQRCode(qrCodeData, statusMessage = 'Scan QR code with your phone') {
52
+ console.log('[Modal] showQRCode called with:', qrCodeData);
53
+ // Check if it's the new dual-platform format with VALID Android QR code
54
+ if (typeof qrCodeData === 'object' && qrCodeData.iosQRCode) {
55
+ const hasValidAndroidQR = qrCodeData.androidQRCode &&
56
+ qrCodeData.androidQRCode.length > 0 &&
57
+ qrCodeData.androidQRCode !== qrCodeData.iosQRCode;
58
+ console.log('[Modal] Has valid Android QR?', hasValidAndroidQR);
59
+ if (hasValidAndroidQR) {
60
+ console.log('[Modal] Using dual-platform modal');
61
+ this.createDualPlatformQRModal(qrCodeData, statusMessage);
62
+ }
63
+ else {
64
+ console.log('[Modal] Android QR missing/empty, using single iOS QR');
65
+ // Only iOS QR code available - show single QR
66
+ this.createModal(`
67
+ <div class="glide-auth-qr-container">
68
+ <img src="${qrCodeData.iosQRCode}" alt="QR Code" class="glide-auth-qr-code" />
69
+ <p class="glide-auth-status">Scan with your iPhone to authenticate</p>
70
+ </div>
71
+ `);
72
+ }
73
+ }
74
+ else {
75
+ console.log('[Modal] Using legacy single QR code modal');
76
+ // Legacy single QR code
77
+ this.createModal(`
78
+ <div class="glide-auth-qr-container">
79
+ <img src="${qrCodeData}" alt="QR Code" class="glide-auth-qr-code" />
80
+ <p class="glide-auth-status">${statusMessage}</p>
81
+ </div>
82
+ `);
83
+ }
84
+ this.show();
85
+ }
86
+ /**
87
+ * Creates a modal with iOS/Android platform toggle
88
+ */
89
+ createDualPlatformQRModal(qrCodeData, statusMessage) {
90
+ this.createModal(`
91
+ <div class="glide-auth-qr-container">
92
+ <!-- Platform Switcher -->
93
+ <div class="glide-platform-switcher">
94
+ <button class="glide-platform-btn glide-platform-ios active" data-platform="ios">
95
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
96
+ <path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/>
97
+ </svg>
98
+ <span>iOS</span>
99
+ </button>
100
+ <button class="glide-platform-btn glide-platform-android" data-platform="android">
101
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
102
+ <path d="M17.6 9.48l1.84-3.18c.16-.31.04-.69-.26-.85-.29-.15-.65-.06-.83.22l-1.88 3.24c-2.86-1.21-6.08-1.21-8.94 0L5.65 5.67c-.19-.28-.54-.38-.83-.22-.3.16-.42.54-.26.85l1.84 3.18C4.08 11.08 2.4 13.97 2.4 17.2h19.2c0-3.23-1.68-6.12-4.0-7.72zM7.0 14.8c-.66 0-1.2-.54-1.2-1.2s.54-1.2 1.2-1.2 1.2.54 1.2 1.2-.54 1.2-1.2 1.2zm10 0c-.66 0-1.2-.54-1.2-1.2s.54-1.2 1.2-1.2 1.2.54 1.2 1.2-.54 1.2-1.2 1.2z"/>
103
+ </svg>
104
+ <span>Android</span>
105
+ </button>
106
+ </div>
107
+
108
+ <!-- QR Code Image -->
109
+ <img
110
+ id="glide-qr-code-img"
111
+ src="${qrCodeData.iosQRCode}"
112
+ alt="QR Code"
113
+ class="glide-auth-qr-code"
114
+ data-ios="${qrCodeData.iosQRCode}"
115
+ data-android="${qrCodeData.androidQRCode}"
116
+ />
117
+
118
+ <!-- Status Message -->
119
+ <p class="glide-auth-status" id="glide-platform-message">Scan with your iPhone to authenticate</p>
120
+ </div>
121
+ `);
122
+ }
123
+ /**
124
+ * Sets a callback to be called when the modal is cancelled/closed
125
+ */
126
+ setCloseCallback(callback) {
127
+ this.closeCallback = callback;
128
+ }
129
+ /**
130
+ * Shows the modal with a button for Link authentication (App Clips)
131
+ * IMPORTANT: The button click is required for iOS to recognize the app link
132
+ */
133
+ showLinkButton(url, buttonText) {
134
+ return new Promise((resolve) => {
135
+ var _a, _b, _c;
136
+ const text = buttonText || ((_a = this.options) === null || _a === void 0 ? void 0 : _a.buttonText) || 'Open Verification App';
137
+ this.createModal(`
138
+ <div class="glide-auth-link-container">
139
+ <p class="glide-auth-description">
140
+ ${((_b = this.options) === null || _b === void 0 ? void 0 : _b.description) || 'Click below to verify your phone number'}
141
+ </p>
142
+ <button class="glide-auth-button" id="glide-auth-link-button">
143
+ ${text}
144
+ </button>
145
+ <p class="glide-auth-helper-text">
146
+ You'll be redirected to complete verification
147
+ </p>
148
+ </div>
149
+ `);
150
+ // Show modal first so elements are in the DOM
151
+ this.show();
152
+ // Add click handler for the button AFTER modal is in DOM
153
+ // CRITICAL: This click event is required for iOS to recognize the app link
154
+ // Do NOT call window.open automatically - it must be triggered by user interaction
155
+ const button = (_c = this.container) === null || _c === void 0 ? void 0 : _c.querySelector('#glide-auth-link-button');
156
+ if (button) {
157
+ button.addEventListener('click', (event) => {
158
+ var _a, _b;
159
+ (_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onAuthStart) === null || _b === void 0 ? void 0 : _b.call(_a);
160
+ // User-initiated click is required for app links to work properly on iOS
161
+ // This ensures the OS recognizes it should open an app, not just a browser tab
162
+ window.open(url, '_blank');
163
+ resolve();
164
+ });
165
+ }
166
+ else {
167
+ console.error('[Modal] Link button not found in modal');
168
+ }
169
+ });
170
+ }
171
+ /**
172
+ * Shows the modal with a button for TS43 authentication
173
+ * IMPORTANT: The button click is required for Digital Credentials API (transient activation)
174
+ */
175
+ showTS43Button(onAuthenticate) {
176
+ return new Promise((resolve, reject) => {
177
+ var _a, _b, _c;
178
+ const text = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.buttonText) || 'Verify with Carrier';
179
+ this.createModal(`
180
+ <div class="glide-auth-ts43-container">
181
+ <p class="glide-auth-description">
182
+ ${((_b = this.options) === null || _b === void 0 ? void 0 : _b.description) || 'Verify using your carrier credentials'}
183
+ </p>
184
+ <button class="glide-auth-button" id="glide-auth-ts43-button">
185
+ ${text}
186
+ </button>
187
+ <p class="glide-auth-helper-text">
188
+ Secure verification through your mobile carrier
189
+ </p>
190
+ </div>
191
+ `);
192
+ // Show modal first so elements are in the DOM
193
+ this.show();
194
+ // Add click handler for the button AFTER modal is in DOM
195
+ // CRITICAL: Digital Credentials API requires "transient activation" (user interaction)
196
+ // Do NOT call onAuthenticate automatically - it must be triggered by user click
197
+ const button = (_c = this.container) === null || _c === void 0 ? void 0 : _c.querySelector('#glide-auth-ts43-button');
198
+ if (button) {
199
+ button.addEventListener('click', (event) => __awaiter(this, void 0, void 0, function* () {
200
+ var _a, _b, _c, _d, _e, _f;
201
+ (_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onAuthStart) === null || _b === void 0 ? void 0 : _b.call(_a);
202
+ button.setAttribute('disabled', 'true');
203
+ button.textContent = 'Verifying...';
204
+ try {
205
+ const result = yield onAuthenticate();
206
+ (_d = (_c = this.callbacks) === null || _c === void 0 ? void 0 : _c.onAuthComplete) === null || _d === void 0 ? void 0 : _d.call(_c, result);
207
+ resolve(result);
208
+ this.close();
209
+ }
210
+ catch (error) {
211
+ (_f = (_e = this.callbacks) === null || _e === void 0 ? void 0 : _e.onError) === null || _f === void 0 ? void 0 : _f.call(_e, error);
212
+ button.removeAttribute('disabled');
213
+ button.textContent = text;
214
+ reject(error);
215
+ }
216
+ }));
217
+ }
218
+ else {
219
+ console.error('[Modal] TS43 button not found in modal');
220
+ }
221
+ });
222
+ }
223
+ /**
224
+ * Updates the status message in the modal
225
+ */
226
+ updateStatus(message, isError = false) {
227
+ var _a;
228
+ const statusEl = (_a = this.container) === null || _a === void 0 ? void 0 : _a.querySelector('.glide-auth-status');
229
+ if (statusEl) {
230
+ statusEl.textContent = message;
231
+ statusEl.className = isError ? 'glide-auth-status glide-auth-error' : 'glide-auth-status';
232
+ }
233
+ }
234
+ /**
235
+ * Creates the modal HTML structure
236
+ */
237
+ createModal(content) {
238
+ var _a, _b, _c;
239
+ // Clean up any existing modal
240
+ this.cleanup();
241
+ // Create backdrop (dark overlay)
242
+ this.backdrop = document.createElement('div');
243
+ this.backdrop.className = 'glide-auth-backdrop';
244
+ this.backdrop.style.cssText = `
245
+ position: fixed;
246
+ top: 0;
247
+ left: 0;
248
+ right: 0;
249
+ bottom: 0;
250
+ background: rgba(0, 0, 0, 0.5);
251
+ z-index: 9998;
252
+ opacity: 0;
253
+ transition: opacity 0.3s ease;
254
+ `;
255
+ // Create modal container
256
+ this.container = document.createElement('div');
257
+ this.container.className = `glide-auth-modal ${((_a = this.options) === null || _a === void 0 ? void 0 : _a.className) || ''}`;
258
+ this.container.style.cssText = `
259
+ position: fixed;
260
+ top: 50%;
261
+ left: 50%;
262
+ transform: translate(-50%, -50%) scale(0.9);
263
+ background: white;
264
+ border-radius: 12px;
265
+ padding: 24px;
266
+ max-width: 400px;
267
+ width: 90%;
268
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
269
+ z-index: 9999;
270
+ opacity: 0;
271
+ transition: opacity 0.3s ease, transform 0.3s ease;
272
+ `;
273
+ // Add modal content
274
+ this.container.innerHTML = `
275
+ <div class="glide-auth-header">
276
+ ${((_b = this.options) === null || _b === void 0 ? void 0 : _b.showCloseButton) !== false ? `
277
+ <button class="glide-auth-close" aria-label="Close">
278
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
279
+ <line x1="18" y1="6" x2="6" y2="18"></line>
280
+ <line x1="6" y1="6" x2="18" y2="18"></line>
281
+ </svg>
282
+ </button>
283
+ ` : ''}
284
+ <h2 class="glide-auth-title">${((_c = this.options) === null || _c === void 0 ? void 0 : _c.title) || 'Phone Verification'}</h2>
285
+ </div>
286
+ <div class="glide-auth-content">
287
+ ${content}
288
+ </div>
289
+ `;
290
+ // Add styles
291
+ this.injectStyles();
292
+ // Add close button handler
293
+ const closeBtn = this.container.querySelector('.glide-auth-close');
294
+ if (closeBtn) {
295
+ closeBtn.addEventListener('click', () => this.close());
296
+ }
297
+ // Add backdrop click handler
298
+ this.backdrop.addEventListener('click', (e) => {
299
+ var _a, _b;
300
+ // Only close if backdrop itself was clicked and closeOnBackdrop is enabled (default true)
301
+ if (e.target === this.backdrop && ((_a = this.options) === null || _a === void 0 ? void 0 : _a.closeOnBackdrop) !== false) {
302
+ (_b = this.closeCallback) === null || _b === void 0 ? void 0 : _b.call(this); // Call cancellation callback if set
303
+ this.close();
304
+ }
305
+ });
306
+ }
307
+ /**
308
+ * Injects CSS styles for the modal
309
+ */
310
+ injectStyles() {
311
+ if (document.getElementById('glide-auth-styles'))
312
+ return;
313
+ const styles = document.createElement('style');
314
+ styles.id = 'glide-auth-styles';
315
+ styles.textContent = `
316
+ .glide-auth-backdrop {
317
+ backdrop-filter: blur(4px);
318
+ }
319
+
320
+ .glide-auth-modal {
321
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
322
+ }
323
+
324
+ .glide-auth-header {
325
+ position: relative;
326
+ margin-bottom: 20px;
327
+ }
328
+
329
+ .glide-auth-close {
330
+ position: absolute;
331
+ top: 0;
332
+ right: 0;
333
+ background: none;
334
+ border: none;
335
+ cursor: pointer;
336
+ padding: 0;
337
+ color: #666;
338
+ transition: color 0.2s;
339
+ }
340
+
341
+ .glide-auth-close:hover {
342
+ color: #000;
343
+ }
344
+
345
+ .glide-auth-title {
346
+ margin: 0;
347
+ font-size: 24px;
348
+ font-weight: 600;
349
+ color: #333;
350
+ text-align: center;
351
+ }
352
+
353
+ .glide-auth-content {
354
+ text-align: center;
355
+ }
356
+
357
+ .glide-auth-description {
358
+ color: #666;
359
+ margin: 0 0 20px 0;
360
+ font-size: 16px;
361
+ line-height: 1.5;
362
+ }
363
+
364
+ .glide-auth-button {
365
+ background: #007AFF;
366
+ color: white;
367
+ border: none;
368
+ border-radius: 8px;
369
+ padding: 12px 24px;
370
+ font-size: 16px;
371
+ font-weight: 500;
372
+ cursor: pointer;
373
+ transition: background 0.2s, transform 0.1s;
374
+ min-width: 200px;
375
+ }
376
+
377
+ .glide-auth-button:hover:not(:disabled) {
378
+ background: #0051D5;
379
+ transform: translateY(-1px);
380
+ }
381
+
382
+ .glide-auth-button:active {
383
+ transform: translateY(0);
384
+ }
385
+
386
+ .glide-auth-button:disabled {
387
+ opacity: 0.6;
388
+ cursor: not-allowed;
389
+ }
390
+
391
+ .glide-auth-helper-text {
392
+ color: #999;
393
+ font-size: 14px;
394
+ margin: 16px 0 0 0;
395
+ }
396
+
397
+ .glide-auth-qr-code {
398
+ max-width: 256px;
399
+ width: 100%;
400
+ height: auto;
401
+ margin: 20px auto;
402
+ display: block;
403
+ }
404
+
405
+ .glide-auth-status {
406
+ color: #666;
407
+ font-size: 16px;
408
+ margin: 16px 0;
409
+ }
410
+
411
+ .glide-auth-error {
412
+ color: #FF3B30;
413
+ }
414
+
415
+ .glide-auth-qr-container,
416
+ .glide-auth-link-container,
417
+ .glide-auth-ts43-container {
418
+ padding: 20px 0;
419
+ }
420
+
421
+ /* Platform Switcher Styles */
422
+ .glide-platform-switcher {
423
+ display: flex;
424
+ justify-content: center;
425
+ gap: 10px;
426
+ margin-bottom: 20px;
427
+ }
428
+
429
+ .glide-platform-btn {
430
+ display: flex;
431
+ align-items: center;
432
+ gap: 6px;
433
+ padding: 10px 20px;
434
+ border: 2px solid;
435
+ background: transparent;
436
+ border-radius: 8px;
437
+ cursor: pointer;
438
+ font-size: 14px;
439
+ font-weight: 600;
440
+ transition: all 0.2s ease;
441
+ }
442
+
443
+ .glide-platform-btn svg {
444
+ flex-shrink: 0;
445
+ }
446
+
447
+ .glide-platform-ios {
448
+ border-color: #007AFF;
449
+ color: #007AFF;
450
+ }
451
+
452
+ .glide-platform-ios.active {
453
+ background: #007AFF;
454
+ color: white;
455
+ }
456
+
457
+ .glide-platform-ios:hover:not(.active) {
458
+ background: rgba(0, 122, 255, 0.1);
459
+ }
460
+
461
+ .glide-platform-android {
462
+ border-color: #3DDC84;
463
+ color: #3DDC84;
464
+ }
465
+
466
+ .glide-platform-android.active {
467
+ background: #3DDC84;
468
+ color: white;
469
+ }
470
+
471
+ .glide-platform-android:hover:not(.active) {
472
+ background: rgba(61, 220, 132, 0.1);
473
+ }
474
+ `;
475
+ document.head.appendChild(styles);
476
+ }
477
+ /**
478
+ * Shows the modal with animation
479
+ */
480
+ show() {
481
+ var _a, _b;
482
+ if (!this.container || !this.backdrop || this.isOpen)
483
+ return;
484
+ document.body.appendChild(this.backdrop);
485
+ document.body.appendChild(this.container);
486
+ // Add escape key listener for closing modal
487
+ document.addEventListener('keydown', this.handleEscapeKey);
488
+ // Setup platform toggle handlers if they exist
489
+ this.setupPlatformToggles();
490
+ // Trigger animation
491
+ requestAnimationFrame(() => {
492
+ if (this.backdrop && this.container) {
493
+ this.backdrop.style.opacity = '1';
494
+ this.container.style.opacity = '1';
495
+ this.container.style.transform = 'translate(-50%, -50%) scale(1)';
496
+ }
497
+ });
498
+ this.isOpen = true;
499
+ (_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onOpen) === null || _b === void 0 ? void 0 : _b.call(_a);
500
+ }
501
+ /**
502
+ * Setup click handlers for iOS/Android platform toggle
503
+ */
504
+ setupPlatformToggles() {
505
+ var _a, _b, _c;
506
+ const platformBtns = (_a = this.container) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.glide-platform-btn');
507
+ const qrImg = (_b = this.container) === null || _b === void 0 ? void 0 : _b.querySelector('#glide-qr-code-img');
508
+ const message = (_c = this.container) === null || _c === void 0 ? void 0 : _c.querySelector('#glide-platform-message');
509
+ if (!platformBtns || !qrImg)
510
+ return;
511
+ platformBtns.forEach((btn) => {
512
+ btn.addEventListener('click', (e) => {
513
+ const target = e.currentTarget;
514
+ const platform = target.getAttribute('data-platform');
515
+ // Update active state
516
+ platformBtns.forEach(b => b.classList.remove('active'));
517
+ target.classList.add('active');
518
+ // Switch QR code
519
+ if (platform === 'ios') {
520
+ qrImg.src = qrImg.getAttribute('data-ios') || '';
521
+ if (message)
522
+ message.textContent = 'Scan with your iPhone to authenticate';
523
+ }
524
+ else if (platform === 'android') {
525
+ qrImg.src = qrImg.getAttribute('data-android') || '';
526
+ if (message)
527
+ message.textContent = 'Scan with your Android device to authenticate';
528
+ }
529
+ });
530
+ });
531
+ }
532
+ /**
533
+ * Closes the modal with animation
534
+ */
535
+ close() {
536
+ if (!this.container || !this.backdrop || !this.isOpen)
537
+ return;
538
+ // Remove escape key listener
539
+ document.removeEventListener('keydown', this.handleEscapeKey);
540
+ // Animate out
541
+ this.backdrop.style.opacity = '0';
542
+ this.container.style.opacity = '0';
543
+ this.container.style.transform = 'translate(-50%, -50%) scale(0.9)';
544
+ // Clear any stored callbacks
545
+ this.closeCallback = undefined;
546
+ // Remove after animation
547
+ setTimeout(() => {
548
+ var _a, _b;
549
+ this.cleanup();
550
+ this.isOpen = false;
551
+ (_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onClose) === null || _b === void 0 ? void 0 : _b.call(_a);
552
+ }, 300);
553
+ }
554
+ /**
555
+ * Removes modal elements from DOM
556
+ */
557
+ cleanup() {
558
+ var _a, _b;
559
+ (_a = this.container) === null || _a === void 0 ? void 0 : _a.remove();
560
+ (_b = this.backdrop) === null || _b === void 0 ? void 0 : _b.remove();
561
+ this.container = null;
562
+ this.backdrop = null;
563
+ }
564
+ /**
565
+ * Check if modal is currently open
566
+ */
567
+ isModalOpen() {
568
+ return this.isOpen;
569
+ }
570
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Validation utilities for phone authentication
3
+ */
4
+ import { PhoneAuthErrorCode } from './error-utils';
5
+ import type { PLMN, UseCase } from './api-types';
6
+ /**
7
+ * Validates E.164 phone number format
8
+ * @param phoneNumber - Phone number to validate
9
+ * @returns Validation result with error if invalid
10
+ */
11
+ export declare function validatePhoneNumber(phoneNumber?: string): {
12
+ valid: boolean;
13
+ error?: string;
14
+ };
15
+ /**
16
+ * Validates PLMN (MCC/MNC) values
17
+ * @param plmn - PLMN object with MCC and MNC
18
+ * @returns Validation result
19
+ */
20
+ export declare function validatePlmn(plmn?: PLMN): {
21
+ valid: boolean;
22
+ error?: string;
23
+ };
24
+ /**
25
+ * Validates use case and phone number combination
26
+ * @param useCase - The use case
27
+ * @param phoneNumber - The phone number (required for VerifyPhoneNumber)
28
+ * @param hasParentSessionId - Whether parent_session_id is provided (allows skipping normal validation)
29
+ * @returns Validation result
30
+ */
31
+ export declare function validateUseCaseRequirements(useCase: UseCase, phoneNumber?: string, hasParentSessionId?: boolean): {
32
+ valid: boolean;
33
+ error?: string;
34
+ };
35
+ /**
36
+ * Validates consent data
37
+ * @param consentData - Consent data object
38
+ * @returns Validation result
39
+ */
40
+ export declare function validateConsentData(consentData?: {
41
+ consent_text: string;
42
+ policy_link: string;
43
+ policy_text: string;
44
+ }): {
45
+ valid: boolean;
46
+ error?: string;
47
+ };
48
+ /**
49
+ * Creates a validation error
50
+ * @param code - Error code
51
+ * @param message - Error message
52
+ * @param field - Field that failed validation
53
+ */
54
+ export declare function createValidationError(code: PhoneAuthErrorCode, message: string, field?: string): Error & {
55
+ code: PhoneAuthErrorCode;
56
+ field?: string;
57
+ };
58
+ /**
59
+ * Validates nonce format
60
+ * @param nonce - Nonce string to validate
61
+ * @returns Validation result
62
+ */
63
+ export declare function validateNonce(nonce: string): {
64
+ valid: boolean;
65
+ error?: string;
66
+ };