@glideidentity/web-client-sdk 4.4.8-beta.1 → 4.4.8-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/adapters/react/usePhoneAuth.d.ts +1 -1
  2. package/dist/adapters/vue/useClient.d.ts +3 -3
  3. package/dist/adapters/vue/usePhoneAuth.d.ts +1 -1
  4. package/dist/browser/web-client-sdk.min.js +1 -1
  5. package/dist/core/phone-auth/api-types.d.ts +112 -27
  6. package/dist/core/phone-auth/client.d.ts +13 -11
  7. package/dist/core/phone-auth/client.js +257 -248
  8. package/dist/core/phone-auth/index.d.ts +1 -1
  9. package/dist/core/phone-auth/index.js +7 -2
  10. package/dist/core/phone-auth/strategies/desktop.d.ts +1 -0
  11. package/dist/core/phone-auth/strategies/desktop.js +64 -18
  12. package/dist/core/phone-auth/type-guards.d.ts +61 -43
  13. package/dist/core/phone-auth/type-guards.js +82 -44
  14. package/dist/core/phone-auth/ui/modal.js +14 -1
  15. package/dist/core/version.js +1 -1
  16. package/dist/esm/adapters/react/usePhoneAuth.d.ts +1 -1
  17. package/dist/esm/adapters/vue/useClient.d.ts +3 -3
  18. package/dist/esm/adapters/vue/usePhoneAuth.d.ts +1 -1
  19. package/dist/esm/core/phone-auth/api-types.d.ts +112 -27
  20. package/dist/esm/core/phone-auth/client.d.ts +13 -11
  21. package/dist/esm/core/phone-auth/client.js +257 -248
  22. package/dist/esm/core/phone-auth/index.d.ts +1 -1
  23. package/dist/esm/core/phone-auth/index.js +3 -1
  24. package/dist/esm/core/phone-auth/strategies/desktop.d.ts +1 -0
  25. package/dist/esm/core/phone-auth/strategies/desktop.js +64 -18
  26. package/dist/esm/core/phone-auth/type-guards.d.ts +61 -43
  27. package/dist/esm/core/phone-auth/type-guards.js +76 -41
  28. package/dist/esm/core/phone-auth/ui/modal.js +14 -1
  29. package/dist/esm/core/version.js +1 -1
  30. package/dist/esm/index.d.ts +2 -2
  31. package/dist/esm/index.js +3 -1
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.js +7 -2
  34. package/package.json +1 -1
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.requiresUserAction = exports.requiresPolling = exports.getStrategy = exports.isDesktopStrategy = exports.isTS43Strategy = exports.isLinkStrategy = exports.isCredential = exports.isHeadlessResult = exports.MobileDebugConsole = exports.validateNonce = exports.validateConsentData = exports.validateUseCaseRequirements = exports.validatePlmn = exports.validatePhoneNumber = exports.createErrorBreadcrumb = exports.serializeError = exports.isRetryableError = exports.getRetryDelay = exports.isErrorCode = exports.getUserMessage = exports.isUserError = exports.isPhoneAuthError = exports.PhoneAuthErrorCode = exports.PhoneAuthClient = void 0;
17
+ exports.requiresUserAction = exports.requiresPolling = exports.isHeadlessResult = exports.hasTrigger = exports.hasPollingControls = exports.getStrategy = exports.isDesktopStrategy = exports.isTS43Strategy = exports.isLinkStrategy = exports.isAuthCredential = exports.isCredential = exports.isExtendedResponse = exports.MobileDebugConsole = exports.validateNonce = exports.validateConsentData = exports.validateUseCaseRequirements = exports.validatePlmn = exports.validatePhoneNumber = exports.createErrorBreadcrumb = exports.serializeError = exports.isRetryableError = exports.getRetryDelay = exports.isErrorCode = exports.getUserMessage = exports.isUserError = exports.isPhoneAuthError = exports.PhoneAuthErrorCode = exports.PhoneAuthClient = void 0;
18
18
  var client_1 = require("./client");
19
19
  Object.defineProperty(exports, "PhoneAuthClient", { enumerable: true, get: function () { return client_1.PhoneAuthClient; } });
20
20
  __exportStar(require("./types"), exports);
@@ -37,11 +37,16 @@ Object.defineProperty(exports, "validateNonce", { enumerable: true, get: functio
37
37
  var mobile_debug_console_1 = require("./ui/mobile-debug-console");
38
38
  Object.defineProperty(exports, "MobileDebugConsole", { enumerable: true, get: function () { return mobile_debug_console_1.MobileDebugConsole; } });
39
39
  var type_guards_1 = require("./type-guards");
40
- Object.defineProperty(exports, "isHeadlessResult", { enumerable: true, get: function () { return type_guards_1.isHeadlessResult; } });
40
+ Object.defineProperty(exports, "isExtendedResponse", { enumerable: true, get: function () { return type_guards_1.isExtendedResponse; } });
41
41
  Object.defineProperty(exports, "isCredential", { enumerable: true, get: function () { return type_guards_1.isCredential; } });
42
+ Object.defineProperty(exports, "isAuthCredential", { enumerable: true, get: function () { return type_guards_1.isAuthCredential; } });
42
43
  Object.defineProperty(exports, "isLinkStrategy", { enumerable: true, get: function () { return type_guards_1.isLinkStrategy; } });
43
44
  Object.defineProperty(exports, "isTS43Strategy", { enumerable: true, get: function () { return type_guards_1.isTS43Strategy; } });
44
45
  Object.defineProperty(exports, "isDesktopStrategy", { enumerable: true, get: function () { return type_guards_1.isDesktopStrategy; } });
45
46
  Object.defineProperty(exports, "getStrategy", { enumerable: true, get: function () { return type_guards_1.getStrategy; } });
47
+ Object.defineProperty(exports, "hasPollingControls", { enumerable: true, get: function () { return type_guards_1.hasPollingControls; } });
48
+ Object.defineProperty(exports, "hasTrigger", { enumerable: true, get: function () { return type_guards_1.hasTrigger; } });
49
+ // Deprecated aliases
50
+ Object.defineProperty(exports, "isHeadlessResult", { enumerable: true, get: function () { return type_guards_1.isHeadlessResult; } });
46
51
  Object.defineProperty(exports, "requiresPolling", { enumerable: true, get: function () { return type_guards_1.requiresPolling; } });
47
52
  Object.defineProperty(exports, "requiresUserAction", { enumerable: true, get: function () { return type_guards_1.requiresUserAction; } });
@@ -55,6 +55,7 @@ export declare class DesktopHandler implements StrategyHandler {
55
55
  private pollingAttempts;
56
56
  private isCancelled;
57
57
  private onCancel?;
58
+ private pollingReject?;
58
59
  /**
59
60
  * Maps backend HTTP status codes to client status
60
61
  * @param httpStatus HTTP status code from backend
@@ -62,7 +62,20 @@ class DesktopHandler {
62
62
  if (desktopData && desktopData.data && typeof desktopData.data === 'object') {
63
63
  const innerData = desktopData.data;
64
64
  // Try to extract from inner data
65
- qrCode = innerData.qr_code_image || innerData.qr_code;
65
+ // Support both single QR (qr_code_image) and dual-platform QR (ios/android)
66
+ if (innerData.ios_qr_image || innerData.android_qr_image) {
67
+ // Dual-platform QR format
68
+ qrCode = {
69
+ iosQRCode: innerData.ios_qr_image,
70
+ androidQRCode: innerData.android_qr_image,
71
+ iosUrl: innerData.ios_url,
72
+ androidUrl: innerData.android_url
73
+ };
74
+ }
75
+ else {
76
+ // Single QR format (legacy)
77
+ qrCode = innerData.qr_code_image || innerData.qr_code;
78
+ }
66
79
  sessionId = innerData.session_id;
67
80
  pollingEndpoint = innerData.status_url;
68
81
  pollingInterval = innerData.polling_interval;
@@ -89,33 +102,44 @@ class DesktopHandler {
89
102
  options.onQRCodeReady(qrCode);
90
103
  }
91
104
  // Use polling endpoint with this priority:
92
- // 1. Developer-provided endpoint from options
105
+ // 1. Developer-provided endpoint from options (highest priority)
93
106
  // 2. Backend-provided endpoint
94
- // 3. Error if none available
95
- const finalPollingEndpoint = (options === null || options === void 0 ? void 0 : options.pollingEndpoint) || pollingEndpoint;
96
- // If no polling endpoint available, return QR code data and let the app handle the rest
107
+ // 3. Hardcoded fallback
108
+ console.log('[Desktop QR] Polling endpoint selection:');
109
+ console.log(' - options?.pollingEndpoint:', options === null || options === void 0 ? void 0 : options.pollingEndpoint);
110
+ console.log(' - backend pollingEndpoint:', pollingEndpoint);
111
+ let finalPollingEndpoint = options === null || options === void 0 ? void 0 : options.pollingEndpoint;
112
+ let endpointSource = 'options';
97
113
  if (!finalPollingEndpoint) {
98
- return {
99
- authenticated: false,
100
- session: data.session,
101
- error: 'No polling endpoint provided - configure endpoints.polling or ensure backend provides status_url'
102
- };
114
+ finalPollingEndpoint = pollingEndpoint; // Backend-provided status_url
115
+ endpointSource = 'backend';
103
116
  }
117
+ if (!finalPollingEndpoint) {
118
+ // Use hardcoded fallback - this will be constructed in the polling function
119
+ console.log('[Desktop QR] No polling endpoint provided, will use hardcoded fallback');
120
+ endpointSource = 'fallback';
121
+ }
122
+ console.log('[Desktop QR] Selected endpoint:', finalPollingEndpoint, 'from source:', endpointSource);
104
123
  // Start polling for authentication status
105
124
  const finalPollingInterval = (options === null || options === void 0 ? void 0 : options.pollingInterval) || pollingInterval || 2000;
106
125
  const maxAttempts = (options === null || options === void 0 ? void 0 : options.maxPollingAttempts) || 150; // Default to 5 minutes
107
- return this.startPolling(finalPollingEndpoint, sessionId, finalPollingInterval, maxAttempts, expiresIn || 300, // Default 5 minutes expiry
108
- options);
126
+ console.log(`[Desktop QR] Starting polling - endpoint source: ${endpointSource}, interval: ${finalPollingInterval}ms, max attempts: ${maxAttempts}`);
127
+ return this.startPolling(finalPollingEndpoint || '', // Pass empty string if undefined, will use fallback
128
+ sessionId, finalPollingInterval, maxAttempts, expiresIn || 300, // Default 5 minutes expiry
129
+ options, endpointSource // Pass the endpoint source for logging
130
+ );
109
131
  });
110
132
  }
111
133
  /**
112
134
  * Start polling for authentication status
113
135
  */
114
- startPolling(endpoint, sessionId, interval, maxAttempts, expiresIn, options) {
115
- return __awaiter(this, void 0, void 0, function* () {
136
+ startPolling(endpoint_1, sessionId_1, interval_1, maxAttempts_1, expiresIn_1, options_1) {
137
+ return __awaiter(this, arguments, void 0, function* (endpoint, sessionId, interval, maxAttempts, expiresIn, options, endpointSource = 'unknown') {
116
138
  const startTime = Date.now();
117
139
  const expiryTime = startTime + (expiresIn * 1000);
118
140
  return new Promise((resolve, reject) => {
141
+ // Store the reject function so we can call it from cancel()
142
+ this.pollingReject = reject;
119
143
  const poll = () => __awaiter(this, void 0, void 0, function* () {
120
144
  try {
121
145
  // Check if cancelled
@@ -130,9 +154,10 @@ class DesktopHandler {
130
154
  message: 'Authentication cancelled'
131
155
  });
132
156
  }
133
- resolve({
134
- authenticated: false,
135
- error: 'Authentication cancelled'
157
+ // Reject the promise with a cancellation error
158
+ reject({
159
+ code: 'USER_DENIED',
160
+ message: 'Authentication cancelled by user'
136
161
  });
137
162
  return;
138
163
  }
@@ -180,12 +205,19 @@ class DesktopHandler {
180
205
  const url = new URL(endpoint);
181
206
  statusUrl = `${url.protocol}//${url.host}/public/public/status/${sessionId}`;
182
207
  }
208
+ else if (endpoint && endpoint !== '') {
209
+ // Relative path provided (e.g. '/api/phone-auth/status')
210
+ // Append session ID to the provided endpoint
211
+ statusUrl = `${endpoint}/${sessionId}`;
212
+ }
183
213
  else {
184
- // Use relative path that will be proxied through the app's server
214
+ // No endpoint provided - use hardcoded fallback
185
215
  // This ensures it goes through the same domain and uses the app's API configuration
186
216
  statusUrl = `/api/phone-auth/status/${sessionId}`;
187
217
  }
188
218
  // Poll the public endpoint - no authentication required
219
+ console.log(`[Desktop QR] Polling status (attempt ${this.pollingAttempts}/${maxAttempts})`);
220
+ console.log(`[Desktop QR] Using ${endpointSource} endpoint: ${statusUrl}`);
189
221
  const response = yield fetch(statusUrl, {
190
222
  method: 'GET',
191
223
  headers: {
@@ -193,6 +225,7 @@ class DesktopHandler {
193
225
  // No Authorization header needed for public endpoint
194
226
  }
195
227
  });
228
+ console.log(`[Desktop QR] Status response: ${response.status} ${response.statusText}`);
196
229
  // Backend Status Code Mapping:
197
230
  // - 200 OK: Session exists (body has 'pending' or 'completed' status)
198
231
  // - 410 Gone: Session expired after timeout
@@ -220,6 +253,7 @@ class DesktopHandler {
220
253
  });
221
254
  }
222
255
  // Return the session data for next steps
256
+ this.pollingReject = undefined; // Clear the reject function on success
223
257
  resolve({
224
258
  authenticated: true,
225
259
  credential: result.credential || result.session_key || sessionId,
@@ -344,10 +378,12 @@ class DesktopHandler {
344
378
  */
345
379
  stopPolling() {
346
380
  if (this.pollingIntervalId) {
381
+ console.log('[Desktop QR] Stopping polling');
347
382
  clearInterval(this.pollingIntervalId);
348
383
  this.pollingIntervalId = undefined;
349
384
  }
350
385
  this.pollingAttempts = 0;
386
+ // Don't clear pollingReject here - it's needed by cancel()
351
387
  }
352
388
  /**
353
389
  * Format response for backend processing
@@ -379,15 +415,25 @@ class DesktopHandler {
379
415
  this.stopPolling();
380
416
  this.isCancelled = false;
381
417
  this.onCancel = undefined;
418
+ this.pollingReject = undefined;
382
419
  }
383
420
  /**
384
421
  * Cancel the ongoing authentication
385
422
  */
386
423
  cancel() {
387
424
  var _a;
425
+ console.log('[Desktop QR] Cancelling authentication');
388
426
  this.isCancelled = true;
389
427
  this.stopPolling();
390
428
  (_a = this.onCancel) === null || _a === void 0 ? void 0 : _a.call(this);
429
+ // Immediately reject the polling promise
430
+ if (this.pollingReject) {
431
+ this.pollingReject({
432
+ code: 'USER_DENIED',
433
+ message: 'Authentication cancelled by user'
434
+ });
435
+ this.pollingReject = undefined;
436
+ }
391
437
  }
392
438
  }
393
439
  exports.DesktopHandler = DesktopHandler;
@@ -4,29 +4,29 @@
4
4
  * These utilities help developers work with the SDK responses in a type-safe way
5
5
  * without having to write their own type checking logic.
6
6
  */
7
- import type { HeadlessResult } from './api-types';
7
+ import type { AnyExtendedResponse, DesktopExtendedResponse, LinkExtendedResponse, TS43ExtendedResponse, AuthCredential } from './api-types';
8
8
  /**
9
- * Type guard to check if the result is a HeadlessResult (headless mode)
10
- * or a Credential (UI mode).
9
+ * Type guard to check if the result is an ExtendedResponse (extended mode)
10
+ * or a Credential (standard mode).
11
11
  *
12
12
  * @example
13
13
  * ```typescript
14
- * const result = await invokeSecurePrompt(sdkRequest);
14
+ * const result = await invokeSecurePrompt(sdkRequest, { executionMode: 'extended' });
15
15
  *
16
- * if (isHeadlessResult(result)) {
17
- * // TypeScript knows this is HeadlessResult
16
+ * if (isExtendedResponse(result)) {
17
+ * // TypeScript knows this is ExtendedResponse
18
18
  * console.log(result.strategy);
19
- * await result.trigger();
19
+ * await result.cancel();
20
20
  * } else {
21
21
  * // TypeScript knows this is a Credential
22
22
  * const processedResult = await verifyPhoneNumberCredential(result, session);
23
23
  * }
24
24
  * ```
25
25
  */
26
- export declare function isHeadlessResult(result: any): result is HeadlessResult;
26
+ export declare function isExtendedResponse(result: any): result is AnyExtendedResponse;
27
27
  /**
28
- * Type guard to check if the result is a Credential (UI mode response).
29
- * A credential is either a string token or an object without HeadlessResult properties.
28
+ * Type guard to check if the result is a Credential (standard mode response).
29
+ * A credential is either a string token or an object without ExtendedResponse properties.
30
30
  *
31
31
  * @example
32
32
  * ```typescript
@@ -40,55 +40,61 @@ export declare function isCredential(result: any): result is string | {
40
40
  [aggregator_id: string]: string | string[];
41
41
  };
42
42
  /**
43
- * Type guard to check if a HeadlessResult is using the Link strategy.
43
+ * Type guard to check if the result is an AuthCredential object.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * if (isAuthCredential(result)) {
48
+ * console.log(result.credential);
49
+ * console.log(result.authenticated);
50
+ * }
51
+ * ```
52
+ */
53
+ export declare function isAuthCredential(result: any): result is AuthCredential;
54
+ /**
55
+ * Type guard to check if an ExtendedResponse is using the Link strategy.
44
56
  * Link strategy involves opening an app link (App Clip on iOS, app on Android).
45
57
  *
46
58
  * @example
47
59
  * ```typescript
48
- * if (isHeadlessResult(result) && isLinkStrategy(result)) {
49
- * // Show custom button for opening app
50
- * myButton.onclick = () => result.trigger();
51
- * await result.pollingPromise;
60
+ * if (isExtendedResponse(result) && isLinkStrategy(result)) {
61
+ * // Re-trigger app opening if needed
62
+ * result.trigger();
63
+ * await result.credential;
52
64
  * }
53
65
  * ```
54
66
  */
55
- export declare function isLinkStrategy(result: HeadlessResult): result is HeadlessResult & {
56
- strategy: 'link';
57
- };
67
+ export declare function isLinkStrategy(result: AnyExtendedResponse): result is LinkExtendedResponse;
58
68
  /**
59
- * Type guard to check if a HeadlessResult is using the TS43 strategy.
69
+ * Type guard to check if an ExtendedResponse is using the TS43 strategy.
60
70
  * TS43 strategy uses the browser's Digital Credentials API.
61
71
  *
62
72
  * @example
63
73
  * ```typescript
64
- * if (isHeadlessResult(result) && isTS43Strategy(result)) {
65
- * // Invoke credential API immediately or on button click
66
- * const credential = await result.trigger();
74
+ * if (isExtendedResponse(result) && isTS43Strategy(result)) {
75
+ * // Re-trigger credential request if needed
76
+ * await result.trigger();
67
77
  * }
68
78
  * ```
69
79
  */
70
- export declare function isTS43Strategy(result: HeadlessResult): result is HeadlessResult & {
71
- strategy: 'ts43';
72
- };
80
+ export declare function isTS43Strategy(result: AnyExtendedResponse): result is TS43ExtendedResponse;
73
81
  /**
74
- * Type guard to check if a HeadlessResult is using the Desktop strategy.
82
+ * Type guard to check if an ExtendedResponse is using the Desktop strategy.
75
83
  * Desktop strategy involves QR codes for cross-device authentication.
76
84
  *
77
85
  * @example
78
86
  * ```typescript
79
- * if (isHeadlessResult(result) && isDesktopStrategy(result)) {
87
+ * if (isExtendedResponse(result) && isDesktopStrategy(result)) {
80
88
  * // Show custom QR code UI
81
- * displayQRCode(result.qrCodeUrl);
82
- * await result.pollingPromise;
89
+ * displayQRCode(result.qr_code_data);
90
+ * await result.start_polling();
83
91
  * }
84
92
  * ```
85
93
  */
86
- export declare function isDesktopStrategy(result: HeadlessResult): result is HeadlessResult & {
87
- strategy: 'desktop';
88
- };
94
+ export declare function isDesktopStrategy(result: AnyExtendedResponse): result is DesktopExtendedResponse;
89
95
  /**
90
96
  * Helper function to safely get the authentication strategy from any result.
91
- * Returns undefined if the result is not a HeadlessResult.
97
+ * Returns undefined if the result is not an ExtendedResponse.
92
98
  *
93
99
  * @example
94
100
  * ```typescript
@@ -100,26 +106,38 @@ export declare function isDesktopStrategy(result: HeadlessResult): result is Hea
100
106
  */
101
107
  export declare function getStrategy(result: any): 'link' | 'ts43' | 'desktop' | undefined;
102
108
  /**
103
- * Helper function to determine if a result requires polling.
104
- * Link and Desktop strategies require polling, TS43 does not.
109
+ * Helper function to determine if a result has polling controls.
110
+ * Link and Desktop strategies have polling controls in extended mode.
105
111
  *
106
112
  * @example
107
113
  * ```typescript
108
- * if (requiresPolling(result)) {
109
- * await result.pollingPromise;
114
+ * if (hasPollingControls(result)) {
115
+ * await result.start_polling();
110
116
  * }
111
117
  * ```
112
118
  */
113
- export declare function requiresPolling(result: any): boolean;
119
+ export declare function hasPollingControls(result: any): boolean;
114
120
  /**
115
- * Helper function to determine if a result requires user interaction.
116
- * All headless strategies require some form of user interaction.
121
+ * Helper function to determine if a result has a trigger method.
122
+ * Link and TS43 strategies have trigger methods in extended mode.
117
123
  *
118
124
  * @example
119
125
  * ```typescript
120
- * if (requiresUserAction(result)) {
121
- * showActionButton();
126
+ * if (hasTrigger(result)) {
127
+ * result.trigger();
122
128
  * }
123
129
  * ```
124
130
  */
125
- export declare function requiresUserAction(result: any): boolean;
131
+ export declare function hasTrigger(result: any): boolean;
132
+ /**
133
+ * @deprecated Use isExtendedResponse instead
134
+ */
135
+ export declare const isHeadlessResult: typeof isExtendedResponse;
136
+ /**
137
+ * @deprecated Use hasPollingControls instead
138
+ */
139
+ export declare const requiresPolling: typeof hasPollingControls;
140
+ /**
141
+ * @deprecated This function is no longer needed as extended mode handles user actions differently
142
+ */
143
+ export declare const requiresUserAction: (result: any) => boolean;
@@ -6,42 +6,45 @@
6
6
  * without having to write their own type checking logic.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.isHeadlessResult = isHeadlessResult;
9
+ exports.requiresUserAction = exports.requiresPolling = exports.isHeadlessResult = void 0;
10
+ exports.isExtendedResponse = isExtendedResponse;
10
11
  exports.isCredential = isCredential;
12
+ exports.isAuthCredential = isAuthCredential;
11
13
  exports.isLinkStrategy = isLinkStrategy;
12
14
  exports.isTS43Strategy = isTS43Strategy;
13
15
  exports.isDesktopStrategy = isDesktopStrategy;
14
16
  exports.getStrategy = getStrategy;
15
- exports.requiresPolling = requiresPolling;
16
- exports.requiresUserAction = requiresUserAction;
17
+ exports.hasPollingControls = hasPollingControls;
18
+ exports.hasTrigger = hasTrigger;
17
19
  /**
18
- * Type guard to check if the result is a HeadlessResult (headless mode)
19
- * or a Credential (UI mode).
20
+ * Type guard to check if the result is an ExtendedResponse (extended mode)
21
+ * or a Credential (standard mode).
20
22
  *
21
23
  * @example
22
24
  * ```typescript
23
- * const result = await invokeSecurePrompt(sdkRequest);
25
+ * const result = await invokeSecurePrompt(sdkRequest, { executionMode: 'extended' });
24
26
  *
25
- * if (isHeadlessResult(result)) {
26
- * // TypeScript knows this is HeadlessResult
27
+ * if (isExtendedResponse(result)) {
28
+ * // TypeScript knows this is ExtendedResponse
27
29
  * console.log(result.strategy);
28
- * await result.trigger();
30
+ * await result.cancel();
29
31
  * } else {
30
32
  * // TypeScript knows this is a Credential
31
33
  * const processedResult = await verifyPhoneNumberCredential(result, session);
32
34
  * }
33
35
  * ```
34
36
  */
35
- function isHeadlessResult(result) {
37
+ function isExtendedResponse(result) {
36
38
  return result &&
37
39
  typeof result === 'object' &&
38
40
  'strategy' in result &&
39
- 'trigger' in result &&
40
- typeof result.trigger === 'function';
41
+ 'credential' in result &&
42
+ 'cancel' in result &&
43
+ typeof result.cancel === 'function';
41
44
  }
42
45
  /**
43
- * Type guard to check if the result is a Credential (UI mode response).
44
- * A credential is either a string token or an object without HeadlessResult properties.
46
+ * Type guard to check if the result is a Credential (standard mode response).
47
+ * A credential is either a string token or an object without ExtendedResponse properties.
45
48
  *
46
49
  * @example
47
50
  * ```typescript
@@ -57,22 +60,40 @@ function isCredential(result) {
57
60
  // String credentials are valid
58
61
  if (typeof result === 'string')
59
62
  return true;
60
- // Object credentials should NOT have HeadlessResult properties
63
+ // Object credentials should NOT have ExtendedResponse properties
61
64
  if (typeof result === 'object') {
62
- return !('strategy' in result) && !('trigger' in result);
65
+ return !('strategy' in result) && !('credential' in result) && !('cancel' in result);
63
66
  }
64
67
  return false;
65
68
  }
66
69
  /**
67
- * Type guard to check if a HeadlessResult is using the Link strategy.
70
+ * Type guard to check if the result is an AuthCredential object.
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * if (isAuthCredential(result)) {
75
+ * console.log(result.credential);
76
+ * console.log(result.authenticated);
77
+ * }
78
+ * ```
79
+ */
80
+ function isAuthCredential(result) {
81
+ return result &&
82
+ typeof result === 'object' &&
83
+ 'credential' in result &&
84
+ 'authenticated' in result &&
85
+ 'session' in result;
86
+ }
87
+ /**
88
+ * Type guard to check if an ExtendedResponse is using the Link strategy.
68
89
  * Link strategy involves opening an app link (App Clip on iOS, app on Android).
69
90
  *
70
91
  * @example
71
92
  * ```typescript
72
- * if (isHeadlessResult(result) && isLinkStrategy(result)) {
73
- * // Show custom button for opening app
74
- * myButton.onclick = () => result.trigger();
75
- * await result.pollingPromise;
93
+ * if (isExtendedResponse(result) && isLinkStrategy(result)) {
94
+ * // Re-trigger app opening if needed
95
+ * result.trigger();
96
+ * await result.credential;
76
97
  * }
77
98
  * ```
78
99
  */
@@ -80,14 +101,14 @@ function isLinkStrategy(result) {
80
101
  return result.strategy === 'link';
81
102
  }
82
103
  /**
83
- * Type guard to check if a HeadlessResult is using the TS43 strategy.
104
+ * Type guard to check if an ExtendedResponse is using the TS43 strategy.
84
105
  * TS43 strategy uses the browser's Digital Credentials API.
85
106
  *
86
107
  * @example
87
108
  * ```typescript
88
- * if (isHeadlessResult(result) && isTS43Strategy(result)) {
89
- * // Invoke credential API immediately or on button click
90
- * const credential = await result.trigger();
109
+ * if (isExtendedResponse(result) && isTS43Strategy(result)) {
110
+ * // Re-trigger credential request if needed
111
+ * await result.trigger();
91
112
  * }
92
113
  * ```
93
114
  */
@@ -95,15 +116,15 @@ function isTS43Strategy(result) {
95
116
  return result.strategy === 'ts43';
96
117
  }
97
118
  /**
98
- * Type guard to check if a HeadlessResult is using the Desktop strategy.
119
+ * Type guard to check if an ExtendedResponse is using the Desktop strategy.
99
120
  * Desktop strategy involves QR codes for cross-device authentication.
100
121
  *
101
122
  * @example
102
123
  * ```typescript
103
- * if (isHeadlessResult(result) && isDesktopStrategy(result)) {
124
+ * if (isExtendedResponse(result) && isDesktopStrategy(result)) {
104
125
  * // Show custom QR code UI
105
- * displayQRCode(result.qrCodeUrl);
106
- * await result.pollingPromise;
126
+ * displayQRCode(result.qr_code_data);
127
+ * await result.start_polling();
107
128
  * }
108
129
  * ```
109
130
  */
@@ -112,7 +133,7 @@ function isDesktopStrategy(result) {
112
133
  }
113
134
  /**
114
135
  * Helper function to safely get the authentication strategy from any result.
115
- * Returns undefined if the result is not a HeadlessResult.
136
+ * Returns undefined if the result is not an ExtendedResponse.
116
137
  *
117
138
  * @example
118
139
  * ```typescript
@@ -123,38 +144,55 @@ function isDesktopStrategy(result) {
123
144
  * ```
124
145
  */
125
146
  function getStrategy(result) {
126
- if (isHeadlessResult(result)) {
147
+ if (isExtendedResponse(result)) {
127
148
  return result.strategy;
128
149
  }
129
150
  return undefined;
130
151
  }
131
152
  /**
132
- * Helper function to determine if a result requires polling.
133
- * Link and Desktop strategies require polling, TS43 does not.
153
+ * Helper function to determine if a result has polling controls.
154
+ * Link and Desktop strategies have polling controls in extended mode.
134
155
  *
135
156
  * @example
136
157
  * ```typescript
137
- * if (requiresPolling(result)) {
138
- * await result.pollingPromise;
158
+ * if (hasPollingControls(result)) {
159
+ * await result.start_polling();
139
160
  * }
140
161
  * ```
141
162
  */
142
- function requiresPolling(result) {
143
- if (!isHeadlessResult(result))
163
+ function hasPollingControls(result) {
164
+ if (!isExtendedResponse(result))
144
165
  return false;
145
- return result.strategy === 'link' || result.strategy === 'desktop';
166
+ return (result.strategy === 'link' && 'start_polling' in result) ||
167
+ (result.strategy === 'desktop' && 'start_polling' in result);
146
168
  }
147
169
  /**
148
- * Helper function to determine if a result requires user interaction.
149
- * All headless strategies require some form of user interaction.
170
+ * Helper function to determine if a result has a trigger method.
171
+ * Link and TS43 strategies have trigger methods in extended mode.
150
172
  *
151
173
  * @example
152
174
  * ```typescript
153
- * if (requiresUserAction(result)) {
154
- * showActionButton();
175
+ * if (hasTrigger(result)) {
176
+ * result.trigger();
155
177
  * }
156
178
  * ```
157
179
  */
158
- function requiresUserAction(result) {
159
- return isHeadlessResult(result);
180
+ function hasTrigger(result) {
181
+ if (!isExtendedResponse(result))
182
+ return false;
183
+ return 'trigger' in result && typeof result.trigger === 'function';
160
184
  }
185
+ // Export legacy function names as deprecated aliases for backward compatibility
186
+ /**
187
+ * @deprecated Use isExtendedResponse instead
188
+ */
189
+ exports.isHeadlessResult = isExtendedResponse;
190
+ /**
191
+ * @deprecated Use hasPollingControls instead
192
+ */
193
+ exports.requiresPolling = hasPollingControls;
194
+ /**
195
+ * @deprecated This function is no longer needed as extended mode handles user actions differently
196
+ */
197
+ const requiresUserAction = (result) => false;
198
+ exports.requiresUserAction = requiresUserAction;
@@ -53,6 +53,11 @@ class AuthModal {
53
53
  */
54
54
  showQRCode(qrCodeData, statusMessage = 'Scan QR code with your phone') {
55
55
  console.log('[Modal] showQRCode called with:', qrCodeData);
56
+ // If modal is already open, don't recreate it
57
+ if (this.isOpen) {
58
+ console.log('[Modal] Modal already open, skipping recreation');
59
+ return;
60
+ }
56
61
  // Check if it's the new dual-platform format with VALID Android QR code
57
62
  if (typeof qrCodeData === 'object' && qrCodeData.iosQRCode) {
58
63
  const hasValidAndroidQR = qrCodeData.androidQRCode &&
@@ -62,6 +67,8 @@ class AuthModal {
62
67
  if (hasValidAndroidQR) {
63
68
  console.log('[Modal] Using dual-platform modal');
64
69
  this.createDualPlatformQRModal(qrCodeData, statusMessage);
70
+ // Note: createDualPlatformQRModal calls show() internally
71
+ return;
65
72
  }
66
73
  else {
67
74
  console.log('[Modal] Android QR missing/empty, using single iOS QR');
@@ -122,6 +129,8 @@ class AuthModal {
122
129
  <p class="glide-auth-status" id="glide-platform-message">Scan with your iPhone to authenticate</p>
123
130
  </div>
124
131
  `);
132
+ // IMPORTANT: Call show() to actually display the modal!
133
+ this.show();
125
134
  }
126
135
  /**
127
136
  * Sets a callback to be called when the modal is cancelled/closed
@@ -295,7 +304,11 @@ class AuthModal {
295
304
  // Add close button handler
296
305
  const closeBtn = this.container.querySelector('.glide-auth-close');
297
306
  if (closeBtn) {
298
- closeBtn.addEventListener('click', () => this.close());
307
+ closeBtn.addEventListener('click', () => {
308
+ var _a;
309
+ (_a = this.closeCallback) === null || _a === void 0 ? void 0 : _a.call(this); // Call cancellation callback if set
310
+ this.close();
311
+ });
299
312
  }
300
313
  // Add backdrop click handler
301
314
  this.backdrop.addEventListener('click', (e) => {
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SDK_VERSION = void 0;
4
4
  // SDK version - injected at build time
5
- exports.SDK_VERSION = '4.4.8-beta.1';
5
+ exports.SDK_VERSION = '4.4.8-beta.2';