@authsome/ui-core 0.1.9 → 1.0.0

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/dist/index.js CHANGED
@@ -1,1863 +1,1724 @@
1
- 'use strict';
2
-
3
- // src/types/auth.ts
4
- var AuthState = /* @__PURE__ */ ((AuthState2) => {
5
- AuthState2["AUTHENTICATED"] = "authenticated";
6
- AuthState2["UNAUTHENTICATED"] = "unauthenticated";
7
- AuthState2["LOADING"] = "loading";
8
- AuthState2["ERROR"] = "error";
9
- return AuthState2;
10
- })(AuthState || {});
11
- var AuthErrorType = /* @__PURE__ */ ((AuthErrorType2) => {
12
- AuthErrorType2["INVALID_CREDENTIALS"] = "invalid_credentials";
13
- AuthErrorType2["USER_NOT_FOUND"] = "user_not_found";
14
- AuthErrorType2["USER_ALREADY_EXISTS"] = "user_already_exists";
15
- AuthErrorType2["INVALID_TOKEN"] = "invalid_token";
16
- AuthErrorType2["TOKEN_EXPIRED"] = "token_expired";
17
- AuthErrorType2["NETWORK_ERROR"] = "network_error";
18
- AuthErrorType2["VALIDATION_ERROR"] = "validation_error";
19
- AuthErrorType2["MFA_REQUIRED"] = "mfa_required";
20
- AuthErrorType2["EMAIL_NOT_VERIFIED"] = "email_not_verified";
21
- AuthErrorType2["PHONE_NOT_VERIFIED"] = "phone_not_verified";
22
- AuthErrorType2["RATE_LIMIT_EXCEEDED"] = "rate_limit_exceeded";
23
- AuthErrorType2["UNKNOWN_ERROR"] = "unknown_error";
24
- return AuthErrorType2;
25
- })(AuthErrorType || {});
26
- var AuthError = class _AuthError extends Error {
27
- constructor(message, type = "unknown_error" /* UNKNOWN_ERROR */, options) {
28
- super(message);
29
- this.name = "AuthError";
30
- this.type = type;
31
- this.details = options?.details;
32
- this.code = options?.code;
33
- this.originalError = options?.originalError;
34
- if (Error.captureStackTrace) {
35
- Error.captureStackTrace(this, _AuthError);
36
- }
37
- }
38
- };
39
- var OAuthProvider = /* @__PURE__ */ ((OAuthProvider2) => {
40
- OAuthProvider2["GOOGLE"] = "google";
41
- OAuthProvider2["GITHUB"] = "github";
42
- OAuthProvider2["FACEBOOK"] = "facebook";
43
- OAuthProvider2["TWITTER"] = "twitter";
44
- OAuthProvider2["MICROSOFT"] = "microsoft";
45
- OAuthProvider2["APPLE"] = "apple";
46
- OAuthProvider2["LINKEDIN"] = "linkedin";
47
- OAuthProvider2["DISCORD"] = "discord";
48
- return OAuthProvider2;
49
- })(OAuthProvider || {});
50
- var TwoFactorMethod = /* @__PURE__ */ ((TwoFactorMethod2) => {
51
- TwoFactorMethod2["TOTP"] = "totp";
52
- TwoFactorMethod2["SMS"] = "sms";
53
- TwoFactorMethod2["EMAIL"] = "email";
54
- TwoFactorMethod2["BACKUP_CODE"] = "backup_code";
55
- return TwoFactorMethod2;
56
- })(TwoFactorMethod || {});
57
-
58
- // src/types/storage.ts
59
- var LocalStorageAdapter = class {
60
- getItem(key) {
61
- if (typeof window === "undefined") return null;
62
- return window.localStorage.getItem(key);
63
- }
64
- setItem(key, value) {
65
- if (typeof window === "undefined") return;
66
- window.localStorage.setItem(key, value);
67
- }
68
- removeItem(key) {
69
- if (typeof window === "undefined") return;
70
- window.localStorage.removeItem(key);
71
- }
72
- clear() {
73
- if (typeof window === "undefined") return;
74
- window.localStorage.clear();
75
- }
76
- };
77
- var SessionStorageAdapter = class {
78
- getItem(key) {
79
- if (typeof window === "undefined") return null;
80
- return window.sessionStorage.getItem(key);
81
- }
82
- setItem(key, value) {
83
- if (typeof window === "undefined") return;
84
- window.sessionStorage.setItem(key, value);
85
- }
86
- removeItem(key) {
87
- if (typeof window === "undefined") return;
88
- window.sessionStorage.removeItem(key);
89
- }
90
- clear() {
91
- if (typeof window === "undefined") return;
92
- window.sessionStorage.clear();
93
- }
94
- };
95
- var MemoryStorageAdapter = class {
96
- constructor() {
97
- this.store = /* @__PURE__ */ new Map();
98
- }
99
- getItem(key) {
100
- return this.store.get(key) ?? null;
101
- }
102
- setItem(key, value) {
103
- this.store.set(key, value);
104
- }
105
- removeItem(key) {
106
- this.store.delete(key);
1
+ // src/generated/api-client.ts
2
+ var AuthClient = class {
3
+ baseURL;
4
+ fetchFn;
5
+ constructor(config) {
6
+ this.baseURL = config.baseURL.replace(/\/+$/, "");
7
+ this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
8
+ }
9
+ // ──────────────────────────────────────────────────
10
+ // Generated methods
11
+ // ──────────────────────────────────────────────────
12
+ /**
13
+ * Get AuthSome manifest
14
+ * GET /.well-known/authsome/manifest
15
+ */
16
+ async getManifest() {
17
+ const path = "/.well-known/authsome/manifest";
18
+ return this.request(
19
+ "GET",
20
+ path,
21
+ void 0
22
+ );
107
23
  }
108
- clear() {
109
- this.store.clear();
24
+ /**
25
+ * Get OpenAPI specification
26
+ * GET /.well-known/authsome/openapi
27
+ */
28
+ async getOpenAPI() {
29
+ const path = "/.well-known/authsome/openapi";
30
+ return this.request(
31
+ "GET",
32
+ path,
33
+ void 0
34
+ );
110
35
  }
111
- };
112
-
113
- // src/types/observable.ts
114
- var Observable = class {
115
- constructor(initialValue) {
116
- this.listeners = /* @__PURE__ */ new Set();
117
- this.value = initialValue;
36
+ /**
37
+ * Stop impersonation (admin)
38
+ * POST /v1/auth/admin/impersonate/stop
39
+ */
40
+ async adminStopImpersonation(body, token) {
41
+ const path = "/v1/auth/admin/impersonate/stop";
42
+ return this.request(
43
+ "POST",
44
+ path,
45
+ body,
46
+ token
47
+ );
118
48
  }
119
49
  /**
120
- * Get current value
50
+ * Impersonate user (admin)
51
+ * POST /v1/auth/admin/impersonate/{userId}
121
52
  */
122
- getValue() {
123
- return this.value;
53
+ async adminImpersonate(userId, body, token) {
54
+ const path = `/v1/auth/admin/impersonate/${userId}`;
55
+ return this.request(
56
+ "POST",
57
+ path,
58
+ body,
59
+ token
60
+ );
124
61
  }
125
62
  /**
126
- * Set new value and notify listeners
63
+ * List organizations (admin)
64
+ * GET /v1/auth/admin/orgs
127
65
  */
128
- setValue(newValue) {
129
- if (this.value !== newValue) {
130
- this.value = newValue;
131
- this.notify();
132
- }
66
+ async adminListOrgs(token) {
67
+ const path = "/v1/auth/admin/orgs";
68
+ return this.request(
69
+ "GET",
70
+ path,
71
+ void 0,
72
+ token
73
+ );
133
74
  }
134
75
  /**
135
- * Update value with a function
76
+ * Get stats (admin)
77
+ * GET /v1/auth/admin/stats
136
78
  */
137
- update(updater) {
138
- this.setValue(updater(this.value));
79
+ async adminGetStats(token) {
80
+ const path = "/v1/auth/admin/stats";
81
+ return this.request(
82
+ "GET",
83
+ path,
84
+ void 0,
85
+ token
86
+ );
139
87
  }
140
88
  /**
141
- * Subscribe to value changes
89
+ * List users (admin)
90
+ * GET /v1/auth/admin/users
142
91
  */
143
- subscribe(listener) {
144
- this.listeners.add(listener);
145
- listener(this.value);
146
- return () => {
147
- this.listeners.delete(listener);
148
- };
92
+ async adminListUsers(token) {
93
+ const path = "/v1/auth/admin/users";
94
+ return this.request(
95
+ "GET",
96
+ path,
97
+ void 0,
98
+ token
99
+ );
149
100
  }
150
101
  /**
151
- * Notify all listeners
102
+ * Get user (admin)
103
+ * GET /v1/auth/admin/users/{userId}
152
104
  */
153
- notify() {
154
- this.listeners.forEach((listener) => listener(this.value));
105
+ async adminGetUser(userId, token) {
106
+ const path = `/v1/auth/admin/users/${userId}`;
107
+ return this.request(
108
+ "GET",
109
+ path,
110
+ void 0,
111
+ token
112
+ );
155
113
  }
156
114
  /**
157
- * Clear all listeners
115
+ * Delete user (admin)
116
+ * DELETE /v1/auth/admin/users/{userId}
158
117
  */
159
- clearListeners() {
160
- this.listeners.clear();
118
+ async adminDeleteUser(userId, body, token) {
119
+ const path = `/v1/auth/admin/users/${userId}`;
120
+ return this.request(
121
+ "DELETE",
122
+ path,
123
+ body,
124
+ token
125
+ );
161
126
  }
162
127
  /**
163
- * Get number of listeners
128
+ * Ban user (admin)
129
+ * POST /v1/auth/admin/users/{userId}/ban
164
130
  */
165
- getListenerCount() {
166
- return this.listeners.size;
131
+ async adminBanUser(userId, body, token) {
132
+ const path = `/v1/auth/admin/users/${userId}/ban`;
133
+ return this.request(
134
+ "POST",
135
+ path,
136
+ body,
137
+ token
138
+ );
167
139
  }
168
- };
169
-
170
- // src/utils/errors.ts
171
- function createAuthError(type, message, details, code) {
172
- return new AuthError(message, type, { details, code });
173
- }
174
- function isAuthError(error) {
175
- return error instanceof AuthError;
176
- }
177
- function toAuthError(error) {
178
- if (isAuthError(error)) {
179
- return error;
180
- }
181
- if (error instanceof Error) {
182
- return new AuthError(error.message, "unknown_error" /* UNKNOWN_ERROR */, {
183
- details: {
184
- originalError: error.name,
185
- stack: error.stack
186
- }
187
- });
140
+ /**
141
+ * Unban user (admin)
142
+ * POST /v1/auth/admin/users/{userId}/unban
143
+ */
144
+ async adminUnbanUser(userId, body, token) {
145
+ const path = `/v1/auth/admin/users/${userId}/unban`;
146
+ return this.request(
147
+ "POST",
148
+ path,
149
+ body,
150
+ token
151
+ );
188
152
  }
189
- if (typeof error === "string") {
190
- return new AuthError(error, "unknown_error" /* UNKNOWN_ERROR */);
153
+ /**
154
+ * Change password
155
+ * POST /v1/auth/change-password
156
+ */
157
+ async changePassword(body, token) {
158
+ const path = "/v1/auth/change-password";
159
+ return this.request(
160
+ "POST",
161
+ path,
162
+ body,
163
+ token
164
+ );
191
165
  }
192
- return new AuthError(
193
- "An unknown error occurred",
194
- "unknown_error" /* UNKNOWN_ERROR */,
195
- { details: { error } }
196
- );
197
- }
198
- function isNetworkError(error) {
199
- if (error instanceof Error) {
200
- return error.name === "NetworkError" || error.message.includes("network") || error.message.includes("fetch");
166
+ /**
167
+ * List devices
168
+ * GET /v1/auth/devices
169
+ */
170
+ async listDevices(token) {
171
+ const path = "/v1/auth/devices";
172
+ return this.request(
173
+ "GET",
174
+ path,
175
+ void 0,
176
+ token
177
+ );
201
178
  }
202
- return false;
203
- }
204
- function isUnauthenticatedError(error) {
205
- if (isAuthError(error)) {
206
- return error.type === "invalid_token" /* INVALID_TOKEN */ || error.type === "token_expired" /* TOKEN_EXPIRED */;
179
+ /**
180
+ * Get device
181
+ * GET /v1/auth/devices/{deviceId}
182
+ */
183
+ async getDevice(deviceId, token) {
184
+ const path = `/v1/auth/devices/${deviceId}`;
185
+ return this.request(
186
+ "GET",
187
+ path,
188
+ void 0,
189
+ token
190
+ );
207
191
  }
208
- return false;
209
- }
210
- function isMFARequiredError(error) {
211
- if (isAuthError(error)) {
212
- return error.type === "mfa_required" /* MFA_REQUIRED */;
192
+ /**
193
+ * Delete device
194
+ * DELETE /v1/auth/devices/{deviceId}
195
+ */
196
+ async deleteDevice(deviceId, body, token) {
197
+ const path = `/v1/auth/devices/${deviceId}`;
198
+ return this.request(
199
+ "DELETE",
200
+ path,
201
+ body,
202
+ token
203
+ );
213
204
  }
214
- return false;
215
- }
216
-
217
- // src/locale/en.ts
218
- var enLocale = {
219
- common: {
220
- loading: "Loading...",
221
- submit: "Submit",
222
- cancel: "Cancel",
223
- continue: "Continue",
224
- back: "Back",
225
- or: "or",
226
- optional: "optional"
227
- },
228
- auth: {
229
- signIn: "Sign In",
230
- signUp: "Sign Up",
231
- signOut: "Sign Out",
232
- email: "Email",
233
- password: "Password",
234
- confirmPassword: "Confirm Password",
235
- username: "Username",
236
- phone: "Phone",
237
- rememberMe: "Remember me",
238
- forgotPassword: "Forgot password?",
239
- continueWith: "Continue with {provider}",
240
- orContinueWith: "Or continue with"
241
- },
242
- oauth: {
243
- google: "Google",
244
- github: "GitHub",
245
- microsoft: "Microsoft",
246
- facebook: "Facebook",
247
- apple: "Apple",
248
- discord: "Discord",
249
- twitter: "Twitter",
250
- linkedin: "LinkedIn",
251
- chooseProvider: "Choose Your Provider",
252
- signInPreferred: "Sign in with your preferred account"
253
- },
254
- magicLink: {
255
- sendLink: "Send magic link",
256
- checkEmail: "Check your email",
257
- linkSent: "Magic link sent! Check your email to continue.",
258
- enterEmail: "Enter your email to receive a magic link"
259
- },
260
- phone: {
261
- enterPhone: "Enter your phone number",
262
- sendCode: "Send code",
263
- enterCode: "Enter verification code",
264
- verifyPhone: "Verify phone number",
265
- codeLabel: "Verification code"
266
- },
267
- mfa: {
268
- required: "Two-factor authentication required",
269
- selectMethod: "Select verification method",
270
- verify: "Verify",
271
- enterCode: "Enter verification code",
272
- sms: "SMS",
273
- authenticator: "Authenticator app",
274
- email: "Email"
275
- },
276
- passkey: {
277
- signInWith: "Sign in with passkey",
278
- register: "Register passkey",
279
- usePasskey: "Use passkey"
280
- },
281
- deviceFlow: {
282
- title: "Authorize Device",
283
- subtitle: "Enter the code displayed on your device",
284
- enterCode: "Authorize Device",
285
- enterCodeDescription: "Enter the code displayed on your device or CLI",
286
- codeLabel: "Device Code",
287
- codePlaceholder: "XXXX-XXXX",
288
- codeHint: "Enter the 8-character code shown on your device",
289
- verify: "Verify Code",
290
- verifyCode: "Verify Code",
291
- invalidCode: "Invalid code. Please check and try again.",
292
- noCode: "Don't have a code?",
293
- getCodeHelp: "Get help",
294
- authorizationTitle: "Authorize Application",
295
- authorizationSubtitle: "An application is requesting access to your account",
296
- authorizeTitle: "Authorize Device",
297
- authorizeDescription: "An application is requesting access to your account",
298
- requestingAccess: "is requesting access to:",
299
- codeConfirm: "Confirm this is your code:",
300
- requestedPermissions: "Requested permissions:",
301
- securityWarning: "Only approve this request if you initiated it",
302
- scopes: "Requested permissions",
303
- approve: "Approve",
304
- deny: "Deny",
305
- authorizedTitle: "Device Authorized",
306
- authorizedMessage: "You can now return to your device to continue",
307
- authorizedDescription: "Your device has been successfully authorized",
308
- authorizedHint: "You can close this window and return to your CLI or device",
309
- returnToCli: "Return to CLI",
310
- deniedTitle: "Access Denied",
311
- deniedMessage: "You have denied access to this device",
312
- deniedDescription: "The device authorization request has been denied",
313
- deniedHint: "You can close this window"
314
- },
315
- signUp: {
316
- title: "Create Account",
317
- subtitle: "Get started with your account",
318
- haveAccount: "Already have an account?",
319
- signInLink: "Sign in",
320
- agreeToTerms: "I agree to the {terms}",
321
- terms: "terms and conditions"
322
- },
323
- signIn: {
324
- title: "Sign In",
325
- subtitle: "Enter your email to continue",
326
- noAccount: "Don't have an account?",
327
- signUpLink: "Sign up",
328
- enterEmail: "Enter your email to continue"
329
- },
330
- validation: {
331
- emailRequired: "Email is required",
332
- emailInvalid: "Invalid email address",
333
- passwordRequired: "Password is required",
334
- passwordTooShort: "Password must be at least {min} characters",
335
- passwordRequireUppercase: "Password must contain an uppercase letter",
336
- passwordRequireLowercase: "Password must contain a lowercase letter",
337
- passwordRequireNumber: "Password must contain a number",
338
- passwordRequireSpecial: "Password must contain a special character",
339
- passwordMismatch: "Passwords do not match",
340
- usernameRequired: "Username is required",
341
- usernameInvalid: "Username must be 3-30 characters and contain only letters, numbers, underscores, and hyphens",
342
- phoneRequired: "Phone number is required",
343
- phoneInvalid: "Invalid phone number",
344
- codeRequired: "Verification code is required",
345
- codeInvalid: "Invalid verification code",
346
- fieldRequired: "{field} is required",
347
- termsRequired: "You must agree to the terms and conditions"
348
- },
349
- errors: {
350
- invalidCredentials: "Invalid email or password",
351
- userNotFound: "User not found",
352
- userExists: "User already exists",
353
- invalidToken: "Invalid or expired token",
354
- tokenExpired: "Token has expired",
355
- networkError: "Network error. Please try again.",
356
- mfaRequired: "Two-factor authentication required",
357
- emailNotVerified: "Email not verified",
358
- phoneNotVerified: "Phone number not verified",
359
- rateLimitExceeded: "Too many attempts. Please try again later.",
360
- unknownError: "An unknown error occurred",
361
- generic: "Something went wrong. Please try again."
362
- },
363
- success: {
364
- signedIn: "Successfully signed in",
365
- signedUp: "Account created successfully",
366
- signedOut: "Successfully signed out",
367
- linkSent: "Link sent successfully",
368
- codeSent: "Verification code sent",
369
- verified: "Successfully verified",
370
- welcome: "Welcome, {name}!"
371
- },
372
- placeholders: {
373
- email: "john@example.com",
374
- password: "Enter your password",
375
- confirmPassword: "Confirm your password",
376
- username: "johndoe",
377
- phone: "+1234567890",
378
- code: "123456",
379
- fullName: "John Doe"
205
+ /**
206
+ * Trust device
207
+ * PATCH /v1/auth/devices/{deviceId}/trust
208
+ */
209
+ async trustDevice(deviceId, body, token) {
210
+ const path = `/v1/auth/devices/${deviceId}/trust`;
211
+ return this.request(
212
+ "PATCH",
213
+ path,
214
+ body,
215
+ token
216
+ );
380
217
  }
381
- };
382
-
383
- // src/locale/utils.ts
384
- var defaultLocale = enLocale;
385
- function deepMerge(target, source) {
386
- const result = { ...target };
387
- for (const key in source) {
388
- if (source[key] !== void 0) {
389
- if (typeof source[key] === "object" && source[key] !== null && !Array.isArray(source[key]) && typeof result[key] === "object" && result[key] !== null) {
390
- result[key] = deepMerge(result[key], source[key]);
391
- } else {
392
- result[key] = source[key];
393
- }
394
- }
218
+ /**
219
+ * Forgot password
220
+ * POST /v1/auth/forgot-password
221
+ */
222
+ async forgotPassword(body) {
223
+ const path = "/v1/auth/forgot-password";
224
+ return this.request(
225
+ "POST",
226
+ path,
227
+ body
228
+ );
395
229
  }
396
- return result;
397
- }
398
- function createLocale(overrides) {
399
- if (!overrides) {
400
- return defaultLocale;
230
+ /**
231
+ * Health check
232
+ * GET /v1/auth/health
233
+ */
234
+ async getHealth() {
235
+ const path = "/v1/auth/health";
236
+ return this.request(
237
+ "GET",
238
+ path,
239
+ void 0
240
+ );
401
241
  }
402
- return deepMerge(defaultLocale, overrides);
403
- }
404
- function interpolate(template, values) {
405
- return template.replace(/\{(\w+)\}/g, (match, key) => {
406
- return values[key] !== void 0 ? String(values[key]) : match;
407
- });
408
- }
409
-
410
- // src/utils/validation.ts
411
- var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
412
- var PHONE_REGEX = /^\+?[1-9]\d{1,14}$/;
413
- var USERNAME_REGEX = /^[a-zA-Z0-9_-]{3,30}$/;
414
- function validateEmail(email, locale) {
415
- const messages = locale?.validation || defaultLocale.validation;
416
- if (!email) {
417
- return { field: "email", message: messages.emailRequired };
418
- }
419
- if (!EMAIL_REGEX.test(email)) {
420
- return { field: "email", message: messages.emailInvalid };
421
- }
422
- return null;
423
- }
424
- function validatePassword(password, options = {}) {
425
- const {
426
- minLength = 8,
427
- requireUppercase = true,
428
- requireLowercase = true,
429
- requireNumber = true,
430
- requireSpecial = false,
431
- locale
432
- } = options;
433
- const messages = locale?.validation || defaultLocale.validation;
434
- if (!password) {
435
- return { field: "password", message: messages.passwordRequired };
436
- }
437
- if (password.length < minLength) {
438
- return {
439
- field: "password",
440
- message: interpolate(messages.passwordTooShort, { min: minLength.toString() })
441
- };
242
+ /**
243
+ * List API keys
244
+ * GET /v1/auth/keys
245
+ */
246
+ async listAPIKeys(token) {
247
+ const path = "/v1/auth/keys";
248
+ return this.request(
249
+ "GET",
250
+ path,
251
+ void 0,
252
+ token
253
+ );
442
254
  }
443
- if (requireUppercase && !/[A-Z]/.test(password)) {
444
- return {
445
- field: "password",
446
- message: messages.passwordRequireUppercase
447
- };
255
+ /**
256
+ * Create API key
257
+ * POST /v1/auth/keys
258
+ */
259
+ async createAPIKey(body, token) {
260
+ const path = "/v1/auth/keys";
261
+ return this.request(
262
+ "POST",
263
+ path,
264
+ body,
265
+ token
266
+ );
448
267
  }
449
- if (requireLowercase && !/[a-z]/.test(password)) {
450
- return {
451
- field: "password",
452
- message: messages.passwordRequireLowercase
453
- };
268
+ /**
269
+ * Revoke API key
270
+ * DELETE /v1/auth/keys/{keyId}
271
+ */
272
+ async revokeAPIKey(keyId, body, token) {
273
+ const path = `/v1/auth/keys/${keyId}`;
274
+ return this.request(
275
+ "DELETE",
276
+ path,
277
+ body,
278
+ token
279
+ );
454
280
  }
455
- if (requireNumber && !/\d/.test(password)) {
456
- return { field: "password", message: messages.passwordRequireNumber };
281
+ /**
282
+ * Send magic link
283
+ * POST /v1/auth/magic-link/send
284
+ */
285
+ async sendMagicLink(body) {
286
+ const path = "/v1/auth/magic-link/send";
287
+ return this.request(
288
+ "POST",
289
+ path,
290
+ body
291
+ );
457
292
  }
458
- if (requireSpecial && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
459
- return {
460
- field: "password",
461
- message: messages.passwordRequireSpecial
462
- };
293
+ /**
294
+ * Verify magic link
295
+ * POST /v1/auth/magic-link/verify
296
+ */
297
+ async verifyMagicLink(body) {
298
+ const path = "/v1/auth/magic-link/verify";
299
+ return this.request(
300
+ "POST",
301
+ path,
302
+ body
303
+ );
463
304
  }
464
- return null;
465
- }
466
- function validatePhone(phone, locale) {
467
- const messages = locale?.validation || defaultLocale.validation;
468
- if (!phone) {
469
- return { field: "phone", message: messages.phoneRequired };
470
- }
471
- if (!PHONE_REGEX.test(phone)) {
472
- return {
473
- field: "phone",
474
- message: messages.phoneInvalid
475
- };
305
+ /**
306
+ * Get current user
307
+ * GET /v1/auth/me
308
+ */
309
+ async getMe(token) {
310
+ const path = "/v1/auth/me";
311
+ return this.request(
312
+ "GET",
313
+ path,
314
+ void 0,
315
+ token
316
+ );
476
317
  }
477
- return null;
478
- }
479
- function validateUsername(username, locale) {
480
- const messages = locale?.validation || defaultLocale.validation;
481
- if (!username) {
482
- return { field: "username", message: messages.usernameRequired };
483
- }
484
- if (!USERNAME_REGEX.test(username)) {
485
- return {
486
- field: "username",
487
- message: messages.usernameInvalid
488
- };
318
+ /**
319
+ * Update current user
320
+ * PATCH /v1/auth/me
321
+ */
322
+ async updateMe(body, token) {
323
+ const path = "/v1/auth/me";
324
+ return this.request(
325
+ "PATCH",
326
+ path,
327
+ body,
328
+ token
329
+ );
489
330
  }
490
- return null;
491
- }
492
- function validate2FACode(code, locale) {
493
- const messages = locale?.validation || defaultLocale.validation;
494
- if (!code) {
495
- return { field: "code", message: messages.codeRequired };
331
+ /**
332
+ * Delete account
333
+ * DELETE /v1/auth/me
334
+ */
335
+ async deleteMe(body, token) {
336
+ const path = "/v1/auth/me";
337
+ return this.request(
338
+ "DELETE",
339
+ path,
340
+ body,
341
+ token
342
+ );
496
343
  }
497
- if (!/^\d{6}$/.test(code)) {
498
- return { field: "code", message: messages.codeInvalid };
344
+ /**
345
+ * Export user data
346
+ * GET /v1/auth/me/export
347
+ */
348
+ async exportMyData(token) {
349
+ const path = "/v1/auth/me/export";
350
+ return this.request(
351
+ "GET",
352
+ path,
353
+ void 0,
354
+ token
355
+ );
499
356
  }
500
- return null;
501
- }
502
- function validateRequired(value, fieldName, locale) {
503
- const messages = locale?.validation || defaultLocale.validation;
504
- if (!value || typeof value === "string" && !value.trim()) {
505
- return {
506
- field: fieldName,
507
- message: interpolate(messages.fieldRequired, { field: fieldName })
508
- };
357
+ /**
358
+ * MFA challenge
359
+ * POST /v1/auth/mfa/challenge
360
+ */
361
+ async challengeMFA(body) {
362
+ const path = "/v1/auth/mfa/challenge";
363
+ return this.request(
364
+ "POST",
365
+ path,
366
+ body
367
+ );
509
368
  }
510
- return null;
511
- }
512
-
513
- // src/utils/tokens.ts
514
- var TOKEN_KEY = "authsome_token";
515
- var REFRESH_TOKEN_KEY = "authsome_refresh_token";
516
- var TokenManager = class {
517
- constructor(storage = new LocalStorageAdapter()) {
518
- this.storage = storage;
369
+ /**
370
+ * Enroll in MFA
371
+ * POST /v1/auth/mfa/enroll
372
+ */
373
+ async enrollMFA(body, token) {
374
+ const path = "/v1/auth/mfa/enroll";
375
+ return this.request(
376
+ "POST",
377
+ path,
378
+ body,
379
+ token
380
+ );
519
381
  }
520
382
  /**
521
- * Get access token
383
+ * Disable MFA
384
+ * DELETE /v1/auth/mfa/enrollment
522
385
  */
523
- async getToken() {
524
- return await Promise.resolve(this.storage.getItem(TOKEN_KEY));
386
+ async disableMFA(body, token) {
387
+ const path = "/v1/auth/mfa/enrollment";
388
+ return this.request(
389
+ "DELETE",
390
+ path,
391
+ body,
392
+ token
393
+ );
525
394
  }
526
395
  /**
527
- * Set access token
396
+ * Regenerate MFA recovery codes
397
+ * POST /v1/auth/mfa/recovery/regenerate
528
398
  */
529
- async setToken(token) {
530
- await Promise.resolve(this.storage.setItem(TOKEN_KEY, token));
399
+ async regenerateMFARecoveryCodes(body, token) {
400
+ const path = "/v1/auth/mfa/recovery/regenerate";
401
+ return this.request(
402
+ "POST",
403
+ path,
404
+ body,
405
+ token
406
+ );
531
407
  }
532
408
  /**
533
- * Remove access token
409
+ * Verify MFA recovery code
410
+ * POST /v1/auth/mfa/recovery/verify
534
411
  */
535
- async removeToken() {
536
- await Promise.resolve(this.storage.removeItem(TOKEN_KEY));
412
+ async verifyRecoveryCode(body) {
413
+ const path = "/v1/auth/mfa/recovery/verify";
414
+ return this.request(
415
+ "POST",
416
+ path,
417
+ body
418
+ );
537
419
  }
538
420
  /**
539
- * Get refresh token
421
+ * Send SMS verification code
422
+ * POST /v1/auth/mfa/sms/send
540
423
  */
541
- async getRefreshToken() {
542
- return await Promise.resolve(this.storage.getItem(REFRESH_TOKEN_KEY));
424
+ async sendSMSCode(body, token) {
425
+ const path = "/v1/auth/mfa/sms/send";
426
+ return this.request(
427
+ "POST",
428
+ path,
429
+ body,
430
+ token
431
+ );
543
432
  }
544
433
  /**
545
- * Set refresh token
434
+ * Verify SMS code
435
+ * POST /v1/auth/mfa/sms/verify
546
436
  */
547
- async setRefreshToken(token) {
548
- await Promise.resolve(this.storage.setItem(REFRESH_TOKEN_KEY, token));
437
+ async verifySMSCode(body, token) {
438
+ const path = "/v1/auth/mfa/sms/verify";
439
+ return this.request(
440
+ "POST",
441
+ path,
442
+ body,
443
+ token
444
+ );
549
445
  }
550
446
  /**
551
- * Remove refresh token
447
+ * Verify MFA code
448
+ * POST /v1/auth/mfa/verify
552
449
  */
553
- async removeRefreshToken() {
554
- await Promise.resolve(this.storage.removeItem(REFRESH_TOKEN_KEY));
450
+ async verifyMFA(body) {
451
+ const path = "/v1/auth/mfa/verify";
452
+ return this.request(
453
+ "POST",
454
+ path,
455
+ body
456
+ );
555
457
  }
556
458
  /**
557
- * Clear all tokens
459
+ * List organizations
460
+ * GET /v1/auth/orgs
558
461
  */
559
- async clearTokens() {
560
- await this.removeToken();
561
- await this.removeRefreshToken();
462
+ async listOrganizations(token) {
463
+ const path = "/v1/auth/orgs";
464
+ return this.request(
465
+ "GET",
466
+ path,
467
+ void 0,
468
+ token
469
+ );
562
470
  }
563
471
  /**
564
- * Check if token is expired
472
+ * Create organization
473
+ * POST /v1/auth/orgs
565
474
  */
566
- isTokenExpired(token) {
567
- try {
568
- const payload = this.decodeToken(token);
569
- if (!payload.exp) return false;
570
- const expiresAt = payload.exp * 1e3;
571
- const now = Date.now();
572
- return expiresAt - now < 6e4;
573
- } catch {
574
- return true;
575
- }
475
+ async createOrganization(body, token) {
476
+ const path = "/v1/auth/orgs";
477
+ return this.request(
478
+ "POST",
479
+ path,
480
+ body,
481
+ token
482
+ );
576
483
  }
577
484
  /**
578
- * Decode JWT token (without verification)
485
+ * Check slug availability
486
+ * GET /v1/auth/orgs/check-slug
579
487
  */
580
- decodeToken(token) {
581
- const parts = token.split(".");
582
- if (parts.length !== 3) {
583
- throw new Error("Invalid token format");
584
- }
585
- const payload = parts[1];
586
- const decoded = atob(payload);
587
- return JSON.parse(decoded);
488
+ async checkOrgSlug(token) {
489
+ const path = "/v1/auth/orgs/check-slug";
490
+ return this.request(
491
+ "GET",
492
+ path,
493
+ void 0,
494
+ token
495
+ );
588
496
  }
589
- };
590
-
591
- // src/utils/cookies.ts
592
- function parseCookie(setCookieHeader) {
593
- if (!setCookieHeader) return null;
594
- const parts = setCookieHeader.split(";").map((p) => p.trim());
595
- if (parts.length === 0) return null;
596
- const [nameValue] = parts;
597
- const [name, value] = nameValue.split("=");
598
- if (!name || value === void 0) return null;
599
- const cookieData = { name, value };
600
- const options = {};
601
- for (let i = 1; i < parts.length; i++) {
602
- const part = parts[i];
603
- const lowerPart = part.toLowerCase();
604
- if (lowerPart === "httponly") {
605
- options.httpOnly = true;
606
- } else if (lowerPart === "secure") {
607
- options.secure = true;
608
- } else if (lowerPart.startsWith("path=")) {
609
- options.path = part.substring(5);
610
- } else if (lowerPart.startsWith("domain=")) {
611
- options.domain = part.substring(7);
612
- } else if (lowerPart.startsWith("max-age=")) {
613
- const maxAge = parseInt(part.substring(8), 10);
614
- if (!isNaN(maxAge)) {
615
- options.maxAge = maxAge;
616
- }
617
- } else if (lowerPart.startsWith("expires=")) {
618
- const expiresStr = part.substring(8);
619
- const expiresDate = new Date(expiresStr);
620
- if (!isNaN(expiresDate.getTime())) {
621
- options.expires = expiresDate;
622
- }
623
- } else if (lowerPart.startsWith("samesite=")) {
624
- const sameSiteValue = lowerPart.substring(9);
625
- if (sameSiteValue === "strict" || sameSiteValue === "lax" || sameSiteValue === "none") {
626
- options.sameSite = sameSiteValue;
627
- }
628
- }
497
+ /**
498
+ * Accept invitation
499
+ * POST /v1/auth/orgs/invitations/accept
500
+ */
501
+ async acceptInvitation(body, token) {
502
+ const path = "/v1/auth/orgs/invitations/accept";
503
+ return this.request(
504
+ "POST",
505
+ path,
506
+ body,
507
+ token
508
+ );
629
509
  }
630
- if (Object.keys(options).length > 0) {
631
- cookieData.options = options;
510
+ /**
511
+ * Decline invitation
512
+ * POST /v1/auth/orgs/invitations/decline
513
+ */
514
+ async declineInvitation(body, token) {
515
+ const path = "/v1/auth/orgs/invitations/decline";
516
+ return this.request(
517
+ "POST",
518
+ path,
519
+ body,
520
+ token
521
+ );
632
522
  }
633
- return cookieData;
634
- }
635
- function extractCookiesFromHeaders(setCookieHeaders) {
636
- const headers = Array.isArray(setCookieHeaders) ? setCookieHeaders : [setCookieHeaders];
637
- const cookies = [];
638
- for (const header of headers) {
639
- const cookie = parseCookie(header);
640
- if (cookie) {
641
- cookies.push(cookie);
642
- }
523
+ /**
524
+ * Get organization
525
+ * GET /v1/auth/orgs/{orgId}
526
+ */
527
+ async getOrganization(orgId, token) {
528
+ const path = `/v1/auth/orgs/${orgId}`;
529
+ return this.request(
530
+ "GET",
531
+ path,
532
+ void 0,
533
+ token
534
+ );
643
535
  }
644
- return cookies;
645
- }
646
- function serializeCookie(cookie) {
647
- const parts = [`${cookie.name}=${cookie.value}`];
648
- if (cookie.options) {
649
- const opts = cookie.options;
650
- if (opts.path) {
651
- parts.push(`Path=${opts.path}`);
652
- }
653
- if (opts.domain) {
654
- parts.push(`Domain=${opts.domain}`);
655
- }
656
- if (opts.expires) {
657
- parts.push(`Expires=${opts.expires.toUTCString()}`);
658
- }
659
- if (opts.maxAge !== void 0) {
660
- parts.push(`Max-Age=${opts.maxAge}`);
661
- }
662
- if (opts.httpOnly) {
663
- parts.push("HttpOnly");
664
- }
665
- if (opts.secure) {
666
- parts.push("Secure");
667
- }
668
- if (opts.sameSite) {
669
- const sameSite = opts.sameSite.charAt(0).toUpperCase() + opts.sameSite.slice(1);
670
- parts.push(`SameSite=${sameSite}`);
671
- }
536
+ /**
537
+ * Update organization
538
+ * PATCH /v1/auth/orgs/{orgId}
539
+ */
540
+ async updateOrganization(orgId, body, token) {
541
+ const path = `/v1/auth/orgs/${orgId}`;
542
+ return this.request(
543
+ "PATCH",
544
+ path,
545
+ body,
546
+ token
547
+ );
672
548
  }
673
- return parts.join("; ");
674
- }
675
- function parseCookieOptions(cookieHeader) {
676
- const cookies = {};
677
- if (!cookieHeader) return cookies;
678
- const pairs = cookieHeader.split(";").map((p) => p.trim());
679
- for (const pair of pairs) {
680
- const [name, value] = pair.split("=");
681
- if (name && value !== void 0) {
682
- cookies[name.trim()] = value.trim();
683
- }
549
+ /**
550
+ * Delete organization
551
+ * DELETE /v1/auth/orgs/{orgId}
552
+ */
553
+ async deleteOrganization(orgId, body, token) {
554
+ const path = `/v1/auth/orgs/${orgId}`;
555
+ return this.request(
556
+ "DELETE",
557
+ path,
558
+ body,
559
+ token
560
+ );
684
561
  }
685
- return cookies;
686
- }
687
- function serializeCookies(cookies) {
688
- return Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join("; ");
689
- }
690
-
691
- // src/adapters/base-provider.ts
692
- var BaseAuthProvider = class {
693
- constructor() {
694
- this.config = {};
695
- this.initialized = false;
562
+ /**
563
+ * List invitations
564
+ * GET /v1/auth/orgs/{orgId}/invitations
565
+ */
566
+ async listInvitations(orgId, token) {
567
+ const path = `/v1/auth/orgs/${orgId}/invitations`;
568
+ return this.request(
569
+ "GET",
570
+ path,
571
+ void 0,
572
+ token
573
+ );
696
574
  }
697
575
  /**
698
- * Initialize the provider
576
+ * Create invitation
577
+ * POST /v1/auth/orgs/{orgId}/invitations
699
578
  */
700
- async initialize(config) {
701
- this.config = config;
702
- this.initialized = true;
579
+ async createInvitation(orgId, body, token) {
580
+ const path = `/v1/auth/orgs/${orgId}/invitations`;
581
+ return this.request(
582
+ "POST",
583
+ path,
584
+ body,
585
+ token
586
+ );
703
587
  }
704
588
  /**
705
- * Ensure provider is initialized
589
+ * List members
590
+ * GET /v1/auth/orgs/{orgId}/members
706
591
  */
707
- ensureInitialized() {
708
- if (!this.initialized) {
709
- throw new Error(`Provider ${this.name} is not initialized`);
710
- }
592
+ async listMembers(orgId, token) {
593
+ const path = `/v1/auth/orgs/${orgId}/members`;
594
+ return this.request(
595
+ "GET",
596
+ path,
597
+ void 0,
598
+ token
599
+ );
711
600
  }
712
601
  /**
713
- * Make HTTP request
602
+ * Add member
603
+ * POST /v1/auth/orgs/{orgId}/members
714
604
  */
715
- async request(url, options = {}) {
716
- const response = await fetch(url, {
717
- ...options,
718
- headers: {
719
- "Content-Type": "application/json",
720
- ...options.headers
721
- }
722
- });
723
- if (!response.ok) {
724
- const error = await response.json().catch(() => ({
725
- message: response.statusText
726
- }));
727
- throw error;
728
- }
729
- return response.json();
605
+ async addMember(orgId, body, token) {
606
+ const path = `/v1/auth/orgs/${orgId}/members`;
607
+ return this.request(
608
+ "POST",
609
+ path,
610
+ body,
611
+ token
612
+ );
730
613
  }
731
614
  /**
732
- * Normalize error to AuthError
615
+ * Update member role
616
+ * PATCH /v1/auth/orgs/{orgId}/members/{memberId}
733
617
  */
734
- normalizeError(error) {
735
- return toAuthError(error);
618
+ async updateMember(orgId, memberId, body, token) {
619
+ const path = `/v1/auth/orgs/${orgId}/members/${memberId}`;
620
+ return this.request(
621
+ "PATCH",
622
+ path,
623
+ body,
624
+ token
625
+ );
736
626
  }
737
- };
738
-
739
- // src/client.ts
740
- var AuthClient = class {
741
- // Expose adapter for accessing provider-specific methods
742
- get adapter() {
743
- return this.provider;
627
+ /**
628
+ * Remove member
629
+ * DELETE /v1/auth/orgs/{orgId}/members/{memberId}
630
+ */
631
+ async removeMember(orgId, memberId, body, token) {
632
+ const path = `/v1/auth/orgs/${orgId}/members/${memberId}`;
633
+ return this.request(
634
+ "DELETE",
635
+ path,
636
+ body,
637
+ token
638
+ );
744
639
  }
745
- constructor(config) {
746
- this.provider = config.provider;
747
- this.autoRefresh = config.autoRefresh ?? true;
748
- this.refreshInterval = config.refreshInterval ?? 5 * 60 * 1e3;
749
- this.state = new Observable({
750
- state: "loading" /* LOADING */,
751
- user: null,
752
- session: null,
753
- error: null,
754
- isAuthenticated: false,
755
- isLoading: true
756
- });
640
+ /**
641
+ * List teams
642
+ * GET /v1/auth/orgs/{orgId}/teams
643
+ */
644
+ async listTeams(orgId, token) {
645
+ const path = `/v1/auth/orgs/${orgId}/teams`;
646
+ return this.request(
647
+ "GET",
648
+ path,
649
+ void 0,
650
+ token
651
+ );
757
652
  }
758
653
  /**
759
- * Initialize the auth client
654
+ * Create team
655
+ * POST /v1/auth/orgs/{orgId}/teams
760
656
  */
761
- async initialize() {
762
- try {
763
- const user = await this.provider.getCurrentUser();
764
- const session = await this.provider.getCurrentSession();
765
- if (user && session) {
766
- this.updateState({
767
- state: "authenticated" /* AUTHENTICATED */,
768
- user,
769
- session,
770
- error: null,
771
- isAuthenticated: true,
772
- isLoading: false
773
- });
774
- if (this.autoRefresh) {
775
- this.startAutoRefresh();
776
- }
777
- } else {
778
- this.updateState({
779
- state: "unauthenticated" /* UNAUTHENTICATED */,
780
- user: null,
781
- session: null,
782
- error: null,
783
- isAuthenticated: false,
784
- isLoading: false
785
- });
786
- }
787
- } catch (error) {
788
- this.handleError(error);
789
- }
657
+ async createTeam(orgId, body, token) {
658
+ const path = `/v1/auth/orgs/${orgId}/teams`;
659
+ return this.request(
660
+ "POST",
661
+ path,
662
+ body,
663
+ token
664
+ );
790
665
  }
791
666
  /**
792
- * Sign in with credentials
667
+ * Get team
668
+ * GET /v1/auth/orgs/{orgId}/teams/{teamId}
793
669
  */
794
- async signIn(request) {
795
- try {
796
- this.setLoading();
797
- const response = await this.provider.signIn(request);
798
- if (response.requiresTwoFactor) {
799
- this.updateState({
800
- state: "unauthenticated" /* UNAUTHENTICATED */,
801
- user: response.user,
802
- session: null,
803
- error: null,
804
- isAuthenticated: false,
805
- isLoading: false
806
- });
807
- return;
808
- }
809
- this.updateState({
810
- state: "authenticated" /* AUTHENTICATED */,
811
- user: response.user,
812
- session: response.session,
813
- error: null,
814
- isAuthenticated: true,
815
- isLoading: false
816
- });
817
- if (this.autoRefresh) {
818
- this.startAutoRefresh();
819
- }
820
- } catch (error) {
821
- this.handleError(error);
822
- }
670
+ async getTeam(orgId, teamId, token) {
671
+ const path = `/v1/auth/orgs/${orgId}/teams/${teamId}`;
672
+ return this.request(
673
+ "GET",
674
+ path,
675
+ void 0,
676
+ token
677
+ );
823
678
  }
824
679
  /**
825
- * Sign up with credentials
680
+ * Update team
681
+ * PATCH /v1/auth/orgs/{orgId}/teams/{teamId}
826
682
  */
827
- async signUp(request) {
828
- try {
829
- this.setLoading();
830
- const response = await this.provider.signUp(request);
831
- this.updateState({
832
- state: "authenticated" /* AUTHENTICATED */,
833
- user: response.user,
834
- session: response.session,
835
- error: null,
836
- isAuthenticated: true,
837
- isLoading: false
838
- });
839
- if (this.autoRefresh) {
840
- this.startAutoRefresh();
841
- }
842
- } catch (error) {
843
- this.handleError(error);
844
- }
683
+ async updateTeam(orgId, teamId, body, token) {
684
+ const path = `/v1/auth/orgs/${orgId}/teams/${teamId}`;
685
+ return this.request(
686
+ "PATCH",
687
+ path,
688
+ body,
689
+ token
690
+ );
845
691
  }
846
692
  /**
847
- * Sign out
693
+ * Delete team
694
+ * DELETE /v1/auth/orgs/{orgId}/teams/{teamId}
848
695
  */
849
- async signOut() {
850
- try {
851
- this.stopAutoRefresh();
852
- await this.provider.signOut();
853
- this.updateState({
854
- state: "unauthenticated" /* UNAUTHENTICATED */,
855
- user: null,
856
- session: null,
857
- error: null,
858
- isAuthenticated: false,
859
- isLoading: false
860
- });
861
- } catch (error) {
862
- this.handleError(error);
863
- }
696
+ async deleteTeam(orgId, teamId, body, token) {
697
+ const path = `/v1/auth/orgs/${orgId}/teams/${teamId}`;
698
+ return this.request(
699
+ "DELETE",
700
+ path,
701
+ body,
702
+ token
703
+ );
864
704
  }
865
705
  /**
866
- * Update user profile
706
+ * List passkeys
707
+ * GET /v1/auth/passkeys/
708
+ */
709
+ async listPasskeys(token) {
710
+ const path = "/v1/auth/passkeys/";
711
+ return this.request(
712
+ "GET",
713
+ path,
714
+ void 0,
715
+ token
716
+ );
717
+ }
718
+ /**
719
+ * Begin passkey login
720
+ * POST /v1/auth/passkeys/login/begin
867
721
  */
868
- async updateUser(request) {
869
- try {
870
- const user = await this.provider.updateUser(request);
871
- const currentState = this.state.getValue();
872
- this.updateState({
873
- ...currentState,
874
- user
875
- });
876
- } catch (error) {
877
- this.handleError(error);
878
- }
722
+ async passkeyLoginBegin(body) {
723
+ const path = "/v1/auth/passkeys/login/begin";
724
+ return this.request(
725
+ "POST",
726
+ path,
727
+ body
728
+ );
879
729
  }
880
730
  /**
881
- * Change password
731
+ * Complete passkey login
732
+ * POST /v1/auth/passkeys/login/finish
882
733
  */
883
- async changePassword(request) {
884
- try {
885
- await this.provider.changePassword(request);
886
- } catch (error) {
887
- throw this.provider.normalizeError(error);
888
- }
734
+ async passkeyLoginFinish(body) {
735
+ const path = "/v1/auth/passkeys/login/finish";
736
+ return this.request(
737
+ "POST",
738
+ path,
739
+ body
740
+ );
889
741
  }
890
742
  /**
891
- * Request password reset
743
+ * Begin passkey registration
744
+ * POST /v1/auth/passkeys/register/begin
892
745
  */
893
- async requestPasswordReset(request) {
894
- try {
895
- await this.provider.requestPasswordReset(request);
896
- } catch (error) {
897
- throw this.provider.normalizeError(error);
898
- }
746
+ async passkeyRegisterBegin(body, token) {
747
+ const path = "/v1/auth/passkeys/register/begin";
748
+ return this.request(
749
+ "POST",
750
+ path,
751
+ body,
752
+ token
753
+ );
899
754
  }
900
755
  /**
901
- * Confirm password reset
756
+ * Complete passkey registration
757
+ * POST /v1/auth/passkeys/register/finish
902
758
  */
903
- async confirmPasswordReset(request) {
904
- try {
905
- await this.provider.confirmPasswordReset(request);
906
- } catch (error) {
907
- throw this.provider.normalizeError(error);
908
- }
759
+ async passkeyRegisterFinish(body, token) {
760
+ const path = "/v1/auth/passkeys/register/finish";
761
+ return this.request(
762
+ "POST",
763
+ path,
764
+ body,
765
+ token
766
+ );
909
767
  }
910
768
  /**
911
- * Get OAuth sign in URL
769
+ * Delete passkey
770
+ * DELETE /v1/auth/passkeys/{credentialId}
771
+ */
772
+ async deletePasskey(credentialId, body, token) {
773
+ const path = `/v1/auth/passkeys/${credentialId}`;
774
+ return this.request(
775
+ "DELETE",
776
+ path,
777
+ body,
778
+ token
779
+ );
780
+ }
781
+ /**
782
+ * Refresh tokens
783
+ * POST /v1/auth/refresh
912
784
  */
913
- async getOAuthUrl(request) {
914
- return this.provider.oauthSignIn(request);
785
+ async refresh(body) {
786
+ const path = "/v1/auth/refresh";
787
+ return this.request(
788
+ "POST",
789
+ path,
790
+ body
791
+ );
915
792
  }
916
793
  /**
917
- * Handle OAuth callback
794
+ * Reset password
795
+ * POST /v1/auth/reset-password
918
796
  */
919
- async handleOAuthCallback(request) {
920
- try {
921
- this.setLoading();
922
- const response = await this.provider.oauthCallback(request);
923
- this.updateState({
924
- state: "authenticated" /* AUTHENTICATED */,
925
- user: response.user,
926
- session: response.session,
927
- error: null,
928
- isAuthenticated: true,
929
- isLoading: false
930
- });
931
- if (this.autoRefresh) {
932
- this.startAutoRefresh();
933
- }
934
- } catch (error) {
935
- this.handleError(error);
936
- }
797
+ async resetPassword(body) {
798
+ const path = "/v1/auth/reset-password";
799
+ return this.request(
800
+ "POST",
801
+ path,
802
+ body
803
+ );
937
804
  }
938
805
  /**
939
- * Get available OAuth providers
806
+ * List roles
807
+ * GET /v1/auth/roles
940
808
  */
941
- async getOAuthProviders() {
942
- return this.provider.getOAuthProviders();
809
+ async listRoles(token) {
810
+ const path = "/v1/auth/roles";
811
+ return this.request(
812
+ "GET",
813
+ path,
814
+ void 0,
815
+ token
816
+ );
943
817
  }
944
818
  /**
945
- * Send magic link
819
+ * Create role
820
+ * POST /v1/auth/roles
946
821
  */
947
- async sendMagicLink(request) {
948
- try {
949
- await this.provider.sendMagicLink(request);
950
- } catch (error) {
951
- throw this.provider.normalizeError(error);
952
- }
822
+ async createRole(body, token) {
823
+ const path = "/v1/auth/roles";
824
+ return this.request(
825
+ "POST",
826
+ path,
827
+ body,
828
+ token
829
+ );
953
830
  }
954
831
  /**
955
- * Verify magic link
832
+ * Get role
833
+ * GET /v1/auth/roles/{roleId}
956
834
  */
957
- async verifyMagicLink(request) {
958
- try {
959
- this.setLoading();
960
- const response = await this.provider.verifyMagicLink(request);
961
- this.updateState({
962
- state: "authenticated" /* AUTHENTICATED */,
963
- user: response.user,
964
- session: response.session,
965
- error: null,
966
- isAuthenticated: true,
967
- isLoading: false
968
- });
969
- if (this.autoRefresh) {
970
- this.startAutoRefresh();
971
- }
972
- } catch (error) {
973
- this.handleError(error);
974
- }
835
+ async getRole(roleId, token) {
836
+ const path = `/v1/auth/roles/${roleId}`;
837
+ return this.request(
838
+ "GET",
839
+ path,
840
+ void 0,
841
+ token
842
+ );
975
843
  }
976
844
  /**
977
- * Send phone verification code
845
+ * Update role
846
+ * PATCH /v1/auth/roles/{roleId}
978
847
  */
979
- async sendPhoneCode(request) {
980
- try {
981
- await this.provider.sendPhoneCode(request);
982
- } catch (error) {
983
- throw this.provider.normalizeError(error);
984
- }
848
+ async updateRole(roleId, body, token) {
849
+ const path = `/v1/auth/roles/${roleId}`;
850
+ return this.request(
851
+ "PATCH",
852
+ path,
853
+ body,
854
+ token
855
+ );
985
856
  }
986
857
  /**
987
- * Verify phone code
858
+ * Delete role
859
+ * DELETE /v1/auth/roles/{roleId}
988
860
  */
989
- async verifyPhoneCode(request) {
990
- try {
991
- this.setLoading();
992
- const response = await this.provider.verifyPhoneCode(request);
993
- this.updateState({
994
- state: "authenticated" /* AUTHENTICATED */,
995
- user: response.user,
996
- session: response.session,
997
- error: null,
998
- isAuthenticated: true,
999
- isLoading: false
1000
- });
1001
- if (this.autoRefresh) {
1002
- this.startAutoRefresh();
1003
- }
1004
- } catch (error) {
1005
- this.handleError(error);
1006
- }
861
+ async deleteRole(roleId, body, token) {
862
+ const path = `/v1/auth/roles/${roleId}`;
863
+ return this.request(
864
+ "DELETE",
865
+ path,
866
+ body,
867
+ token
868
+ );
1007
869
  }
1008
870
  /**
1009
- * Setup 2FA
871
+ * Assign role to user
872
+ * POST /v1/auth/roles/{roleId}/assign
1010
873
  */
1011
- async setupTwoFactor(request) {
1012
- return this.provider.setupTwoFactor(request);
874
+ async assignRole(roleId, body, token) {
875
+ const path = `/v1/auth/roles/${roleId}/assign`;
876
+ return this.request(
877
+ "POST",
878
+ path,
879
+ body,
880
+ token
881
+ );
1013
882
  }
1014
883
  /**
1015
- * Verify 2FA code
884
+ * List role permissions
885
+ * GET /v1/auth/roles/{roleId}/permissions
1016
886
  */
1017
- async verifyTwoFactor(request) {
1018
- try {
1019
- this.setLoading();
1020
- const response = await this.provider.verifyTwoFactor(request);
1021
- this.updateState({
1022
- state: "authenticated" /* AUTHENTICATED */,
1023
- user: response.user,
1024
- session: response.session,
1025
- error: null,
1026
- isAuthenticated: true,
1027
- isLoading: false
1028
- });
1029
- if (this.autoRefresh) {
1030
- this.startAutoRefresh();
1031
- }
1032
- } catch (error) {
1033
- this.handleError(error);
1034
- }
887
+ async listRolePermissions(roleId, token) {
888
+ const path = `/v1/auth/roles/${roleId}/permissions`;
889
+ return this.request(
890
+ "GET",
891
+ path,
892
+ void 0,
893
+ token
894
+ );
1035
895
  }
1036
896
  /**
1037
- * Disable 2FA
897
+ * Add permission to role
898
+ * POST /v1/auth/roles/{roleId}/permissions
1038
899
  */
1039
- async disableTwoFactor() {
1040
- return this.provider.disableTwoFactor();
900
+ async addPermission(roleId, body, token) {
901
+ const path = `/v1/auth/roles/${roleId}/permissions`;
902
+ return this.request(
903
+ "POST",
904
+ path,
905
+ body,
906
+ token
907
+ );
1041
908
  }
1042
909
  /**
1043
- * Get 2FA status
910
+ * Remove permission from role
911
+ * DELETE /v1/auth/roles/{roleId}/permissions/{permissionId}
1044
912
  */
1045
- async getTwoFactorStatus() {
1046
- return this.provider.getTwoFactorStatus();
913
+ async removePermission(roleId, permissionId, body, token) {
914
+ const path = `/v1/auth/roles/${roleId}/permissions/${permissionId}`;
915
+ return this.request(
916
+ "DELETE",
917
+ path,
918
+ body,
919
+ token
920
+ );
1047
921
  }
1048
922
  /**
1049
- * Register passkey
923
+ * Unassign role from user
924
+ * POST /v1/auth/roles/{roleId}/unassign
1050
925
  */
1051
- async registerPasskey(request) {
1052
- return this.provider.registerPasskey(request);
926
+ async unassignRole(roleId, body, token) {
927
+ const path = `/v1/auth/roles/${roleId}/unassign`;
928
+ return this.request(
929
+ "POST",
930
+ path,
931
+ body,
932
+ token
933
+ );
1053
934
  }
1054
935
  /**
1055
- * Authenticate with passkey
936
+ * List sessions
937
+ * GET /v1/auth/sessions
1056
938
  */
1057
- async authenticatePasskey(request) {
1058
- try {
1059
- this.setLoading();
1060
- const response = await this.provider.authenticatePasskey(request);
1061
- this.updateState({
1062
- state: "authenticated" /* AUTHENTICATED */,
1063
- user: response.user,
1064
- session: response.session,
1065
- error: null,
1066
- isAuthenticated: true,
1067
- isLoading: false
1068
- });
1069
- if (this.autoRefresh) {
1070
- this.startAutoRefresh();
1071
- }
1072
- } catch (error) {
1073
- this.handleError(error);
1074
- }
939
+ async listSessions(token) {
940
+ const path = "/v1/auth/sessions";
941
+ return this.request(
942
+ "GET",
943
+ path,
944
+ void 0,
945
+ token
946
+ );
1075
947
  }
1076
948
  /**
1077
- * List passkeys
949
+ * Revoke session
950
+ * DELETE /v1/auth/sessions/{sessionId}
1078
951
  */
1079
- async listPasskeys() {
1080
- return this.provider.listPasskeys();
952
+ async revokeSession(sessionId, body, token) {
953
+ const path = `/v1/auth/sessions/${sessionId}`;
954
+ return this.request(
955
+ "DELETE",
956
+ path,
957
+ body,
958
+ token
959
+ );
1081
960
  }
1082
961
  /**
1083
- * Delete passkey
962
+ * Sign in
963
+ * POST /v1/auth/signin
1084
964
  */
1085
- async deletePasskey(credentialId) {
1086
- return this.provider.deletePasskey(credentialId);
965
+ async signIn(body) {
966
+ const path = "/v1/auth/signin";
967
+ return this.request(
968
+ "POST",
969
+ path,
970
+ body
971
+ );
1087
972
  }
1088
973
  /**
1089
- * Get all organizations the user belongs to
1090
- * Only available if the provider supports organizations
974
+ * Sign out
975
+ * POST /v1/auth/signout
976
+ */
977
+ async signOut(body, token) {
978
+ const path = "/v1/auth/signout";
979
+ return this.request(
980
+ "POST",
981
+ path,
982
+ body,
983
+ token
984
+ );
985
+ }
986
+ /**
987
+ * Sign up
988
+ * POST /v1/auth/signup
1091
989
  */
1092
- async getOrganizations() {
1093
- if (!this.provider.getOrganizations) {
1094
- throw this.createUnsupportedError("Organization support");
1095
- }
1096
- return this.provider.getOrganizations();
990
+ async signUp(body) {
991
+ const path = "/v1/auth/signup";
992
+ return this.request(
993
+ "POST",
994
+ path,
995
+ body
996
+ );
1097
997
  }
1098
998
  /**
1099
- * Get the currently active organization
1100
- * Only available if the provider supports organizations
999
+ * Start OAuth flow
1000
+ * POST /v1/auth/social/{provider}
1101
1001
  */
1102
- async getActiveOrganization() {
1103
- if (!this.provider.getActiveOrganization) {
1104
- throw this.createUnsupportedError("Organization support");
1105
- }
1106
- return this.provider.getActiveOrganization();
1002
+ async startOAuth(provider, body) {
1003
+ const path = `/v1/auth/social/${provider}`;
1004
+ return this.request(
1005
+ "POST",
1006
+ path,
1007
+ body
1008
+ );
1107
1009
  }
1108
1010
  /**
1109
- * Set the active organization and refresh user state
1110
- * Only available if the provider supports organizations
1011
+ * OAuth callback
1012
+ * GET /v1/auth/social/{provider}/callback
1111
1013
  */
1112
- async setActiveOrganization(organizationId) {
1113
- if (!this.provider.setActiveOrganization) {
1114
- throw this.createUnsupportedError("Organization support");
1115
- }
1116
- await this.provider.setActiveOrganization(organizationId);
1117
- await this.refreshSession();
1014
+ async oauthCallback(provider) {
1015
+ const path = `/v1/auth/social/${provider}/callback`;
1016
+ return this.request(
1017
+ "GET",
1018
+ path,
1019
+ void 0
1020
+ );
1118
1021
  }
1119
1022
  /**
1120
- * Get organization memberships with roles and permissions
1121
- * Only available if the provider supports organizations
1023
+ * SSO SAML ACS endpoint
1024
+ * POST /v1/auth/sso/{provider}/acs
1122
1025
  */
1123
- async getOrganizationMemberships() {
1124
- if (!this.provider.getOrganizationMemberships) {
1125
- throw this.createUnsupportedError("Organization memberships");
1126
- }
1127
- return this.provider.getOrganizationMemberships();
1026
+ async ssoACS(provider, body) {
1027
+ const path = `/v1/auth/sso/${provider}/acs`;
1028
+ return this.request(
1029
+ "POST",
1030
+ path,
1031
+ body
1032
+ );
1128
1033
  }
1129
1034
  /**
1130
- * Check if the provider supports organizations
1035
+ * SSO callback (OIDC)
1036
+ * POST /v1/auth/sso/{provider}/callback
1131
1037
  */
1132
- supportsOrganizations() {
1133
- return !!(this.provider.getOrganizations && this.provider.getActiveOrganization && this.provider.setActiveOrganization);
1038
+ async ssoCallback(provider, body) {
1039
+ const path = `/v1/auth/sso/${provider}/callback`;
1040
+ return this.request(
1041
+ "POST",
1042
+ path,
1043
+ body
1044
+ );
1134
1045
  }
1135
1046
  /**
1136
- * Refresh session
1047
+ * Start SSO login flow
1048
+ * POST /v1/auth/sso/{provider}/login
1137
1049
  */
1138
- async refreshSession() {
1139
- try {
1140
- const session = await this.provider.refreshSession();
1141
- const currentState = this.state.getValue();
1142
- this.updateState({
1143
- ...currentState,
1144
- session
1145
- });
1146
- } catch (error) {
1147
- console.warn("[AuthClient] Session refresh failed:", error);
1148
- }
1050
+ async startSSOLogin(provider, body) {
1051
+ const path = `/v1/auth/sso/${provider}/login`;
1052
+ return this.request(
1053
+ "POST",
1054
+ path,
1055
+ body
1056
+ );
1149
1057
  }
1150
1058
  /**
1151
- * Get current user
1059
+ * List user roles
1060
+ * GET /v1/auth/users/{userId}/roles
1152
1061
  */
1153
- getUser() {
1154
- return this.state.getValue().user;
1062
+ async listUserRoles(userId, token) {
1063
+ const path = `/v1/auth/users/${userId}/roles`;
1064
+ return this.request(
1065
+ "GET",
1066
+ path,
1067
+ void 0,
1068
+ token
1069
+ );
1155
1070
  }
1156
1071
  /**
1157
- * Get current session
1072
+ * Verify email
1073
+ * POST /v1/auth/verify-email
1158
1074
  */
1159
- getSession() {
1160
- return this.state.getValue().session;
1075
+ async verifyEmail(body) {
1076
+ const path = "/v1/auth/verify-email";
1077
+ return this.request(
1078
+ "POST",
1079
+ path,
1080
+ body
1081
+ );
1161
1082
  }
1162
1083
  /**
1163
- * Check if authenticated
1084
+ * List webhooks
1085
+ * GET /v1/auth/webhooks
1164
1086
  */
1165
- isAuthenticated() {
1166
- return this.state.getValue().isAuthenticated;
1087
+ async listWebhooks(token) {
1088
+ const path = "/v1/auth/webhooks";
1089
+ return this.request(
1090
+ "GET",
1091
+ path,
1092
+ void 0,
1093
+ token
1094
+ );
1167
1095
  }
1168
1096
  /**
1169
- * Get current error
1097
+ * Create webhook
1098
+ * POST /v1/auth/webhooks
1170
1099
  */
1171
- getError() {
1172
- return this.state.getValue().error;
1100
+ async createWebhook(body, token) {
1101
+ const path = "/v1/auth/webhooks";
1102
+ return this.request(
1103
+ "POST",
1104
+ path,
1105
+ body,
1106
+ token
1107
+ );
1173
1108
  }
1174
1109
  /**
1175
- * Clear error
1110
+ * Get webhook
1111
+ * GET /v1/auth/webhooks/{webhookId}
1176
1112
  */
1177
- clearError() {
1178
- const currentState = this.state.getValue();
1179
- this.updateState({
1180
- ...currentState,
1181
- error: null
1182
- });
1113
+ async getWebhook(webhookId, token) {
1114
+ const path = `/v1/auth/webhooks/${webhookId}`;
1115
+ return this.request(
1116
+ "GET",
1117
+ path,
1118
+ void 0,
1119
+ token
1120
+ );
1183
1121
  }
1184
1122
  /**
1185
- * Subscribe to auth state changes
1123
+ * Update webhook
1124
+ * PATCH /v1/auth/webhooks/{webhookId}
1186
1125
  */
1187
- subscribe(listener) {
1188
- return this.state.subscribe(listener);
1126
+ async updateWebhook(webhookId, body, token) {
1127
+ const path = `/v1/auth/webhooks/${webhookId}`;
1128
+ return this.request(
1129
+ "PATCH",
1130
+ path,
1131
+ body,
1132
+ token
1133
+ );
1189
1134
  }
1190
1135
  /**
1191
- * Cleanup resources
1136
+ * Delete webhook
1137
+ * DELETE /v1/auth/webhooks/{webhookId}
1192
1138
  */
1193
- destroy() {
1194
- this.stopAutoRefresh();
1195
- this.state.clearListeners();
1196
- }
1197
- // Private methods
1198
- updateState(newState) {
1199
- this.state.setValue(newState);
1200
- }
1201
- setLoading() {
1202
- const currentState = this.state.getValue();
1203
- this.updateState({
1204
- ...currentState,
1205
- state: "loading" /* LOADING */,
1206
- isLoading: true,
1207
- error: null
1208
- });
1139
+ async deleteWebhook(webhookId, body, token) {
1140
+ const path = `/v1/auth/webhooks/${webhookId}`;
1141
+ return this.request(
1142
+ "DELETE",
1143
+ path,
1144
+ body,
1145
+ token
1146
+ );
1209
1147
  }
1210
- handleError(error) {
1211
- const authError = this.provider.normalizeError(error);
1212
- const currentState = this.state.getValue();
1213
- this.updateState({
1214
- ...currentState,
1215
- state: "error" /* ERROR */,
1216
- error: authError,
1217
- isLoading: false
1148
+ // ──────────────────────────────────────────────────
1149
+ // Internal request helper
1150
+ // ──────────────────────────────────────────────────
1151
+ async request(method, path, body, token) {
1152
+ const headers = {
1153
+ "Content-Type": "application/json",
1154
+ "Accept": "application/json"
1155
+ };
1156
+ if (token) {
1157
+ headers["Authorization"] = `Bearer ${token}`;
1158
+ }
1159
+ const response = await this.fetchFn(`${this.baseURL}${path}`, {
1160
+ method,
1161
+ headers,
1162
+ body: body !== void 0 ? JSON.stringify(body) : void 0
1218
1163
  });
1219
- throw authError;
1220
- }
1221
- startAutoRefresh() {
1222
- this.stopAutoRefresh();
1223
- this.refreshTimer = setInterval(() => {
1224
- this.refreshSession();
1225
- }, this.refreshInterval);
1226
- }
1227
- stopAutoRefresh() {
1228
- if (this.refreshTimer) {
1229
- clearInterval(this.refreshTimer);
1230
- this.refreshTimer = void 0;
1164
+ if (!response.ok) {
1165
+ let apiError;
1166
+ try {
1167
+ apiError = await response.json();
1168
+ } catch {
1169
+ }
1170
+ throw new AuthClientError(
1171
+ apiError?.error ?? `Request failed with status ${response.status}`,
1172
+ apiError?.code ?? response.status
1173
+ );
1231
1174
  }
1175
+ if (response.status === 204) {
1176
+ return void 0;
1177
+ }
1178
+ return response.json();
1232
1179
  }
1233
- createUnsupportedError(feature) {
1234
- return {
1235
- name: "AuthError",
1236
- message: `${feature} is not available with this auth provider`,
1237
- type: "unknown_error" /* UNKNOWN_ERROR */
1238
- };
1180
+ };
1181
+ var AuthClientError = class extends Error {
1182
+ code;
1183
+ constructor(message, code) {
1184
+ super(message);
1185
+ this.name = "AuthClientError";
1186
+ this.code = code;
1239
1187
  }
1240
1188
  };
1241
1189
 
1242
- // src/flows/types.ts
1243
- var FlowStep = /* @__PURE__ */ ((FlowStep2) => {
1244
- FlowStep2["SIGN_IN"] = "sign_in";
1245
- FlowStep2["SIGN_UP"] = "sign_up";
1246
- FlowStep2["EMAIL_PASSWORD_SIGN_IN"] = "email_password_sign_in";
1247
- FlowStep2["EMAIL_PASSWORD_SIGN_UP"] = "email_password_sign_up";
1248
- FlowStep2["OAUTH_SELECT"] = "oauth_select";
1249
- FlowStep2["OAUTH_CALLBACK"] = "oauth_callback";
1250
- FlowStep2["MAGIC_LINK_REQUEST"] = "magic_link_request";
1251
- FlowStep2["MAGIC_LINK_VERIFY"] = "magic_link_verify";
1252
- FlowStep2["MAGIC_LINK_SENT"] = "magic_link_sent";
1253
- FlowStep2["PHONE_REQUEST"] = "phone_request";
1254
- FlowStep2["PHONE_VERIFY"] = "phone_verify";
1255
- FlowStep2["USERNAME_SIGN_IN"] = "username_sign_in";
1256
- FlowStep2["USERNAME_SIGN_UP"] = "username_sign_up";
1257
- FlowStep2["PASSKEY_REGISTER"] = "passkey_register";
1258
- FlowStep2["PASSKEY_AUTHENTICATE"] = "passkey_authenticate";
1259
- FlowStep2["MFA_REQUIRED"] = "mfa_required";
1260
- FlowStep2["MFA_SETUP"] = "mfa_setup";
1261
- FlowStep2["MFA_VERIFY"] = "mfa_verify";
1262
- FlowStep2["MFA_SELECT_METHOD"] = "mfa_select_method";
1263
- FlowStep2["EMAIL_VERIFICATION_REQUIRED"] = "email_verification_required";
1264
- FlowStep2["EMAIL_VERIFICATION_SENT"] = "email_verification_sent";
1265
- FlowStep2["PHONE_VERIFICATION_REQUIRED"] = "phone_verification_required";
1266
- FlowStep2["PASSWORD_RESET_REQUEST"] = "password_reset_request";
1267
- FlowStep2["PASSWORD_RESET_SENT"] = "password_reset_sent";
1268
- FlowStep2["PASSWORD_RESET_CONFIRM"] = "password_reset_confirm";
1269
- FlowStep2["PASSWORD_CHANGE"] = "password_change";
1270
- FlowStep2["PROFILE_UPDATE"] = "profile_update";
1271
- FlowStep2["PROFILE_COMPLETE"] = "profile_complete";
1272
- FlowStep2["DEVICE_FLOW_INITIATE"] = "device_flow_initiate";
1273
- FlowStep2["DEVICE_CODE_ENTRY"] = "device_code_entry";
1274
- FlowStep2["DEVICE_CODE_VERIFY"] = "device_code_verify";
1275
- FlowStep2["DEVICE_AUTHORIZE"] = "device_authorize";
1276
- FlowStep2["DEVICE_POLLING"] = "device_polling";
1277
- FlowStep2["DEVICE_AUTHORIZED"] = "device_authorized";
1278
- FlowStep2["DEVICE_DENIED"] = "device_denied";
1279
- FlowStep2["SUCCESS"] = "success";
1280
- FlowStep2["ERROR"] = "error";
1281
- FlowStep2["CANCELLED"] = "cancelled";
1282
- return FlowStep2;
1283
- })(FlowStep || {});
1284
- var FlowConfigType = /* @__PURE__ */ ((FlowConfigType2) => {
1285
- FlowConfigType2["SIMPLE_SIGN_IN"] = "simple_sign_in";
1286
- FlowConfigType2["SIMPLE_SIGN_UP"] = "simple_sign_up";
1287
- FlowConfigType2["SIGN_UP_WITH_EMAIL_VERIFICATION"] = "sign_up_with_email_verification";
1288
- FlowConfigType2["SIGN_IN_WITH_MFA"] = "sign_in_with_mfa";
1289
- FlowConfigType2["OAUTH_SIGN_IN"] = "oauth_sign_in";
1290
- FlowConfigType2["MAGIC_LINK_FLOW"] = "magic_link_flow";
1291
- FlowConfigType2["PHONE_AUTH_FLOW"] = "phone_auth_flow";
1292
- FlowConfigType2["COMPLETE_SIGN_UP_FLOW"] = "complete_sign_up_flow";
1293
- FlowConfigType2["SECURE_SIGN_IN_FLOW"] = "secure_sign_in_flow";
1294
- FlowConfigType2["PASSWORD_RESET_FLOW"] = "password_reset_flow";
1295
- FlowConfigType2["EMAIL_VERIFICATION_FLOW"] = "email_verification_flow";
1296
- FlowConfigType2["DEVICE_FLOW"] = "device_flow";
1297
- FlowConfigType2["CUSTOM"] = "custom";
1298
- return FlowConfigType2;
1299
- })(FlowConfigType || {});
1300
- var FlowAction = /* @__PURE__ */ ((FlowAction2) => {
1301
- FlowAction2["START"] = "start";
1302
- FlowAction2["NEXT"] = "next";
1303
- FlowAction2["BACK"] = "back";
1304
- FlowAction2["CANCEL"] = "cancel";
1305
- FlowAction2["ERROR"] = "error";
1306
- FlowAction2["RESET"] = "reset";
1307
- return FlowAction2;
1308
- })(FlowAction || {});
1309
-
1310
- // src/flows/engine.ts
1311
- var FlowEngine = class {
1312
- constructor(config, initialState) {
1313
- this.history = [];
1314
- this.config = config;
1315
- this.state = {
1316
- currentStep: config.initialStep,
1317
- ...initialState
1318
- };
1319
- this.history.push(this.state.currentStep);
1190
+ // src/client.ts
1191
+ var AuthClient2 = class extends AuthClient {
1192
+ /**
1193
+ * Refresh session tokens.
1194
+ *
1195
+ * Accepts a raw refresh-token string (used by auth.ts) or the full
1196
+ * RefreshRequest body.
1197
+ */
1198
+ async refresh(body) {
1199
+ const req = typeof body === "string" ? { refresh_token: body } : body;
1200
+ return super.refresh(req);
1320
1201
  }
1321
1202
  /**
1322
- * Get current flow state
1203
+ * Sign out.
1204
+ *
1205
+ * Accepts a raw token string (used by auth.ts) or the full
1206
+ * (body, token) pair from the generated client.
1323
1207
  */
1324
- getState() {
1325
- return { ...this.state };
1208
+ async signOut(bodyOrToken, token) {
1209
+ if (typeof bodyOrToken === "string") {
1210
+ return super.signOut({}, bodyOrToken);
1211
+ }
1212
+ return super.signOut(bodyOrToken, token);
1326
1213
  }
1327
1214
  /**
1328
- * Get current step
1215
+ * MFA challenge — bridge for auth.ts.
1216
+ *
1217
+ * auth.ts calls `mfaChallenge({ enrollment_id, code })` and expects
1218
+ * an AuthResponse back. The generated client uses `challengeMFA`.
1329
1219
  */
1330
- getCurrentStep() {
1331
- return this.state.currentStep;
1220
+ async mfaChallenge(body) {
1221
+ return super.challengeMFA(body);
1332
1222
  }
1333
1223
  /**
1334
- * Check if step is allowed in this flow
1224
+ * Verify an MFA recovery code.
1225
+ *
1226
+ * Accepts a raw code string (used by auth.ts) or the full request body.
1335
1227
  */
1336
- isStepAllowed(step) {
1337
- return this.config.allowedSteps.includes(step);
1228
+ async verifyRecoveryCode(body) {
1229
+ const req = typeof body === "string" ? { code: body } : body;
1230
+ return super.verifyRecoveryCode(req);
1338
1231
  }
1339
1232
  /**
1340
- * Transition to next step based on action
1233
+ * Send an SMS code for MFA — bridge for auth.ts.
1234
+ *
1235
+ * Simplifies the call-site by accepting just the session token.
1341
1236
  */
1342
- async transition(event) {
1343
- const { action, data, error } = event;
1344
- switch (action) {
1345
- case "start":
1346
- return this.handleStart(data);
1347
- case "next":
1348
- return this.handleNext(data);
1349
- case "back":
1350
- return this.handleBack();
1351
- case "cancel":
1352
- return this.handleCancel();
1353
- case "error":
1354
- return this.handleError(error);
1355
- case "reset":
1356
- return this.handleReset();
1357
- default:
1358
- throw new AuthError(
1359
- `Unknown flow action: ${action}`,
1360
- "validation_error" /* VALIDATION_ERROR */
1361
- );
1362
- }
1237
+ async sendSMSCodeForMFA(token) {
1238
+ return super.sendSMSCode({}, token);
1363
1239
  }
1364
1240
  /**
1365
- * Start or restart the flow
1241
+ * Verify an SMS code for MFA — bridge for auth.ts.
1242
+ *
1243
+ * Simplifies the call-site by accepting code + token directly.
1366
1244
  */
1367
- handleStart(data) {
1368
- this.state = {
1369
- currentStep: this.config.initialStep,
1370
- ...data
1371
- };
1372
- this.history = [this.state.currentStep];
1373
- if (this.config.onStepChange) {
1374
- this.config.onStepChange(this.state.currentStep, this.state);
1375
- }
1376
- return this.getState();
1245
+ async verifySMSCodeForMFA(code, token) {
1246
+ return super.verifySMSCode({ code }, token);
1377
1247
  }
1378
1248
  /**
1379
- * Move to next step
1249
+ * Fetch the client configuration from the backend.
1250
+ *
1251
+ * The config describes which auth methods are enabled so SDK
1252
+ * components can auto-configure without manual props.
1380
1253
  */
1381
- handleNext(data) {
1382
- this.state = {
1383
- ...this.state,
1384
- ...data,
1385
- previousStep: this.state.currentStep
1386
- };
1387
- const transitionConfig = this.config.transitions[this.state.currentStep];
1388
- if (!transitionConfig) {
1389
- throw new AuthError(
1390
- `No transition configured for step: ${this.state.currentStep}`,
1391
- "validation_error" /* VALIDATION_ERROR */
1392
- );
1254
+ async fetchClientConfig(publishableKey) {
1255
+ const url = new URL("/v1/auth/client-config", this.config.baseURL);
1256
+ if (publishableKey) {
1257
+ url.searchParams.set("key", publishableKey);
1393
1258
  }
1394
- if (transitionConfig.conditions) {
1395
- for (const condition of transitionConfig.conditions) {
1396
- if (condition.when(this.state)) {
1397
- return this.moveToStep(condition.then);
1398
- }
1399
- }
1259
+ const fetchFn = this.config.fetch ?? globalThis.fetch;
1260
+ const res = await fetchFn(url.toString(), {
1261
+ method: "GET",
1262
+ headers: { "Content-Type": "application/json" }
1263
+ });
1264
+ if (!res.ok) {
1265
+ throw new AuthClientError("Failed to fetch client config", res.status);
1266
+ }
1267
+ return res.json();
1268
+ }
1269
+ };
1270
+
1271
+ // src/auth.ts
1272
+ var SESSION_KEY = "authsome:session";
1273
+ var CONFIG_KEY = "authsome:client_config";
1274
+ var REFRESH_BEFORE_MS = 6e4;
1275
+ var CONFIG_TTL_MS = 5 * 6e4;
1276
+ var memoryStorage = /* @__PURE__ */ (() => {
1277
+ const store = /* @__PURE__ */ new Map();
1278
+ return {
1279
+ getItem: (key) => store.get(key) ?? null,
1280
+ setItem: (key, value) => {
1281
+ store.set(key, value);
1282
+ },
1283
+ removeItem: (key) => {
1284
+ store.delete(key);
1400
1285
  }
1401
- if (transitionConfig.onSuccess) {
1402
- return this.moveToStep(transitionConfig.onSuccess);
1286
+ };
1287
+ })();
1288
+ function defaultStorage() {
1289
+ try {
1290
+ if (typeof window !== "undefined" && window.localStorage) {
1291
+ return window.localStorage;
1403
1292
  }
1404
- throw new AuthError(
1405
- `No valid transition found for step: ${this.state.currentStep}`,
1406
- "validation_error" /* VALIDATION_ERROR */
1407
- );
1293
+ } catch {
1408
1294
  }
1409
- /**
1410
- * Go back to previous step
1411
- */
1412
- handleBack() {
1413
- if (this.history.length < 2) {
1414
- throw new AuthError(
1415
- "Cannot go back - already at first step",
1416
- "validation_error" /* VALIDATION_ERROR */
1417
- );
1295
+ return memoryStorage;
1296
+ }
1297
+ var AuthManager = class {
1298
+ client;
1299
+ storage;
1300
+ state = { status: "idle" };
1301
+ listeners = /* @__PURE__ */ new Set();
1302
+ refreshTimer = null;
1303
+ onError;
1304
+ publishableKey;
1305
+ clientConfig = null;
1306
+ configListeners = /* @__PURE__ */ new Set();
1307
+ configFetchPromise = null;
1308
+ constructor(config) {
1309
+ this.client = new AuthClient2(config);
1310
+ this.storage = config.storage ?? defaultStorage();
1311
+ this.onError = config.onError;
1312
+ this.publishableKey = config.publishableKey;
1313
+ if (config.initialClientConfig) {
1314
+ this.clientConfig = config.initialClientConfig;
1418
1315
  }
1419
- this.history.pop();
1420
- const previousStep = this.history[this.history.length - 1];
1421
- const transitionConfig = this.config.transitions[this.state.currentStep];
1422
- const targetStep = transitionConfig?.onBack || previousStep;
1423
- return this.moveToStep(targetStep, false);
1316
+ if (config.onStateChange) {
1317
+ this.listeners.add(config.onStateChange);
1318
+ }
1319
+ }
1320
+ // ── Public API ────────────────────────────────────
1321
+ /** Current auth state (snapshot). */
1322
+ getState() {
1323
+ return this.state;
1324
+ }
1325
+ /** Subscribe to state changes. Returns an unsubscribe function. */
1326
+ subscribe(listener) {
1327
+ this.listeners.add(listener);
1328
+ return () => {
1329
+ this.listeners.delete(listener);
1330
+ };
1331
+ }
1332
+ /** Access the underlying HTTP client. */
1333
+ getClient() {
1334
+ return this.client;
1424
1335
  }
1425
1336
  /**
1426
- * Cancel the flow
1337
+ * Initialize by hydrating the session from storage.
1338
+ * When a publishableKey is set, also fetches client config in parallel.
1339
+ * Call this once on app start.
1427
1340
  */
1428
- handleCancel() {
1429
- const transitionConfig = this.config.transitions[this.state.currentStep];
1430
- const targetStep = transitionConfig?.onCancel;
1431
- if (this.config.onCancel) {
1432
- this.config.onCancel(this.state);
1341
+ async initialize() {
1342
+ if (this.publishableKey && !this.clientConfig) {
1343
+ void this.fetchClientConfig();
1433
1344
  }
1434
- if (targetStep) {
1435
- return this.moveToStep(targetStep);
1345
+ try {
1346
+ const raw = await this.storage.getItem(SESSION_KEY);
1347
+ if (!raw) {
1348
+ this.setState({ status: "unauthenticated" });
1349
+ return;
1350
+ }
1351
+ const session = JSON.parse(raw);
1352
+ const expiresAt = new Date(session.expires_at).getTime();
1353
+ if (Date.now() >= expiresAt) {
1354
+ await this.refreshSession(session.refresh_token);
1355
+ return;
1356
+ }
1357
+ this.setState({ status: "loading" });
1358
+ const user = await this.client.getMe(session.session_token);
1359
+ this.setState({ status: "authenticated", user, session });
1360
+ this.scheduleRefresh(session);
1361
+ } catch {
1362
+ await this.clearSession();
1363
+ this.setState({ status: "unauthenticated" });
1436
1364
  }
1437
- this.state.currentStep = "cancelled";
1438
- return this.getState();
1439
1365
  }
1440
- /**
1441
- * Handle error in flow
1442
- */
1443
- handleError(error) {
1444
- this.state.error = error;
1445
- const transitionConfig = this.config.transitions[this.state.currentStep];
1446
- const targetStep = transitionConfig?.onError;
1447
- if (this.config.onError) {
1448
- this.config.onError(error, this.state);
1366
+ /** Sign in with email & password. */
1367
+ async signIn(credentials) {
1368
+ this.setState({ status: "loading" });
1369
+ try {
1370
+ const res = await this.client.signIn(credentials);
1371
+ const session = {
1372
+ session_token: res.session_token,
1373
+ refresh_token: res.refresh_token,
1374
+ expires_at: new Date(Date.now() + 36e5).toISOString()
1375
+ // fallback
1376
+ };
1377
+ await this.handleAuthResponse(res.user, session);
1378
+ } catch (err) {
1379
+ this.handleError(err);
1380
+ throw err;
1449
1381
  }
1450
- if (targetStep) {
1451
- return this.moveToStep(targetStep);
1382
+ }
1383
+ /** Sign up with email & password. */
1384
+ async signUp(data) {
1385
+ this.setState({ status: "loading" });
1386
+ try {
1387
+ const res = await this.client.signUp(data);
1388
+ const session = {
1389
+ session_token: res.session_token,
1390
+ refresh_token: res.refresh_token,
1391
+ expires_at: new Date(Date.now() + 36e5).toISOString()
1392
+ };
1393
+ await this.handleAuthResponse(res.user, session);
1394
+ } catch (err) {
1395
+ this.handleError(err);
1396
+ throw err;
1452
1397
  }
1453
- return this.getState();
1454
1398
  }
1455
- /**
1456
- * Reset flow to initial state
1457
- */
1458
- handleReset() {
1459
- return this.handleStart();
1399
+ /** Sign out and clear the session. */
1400
+ async signOut() {
1401
+ const token = this.getSessionToken();
1402
+ if (token) {
1403
+ try {
1404
+ await this.client.signOut(token);
1405
+ } catch {
1406
+ }
1407
+ }
1408
+ this.clearRefreshTimer();
1409
+ await this.clearSession();
1410
+ this.setState({ status: "unauthenticated" });
1460
1411
  }
1461
- /**
1462
- * Move to a specific step
1463
- */
1464
- moveToStep(step, addToHistory = true) {
1465
- if (!this.isStepAllowed(step)) {
1466
- throw new AuthError(
1467
- `Step ${step} is not allowed in this flow`,
1468
- "validation_error" /* VALIDATION_ERROR */
1469
- );
1412
+ /** Submit an MFA challenge code. */
1413
+ async submitMFACode(enrollmentId, code) {
1414
+ this.setState({ status: "loading" });
1415
+ try {
1416
+ const res = await this.client.mfaChallenge({ enrollment_id: enrollmentId, code });
1417
+ const session = {
1418
+ session_token: res.session_token,
1419
+ refresh_token: res.refresh_token,
1420
+ expires_at: new Date(Date.now() + 36e5).toISOString()
1421
+ };
1422
+ await this.handleAuthResponse(res.user, session);
1423
+ } catch (err) {
1424
+ this.handleError(err);
1425
+ }
1426
+ }
1427
+ /** Submit an MFA recovery code. */
1428
+ async submitRecoveryCode(code) {
1429
+ this.setState({ status: "loading" });
1430
+ try {
1431
+ const res = await this.client.verifyRecoveryCode(code);
1432
+ const session = {
1433
+ session_token: res.session_token,
1434
+ refresh_token: res.refresh_token,
1435
+ expires_at: new Date(Date.now() + 36e5).toISOString()
1436
+ };
1437
+ await this.handleAuthResponse(res.user, session);
1438
+ } catch (err) {
1439
+ this.handleError(err);
1470
1440
  }
1471
- this.state.currentStep = step;
1472
- if (addToHistory) {
1473
- this.history.push(step);
1441
+ }
1442
+ /** Send an SMS code for MFA verification. Returns masked phone + expiry info. */
1443
+ async sendSMSCode() {
1444
+ const token = this.getSessionToken();
1445
+ if (!token) throw new Error("No session token available");
1446
+ return this.client.sendSMSCodeForMFA(token);
1447
+ }
1448
+ /** Submit an SMS verification code during MFA challenge. */
1449
+ async submitSMSCode(code) {
1450
+ this.setState({ status: "loading" });
1451
+ try {
1452
+ const token = this.getSessionToken();
1453
+ if (!token) throw new Error("No session token available");
1454
+ const res = await this.client.verifySMSCodeForMFA(code, token);
1455
+ const session = {
1456
+ session_token: res.session_token,
1457
+ refresh_token: res.refresh_token,
1458
+ expires_at: new Date(Date.now() + 36e5).toISOString()
1459
+ };
1460
+ await this.handleAuthResponse(res.user, session);
1461
+ } catch (err) {
1462
+ this.handleError(err);
1474
1463
  }
1475
- if (this.config.onStepChange) {
1476
- this.config.onStepChange(step, this.state);
1464
+ }
1465
+ /** Refresh the current session manually. */
1466
+ async refreshNow() {
1467
+ const state = this.state;
1468
+ if (state.status !== "authenticated") return;
1469
+ await this.refreshSession(state.session.refresh_token);
1470
+ }
1471
+ /** Get the current session token (if authenticated). */
1472
+ getSessionToken() {
1473
+ if (this.state.status === "authenticated") {
1474
+ return this.state.session.session_token;
1477
1475
  }
1478
- if (step === "success" && this.state.user && this.state.session) {
1479
- if (this.config.onComplete) {
1480
- this.config.onComplete(this.state.user, this.state.session);
1481
- }
1476
+ if (this.state.status === "mfa_required") {
1477
+ return this.state.session.session_token;
1482
1478
  }
1483
- return this.getState();
1479
+ return null;
1484
1480
  }
1485
- /**
1486
- * Get flow history
1487
- */
1488
- getHistory() {
1489
- return [...this.history];
1481
+ /** Get the current user (if authenticated). */
1482
+ getUser() {
1483
+ if (this.state.status === "authenticated") {
1484
+ return this.state.user;
1485
+ }
1486
+ return null;
1487
+ }
1488
+ // ── Client Config API ────────────────────────────
1489
+ /** Get the cached client config (or null if not yet fetched). */
1490
+ getClientConfig() {
1491
+ return this.clientConfig;
1492
+ }
1493
+ /** Subscribe to client config changes. Returns an unsubscribe function. */
1494
+ subscribeConfig(listener) {
1495
+ this.configListeners.add(listener);
1496
+ return () => {
1497
+ this.configListeners.delete(listener);
1498
+ };
1490
1499
  }
1491
1500
  /**
1492
- * Check if can go back
1501
+ * Fetch client config from the backend.
1502
+ * Deduplicates concurrent calls and caches the result with a TTL.
1493
1503
  */
1494
- canGoBack() {
1495
- return this.history.length > 1;
1496
- }
1497
- };
1498
-
1499
- // src/flows/configs.ts
1500
- var simpleSignInFlow = {
1501
- name: "Simple Sign In",
1502
- description: "Basic email/password sign-in",
1503
- initialStep: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1504
- allowedSteps: [
1505
- "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1506
- "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1507
- "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1508
- "password_reset_request" /* PASSWORD_RESET_REQUEST */,
1509
- "password_reset_sent" /* PASSWORD_RESET_SENT */,
1510
- "success" /* SUCCESS */,
1511
- "error" /* ERROR */
1512
- ],
1513
- transitions: {
1514
- ["email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */]: {
1515
- onSuccess: "success" /* SUCCESS */,
1516
- onError: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1517
- },
1518
- ["email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */]: {
1519
- onSuccess: "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1520
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1521
- },
1522
- ["email_verification_sent" /* EMAIL_VERIFICATION_SENT */]: {
1523
- onSuccess: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1524
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1525
- },
1526
- ["password_reset_request" /* PASSWORD_RESET_REQUEST */]: {
1527
- onSuccess: "password_reset_sent" /* PASSWORD_RESET_SENT */,
1528
- onBack: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1529
- },
1530
- ["password_reset_sent" /* PASSWORD_RESET_SENT */]: {
1531
- onSuccess: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1504
+ async fetchClientConfig() {
1505
+ if (this.configFetchPromise) {
1506
+ return this.configFetchPromise;
1532
1507
  }
1533
- }
1534
- };
1535
- var signInWithMFAFlow = {
1536
- name: "Sign In with MFA",
1537
- description: "Sign-in that handles MFA if enabled",
1538
- initialStep: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1539
- allowedSteps: [
1540
- "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1541
- "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1542
- "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1543
- "mfa_required" /* MFA_REQUIRED */,
1544
- "mfa_select_method" /* MFA_SELECT_METHOD */,
1545
- "mfa_verify" /* MFA_VERIFY */,
1546
- "password_reset_request" /* PASSWORD_RESET_REQUEST */,
1547
- "password_reset_sent" /* PASSWORD_RESET_SENT */,
1548
- "success" /* SUCCESS */,
1549
- "error" /* ERROR */
1550
- ],
1551
- transitions: {
1552
- ["email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */]: {
1553
- onSuccess: "success" /* SUCCESS */,
1554
- onError: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1555
- conditions: [
1556
- {
1557
- when: (state) => state.mfaRequired === true,
1558
- then: "mfa_required" /* MFA_REQUIRED */
1559
- }
1560
- ]
1561
- },
1562
- ["email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */]: {
1563
- onSuccess: "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1564
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1565
- },
1566
- ["email_verification_sent" /* EMAIL_VERIFICATION_SENT */]: {
1567
- onSuccess: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1568
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1569
- },
1570
- ["mfa_required" /* MFA_REQUIRED */]: {
1571
- onSuccess: "mfa_verify" /* MFA_VERIFY */,
1572
- conditions: [
1573
- {
1574
- when: (state) => (state.mfaMethods?.length || 0) > 1,
1575
- then: "mfa_select_method" /* MFA_SELECT_METHOD */
1508
+ try {
1509
+ const cached = await this.storage.getItem(CONFIG_KEY);
1510
+ if (cached) {
1511
+ const { config, fetchedAt } = JSON.parse(cached);
1512
+ if (Date.now() - fetchedAt < CONFIG_TTL_MS) {
1513
+ this.setClientConfig(config);
1514
+ return config;
1576
1515
  }
1577
- ]
1578
- },
1579
- ["mfa_select_method" /* MFA_SELECT_METHOD */]: {
1580
- onSuccess: "mfa_verify" /* MFA_VERIFY */,
1581
- onBack: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1582
- },
1583
- ["mfa_verify" /* MFA_VERIFY */]: {
1584
- onSuccess: "success" /* SUCCESS */,
1585
- onError: "mfa_verify" /* MFA_VERIFY */,
1586
- onBack: "mfa_select_method" /* MFA_SELECT_METHOD */
1587
- },
1588
- ["password_reset_request" /* PASSWORD_RESET_REQUEST */]: {
1589
- onSuccess: "password_reset_sent" /* PASSWORD_RESET_SENT */,
1590
- onBack: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1516
+ }
1517
+ } catch {
1591
1518
  }
1519
+ this.configFetchPromise = this.client.fetchClientConfig(this.publishableKey).then(async (config) => {
1520
+ this.setClientConfig(config);
1521
+ try {
1522
+ await this.storage.setItem(
1523
+ CONFIG_KEY,
1524
+ JSON.stringify({ config, fetchedAt: Date.now() })
1525
+ );
1526
+ } catch {
1527
+ }
1528
+ return config;
1529
+ }).finally(() => {
1530
+ this.configFetchPromise = null;
1531
+ });
1532
+ return this.configFetchPromise;
1592
1533
  }
1593
- };
1594
- var completeSignUpFlow = {
1595
- name: "Complete Sign Up",
1596
- description: "Sign-up with email verification and profile completion",
1597
- initialStep: "email_password_sign_up" /* EMAIL_PASSWORD_SIGN_UP */,
1598
- allowedSteps: [
1599
- "email_password_sign_up" /* EMAIL_PASSWORD_SIGN_UP */,
1600
- "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1601
- "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1602
- "profile_complete" /* PROFILE_COMPLETE */,
1603
- "success" /* SUCCESS */,
1604
- "error" /* ERROR */
1605
- ],
1606
- transitions: {
1607
- ["email_password_sign_up" /* EMAIL_PASSWORD_SIGN_UP */]: {
1608
- onSuccess: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1609
- onError: "email_password_sign_up" /* EMAIL_PASSWORD_SIGN_UP */,
1610
- conditions: [
1611
- {
1612
- when: (state) => state.verificationRequired === false,
1613
- then: "profile_complete" /* PROFILE_COMPLETE */
1614
- }
1615
- ]
1616
- },
1617
- ["email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */]: {
1618
- onSuccess: "email_verification_sent" /* EMAIL_VERIFICATION_SENT */
1619
- },
1620
- ["email_verification_sent" /* EMAIL_VERIFICATION_SENT */]: {
1621
- onSuccess: "profile_complete" /* PROFILE_COMPLETE */
1622
- },
1623
- ["profile_complete" /* PROFILE_COMPLETE */]: {
1624
- onSuccess: "success" /* SUCCESS */,
1625
- onError: "profile_complete" /* PROFILE_COMPLETE */
1534
+ /** Tear down: clear timers and listeners. */
1535
+ destroy() {
1536
+ this.clearRefreshTimer();
1537
+ this.listeners.clear();
1538
+ this.configListeners.clear();
1539
+ }
1540
+ // ── Internals ─────────────────────────────────────
1541
+ async handleAuthResponse(user, session) {
1542
+ await this.persistSession(session);
1543
+ this.setState({ status: "authenticated", user, session });
1544
+ this.scheduleRefresh(session);
1545
+ }
1546
+ async refreshSession(refreshToken) {
1547
+ try {
1548
+ const newSession = await this.client.refresh(refreshToken);
1549
+ const user = await this.client.getMe(newSession.session_token);
1550
+ await this.persistSession(newSession);
1551
+ this.setState({ status: "authenticated", user, session: newSession });
1552
+ this.scheduleRefresh(newSession);
1553
+ } catch {
1554
+ await this.clearSession();
1555
+ this.setState({ status: "unauthenticated" });
1626
1556
  }
1627
1557
  }
1628
- };
1629
- var magicLinkFlow = {
1630
- name: "Magic Link",
1631
- description: "Passwordless authentication via email",
1632
- initialStep: "magic_link_request" /* MAGIC_LINK_REQUEST */,
1633
- allowedSteps: [
1634
- "magic_link_request" /* MAGIC_LINK_REQUEST */,
1635
- "magic_link_sent" /* MAGIC_LINK_SENT */,
1636
- "magic_link_verify" /* MAGIC_LINK_VERIFY */,
1637
- "success" /* SUCCESS */,
1638
- "error" /* ERROR */
1639
- ],
1640
- transitions: {
1641
- ["magic_link_request" /* MAGIC_LINK_REQUEST */]: {
1642
- onSuccess: "magic_link_sent" /* MAGIC_LINK_SENT */,
1643
- onError: "magic_link_request" /* MAGIC_LINK_REQUEST */
1644
- },
1645
- ["magic_link_sent" /* MAGIC_LINK_SENT */]: {
1646
- onSuccess: "magic_link_verify" /* MAGIC_LINK_VERIFY */
1647
- },
1648
- ["magic_link_verify" /* MAGIC_LINK_VERIFY */]: {
1649
- onSuccess: "success" /* SUCCESS */,
1650
- onError: "magic_link_request" /* MAGIC_LINK_REQUEST */
1558
+ scheduleRefresh(session) {
1559
+ this.clearRefreshTimer();
1560
+ const expiresAt = new Date(session.expires_at).getTime();
1561
+ const delay = expiresAt - Date.now() - REFRESH_BEFORE_MS;
1562
+ if (delay <= 0) {
1563
+ void this.refreshSession(session.refresh_token);
1564
+ return;
1565
+ }
1566
+ this.refreshTimer = setTimeout(() => {
1567
+ void this.refreshSession(session.refresh_token);
1568
+ }, delay);
1569
+ }
1570
+ clearRefreshTimer() {
1571
+ if (this.refreshTimer !== null) {
1572
+ clearTimeout(this.refreshTimer);
1573
+ this.refreshTimer = null;
1651
1574
  }
1652
1575
  }
1653
- };
1654
- var phoneAuthFlow = {
1655
- name: "Phone Authentication",
1656
- description: "SMS-based authentication",
1657
- initialStep: "phone_request" /* PHONE_REQUEST */,
1658
- allowedSteps: [
1659
- "phone_request" /* PHONE_REQUEST */,
1660
- "phone_verify" /* PHONE_VERIFY */,
1661
- "success" /* SUCCESS */,
1662
- "error" /* ERROR */
1663
- ],
1664
- transitions: {
1665
- ["phone_request" /* PHONE_REQUEST */]: {
1666
- onSuccess: "phone_verify" /* PHONE_VERIFY */,
1667
- onError: "phone_request" /* PHONE_REQUEST */
1668
- },
1669
- ["phone_verify" /* PHONE_VERIFY */]: {
1670
- onSuccess: "success" /* SUCCESS */,
1671
- onError: "phone_verify" /* PHONE_VERIFY */,
1672
- onBack: "phone_request" /* PHONE_REQUEST */
1576
+ async persistSession(session) {
1577
+ await this.storage.setItem(SESSION_KEY, JSON.stringify(session));
1578
+ }
1579
+ async clearSession() {
1580
+ await this.storage.removeItem(SESSION_KEY);
1581
+ }
1582
+ setClientConfig(config) {
1583
+ this.clientConfig = config;
1584
+ for (const listener of this.configListeners) {
1585
+ try {
1586
+ listener(config);
1587
+ } catch {
1588
+ }
1673
1589
  }
1674
1590
  }
1675
- };
1676
- var oauthSignInFlow = {
1677
- name: "OAuth Sign In",
1678
- description: "Third-party OAuth authentication",
1679
- initialStep: "oauth_select" /* OAUTH_SELECT */,
1680
- allowedSteps: [
1681
- "oauth_select" /* OAUTH_SELECT */,
1682
- "oauth_callback" /* OAUTH_CALLBACK */,
1683
- "success" /* SUCCESS */,
1684
- "error" /* ERROR */
1685
- ],
1686
- transitions: {
1687
- ["oauth_select" /* OAUTH_SELECT */]: {
1688
- onSuccess: "oauth_callback" /* OAUTH_CALLBACK */,
1689
- onError: "oauth_select" /* OAUTH_SELECT */
1690
- },
1691
- ["oauth_callback" /* OAUTH_CALLBACK */]: {
1692
- onSuccess: "success" /* SUCCESS */,
1693
- onError: "oauth_select" /* OAUTH_SELECT */
1591
+ setState(newState) {
1592
+ this.state = newState;
1593
+ for (const listener of this.listeners) {
1594
+ try {
1595
+ listener(newState);
1596
+ } catch {
1597
+ }
1694
1598
  }
1695
1599
  }
1696
- };
1697
- var passwordResetFlow = {
1698
- name: "Password Reset",
1699
- description: "Reset forgotten password",
1700
- initialStep: "password_reset_request" /* PASSWORD_RESET_REQUEST */,
1701
- allowedSteps: [
1702
- "password_reset_request" /* PASSWORD_RESET_REQUEST */,
1703
- "password_reset_sent" /* PASSWORD_RESET_SENT */,
1704
- "password_reset_confirm" /* PASSWORD_RESET_CONFIRM */,
1705
- "success" /* SUCCESS */,
1706
- "error" /* ERROR */
1707
- ],
1708
- transitions: {
1709
- ["password_reset_request" /* PASSWORD_RESET_REQUEST */]: {
1710
- onSuccess: "password_reset_sent" /* PASSWORD_RESET_SENT */,
1711
- onError: "password_reset_request" /* PASSWORD_RESET_REQUEST */
1712
- },
1713
- ["password_reset_sent" /* PASSWORD_RESET_SENT */]: {
1714
- onSuccess: "password_reset_confirm" /* PASSWORD_RESET_CONFIRM */
1715
- },
1716
- ["password_reset_confirm" /* PASSWORD_RESET_CONFIRM */]: {
1717
- onSuccess: "success" /* SUCCESS */,
1718
- onError: "password_reset_confirm" /* PASSWORD_RESET_CONFIRM */
1600
+ handleError(err) {
1601
+ const message = err instanceof AuthClientError ? err.message : "An unexpected error occurred";
1602
+ const code = err instanceof AuthClientError ? err.code : void 0;
1603
+ if (code === 403 && message.toLowerCase().includes("mfa")) {
1604
+ const token = this.getSessionToken();
1605
+ if (token) {
1606
+ this.setState({
1607
+ status: "mfa_required",
1608
+ session: {
1609
+ session_token: token,
1610
+ refresh_token: "",
1611
+ expires_at: new Date(Date.now() + 3e5).toISOString()
1612
+ }
1613
+ });
1614
+ return;
1615
+ }
1719
1616
  }
1617
+ this.setState({ status: "error", error: message });
1618
+ this.onError?.({ error: message, code });
1720
1619
  }
1721
1620
  };
1722
- var emailVerificationFlow = {
1723
- name: "Email Verification",
1724
- description: "Verify email address with code or link",
1725
- initialStep: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1726
- allowedSteps: [
1727
- "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1728
- "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1729
- "success" /* SUCCESS */,
1730
- "error" /* ERROR */
1731
- ],
1732
- transitions: {
1733
- ["email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */]: {
1734
- onSuccess: "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1735
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1736
- },
1737
- ["email_verification_sent" /* EMAIL_VERIFICATION_SENT */]: {
1738
- onSuccess: "success" /* SUCCESS */,
1739
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1621
+
1622
+ // src/webauthn.ts
1623
+ function base64urlToBuffer(base64url) {
1624
+ const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
1625
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
1626
+ const binary = atob(padded);
1627
+ const bytes = new Uint8Array(binary.length);
1628
+ for (let i = 0; i < binary.length; i++) {
1629
+ bytes[i] = binary.charCodeAt(i);
1630
+ }
1631
+ return bytes;
1632
+ }
1633
+ function bufferToBase64url(buffer) {
1634
+ const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
1635
+ let binary = "";
1636
+ for (let i = 0; i < bytes.byteLength; i++) {
1637
+ binary += String.fromCharCode(bytes[i]);
1638
+ }
1639
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1640
+ }
1641
+ function prepareCreationOptions(options) {
1642
+ const publicKey = options.publicKey ?? options;
1643
+ const out = { ...publicKey };
1644
+ if (typeof out.challenge === "string") {
1645
+ out.challenge = base64urlToBuffer(out.challenge);
1646
+ }
1647
+ if (out.user && typeof out.user === "object") {
1648
+ const user = { ...out.user };
1649
+ if (typeof user.id === "string") {
1650
+ user.id = base64urlToBuffer(user.id);
1740
1651
  }
1652
+ out.user = user;
1741
1653
  }
1742
- };
1743
- var deviceFlow = {
1744
- name: "Device Flow",
1745
- description: "OAuth 2.0 Device Authorization Grant for CLI/device login",
1746
- initialStep: "device_code_entry" /* DEVICE_CODE_ENTRY */,
1747
- allowedSteps: [
1748
- "device_code_entry" /* DEVICE_CODE_ENTRY */,
1749
- "device_code_verify" /* DEVICE_CODE_VERIFY */,
1750
- "device_authorize" /* DEVICE_AUTHORIZE */,
1751
- "device_authorized" /* DEVICE_AUTHORIZED */,
1752
- "device_denied" /* DEVICE_DENIED */,
1753
- "success" /* SUCCESS */,
1754
- "error" /* ERROR */
1755
- ],
1756
- transitions: {
1757
- ["device_code_entry" /* DEVICE_CODE_ENTRY */]: {
1758
- onSuccess: "device_code_verify" /* DEVICE_CODE_VERIFY */,
1759
- onError: "device_code_entry" /* DEVICE_CODE_ENTRY */,
1760
- onCancel: "cancelled" /* CANCELLED */
1761
- },
1762
- ["device_code_verify" /* DEVICE_CODE_VERIFY */]: {
1763
- onSuccess: "device_authorize" /* DEVICE_AUTHORIZE */,
1764
- onError: "device_code_entry" /* DEVICE_CODE_ENTRY */,
1765
- onBack: "device_code_entry" /* DEVICE_CODE_ENTRY */
1766
- },
1767
- ["device_authorize" /* DEVICE_AUTHORIZE */]: {
1768
- onSuccess: "device_authorized" /* DEVICE_AUTHORIZED */,
1769
- onError: "device_denied" /* DEVICE_DENIED */,
1770
- onCancel: "device_denied" /* DEVICE_DENIED */
1771
- },
1772
- ["device_authorized" /* DEVICE_AUTHORIZED */]: {
1773
- onSuccess: "success" /* SUCCESS */
1774
- },
1775
- ["device_denied" /* DEVICE_DENIED */]: {
1776
- onSuccess: "error" /* ERROR */
1654
+ if (Array.isArray(out.excludeCredentials)) {
1655
+ out.excludeCredentials = out.excludeCredentials.map((c) => {
1656
+ if (typeof c.id === "string") {
1657
+ return { ...c, id: base64urlToBuffer(c.id) };
1658
+ }
1659
+ return c;
1660
+ });
1661
+ }
1662
+ return out;
1663
+ }
1664
+ function prepareRequestOptions(options) {
1665
+ const publicKey = options.publicKey ?? options;
1666
+ const out = { ...publicKey };
1667
+ if (typeof out.challenge === "string") {
1668
+ out.challenge = base64urlToBuffer(out.challenge);
1669
+ }
1670
+ if (Array.isArray(out.allowCredentials)) {
1671
+ out.allowCredentials = out.allowCredentials.map((c) => {
1672
+ if (typeof c.id === "string") {
1673
+ return { ...c, id: base64urlToBuffer(c.id) };
1674
+ }
1675
+ return c;
1676
+ });
1677
+ }
1678
+ return out;
1679
+ }
1680
+ function serializeCredential(credential) {
1681
+ const cred = credential;
1682
+ const response = cred.response;
1683
+ const result = {
1684
+ id: cred.id,
1685
+ rawId: bufferToBase64url(cred.rawId),
1686
+ type: cred.type,
1687
+ response: {}
1688
+ };
1689
+ const serializedResponse = {
1690
+ clientDataJSON: bufferToBase64url(response.clientDataJSON)
1691
+ };
1692
+ if ("attestationObject" in response) {
1693
+ const attestation = response;
1694
+ serializedResponse.attestationObject = bufferToBase64url(
1695
+ attestation.attestationObject
1696
+ );
1697
+ }
1698
+ if ("authenticatorData" in response) {
1699
+ const assertion = response;
1700
+ serializedResponse.authenticatorData = bufferToBase64url(
1701
+ assertion.authenticatorData
1702
+ );
1703
+ serializedResponse.signature = bufferToBase64url(assertion.signature);
1704
+ if (assertion.userHandle) {
1705
+ serializedResponse.userHandle = bufferToBase64url(assertion.userHandle);
1777
1706
  }
1778
1707
  }
1779
- };
1780
- function getFlowConfig(type) {
1781
- switch (type) {
1782
- case "simple_sign_in" /* SIMPLE_SIGN_IN */:
1783
- return simpleSignInFlow;
1784
- case "sign_in_with_mfa" /* SIGN_IN_WITH_MFA */:
1785
- return signInWithMFAFlow;
1786
- case "complete_sign_up_flow" /* COMPLETE_SIGN_UP_FLOW */:
1787
- return completeSignUpFlow;
1788
- case "magic_link_flow" /* MAGIC_LINK_FLOW */:
1789
- return magicLinkFlow;
1790
- case "phone_auth_flow" /* PHONE_AUTH_FLOW */:
1791
- return phoneAuthFlow;
1792
- case "oauth_sign_in" /* OAUTH_SIGN_IN */:
1793
- return oauthSignInFlow;
1794
- case "password_reset_flow" /* PASSWORD_RESET_FLOW */:
1795
- return passwordResetFlow;
1796
- case "email_verification_flow" /* EMAIL_VERIFICATION_FLOW */:
1797
- return emailVerificationFlow;
1798
- case "device_flow" /* DEVICE_FLOW */:
1799
- return deviceFlow;
1800
- default:
1801
- throw new Error(`Unknown flow type: ${type}`);
1708
+ result.response = serializedResponse;
1709
+ if (cred.authenticatorAttachment) {
1710
+ result.authenticatorAttachment = cred.authenticatorAttachment;
1802
1711
  }
1712
+ return result;
1803
1713
  }
1804
- var predefinedFlows = {
1805
- ["simple_sign_in" /* SIMPLE_SIGN_IN */]: simpleSignInFlow,
1806
- ["sign_in_with_mfa" /* SIGN_IN_WITH_MFA */]: signInWithMFAFlow,
1807
- ["complete_sign_up_flow" /* COMPLETE_SIGN_UP_FLOW */]: completeSignUpFlow,
1808
- ["magic_link_flow" /* MAGIC_LINK_FLOW */]: magicLinkFlow,
1809
- ["phone_auth_flow" /* PHONE_AUTH_FLOW */]: phoneAuthFlow,
1810
- ["oauth_sign_in" /* OAUTH_SIGN_IN */]: oauthSignInFlow,
1811
- ["password_reset_flow" /* PASSWORD_RESET_FLOW */]: passwordResetFlow,
1812
- ["email_verification_flow" /* EMAIL_VERIFICATION_FLOW */]: emailVerificationFlow,
1813
- ["device_flow" /* DEVICE_FLOW */]: deviceFlow
1714
+ export {
1715
+ AuthClient2 as AuthClient,
1716
+ AuthClientError,
1717
+ AuthManager,
1718
+ base64urlToBuffer,
1719
+ bufferToBase64url,
1720
+ prepareCreationOptions,
1721
+ prepareRequestOptions,
1722
+ serializeCredential
1814
1723
  };
1815
-
1816
- exports.AuthClient = AuthClient;
1817
- exports.AuthError = AuthError;
1818
- exports.AuthErrorType = AuthErrorType;
1819
- exports.AuthState = AuthState;
1820
- exports.BaseAuthProvider = BaseAuthProvider;
1821
- exports.FlowAction = FlowAction;
1822
- exports.FlowConfigType = FlowConfigType;
1823
- exports.FlowEngine = FlowEngine;
1824
- exports.FlowStep = FlowStep;
1825
- exports.LocalStorageAdapter = LocalStorageAdapter;
1826
- exports.MemoryStorageAdapter = MemoryStorageAdapter;
1827
- exports.OAuthProvider = OAuthProvider;
1828
- exports.Observable = Observable;
1829
- exports.SessionStorageAdapter = SessionStorageAdapter;
1830
- exports.TokenManager = TokenManager;
1831
- exports.TwoFactorMethod = TwoFactorMethod;
1832
- exports.completeSignUpFlow = completeSignUpFlow;
1833
- exports.createAuthError = createAuthError;
1834
- exports.createLocale = createLocale;
1835
- exports.defaultLocale = defaultLocale;
1836
- exports.emailVerificationFlow = emailVerificationFlow;
1837
- exports.extractCookiesFromHeaders = extractCookiesFromHeaders;
1838
- exports.getFlowConfig = getFlowConfig;
1839
- exports.interpolate = interpolate;
1840
- exports.isAuthError = isAuthError;
1841
- exports.isMFARequiredError = isMFARequiredError;
1842
- exports.isNetworkError = isNetworkError;
1843
- exports.isUnauthenticatedError = isUnauthenticatedError;
1844
- exports.magicLinkFlow = magicLinkFlow;
1845
- exports.oauthSignInFlow = oauthSignInFlow;
1846
- exports.parseCookie = parseCookie;
1847
- exports.parseCookieOptions = parseCookieOptions;
1848
- exports.passwordResetFlow = passwordResetFlow;
1849
- exports.phoneAuthFlow = phoneAuthFlow;
1850
- exports.predefinedFlows = predefinedFlows;
1851
- exports.serializeCookie = serializeCookie;
1852
- exports.serializeCookies = serializeCookies;
1853
- exports.signInWithMFAFlow = signInWithMFAFlow;
1854
- exports.simpleSignInFlow = simpleSignInFlow;
1855
- exports.toAuthError = toAuthError;
1856
- exports.validate2FACode = validate2FACode;
1857
- exports.validateEmail = validateEmail;
1858
- exports.validatePassword = validatePassword;
1859
- exports.validatePhone = validatePhone;
1860
- exports.validateRequired = validateRequired;
1861
- exports.validateUsername = validateUsername;
1862
- //# sourceMappingURL=index.js.map
1863
1724
  //# sourceMappingURL=index.js.map