@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.
- package/README.md +337 -526
- package/dist/browser/web-client-sdk.min.js +1 -1
- package/dist/cjs/adapters/index.js +15 -0
- package/dist/cjs/adapters/react.js +192 -0
- package/dist/cjs/adapters/vanilla.js +38 -0
- package/dist/cjs/adapters/vue.js +187 -0
- package/dist/cjs/browser.js +58 -0
- package/dist/cjs/client/http.js +159 -0
- package/dist/cjs/client/index.js +19 -0
- package/dist/cjs/client/logger.js +135 -0
- package/dist/cjs/client/phone-auth-client.js +428 -0
- package/dist/cjs/client/strategies/polling.js +177 -0
- package/dist/cjs/core/errors.js +204 -0
- package/dist/cjs/core/index.js +83 -0
- package/dist/cjs/core/type-guards.js +196 -0
- package/dist/cjs/core/types.js +25 -0
- package/dist/{core/phone-auth/validation-utils.js → cjs/core/validators.js} +70 -23
- package/dist/cjs/index.js +81 -0
- package/dist/cjs/ui/index.js +11 -0
- package/dist/{core/phone-auth → cjs}/ui/mobile-debug-console.js +149 -78
- package/dist/cjs/ui/modal.js +1122 -0
- package/dist/esm/adapters/index.js +11 -0
- package/dist/esm/adapters/react.js +182 -0
- package/dist/esm/adapters/vanilla.js +29 -0
- package/dist/esm/adapters/vue.js +177 -0
- package/dist/esm/browser.js +30 -11
- package/dist/esm/client/http.js +156 -0
- package/dist/esm/client/index.js +11 -0
- package/dist/esm/client/logger.js +131 -0
- package/dist/esm/client/phone-auth-client.js +424 -0
- package/dist/esm/client/strategies/polling.js +174 -0
- package/dist/esm/core/errors.js +193 -0
- package/dist/esm/core/index.js +60 -0
- package/dist/esm/core/type-guards.js +181 -0
- package/dist/esm/core/types.js +22 -1
- package/dist/esm/core/{phone-auth/validation-utils.js → validators.js} +66 -21
- package/dist/esm/index.js +45 -17
- package/dist/esm/ui/index.js +5 -0
- package/dist/esm/{core/phone-auth/ui → ui}/mobile-debug-console.js +149 -78
- package/dist/esm/ui/modal.js +1117 -0
- package/dist/types/adapters/index.d.ts +10 -0
- package/dist/types/adapters/index.d.ts.map +1 -0
- package/dist/types/adapters/react.d.ts +70 -0
- package/dist/types/adapters/react.d.ts.map +1 -0
- package/dist/types/adapters/vanilla.d.ts +29 -0
- package/dist/types/adapters/vanilla.d.ts.map +1 -0
- package/dist/types/adapters/vue.d.ts +71 -0
- package/dist/types/adapters/vue.d.ts.map +1 -0
- package/dist/types/browser.d.ts +27 -0
- package/dist/types/browser.d.ts.map +1 -0
- package/dist/types/client/http.d.ts +41 -0
- package/dist/types/client/http.d.ts.map +1 -0
- package/dist/types/client/index.d.ts +10 -0
- package/dist/types/client/index.d.ts.map +1 -0
- package/dist/types/client/logger.d.ts +36 -0
- package/dist/types/client/logger.d.ts.map +1 -0
- package/dist/types/client/phone-auth-client.d.ts +91 -0
- package/dist/types/client/phone-auth-client.d.ts.map +1 -0
- package/dist/types/client/strategies/polling.d.ts +36 -0
- package/dist/types/client/strategies/polling.d.ts.map +1 -0
- package/dist/types/core/errors.d.ts +71 -0
- package/dist/types/core/errors.d.ts.map +1 -0
- package/dist/types/core/index.d.ts +38 -0
- package/dist/types/core/index.d.ts.map +1 -0
- package/dist/types/core/type-guards.d.ts +118 -0
- package/dist/types/core/type-guards.d.ts.map +1 -0
- package/dist/types/core/types.d.ts +535 -0
- package/dist/types/core/types.d.ts.map +1 -0
- package/dist/types/core/validators.d.ts +63 -0
- package/dist/types/core/validators.d.ts.map +1 -0
- package/dist/types/index.d.ts +40 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/ui/index.d.ts +6 -0
- package/dist/types/ui/index.d.ts.map +1 -0
- package/dist/{esm/core/phone-auth → types}/ui/mobile-debug-console.d.ts +1 -0
- package/dist/types/ui/mobile-debug-console.d.ts.map +1 -0
- package/dist/types/ui/modal.d.ts +87 -0
- package/dist/types/ui/modal.d.ts.map +1 -0
- package/package.json +48 -34
- package/dist/adapters/angular/client.service.d.ts +0 -7
- package/dist/adapters/angular/client.service.js +0 -30
- package/dist/adapters/angular/index.d.ts +0 -3
- package/dist/adapters/angular/index.js +0 -18
- package/dist/adapters/angular/phone-auth.service.d.ts +0 -38
- package/dist/adapters/angular/phone-auth.service.js +0 -130
- package/dist/adapters/react/index.d.ts +0 -9
- package/dist/adapters/react/index.js +0 -28
- package/dist/adapters/react/useClient.d.ts +0 -26
- package/dist/adapters/react/useClient.js +0 -121
- package/dist/adapters/react/usePhoneAuth.d.ts +0 -23
- package/dist/adapters/react/usePhoneAuth.js +0 -95
- package/dist/adapters/vanilla/client.d.ts +0 -8
- package/dist/adapters/vanilla/client.js +0 -33
- package/dist/adapters/vanilla/index.d.ts +0 -3
- package/dist/adapters/vanilla/index.js +0 -18
- package/dist/adapters/vanilla/phone-auth.d.ts +0 -46
- package/dist/adapters/vanilla/phone-auth.js +0 -138
- package/dist/adapters/vue/index.d.ts +0 -10
- package/dist/adapters/vue/index.js +0 -36
- package/dist/adapters/vue/useClient.d.ts +0 -115
- package/dist/adapters/vue/useClient.js +0 -131
- package/dist/adapters/vue/usePhoneAuth.d.ts +0 -94
- package/dist/adapters/vue/usePhoneAuth.js +0 -103
- package/dist/browser.d.ts +0 -7
- package/dist/browser.js +0 -31
- package/dist/core/client.d.ts +0 -22
- package/dist/core/client.js +0 -77
- package/dist/core/logger.d.ts +0 -130
- package/dist/core/logger.js +0 -370
- package/dist/core/phone-auth/api-types.d.ts +0 -593
- package/dist/core/phone-auth/api-types.js +0 -215
- package/dist/core/phone-auth/client.d.ts +0 -189
- package/dist/core/phone-auth/client.js +0 -1441
- package/dist/core/phone-auth/error-utils.d.ts +0 -110
- package/dist/core/phone-auth/error-utils.js +0 -350
- package/dist/core/phone-auth/index.d.ts +0 -7
- package/dist/core/phone-auth/index.js +0 -50
- package/dist/core/phone-auth/status-types.d.ts +0 -107
- package/dist/core/phone-auth/status-types.js +0 -31
- package/dist/core/phone-auth/strategies/desktop.d.ts +0 -122
- package/dist/core/phone-auth/strategies/desktop.js +0 -596
- package/dist/core/phone-auth/strategies/index.d.ts +0 -11
- package/dist/core/phone-auth/strategies/index.js +0 -15
- package/dist/core/phone-auth/strategies/link.d.ts +0 -89
- package/dist/core/phone-auth/strategies/link.js +0 -384
- package/dist/core/phone-auth/strategies/ts43.d.ts +0 -32
- package/dist/core/phone-auth/strategies/ts43.js +0 -161
- package/dist/core/phone-auth/strategies/types.d.ts +0 -18
- package/dist/core/phone-auth/strategies/types.js +0 -6
- package/dist/core/phone-auth/type-guards.d.ts +0 -143
- package/dist/core/phone-auth/type-guards.js +0 -198
- package/dist/core/phone-auth/types.d.ts +0 -237
- package/dist/core/phone-auth/types.js +0 -93
- package/dist/core/phone-auth/ui/mobile-debug-console.d.ts +0 -25
- package/dist/core/phone-auth/ui/modal.d.ts +0 -88
- package/dist/core/phone-auth/ui/modal.js +0 -598
- package/dist/core/phone-auth/validation-utils.d.ts +0 -44
- package/dist/core/types.d.ts +0 -62
- package/dist/core/types.js +0 -2
- package/dist/core/version.d.ts +0 -1
- package/dist/core/version.js +0 -5
- package/dist/esm/adapters/angular/client.service.d.ts +0 -7
- package/dist/esm/adapters/angular/client.service.js +0 -27
- package/dist/esm/adapters/angular/index.d.ts +0 -3
- package/dist/esm/adapters/angular/index.js +0 -4
- package/dist/esm/adapters/angular/phone-auth.service.d.ts +0 -38
- package/dist/esm/adapters/angular/phone-auth.service.js +0 -127
- package/dist/esm/adapters/react/index.d.ts +0 -9
- package/dist/esm/adapters/react/index.js +0 -8
- package/dist/esm/adapters/react/useClient.d.ts +0 -26
- package/dist/esm/adapters/react/useClient.js +0 -116
- package/dist/esm/adapters/react/usePhoneAuth.d.ts +0 -23
- package/dist/esm/adapters/react/usePhoneAuth.js +0 -92
- package/dist/esm/adapters/vanilla/client.d.ts +0 -8
- package/dist/esm/adapters/vanilla/client.js +0 -29
- package/dist/esm/adapters/vanilla/index.d.ts +0 -3
- package/dist/esm/adapters/vanilla/index.js +0 -4
- package/dist/esm/adapters/vanilla/phone-auth.d.ts +0 -46
- package/dist/esm/adapters/vanilla/phone-auth.js +0 -134
- package/dist/esm/adapters/vue/index.d.ts +0 -10
- package/dist/esm/adapters/vue/index.js +0 -11
- package/dist/esm/adapters/vue/useClient.d.ts +0 -115
- package/dist/esm/adapters/vue/useClient.js +0 -127
- package/dist/esm/adapters/vue/usePhoneAuth.d.ts +0 -94
- package/dist/esm/adapters/vue/usePhoneAuth.js +0 -100
- package/dist/esm/browser.d.ts +0 -7
- package/dist/esm/core/client.d.ts +0 -22
- package/dist/esm/core/client.js +0 -70
- package/dist/esm/core/logger.d.ts +0 -130
- package/dist/esm/core/logger.js +0 -359
- package/dist/esm/core/phone-auth/api-types.d.ts +0 -593
- package/dist/esm/core/phone-auth/api-types.js +0 -203
- package/dist/esm/core/phone-auth/client.d.ts +0 -189
- package/dist/esm/core/phone-auth/client.js +0 -1404
- package/dist/esm/core/phone-auth/error-utils.d.ts +0 -110
- package/dist/esm/core/phone-auth/error-utils.js +0 -338
- package/dist/esm/core/phone-auth/index.d.ts +0 -7
- package/dist/esm/core/phone-auth/index.js +0 -8
- package/dist/esm/core/phone-auth/status-types.d.ts +0 -107
- package/dist/esm/core/phone-auth/status-types.js +0 -26
- package/dist/esm/core/phone-auth/strategies/desktop.d.ts +0 -122
- package/dist/esm/core/phone-auth/strategies/desktop.js +0 -590
- package/dist/esm/core/phone-auth/strategies/index.d.ts +0 -11
- package/dist/esm/core/phone-auth/strategies/index.js +0 -7
- package/dist/esm/core/phone-auth/strategies/link.d.ts +0 -89
- package/dist/esm/core/phone-auth/strategies/link.js +0 -380
- package/dist/esm/core/phone-auth/strategies/ts43.d.ts +0 -32
- package/dist/esm/core/phone-auth/strategies/ts43.js +0 -157
- package/dist/esm/core/phone-auth/strategies/types.d.ts +0 -18
- package/dist/esm/core/phone-auth/strategies/types.js +0 -5
- package/dist/esm/core/phone-auth/type-guards.d.ts +0 -143
- package/dist/esm/core/phone-auth/type-guards.js +0 -185
- package/dist/esm/core/phone-auth/types.d.ts +0 -237
- package/dist/esm/core/phone-auth/types.js +0 -76
- package/dist/esm/core/phone-auth/ui/modal.d.ts +0 -88
- package/dist/esm/core/phone-auth/ui/modal.js +0 -594
- package/dist/esm/core/phone-auth/validation-utils.d.ts +0 -44
- package/dist/esm/core/types.d.ts +0 -62
- package/dist/esm/core/version.d.ts +0 -1
- package/dist/esm/core/version.js +0 -2
- package/dist/esm/index.d.ts +0 -12
- package/dist/index.d.ts +0 -12
- 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
|
+
}
|
package/dist/esm/core/types.js
CHANGED
|
@@ -1 +1,22 @@
|
|
|
1
|
-
|
|
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
|
+
};
|