@glideidentity/web-client-sdk 5.1.3 → 6.0.0-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 (203) hide show
  1. package/README.md +337 -526
  2. package/dist/browser/web-client-sdk.min.js +1 -1
  3. package/dist/cjs/adapters/index.js +15 -0
  4. package/dist/cjs/adapters/react.js +192 -0
  5. package/dist/cjs/adapters/vanilla.js +38 -0
  6. package/dist/cjs/adapters/vue.js +187 -0
  7. package/dist/cjs/browser.js +58 -0
  8. package/dist/cjs/client/http.js +159 -0
  9. package/dist/cjs/client/index.js +19 -0
  10. package/dist/cjs/client/logger.js +135 -0
  11. package/dist/cjs/client/phone-auth-client.js +428 -0
  12. package/dist/cjs/client/strategies/polling.js +177 -0
  13. package/dist/cjs/core/errors.js +204 -0
  14. package/dist/cjs/core/index.js +83 -0
  15. package/dist/cjs/core/type-guards.js +196 -0
  16. package/dist/cjs/core/types.js +25 -0
  17. package/dist/{core/phone-auth/validation-utils.js → cjs/core/validators.js} +70 -23
  18. package/dist/cjs/index.js +81 -0
  19. package/dist/cjs/ui/index.js +11 -0
  20. package/dist/{core/phone-auth → cjs}/ui/mobile-debug-console.js +149 -78
  21. package/dist/cjs/ui/modal.js +1122 -0
  22. package/dist/esm/adapters/index.js +11 -0
  23. package/dist/esm/adapters/react.js +182 -0
  24. package/dist/esm/adapters/vanilla.js +29 -0
  25. package/dist/esm/adapters/vue.js +177 -0
  26. package/dist/esm/browser.js +30 -11
  27. package/dist/esm/client/http.js +156 -0
  28. package/dist/esm/client/index.js +11 -0
  29. package/dist/esm/client/logger.js +131 -0
  30. package/dist/esm/client/phone-auth-client.js +424 -0
  31. package/dist/esm/client/strategies/polling.js +174 -0
  32. package/dist/esm/core/errors.js +193 -0
  33. package/dist/esm/core/index.js +60 -0
  34. package/dist/esm/core/type-guards.js +181 -0
  35. package/dist/esm/core/types.js +22 -1
  36. package/dist/esm/core/{phone-auth/validation-utils.js → validators.js} +66 -21
  37. package/dist/esm/index.js +45 -17
  38. package/dist/esm/ui/index.js +5 -0
  39. package/dist/esm/{core/phone-auth/ui → ui}/mobile-debug-console.js +149 -78
  40. package/dist/esm/ui/modal.js +1117 -0
  41. package/dist/types/adapters/index.d.ts +10 -0
  42. package/dist/types/adapters/index.d.ts.map +1 -0
  43. package/dist/types/adapters/react.d.ts +70 -0
  44. package/dist/types/adapters/react.d.ts.map +1 -0
  45. package/dist/types/adapters/vanilla.d.ts +29 -0
  46. package/dist/types/adapters/vanilla.d.ts.map +1 -0
  47. package/dist/types/adapters/vue.d.ts +71 -0
  48. package/dist/types/adapters/vue.d.ts.map +1 -0
  49. package/dist/types/browser.d.ts +27 -0
  50. package/dist/types/browser.d.ts.map +1 -0
  51. package/dist/types/client/http.d.ts +41 -0
  52. package/dist/types/client/http.d.ts.map +1 -0
  53. package/dist/types/client/index.d.ts +10 -0
  54. package/dist/types/client/index.d.ts.map +1 -0
  55. package/dist/types/client/logger.d.ts +36 -0
  56. package/dist/types/client/logger.d.ts.map +1 -0
  57. package/dist/types/client/phone-auth-client.d.ts +91 -0
  58. package/dist/types/client/phone-auth-client.d.ts.map +1 -0
  59. package/dist/types/client/strategies/polling.d.ts +36 -0
  60. package/dist/types/client/strategies/polling.d.ts.map +1 -0
  61. package/dist/types/core/errors.d.ts +71 -0
  62. package/dist/types/core/errors.d.ts.map +1 -0
  63. package/dist/types/core/index.d.ts +38 -0
  64. package/dist/types/core/index.d.ts.map +1 -0
  65. package/dist/types/core/type-guards.d.ts +118 -0
  66. package/dist/types/core/type-guards.d.ts.map +1 -0
  67. package/dist/types/core/types.d.ts +535 -0
  68. package/dist/types/core/types.d.ts.map +1 -0
  69. package/dist/types/core/validators.d.ts +63 -0
  70. package/dist/types/core/validators.d.ts.map +1 -0
  71. package/dist/types/index.d.ts +40 -0
  72. package/dist/types/index.d.ts.map +1 -0
  73. package/dist/types/ui/index.d.ts +6 -0
  74. package/dist/types/ui/index.d.ts.map +1 -0
  75. package/dist/{esm/core/phone-auth → types}/ui/mobile-debug-console.d.ts +1 -0
  76. package/dist/types/ui/mobile-debug-console.d.ts.map +1 -0
  77. package/dist/types/ui/modal.d.ts +87 -0
  78. package/dist/types/ui/modal.d.ts.map +1 -0
  79. package/package.json +48 -34
  80. package/dist/adapters/angular/client.service.d.ts +0 -7
  81. package/dist/adapters/angular/client.service.js +0 -30
  82. package/dist/adapters/angular/index.d.ts +0 -3
  83. package/dist/adapters/angular/index.js +0 -18
  84. package/dist/adapters/angular/phone-auth.service.d.ts +0 -38
  85. package/dist/adapters/angular/phone-auth.service.js +0 -130
  86. package/dist/adapters/react/index.d.ts +0 -9
  87. package/dist/adapters/react/index.js +0 -28
  88. package/dist/adapters/react/useClient.d.ts +0 -26
  89. package/dist/adapters/react/useClient.js +0 -121
  90. package/dist/adapters/react/usePhoneAuth.d.ts +0 -23
  91. package/dist/adapters/react/usePhoneAuth.js +0 -95
  92. package/dist/adapters/vanilla/client.d.ts +0 -8
  93. package/dist/adapters/vanilla/client.js +0 -33
  94. package/dist/adapters/vanilla/index.d.ts +0 -3
  95. package/dist/adapters/vanilla/index.js +0 -18
  96. package/dist/adapters/vanilla/phone-auth.d.ts +0 -46
  97. package/dist/adapters/vanilla/phone-auth.js +0 -138
  98. package/dist/adapters/vue/index.d.ts +0 -10
  99. package/dist/adapters/vue/index.js +0 -36
  100. package/dist/adapters/vue/useClient.d.ts +0 -115
  101. package/dist/adapters/vue/useClient.js +0 -131
  102. package/dist/adapters/vue/usePhoneAuth.d.ts +0 -94
  103. package/dist/adapters/vue/usePhoneAuth.js +0 -103
  104. package/dist/browser.d.ts +0 -7
  105. package/dist/browser.js +0 -31
  106. package/dist/core/client.d.ts +0 -22
  107. package/dist/core/client.js +0 -77
  108. package/dist/core/logger.d.ts +0 -130
  109. package/dist/core/logger.js +0 -370
  110. package/dist/core/phone-auth/api-types.d.ts +0 -593
  111. package/dist/core/phone-auth/api-types.js +0 -215
  112. package/dist/core/phone-auth/client.d.ts +0 -189
  113. package/dist/core/phone-auth/client.js +0 -1441
  114. package/dist/core/phone-auth/error-utils.d.ts +0 -110
  115. package/dist/core/phone-auth/error-utils.js +0 -350
  116. package/dist/core/phone-auth/index.d.ts +0 -7
  117. package/dist/core/phone-auth/index.js +0 -50
  118. package/dist/core/phone-auth/status-types.d.ts +0 -107
  119. package/dist/core/phone-auth/status-types.js +0 -31
  120. package/dist/core/phone-auth/strategies/desktop.d.ts +0 -122
  121. package/dist/core/phone-auth/strategies/desktop.js +0 -596
  122. package/dist/core/phone-auth/strategies/index.d.ts +0 -11
  123. package/dist/core/phone-auth/strategies/index.js +0 -15
  124. package/dist/core/phone-auth/strategies/link.d.ts +0 -89
  125. package/dist/core/phone-auth/strategies/link.js +0 -384
  126. package/dist/core/phone-auth/strategies/ts43.d.ts +0 -32
  127. package/dist/core/phone-auth/strategies/ts43.js +0 -161
  128. package/dist/core/phone-auth/strategies/types.d.ts +0 -18
  129. package/dist/core/phone-auth/strategies/types.js +0 -6
  130. package/dist/core/phone-auth/type-guards.d.ts +0 -143
  131. package/dist/core/phone-auth/type-guards.js +0 -198
  132. package/dist/core/phone-auth/types.d.ts +0 -237
  133. package/dist/core/phone-auth/types.js +0 -93
  134. package/dist/core/phone-auth/ui/mobile-debug-console.d.ts +0 -25
  135. package/dist/core/phone-auth/ui/modal.d.ts +0 -88
  136. package/dist/core/phone-auth/ui/modal.js +0 -598
  137. package/dist/core/phone-auth/validation-utils.d.ts +0 -44
  138. package/dist/core/types.d.ts +0 -62
  139. package/dist/core/types.js +0 -2
  140. package/dist/core/version.d.ts +0 -1
  141. package/dist/core/version.js +0 -5
  142. package/dist/esm/adapters/angular/client.service.d.ts +0 -7
  143. package/dist/esm/adapters/angular/client.service.js +0 -27
  144. package/dist/esm/adapters/angular/index.d.ts +0 -3
  145. package/dist/esm/adapters/angular/index.js +0 -4
  146. package/dist/esm/adapters/angular/phone-auth.service.d.ts +0 -38
  147. package/dist/esm/adapters/angular/phone-auth.service.js +0 -127
  148. package/dist/esm/adapters/react/index.d.ts +0 -9
  149. package/dist/esm/adapters/react/index.js +0 -8
  150. package/dist/esm/adapters/react/useClient.d.ts +0 -26
  151. package/dist/esm/adapters/react/useClient.js +0 -116
  152. package/dist/esm/adapters/react/usePhoneAuth.d.ts +0 -23
  153. package/dist/esm/adapters/react/usePhoneAuth.js +0 -92
  154. package/dist/esm/adapters/vanilla/client.d.ts +0 -8
  155. package/dist/esm/adapters/vanilla/client.js +0 -29
  156. package/dist/esm/adapters/vanilla/index.d.ts +0 -3
  157. package/dist/esm/adapters/vanilla/index.js +0 -4
  158. package/dist/esm/adapters/vanilla/phone-auth.d.ts +0 -46
  159. package/dist/esm/adapters/vanilla/phone-auth.js +0 -134
  160. package/dist/esm/adapters/vue/index.d.ts +0 -10
  161. package/dist/esm/adapters/vue/index.js +0 -11
  162. package/dist/esm/adapters/vue/useClient.d.ts +0 -115
  163. package/dist/esm/adapters/vue/useClient.js +0 -127
  164. package/dist/esm/adapters/vue/usePhoneAuth.d.ts +0 -94
  165. package/dist/esm/adapters/vue/usePhoneAuth.js +0 -100
  166. package/dist/esm/browser.d.ts +0 -7
  167. package/dist/esm/core/client.d.ts +0 -22
  168. package/dist/esm/core/client.js +0 -70
  169. package/dist/esm/core/logger.d.ts +0 -130
  170. package/dist/esm/core/logger.js +0 -359
  171. package/dist/esm/core/phone-auth/api-types.d.ts +0 -593
  172. package/dist/esm/core/phone-auth/api-types.js +0 -203
  173. package/dist/esm/core/phone-auth/client.d.ts +0 -189
  174. package/dist/esm/core/phone-auth/client.js +0 -1404
  175. package/dist/esm/core/phone-auth/error-utils.d.ts +0 -110
  176. package/dist/esm/core/phone-auth/error-utils.js +0 -338
  177. package/dist/esm/core/phone-auth/index.d.ts +0 -7
  178. package/dist/esm/core/phone-auth/index.js +0 -8
  179. package/dist/esm/core/phone-auth/status-types.d.ts +0 -107
  180. package/dist/esm/core/phone-auth/status-types.js +0 -26
  181. package/dist/esm/core/phone-auth/strategies/desktop.d.ts +0 -122
  182. package/dist/esm/core/phone-auth/strategies/desktop.js +0 -590
  183. package/dist/esm/core/phone-auth/strategies/index.d.ts +0 -11
  184. package/dist/esm/core/phone-auth/strategies/index.js +0 -7
  185. package/dist/esm/core/phone-auth/strategies/link.d.ts +0 -89
  186. package/dist/esm/core/phone-auth/strategies/link.js +0 -380
  187. package/dist/esm/core/phone-auth/strategies/ts43.d.ts +0 -32
  188. package/dist/esm/core/phone-auth/strategies/ts43.js +0 -157
  189. package/dist/esm/core/phone-auth/strategies/types.d.ts +0 -18
  190. package/dist/esm/core/phone-auth/strategies/types.js +0 -5
  191. package/dist/esm/core/phone-auth/type-guards.d.ts +0 -143
  192. package/dist/esm/core/phone-auth/type-guards.js +0 -185
  193. package/dist/esm/core/phone-auth/types.d.ts +0 -237
  194. package/dist/esm/core/phone-auth/types.js +0 -76
  195. package/dist/esm/core/phone-auth/ui/modal.d.ts +0 -88
  196. package/dist/esm/core/phone-auth/ui/modal.js +0 -594
  197. package/dist/esm/core/phone-auth/validation-utils.d.ts +0 -44
  198. package/dist/esm/core/types.d.ts +0 -62
  199. package/dist/esm/core/version.d.ts +0 -1
  200. package/dist/esm/core/version.js +0 -2
  201. package/dist/esm/index.d.ts +0 -12
  202. package/dist/index.d.ts +0 -12
  203. package/dist/index.js +0 -55
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Shared polling utility for Link and Desktop strategies.
3
+ * Handles authentication status polling with cancel support.
4
+ */
5
+ import { createAuthError, ERROR_CODES } from '../../core/errors';
6
+ // ============================================================================
7
+ // POLLING HANDLER
8
+ // ============================================================================
9
+ /**
10
+ * Creates a polling handler for authentication status.
11
+ */
12
+ export function createPollingHandler(config) {
13
+ const { sessionKey, interval = 2000, maxAttempts = 30, pollingEndpoint, statusUrl, logger, } = config;
14
+ let pollingIntervalId;
15
+ let attempts = 0;
16
+ let isCancelled = false;
17
+ let isPollingActive = false;
18
+ let rejectFn;
19
+ /**
20
+ * Build the status URL.
21
+ * Priority: 1. Client config endpoint > 2. Backend status_url > 3. Prod fallback
22
+ */
23
+ function buildStatusUrl() {
24
+ // Priority 1: Developer-provided endpoint from client config (highest priority)
25
+ // Developer provides base path, we append session key
26
+ // Examples:
27
+ // /api/phone-auth/status → /api/phone-auth/status/{sessionKey}
28
+ // https://myserver.com/polling → https://myserver.com/polling/{sessionKey}
29
+ if (pollingEndpoint) {
30
+ logger?.debug('Using developer config endpoint for polling', { pollingEndpoint });
31
+ return `${pollingEndpoint}/${sessionKey}`;
32
+ }
33
+ // Priority 2: Backend-provided status_url from prepare response
34
+ // This URL already includes the session key - use as-is
35
+ // Example: https://api-dev.glideidentity.app/public/status/ee25b966c9395f0b
36
+ if (statusUrl) {
37
+ logger?.debug('Using backend status_url for polling', { statusUrl });
38
+ return statusUrl;
39
+ }
40
+ // Priority 3: Fallback to prod API - build URL with session key
41
+ logger?.debug('Using prod fallback for status polling');
42
+ return `https://api.glideidentity.app/public/status/${sessionKey}`;
43
+ }
44
+ /**
45
+ * Start polling.
46
+ */
47
+ function start() {
48
+ return new Promise((resolve, reject) => {
49
+ rejectFn = reject;
50
+ isPollingActive = true;
51
+ attempts = 0;
52
+ const poll = async () => {
53
+ if (!isPollingActive || isCancelled) {
54
+ return;
55
+ }
56
+ // Check max attempts
57
+ if (attempts >= maxAttempts) {
58
+ stop();
59
+ logger?.warn('Polling timeout reached', { attempts, maxAttempts });
60
+ resolve({
61
+ status: 'expired',
62
+ message: 'Authentication timeout',
63
+ });
64
+ return;
65
+ }
66
+ try {
67
+ const url = buildStatusUrl();
68
+ logger?.debug('Polling status', { url, attempt: attempts + 1, maxAttempts });
69
+ const response = await fetch(url, {
70
+ method: 'GET',
71
+ headers: { 'Accept': 'application/json' },
72
+ });
73
+ if (response.status === 200) {
74
+ const result = await response.json();
75
+ if (result.status === 'completed') {
76
+ stop();
77
+ logger?.info('Authentication completed');
78
+ resolve({
79
+ status: 'completed',
80
+ credential: result.credential || sessionKey,
81
+ session: result.session || { session_key: sessionKey },
82
+ });
83
+ return;
84
+ }
85
+ // Still pending - continue
86
+ attempts++;
87
+ }
88
+ else if (response.status === 410) {
89
+ // Session expired
90
+ stop();
91
+ const data = await response.json().catch(() => ({}));
92
+ resolve({
93
+ status: 'expired',
94
+ message: data.message || 'Session expired',
95
+ });
96
+ }
97
+ else if (response.status === 422) {
98
+ // Authentication failed
99
+ stop();
100
+ const data = await response.json().catch(() => ({}));
101
+ resolve({
102
+ status: 'error',
103
+ message: data.message || 'Authentication failed',
104
+ });
105
+ }
106
+ else if (response.status === 404) {
107
+ // Session not found
108
+ stop();
109
+ resolve({
110
+ status: 'error',
111
+ message: 'Session not found',
112
+ });
113
+ }
114
+ else {
115
+ // Unexpected status - continue polling
116
+ attempts++;
117
+ }
118
+ }
119
+ catch (error) {
120
+ // Network error - continue polling
121
+ logger?.debug('Polling error, retrying', { error, attempt: attempts + 1 });
122
+ attempts++;
123
+ }
124
+ };
125
+ // Start immediately
126
+ poll();
127
+ // Set up interval
128
+ pollingIntervalId = setInterval(poll, interval);
129
+ });
130
+ }
131
+ /**
132
+ * Stop polling.
133
+ */
134
+ function stop() {
135
+ isPollingActive = false;
136
+ if (pollingIntervalId) {
137
+ clearInterval(pollingIntervalId);
138
+ pollingIntervalId = undefined;
139
+ }
140
+ }
141
+ /**
142
+ * Cancel polling and reject the promise.
143
+ */
144
+ function cancel() {
145
+ logger?.debug('Polling cancelled');
146
+ isCancelled = true;
147
+ stop();
148
+ if (rejectFn) {
149
+ rejectFn(createAuthError(ERROR_CODES.CANCELLED, 'Authentication cancelled'));
150
+ rejectFn = undefined;
151
+ }
152
+ }
153
+ /**
154
+ * Check if polling is active.
155
+ */
156
+ function isPolling() {
157
+ return pollingIntervalId !== undefined;
158
+ }
159
+ /**
160
+ * Cleanup resources.
161
+ */
162
+ function cleanup() {
163
+ stop();
164
+ isCancelled = false;
165
+ rejectFn = undefined;
166
+ }
167
+ return {
168
+ start,
169
+ stop,
170
+ cancel,
171
+ isPolling,
172
+ cleanup,
173
+ };
174
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Error utilities for phone authentication.
3
+ *
4
+ * This file only handles CLIENT-SIDE errors (validation, browser issues, etc.).
5
+ * Server errors from Magic Auth are passed through as-is since they already
6
+ * have proper error codes and messages.
7
+ */
8
+ // ============================================================================
9
+ // CLIENT-SIDE ERROR CODES
10
+ // ============================================================================
11
+ /**
12
+ * Error codes for client-side errors only.
13
+ * Server errors use their own codes from Magic Auth backend.
14
+ */
15
+ export const ERROR_CODES = {
16
+ // --- Validation Errors (before sending to server) ---
17
+ INVALID_PHONE_NUMBER: 'INVALID_PHONE_NUMBER',
18
+ INVALID_PLMN: 'INVALID_PLMN',
19
+ MISSING_PARAMETERS: 'MISSING_PARAMETERS',
20
+ // --- Browser/Platform Errors ---
21
+ BROWSER_NOT_SUPPORTED: 'BROWSER_NOT_SUPPORTED',
22
+ UNSUPPORTED_STRATEGY: 'UNSUPPORTED_STRATEGY',
23
+ // --- User Actions ---
24
+ USER_CANCELLED: 'USER_CANCELLED',
25
+ CANCELLED: 'CANCELLED',
26
+ // --- Verification Errors (client-side) ---
27
+ VERIFICATION_FAILED: 'VERIFICATION_FAILED',
28
+ // --- Network/Client Errors ---
29
+ NETWORK_ERROR: 'NETWORK_ERROR',
30
+ TIMEOUT: 'TIMEOUT',
31
+ INVALID_RESPONSE: 'INVALID_RESPONSE',
32
+ };
33
+ // ============================================================================
34
+ // CLIENT-SIDE ERROR MESSAGES
35
+ // ============================================================================
36
+ /**
37
+ * User-facing messages for client-side errors only.
38
+ */
39
+ const CLIENT_ERROR_MESSAGES = {
40
+ [ERROR_CODES.INVALID_PHONE_NUMBER]: 'Please enter a valid phone number in E.164 format (e.g., +14155551234).',
41
+ [ERROR_CODES.INVALID_PLMN]: 'Invalid carrier information provided.',
42
+ [ERROR_CODES.MISSING_PARAMETERS]: 'Required information is missing.',
43
+ [ERROR_CODES.BROWSER_NOT_SUPPORTED]: 'Your browser does not support this authentication method. Please use Chrome or Edge with the Digital Credentials flag enabled.',
44
+ [ERROR_CODES.UNSUPPORTED_STRATEGY]: 'This authentication strategy is not supported.',
45
+ [ERROR_CODES.USER_CANCELLED]: 'Authentication was cancelled.',
46
+ [ERROR_CODES.CANCELLED]: 'Authentication was cancelled.',
47
+ [ERROR_CODES.VERIFICATION_FAILED]: 'Verification failed. Please try again.',
48
+ [ERROR_CODES.NETWORK_ERROR]: 'Network connection failed. Please check your connection and try again.',
49
+ [ERROR_CODES.TIMEOUT]: 'Request timed out. Please try again.',
50
+ [ERROR_CODES.INVALID_RESPONSE]: 'Invalid response received.',
51
+ };
52
+ // ============================================================================
53
+ // ERROR HELPER FUNCTIONS
54
+ // ============================================================================
55
+ /**
56
+ * Type guard to check if an error is an AuthError.
57
+ */
58
+ export function isAuthError(error) {
59
+ return (error !== null &&
60
+ typeof error === 'object' &&
61
+ 'code' in error &&
62
+ 'message' in error &&
63
+ typeof error.code === 'string' &&
64
+ typeof error.message === 'string');
65
+ }
66
+ /**
67
+ * Check if error is a client-side error (not from server).
68
+ */
69
+ export function isClientError(error) {
70
+ return Object.values(ERROR_CODES).includes(error.code);
71
+ }
72
+ /**
73
+ * Check if error is retryable.
74
+ */
75
+ export function isRetryableError(error) {
76
+ return error.code === ERROR_CODES.NETWORK_ERROR || error.code === ERROR_CODES.TIMEOUT;
77
+ }
78
+ /**
79
+ * Get user-friendly message for client-side errors.
80
+ * For server errors, returns the server's message as-is.
81
+ */
82
+ export function getUserMessage(error) {
83
+ // For client-side errors, use our messages
84
+ if (isClientError(error)) {
85
+ return CLIENT_ERROR_MESSAGES[error.code] || error.message;
86
+ }
87
+ // For server errors, use the server's message directly
88
+ return error.message;
89
+ }
90
+ /**
91
+ * Create a client-side AuthError.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * throw createAuthError('INVALID_PHONE_NUMBER', 'Phone number must start with +');
96
+ * ```
97
+ */
98
+ export function createAuthError(code, message, details) {
99
+ const error = new Error(message || CLIENT_ERROR_MESSAGES[code] || code);
100
+ error.code = code;
101
+ error.details = details;
102
+ error.timestamp = new Date().toISOString();
103
+ return error;
104
+ }
105
+ /**
106
+ * Create a client-side AuthError with context.
107
+ */
108
+ export function createAuthErrorWithContext(code, context) {
109
+ const error = createAuthError(code, context.message, context.details);
110
+ error.context = {
111
+ step: context.step,
112
+ useCase: context.useCase,
113
+ timestamp: new Date().toISOString(),
114
+ userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,
115
+ url: typeof window !== 'undefined' ? window.location.href : undefined,
116
+ };
117
+ return error;
118
+ }
119
+ /**
120
+ * Parse error response from backend API.
121
+ * Simply converts the server response to AuthError format without modifying the message.
122
+ */
123
+ export function parseBackendError(response) {
124
+ // Server error with code and message - pass through as-is
125
+ if (response && typeof response === 'object' && ('code' in response || 'error' in response)) {
126
+ const resp = response;
127
+ const errorCode = (resp.code || resp.error);
128
+ const errorMessage = resp.message;
129
+ // Create error with server's message directly
130
+ const error = new Error(errorMessage || 'An error occurred');
131
+ error.code = errorCode;
132
+ error.status = resp.status;
133
+ error.requestId = (resp.requestId || resp.request_id);
134
+ error.timestamp = resp.timestamp;
135
+ error.details = resp.details;
136
+ error.traceId = (resp.trace_id || resp.traceId);
137
+ error.spanId = (resp.span_id || resp.spanId);
138
+ error.service = resp.service;
139
+ // Extract retryAfter if present
140
+ if (resp.details && typeof resp.details === 'object' && 'retryAfter' in resp.details) {
141
+ error.retryAfter = resp.details.retryAfter;
142
+ }
143
+ return error;
144
+ }
145
+ // HTTP response without structured error - use status to create generic error
146
+ if (response && typeof response === 'object' && 'status' in response) {
147
+ const resp = response;
148
+ const status = resp.status;
149
+ const error = new Error(resp.message || `Request failed with status ${status}`);
150
+ error.code = `HTTP_${status}`;
151
+ error.status = status;
152
+ return error;
153
+ }
154
+ // Unknown error format
155
+ const error = new Error('An unexpected error occurred');
156
+ error.code = 'UNKNOWN_ERROR';
157
+ return error;
158
+ }
159
+ /**
160
+ * Serialize error for logging (sanitizes sensitive info).
161
+ */
162
+ export function serializeError(error) {
163
+ return {
164
+ code: error.code,
165
+ message: error.message,
166
+ status: error.status,
167
+ requestId: error.requestId,
168
+ timestamp: error.timestamp,
169
+ traceId: error.traceId,
170
+ spanId: error.spanId,
171
+ service: error.service,
172
+ retryAfter: error.retryAfter,
173
+ browserError: error.browserError,
174
+ context: error.context,
175
+ details: sanitizeDetails(error.details),
176
+ };
177
+ }
178
+ /**
179
+ * Sanitize error details to remove sensitive information.
180
+ */
181
+ function sanitizeDetails(details) {
182
+ if (!details || typeof details !== 'object') {
183
+ return details;
184
+ }
185
+ const sanitized = JSON.parse(JSON.stringify(details));
186
+ const sensitiveFields = ['carrier', 'phone_number', 'mnc', 'mcc', 'carrier_name'];
187
+ for (const field of sensitiveFields) {
188
+ delete sanitized[field];
189
+ }
190
+ return sanitized;
191
+ }
192
+ // TODO: Test cancel behavior - when cancel() is called, credential promise should reject
193
+ // with error code 'CANCELLED'. Need to verify this works correctly in all scenarios.
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Glide Phone Authentication - Core Package
3
+ *
4
+ * This package contains:
5
+ * - All TypeScript types (API and SDK types)
6
+ * - Pure validation functions
7
+ * - Type guards for type-safe development
8
+ * - Error codes and utilities
9
+ *
10
+ * ZERO RUNTIME DEPENDENCIES - safe to import anywhere.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // Import from core for types-only usage
15
+ * import {
16
+ * type PrepareRequest,
17
+ * type PrepareResponse,
18
+ * validatePhoneNumber,
19
+ * isDesktopStrategy,
20
+ * ERROR_CODES
21
+ * } from '@glideidentity/web-client-sdk/core';
22
+ * ```
23
+ */
24
+ // ============================================================================
25
+ // CONSTANTS
26
+ // ============================================================================
27
+ export { USE_CASE, AUTHENTICATION_STRATEGY, } from './types';
28
+ export { ERROR_CODES, } from './errors';
29
+ // ============================================================================
30
+ // VALIDATORS
31
+ // ============================================================================
32
+ export { validatePhoneNumber, validatePlmn, validateUseCaseRequirements, validateNonce, validateSessionKey, E164_REGEX, } from './validators';
33
+ // ============================================================================
34
+ // TYPE GUARDS
35
+ // ============================================================================
36
+ export {
37
+ // Invoke result guards
38
+ isInvokeResult, isAuthCredential,
39
+ // Strategy guards
40
+ isTS43Strategy, isLinkStrategy, isDesktopStrategy, isCancellable,
41
+ // Prepare response guards
42
+ isTS43Data, isLinkData, isDesktopData, getStrategyData,
43
+ // Process response guards
44
+ isGetPhoneNumberResponse, isVerifyPhoneNumberResponse,
45
+ // Error response guard
46
+ isErrorResponse, } from './type-guards';
47
+ // ============================================================================
48
+ // ERROR UTILITIES
49
+ // ============================================================================
50
+ export {
51
+ // Type guards
52
+ isAuthError, isClientError, isRetryableError,
53
+ // Message helpers
54
+ getUserMessage,
55
+ // Error creation (for client-side errors only)
56
+ createAuthError, createAuthErrorWithContext,
57
+ // Server error parsing (passes through as-is)
58
+ parseBackendError,
59
+ // Logging
60
+ serializeError, } from './errors';
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Type Guards for Phone Authentication.
3
+ *
4
+ * These utilities help developers work with SDK responses in a type-safe way
5
+ * without having to write their own type checking logic.
6
+ */
7
+ import { AUTHENTICATION_STRATEGY } from './types';
8
+ // ============================================================================
9
+ // INVOKE RESULT TYPE GUARDS
10
+ // ============================================================================
11
+ /**
12
+ * Type guard to check if result is an InvokeResult.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const result = await sdk.invokeSecurePrompt(prepared);
17
+ * if (isInvokeResult(result)) {
18
+ * const credential = await result.credential;
19
+ * }
20
+ * ```
21
+ */
22
+ export function isInvokeResult(result) {
23
+ return (result !== null &&
24
+ typeof result === 'object' &&
25
+ 'credential' in result &&
26
+ 'strategy' in result &&
27
+ 'session' in result);
28
+ }
29
+ /**
30
+ * Type guard to check if result is an AuthCredential.
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const credential = await result.credential;
35
+ * if (isAuthCredential(credential)) {
36
+ * console.log(credential.phone_number);
37
+ * }
38
+ * ```
39
+ */
40
+ export function isAuthCredential(result) {
41
+ return (result !== null &&
42
+ typeof result === 'object' &&
43
+ 'credential' in result &&
44
+ 'authenticated' in result &&
45
+ 'session' in result);
46
+ }
47
+ // ============================================================================
48
+ // STRATEGY TYPE GUARDS
49
+ // ============================================================================
50
+ /**
51
+ * Check if result is from TS43 strategy.
52
+ * TS43 uses Android Digital Credentials API.
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const result = await sdk.invokeSecurePrompt(prepared);
57
+ * if (isTS43Strategy(result)) {
58
+ * // result.cancel is undefined for TS43
59
+ * // To retry: call invokeSecurePrompt again
60
+ * }
61
+ * ```
62
+ */
63
+ export function isTS43Strategy(result) {
64
+ return result.strategy === AUTHENTICATION_STRATEGY.TS43;
65
+ }
66
+ /**
67
+ * Check if result is from Link strategy.
68
+ * Link strategy uses iOS App Clips or Android App Links.
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const result = await sdk.invokeSecurePrompt(prepared);
73
+ * if (isLinkStrategy(result)) {
74
+ * // Can cancel polling
75
+ * result.cancel?.();
76
+ * }
77
+ * ```
78
+ */
79
+ export function isLinkStrategy(result) {
80
+ return result.strategy === AUTHENTICATION_STRATEGY.LINK;
81
+ }
82
+ /**
83
+ * Check if result is from Desktop strategy.
84
+ * Desktop strategy uses QR codes for cross-device auth.
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const result = await sdk.invokeSecurePrompt(prepared);
89
+ * if (isDesktopStrategy(result)) {
90
+ * // QR code data is in prepared.data
91
+ * // Can cancel polling
92
+ * result.cancel?.();
93
+ * }
94
+ * ```
95
+ */
96
+ export function isDesktopStrategy(result) {
97
+ return result.strategy === AUTHENTICATION_STRATEGY.DESKTOP;
98
+ }
99
+ /**
100
+ * Check if result has cancel capability.
101
+ * Only Link and Desktop strategies support cancel.
102
+ */
103
+ export function isCancellable(result) {
104
+ return result.cancel !== undefined;
105
+ }
106
+ // ============================================================================
107
+ // PREPARE RESPONSE TYPE GUARDS
108
+ // ============================================================================
109
+ /**
110
+ * Check if prepare response data is TS43Data.
111
+ */
112
+ export function isTS43Data(data) {
113
+ return (data !== null &&
114
+ typeof data === 'object' &&
115
+ 'protocol' in data &&
116
+ 'data' in data &&
117
+ typeof data.data === 'object' &&
118
+ 'dcql_query' in data.data);
119
+ }
120
+ /**
121
+ * Check if prepare response data is LinkData.
122
+ */
123
+ export function isLinkData(data) {
124
+ return (data !== null &&
125
+ typeof data === 'object' &&
126
+ 'url' in data &&
127
+ typeof data.url === 'string');
128
+ }
129
+ /**
130
+ * Check if prepare response data is DesktopData.
131
+ */
132
+ export function isDesktopData(data) {
133
+ return (data !== null &&
134
+ typeof data === 'object' &&
135
+ 'data' in data &&
136
+ typeof data.data === 'object');
137
+ }
138
+ /**
139
+ * Get strategy-specific data from PrepareResponse with proper typing.
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * const prepared = await sdk.prepare(request);
144
+ *
145
+ * if (prepared.authentication_strategy === 'desktop') {
146
+ * const desktopData = getStrategyData(prepared);
147
+ * // Show QR code: desktopData.data.ios_qr_image
148
+ * }
149
+ * ```
150
+ */
151
+ export function getStrategyData(prepared) {
152
+ return prepared.data;
153
+ }
154
+ // ============================================================================
155
+ // PROCESS RESPONSE TYPE GUARDS
156
+ // ============================================================================
157
+ /**
158
+ * Check if response is GetPhoneNumberResponse.
159
+ */
160
+ export function isGetPhoneNumberResponse(result) {
161
+ return !('verified' in result);
162
+ }
163
+ /**
164
+ * Check if response is VerifyPhoneNumberResponse.
165
+ */
166
+ export function isVerifyPhoneNumberResponse(result) {
167
+ return 'verified' in result;
168
+ }
169
+ // ============================================================================
170
+ // ERROR TYPE GUARDS
171
+ // ============================================================================
172
+ // Note: isAuthError is exported from errors.ts to avoid duplication
173
+ /**
174
+ * Check if response is an error response from server.
175
+ */
176
+ export function isErrorResponse(response) {
177
+ return (response !== null &&
178
+ typeof response === 'object' &&
179
+ 'code' in response &&
180
+ 'message' in response);
181
+ }
@@ -1 +1,22 @@
1
- export {};
1
+ /**
2
+ * Glide Phone Authentication - Core Types
3
+ *
4
+ * This file contains all types for the Phone Auth SDK.
5
+ * Zero runtime dependencies - pure TypeScript types and constants.
6
+ *
7
+ * NAMING CONVENTION:
8
+ * - All types use snake_case to match API communication
9
+ * - This eliminates conversion errors and makes debugging easier
10
+ */
11
+ // ============================================================================
12
+ // CONSTANTS
13
+ // ============================================================================
14
+ export const USE_CASE = {
15
+ GET_PHONE_NUMBER: 'GetPhoneNumber',
16
+ VERIFY_PHONE_NUMBER: 'VerifyPhoneNumber'
17
+ };
18
+ export const AUTHENTICATION_STRATEGY = {
19
+ TS43: 'ts43',
20
+ LINK: 'link',
21
+ DESKTOP: 'desktop'
22
+ };