@authsome/ui-core 0.1.8 → 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,1781 +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
- signUp: {
282
- title: "Create Account",
283
- subtitle: "Get started with your account",
284
- haveAccount: "Already have an account?",
285
- signInLink: "Sign in",
286
- agreeToTerms: "I agree to the {terms}",
287
- terms: "terms and conditions"
288
- },
289
- signIn: {
290
- title: "Sign In",
291
- subtitle: "Enter your email to continue",
292
- noAccount: "Don't have an account?",
293
- signUpLink: "Sign up",
294
- enterEmail: "Enter your email to continue"
295
- },
296
- validation: {
297
- emailRequired: "Email is required",
298
- emailInvalid: "Invalid email address",
299
- passwordRequired: "Password is required",
300
- passwordTooShort: "Password must be at least {min} characters",
301
- passwordRequireUppercase: "Password must contain an uppercase letter",
302
- passwordRequireLowercase: "Password must contain a lowercase letter",
303
- passwordRequireNumber: "Password must contain a number",
304
- passwordRequireSpecial: "Password must contain a special character",
305
- passwordMismatch: "Passwords do not match",
306
- usernameRequired: "Username is required",
307
- usernameInvalid: "Username must be 3-30 characters and contain only letters, numbers, underscores, and hyphens",
308
- phoneRequired: "Phone number is required",
309
- phoneInvalid: "Invalid phone number",
310
- codeRequired: "Verification code is required",
311
- codeInvalid: "Invalid verification code",
312
- fieldRequired: "{field} is required",
313
- termsRequired: "You must agree to the terms and conditions"
314
- },
315
- errors: {
316
- invalidCredentials: "Invalid email or password",
317
- userNotFound: "User not found",
318
- userExists: "User already exists",
319
- invalidToken: "Invalid or expired token",
320
- tokenExpired: "Token has expired",
321
- networkError: "Network error. Please try again.",
322
- mfaRequired: "Two-factor authentication required",
323
- emailNotVerified: "Email not verified",
324
- phoneNotVerified: "Phone number not verified",
325
- rateLimitExceeded: "Too many attempts. Please try again later.",
326
- unknownError: "An unknown error occurred",
327
- generic: "Something went wrong. Please try again."
328
- },
329
- success: {
330
- signedIn: "Successfully signed in",
331
- signedUp: "Account created successfully",
332
- signedOut: "Successfully signed out",
333
- linkSent: "Link sent successfully",
334
- codeSent: "Verification code sent",
335
- verified: "Successfully verified",
336
- welcome: "Welcome, {name}!"
337
- },
338
- placeholders: {
339
- email: "john@example.com",
340
- password: "Enter your password",
341
- confirmPassword: "Confirm your password",
342
- username: "johndoe",
343
- phone: "+1234567890",
344
- code: "123456",
345
- 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
+ );
346
217
  }
347
- };
348
-
349
- // src/locale/utils.ts
350
- var defaultLocale = enLocale;
351
- function deepMerge(target, source) {
352
- const result = { ...target };
353
- for (const key in source) {
354
- if (source[key] !== void 0) {
355
- if (typeof source[key] === "object" && source[key] !== null && !Array.isArray(source[key]) && typeof result[key] === "object" && result[key] !== null) {
356
- result[key] = deepMerge(result[key], source[key]);
357
- } else {
358
- result[key] = source[key];
359
- }
360
- }
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
+ );
361
229
  }
362
- return result;
363
- }
364
- function createLocale(overrides) {
365
- if (!overrides) {
366
- 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
+ );
367
241
  }
368
- return deepMerge(defaultLocale, overrides);
369
- }
370
- function interpolate(template, values) {
371
- return template.replace(/\{(\w+)\}/g, (match, key) => {
372
- return values[key] !== void 0 ? String(values[key]) : match;
373
- });
374
- }
375
-
376
- // src/utils/validation.ts
377
- var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
378
- var PHONE_REGEX = /^\+?[1-9]\d{1,14}$/;
379
- var USERNAME_REGEX = /^[a-zA-Z0-9_-]{3,30}$/;
380
- function validateEmail(email, locale) {
381
- const messages = locale?.validation || defaultLocale.validation;
382
- if (!email) {
383
- return { field: "email", message: messages.emailRequired };
384
- }
385
- if (!EMAIL_REGEX.test(email)) {
386
- return { field: "email", message: messages.emailInvalid };
387
- }
388
- return null;
389
- }
390
- function validatePassword(password, options = {}) {
391
- const {
392
- minLength = 8,
393
- requireUppercase = true,
394
- requireLowercase = true,
395
- requireNumber = true,
396
- requireSpecial = false,
397
- locale
398
- } = options;
399
- const messages = locale?.validation || defaultLocale.validation;
400
- if (!password) {
401
- return { field: "password", message: messages.passwordRequired };
402
- }
403
- if (password.length < minLength) {
404
- return {
405
- field: "password",
406
- message: interpolate(messages.passwordTooShort, { min: minLength.toString() })
407
- };
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
+ );
408
254
  }
409
- if (requireUppercase && !/[A-Z]/.test(password)) {
410
- return {
411
- field: "password",
412
- message: messages.passwordRequireUppercase
413
- };
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
+ );
414
267
  }
415
- if (requireLowercase && !/[a-z]/.test(password)) {
416
- return {
417
- field: "password",
418
- message: messages.passwordRequireLowercase
419
- };
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
+ );
420
280
  }
421
- if (requireNumber && !/\d/.test(password)) {
422
- 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
+ );
423
292
  }
424
- if (requireSpecial && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
425
- return {
426
- field: "password",
427
- message: messages.passwordRequireSpecial
428
- };
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
+ );
429
304
  }
430
- return null;
431
- }
432
- function validatePhone(phone, locale) {
433
- const messages = locale?.validation || defaultLocale.validation;
434
- if (!phone) {
435
- return { field: "phone", message: messages.phoneRequired };
436
- }
437
- if (!PHONE_REGEX.test(phone)) {
438
- return {
439
- field: "phone",
440
- message: messages.phoneInvalid
441
- };
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
+ );
442
317
  }
443
- return null;
444
- }
445
- function validateUsername(username, locale) {
446
- const messages = locale?.validation || defaultLocale.validation;
447
- if (!username) {
448
- return { field: "username", message: messages.usernameRequired };
449
- }
450
- if (!USERNAME_REGEX.test(username)) {
451
- return {
452
- field: "username",
453
- message: messages.usernameInvalid
454
- };
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
+ );
455
330
  }
456
- return null;
457
- }
458
- function validate2FACode(code, locale) {
459
- const messages = locale?.validation || defaultLocale.validation;
460
- if (!code) {
461
- 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
+ );
462
343
  }
463
- if (!/^\d{6}$/.test(code)) {
464
- 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
+ );
465
356
  }
466
- return null;
467
- }
468
- function validateRequired(value, fieldName, locale) {
469
- const messages = locale?.validation || defaultLocale.validation;
470
- if (!value || typeof value === "string" && !value.trim()) {
471
- return {
472
- field: fieldName,
473
- message: interpolate(messages.fieldRequired, { field: fieldName })
474
- };
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
+ );
475
368
  }
476
- return null;
477
- }
478
-
479
- // src/utils/tokens.ts
480
- var TOKEN_KEY = "authsome_token";
481
- var REFRESH_TOKEN_KEY = "authsome_refresh_token";
482
- var TokenManager = class {
483
- constructor(storage = new LocalStorageAdapter()) {
484
- 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
+ );
485
381
  }
486
382
  /**
487
- * Get access token
383
+ * Disable MFA
384
+ * DELETE /v1/auth/mfa/enrollment
488
385
  */
489
- async getToken() {
490
- 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
+ );
491
394
  }
492
395
  /**
493
- * Set access token
396
+ * Regenerate MFA recovery codes
397
+ * POST /v1/auth/mfa/recovery/regenerate
494
398
  */
495
- async setToken(token) {
496
- 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
+ );
497
407
  }
498
408
  /**
499
- * Remove access token
409
+ * Verify MFA recovery code
410
+ * POST /v1/auth/mfa/recovery/verify
500
411
  */
501
- async removeToken() {
502
- 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
+ );
503
419
  }
504
420
  /**
505
- * Get refresh token
421
+ * Send SMS verification code
422
+ * POST /v1/auth/mfa/sms/send
506
423
  */
507
- async getRefreshToken() {
508
- 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
+ );
509
432
  }
510
433
  /**
511
- * Set refresh token
434
+ * Verify SMS code
435
+ * POST /v1/auth/mfa/sms/verify
512
436
  */
513
- async setRefreshToken(token) {
514
- 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
+ );
515
445
  }
516
446
  /**
517
- * Remove refresh token
447
+ * Verify MFA code
448
+ * POST /v1/auth/mfa/verify
518
449
  */
519
- async removeRefreshToken() {
520
- 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
+ );
521
457
  }
522
458
  /**
523
- * Clear all tokens
459
+ * List organizations
460
+ * GET /v1/auth/orgs
524
461
  */
525
- async clearTokens() {
526
- await this.removeToken();
527
- 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
+ );
528
470
  }
529
471
  /**
530
- * Check if token is expired
472
+ * Create organization
473
+ * POST /v1/auth/orgs
531
474
  */
532
- isTokenExpired(token) {
533
- try {
534
- const payload = this.decodeToken(token);
535
- if (!payload.exp) return false;
536
- const expiresAt = payload.exp * 1e3;
537
- const now = Date.now();
538
- return expiresAt - now < 6e4;
539
- } catch {
540
- return true;
541
- }
475
+ async createOrganization(body, token) {
476
+ const path = "/v1/auth/orgs";
477
+ return this.request(
478
+ "POST",
479
+ path,
480
+ body,
481
+ token
482
+ );
542
483
  }
543
484
  /**
544
- * Decode JWT token (without verification)
485
+ * Check slug availability
486
+ * GET /v1/auth/orgs/check-slug
545
487
  */
546
- decodeToken(token) {
547
- const parts = token.split(".");
548
- if (parts.length !== 3) {
549
- throw new Error("Invalid token format");
550
- }
551
- const payload = parts[1];
552
- const decoded = atob(payload);
553
- 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
+ );
554
496
  }
555
- };
556
-
557
- // src/utils/cookies.ts
558
- function parseCookie(setCookieHeader) {
559
- if (!setCookieHeader) return null;
560
- const parts = setCookieHeader.split(";").map((p) => p.trim());
561
- if (parts.length === 0) return null;
562
- const [nameValue] = parts;
563
- const [name, value] = nameValue.split("=");
564
- if (!name || value === void 0) return null;
565
- const cookieData = { name, value };
566
- const options = {};
567
- for (let i = 1; i < parts.length; i++) {
568
- const part = parts[i];
569
- const lowerPart = part.toLowerCase();
570
- if (lowerPart === "httponly") {
571
- options.httpOnly = true;
572
- } else if (lowerPart === "secure") {
573
- options.secure = true;
574
- } else if (lowerPart.startsWith("path=")) {
575
- options.path = part.substring(5);
576
- } else if (lowerPart.startsWith("domain=")) {
577
- options.domain = part.substring(7);
578
- } else if (lowerPart.startsWith("max-age=")) {
579
- const maxAge = parseInt(part.substring(8), 10);
580
- if (!isNaN(maxAge)) {
581
- options.maxAge = maxAge;
582
- }
583
- } else if (lowerPart.startsWith("expires=")) {
584
- const expiresStr = part.substring(8);
585
- const expiresDate = new Date(expiresStr);
586
- if (!isNaN(expiresDate.getTime())) {
587
- options.expires = expiresDate;
588
- }
589
- } else if (lowerPart.startsWith("samesite=")) {
590
- const sameSiteValue = lowerPart.substring(9);
591
- if (sameSiteValue === "strict" || sameSiteValue === "lax" || sameSiteValue === "none") {
592
- options.sameSite = sameSiteValue;
593
- }
594
- }
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
+ );
595
509
  }
596
- if (Object.keys(options).length > 0) {
597
- 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
+ );
598
522
  }
599
- return cookieData;
600
- }
601
- function extractCookiesFromHeaders(setCookieHeaders) {
602
- const headers = Array.isArray(setCookieHeaders) ? setCookieHeaders : [setCookieHeaders];
603
- const cookies = [];
604
- for (const header of headers) {
605
- const cookie = parseCookie(header);
606
- if (cookie) {
607
- cookies.push(cookie);
608
- }
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
+ );
609
535
  }
610
- return cookies;
611
- }
612
- function serializeCookie(cookie) {
613
- const parts = [`${cookie.name}=${cookie.value}`];
614
- if (cookie.options) {
615
- const opts = cookie.options;
616
- if (opts.path) {
617
- parts.push(`Path=${opts.path}`);
618
- }
619
- if (opts.domain) {
620
- parts.push(`Domain=${opts.domain}`);
621
- }
622
- if (opts.expires) {
623
- parts.push(`Expires=${opts.expires.toUTCString()}`);
624
- }
625
- if (opts.maxAge !== void 0) {
626
- parts.push(`Max-Age=${opts.maxAge}`);
627
- }
628
- if (opts.httpOnly) {
629
- parts.push("HttpOnly");
630
- }
631
- if (opts.secure) {
632
- parts.push("Secure");
633
- }
634
- if (opts.sameSite) {
635
- const sameSite = opts.sameSite.charAt(0).toUpperCase() + opts.sameSite.slice(1);
636
- parts.push(`SameSite=${sameSite}`);
637
- }
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
+ );
638
548
  }
639
- return parts.join("; ");
640
- }
641
- function parseCookieOptions(cookieHeader) {
642
- const cookies = {};
643
- if (!cookieHeader) return cookies;
644
- const pairs = cookieHeader.split(";").map((p) => p.trim());
645
- for (const pair of pairs) {
646
- const [name, value] = pair.split("=");
647
- if (name && value !== void 0) {
648
- cookies[name.trim()] = value.trim();
649
- }
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
+ );
650
561
  }
651
- return cookies;
652
- }
653
- function serializeCookies(cookies) {
654
- return Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join("; ");
655
- }
656
-
657
- // src/adapters/base-provider.ts
658
- var BaseAuthProvider = class {
659
- constructor() {
660
- this.config = {};
661
- 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
+ );
662
574
  }
663
575
  /**
664
- * Initialize the provider
576
+ * Create invitation
577
+ * POST /v1/auth/orgs/{orgId}/invitations
665
578
  */
666
- async initialize(config) {
667
- this.config = config;
668
- 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
+ );
669
587
  }
670
588
  /**
671
- * Ensure provider is initialized
589
+ * List members
590
+ * GET /v1/auth/orgs/{orgId}/members
672
591
  */
673
- ensureInitialized() {
674
- if (!this.initialized) {
675
- throw new Error(`Provider ${this.name} is not initialized`);
676
- }
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
+ );
677
600
  }
678
601
  /**
679
- * Make HTTP request
602
+ * Add member
603
+ * POST /v1/auth/orgs/{orgId}/members
680
604
  */
681
- async request(url, options = {}) {
682
- const response = await fetch(url, {
683
- ...options,
684
- headers: {
685
- "Content-Type": "application/json",
686
- ...options.headers
687
- }
688
- });
689
- if (!response.ok) {
690
- const error = await response.json().catch(() => ({
691
- message: response.statusText
692
- }));
693
- throw error;
694
- }
695
- 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
+ );
696
613
  }
697
614
  /**
698
- * Normalize error to AuthError
615
+ * Update member role
616
+ * PATCH /v1/auth/orgs/{orgId}/members/{memberId}
699
617
  */
700
- normalizeError(error) {
701
- 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
+ );
702
626
  }
703
- };
704
-
705
- // src/client.ts
706
- var AuthClient = class {
707
- // Expose adapter for accessing provider-specific methods
708
- get adapter() {
709
- 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
+ );
710
639
  }
711
- constructor(config) {
712
- this.provider = config.provider;
713
- this.autoRefresh = config.autoRefresh ?? true;
714
- this.refreshInterval = config.refreshInterval ?? 5 * 60 * 1e3;
715
- this.state = new Observable({
716
- state: "loading" /* LOADING */,
717
- user: null,
718
- session: null,
719
- error: null,
720
- isAuthenticated: false,
721
- isLoading: true
722
- });
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
+ );
723
652
  }
724
653
  /**
725
- * Initialize the auth client
654
+ * Create team
655
+ * POST /v1/auth/orgs/{orgId}/teams
726
656
  */
727
- async initialize() {
728
- try {
729
- const user = await this.provider.getCurrentUser();
730
- const session = await this.provider.getCurrentSession();
731
- if (user && session) {
732
- this.updateState({
733
- state: "authenticated" /* AUTHENTICATED */,
734
- user,
735
- session,
736
- error: null,
737
- isAuthenticated: true,
738
- isLoading: false
739
- });
740
- if (this.autoRefresh) {
741
- this.startAutoRefresh();
742
- }
743
- } else {
744
- this.updateState({
745
- state: "unauthenticated" /* UNAUTHENTICATED */,
746
- user: null,
747
- session: null,
748
- error: null,
749
- isAuthenticated: false,
750
- isLoading: false
751
- });
752
- }
753
- } catch (error) {
754
- this.handleError(error);
755
- }
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
+ );
756
665
  }
757
666
  /**
758
- * Sign in with credentials
667
+ * Get team
668
+ * GET /v1/auth/orgs/{orgId}/teams/{teamId}
759
669
  */
760
- async signIn(request) {
761
- try {
762
- this.setLoading();
763
- const response = await this.provider.signIn(request);
764
- if (response.requiresTwoFactor) {
765
- this.updateState({
766
- state: "unauthenticated" /* UNAUTHENTICATED */,
767
- user: response.user,
768
- session: null,
769
- error: null,
770
- isAuthenticated: false,
771
- isLoading: false
772
- });
773
- return;
774
- }
775
- this.updateState({
776
- state: "authenticated" /* AUTHENTICATED */,
777
- user: response.user,
778
- session: response.session,
779
- error: null,
780
- isAuthenticated: true,
781
- isLoading: false
782
- });
783
- if (this.autoRefresh) {
784
- this.startAutoRefresh();
785
- }
786
- } catch (error) {
787
- this.handleError(error);
788
- }
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
+ );
789
678
  }
790
679
  /**
791
- * Sign up with credentials
680
+ * Update team
681
+ * PATCH /v1/auth/orgs/{orgId}/teams/{teamId}
792
682
  */
793
- async signUp(request) {
794
- try {
795
- this.setLoading();
796
- const response = await this.provider.signUp(request);
797
- this.updateState({
798
- state: "authenticated" /* AUTHENTICATED */,
799
- user: response.user,
800
- session: response.session,
801
- error: null,
802
- isAuthenticated: true,
803
- isLoading: false
804
- });
805
- if (this.autoRefresh) {
806
- this.startAutoRefresh();
807
- }
808
- } catch (error) {
809
- this.handleError(error);
810
- }
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
+ );
811
691
  }
812
692
  /**
813
- * Sign out
693
+ * Delete team
694
+ * DELETE /v1/auth/orgs/{orgId}/teams/{teamId}
814
695
  */
815
- async signOut() {
816
- try {
817
- this.stopAutoRefresh();
818
- await this.provider.signOut();
819
- this.updateState({
820
- state: "unauthenticated" /* UNAUTHENTICATED */,
821
- user: null,
822
- session: null,
823
- error: null,
824
- isAuthenticated: false,
825
- isLoading: false
826
- });
827
- } catch (error) {
828
- this.handleError(error);
829
- }
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
+ );
830
704
  }
831
705
  /**
832
- * 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
833
721
  */
834
- async updateUser(request) {
835
- try {
836
- const user = await this.provider.updateUser(request);
837
- const currentState = this.state.getValue();
838
- this.updateState({
839
- ...currentState,
840
- user
841
- });
842
- } catch (error) {
843
- this.handleError(error);
844
- }
722
+ async passkeyLoginBegin(body) {
723
+ const path = "/v1/auth/passkeys/login/begin";
724
+ return this.request(
725
+ "POST",
726
+ path,
727
+ body
728
+ );
845
729
  }
846
730
  /**
847
- * Change password
731
+ * Complete passkey login
732
+ * POST /v1/auth/passkeys/login/finish
848
733
  */
849
- async changePassword(request) {
850
- try {
851
- await this.provider.changePassword(request);
852
- } catch (error) {
853
- throw this.provider.normalizeError(error);
854
- }
734
+ async passkeyLoginFinish(body) {
735
+ const path = "/v1/auth/passkeys/login/finish";
736
+ return this.request(
737
+ "POST",
738
+ path,
739
+ body
740
+ );
855
741
  }
856
742
  /**
857
- * Request password reset
743
+ * Begin passkey registration
744
+ * POST /v1/auth/passkeys/register/begin
858
745
  */
859
- async requestPasswordReset(request) {
860
- try {
861
- await this.provider.requestPasswordReset(request);
862
- } catch (error) {
863
- throw this.provider.normalizeError(error);
864
- }
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
+ );
865
754
  }
866
755
  /**
867
- * Confirm password reset
756
+ * Complete passkey registration
757
+ * POST /v1/auth/passkeys/register/finish
868
758
  */
869
- async confirmPasswordReset(request) {
870
- try {
871
- await this.provider.confirmPasswordReset(request);
872
- } catch (error) {
873
- throw this.provider.normalizeError(error);
874
- }
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
+ );
767
+ }
768
+ /**
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
+ );
875
780
  }
876
781
  /**
877
- * Get OAuth sign in URL
782
+ * Refresh tokens
783
+ * POST /v1/auth/refresh
878
784
  */
879
- async getOAuthUrl(request) {
880
- 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
+ );
881
792
  }
882
793
  /**
883
- * Handle OAuth callback
794
+ * Reset password
795
+ * POST /v1/auth/reset-password
884
796
  */
885
- async handleOAuthCallback(request) {
886
- try {
887
- this.setLoading();
888
- const response = await this.provider.oauthCallback(request);
889
- this.updateState({
890
- state: "authenticated" /* AUTHENTICATED */,
891
- user: response.user,
892
- session: response.session,
893
- error: null,
894
- isAuthenticated: true,
895
- isLoading: false
896
- });
897
- if (this.autoRefresh) {
898
- this.startAutoRefresh();
899
- }
900
- } catch (error) {
901
- this.handleError(error);
902
- }
797
+ async resetPassword(body) {
798
+ const path = "/v1/auth/reset-password";
799
+ return this.request(
800
+ "POST",
801
+ path,
802
+ body
803
+ );
903
804
  }
904
805
  /**
905
- * Get available OAuth providers
806
+ * List roles
807
+ * GET /v1/auth/roles
906
808
  */
907
- async getOAuthProviders() {
908
- 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
+ );
909
817
  }
910
818
  /**
911
- * Send magic link
819
+ * Create role
820
+ * POST /v1/auth/roles
912
821
  */
913
- async sendMagicLink(request) {
914
- try {
915
- await this.provider.sendMagicLink(request);
916
- } catch (error) {
917
- throw this.provider.normalizeError(error);
918
- }
822
+ async createRole(body, token) {
823
+ const path = "/v1/auth/roles";
824
+ return this.request(
825
+ "POST",
826
+ path,
827
+ body,
828
+ token
829
+ );
919
830
  }
920
831
  /**
921
- * Verify magic link
832
+ * Get role
833
+ * GET /v1/auth/roles/{roleId}
922
834
  */
923
- async verifyMagicLink(request) {
924
- try {
925
- this.setLoading();
926
- const response = await this.provider.verifyMagicLink(request);
927
- this.updateState({
928
- state: "authenticated" /* AUTHENTICATED */,
929
- user: response.user,
930
- session: response.session,
931
- error: null,
932
- isAuthenticated: true,
933
- isLoading: false
934
- });
935
- if (this.autoRefresh) {
936
- this.startAutoRefresh();
937
- }
938
- } catch (error) {
939
- this.handleError(error);
940
- }
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
+ );
941
843
  }
942
844
  /**
943
- * Send phone verification code
845
+ * Update role
846
+ * PATCH /v1/auth/roles/{roleId}
944
847
  */
945
- async sendPhoneCode(request) {
946
- try {
947
- await this.provider.sendPhoneCode(request);
948
- } catch (error) {
949
- throw this.provider.normalizeError(error);
950
- }
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
+ );
951
856
  }
952
857
  /**
953
- * Verify phone code
858
+ * Delete role
859
+ * DELETE /v1/auth/roles/{roleId}
954
860
  */
955
- async verifyPhoneCode(request) {
956
- try {
957
- this.setLoading();
958
- const response = await this.provider.verifyPhoneCode(request);
959
- this.updateState({
960
- state: "authenticated" /* AUTHENTICATED */,
961
- user: response.user,
962
- session: response.session,
963
- error: null,
964
- isAuthenticated: true,
965
- isLoading: false
966
- });
967
- if (this.autoRefresh) {
968
- this.startAutoRefresh();
969
- }
970
- } catch (error) {
971
- this.handleError(error);
972
- }
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
+ );
973
869
  }
974
870
  /**
975
- * Setup 2FA
871
+ * Assign role to user
872
+ * POST /v1/auth/roles/{roleId}/assign
976
873
  */
977
- async setupTwoFactor(request) {
978
- 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
+ );
979
882
  }
980
883
  /**
981
- * Verify 2FA code
884
+ * List role permissions
885
+ * GET /v1/auth/roles/{roleId}/permissions
982
886
  */
983
- async verifyTwoFactor(request) {
984
- try {
985
- this.setLoading();
986
- const response = await this.provider.verifyTwoFactor(request);
987
- this.updateState({
988
- state: "authenticated" /* AUTHENTICATED */,
989
- user: response.user,
990
- session: response.session,
991
- error: null,
992
- isAuthenticated: true,
993
- isLoading: false
994
- });
995
- if (this.autoRefresh) {
996
- this.startAutoRefresh();
997
- }
998
- } catch (error) {
999
- this.handleError(error);
1000
- }
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
+ );
1001
895
  }
1002
896
  /**
1003
- * Disable 2FA
897
+ * Add permission to role
898
+ * POST /v1/auth/roles/{roleId}/permissions
1004
899
  */
1005
- async disableTwoFactor() {
1006
- 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
+ );
1007
908
  }
1008
909
  /**
1009
- * Get 2FA status
910
+ * Remove permission from role
911
+ * DELETE /v1/auth/roles/{roleId}/permissions/{permissionId}
1010
912
  */
1011
- async getTwoFactorStatus() {
1012
- 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
+ );
1013
921
  }
1014
922
  /**
1015
- * Register passkey
923
+ * Unassign role from user
924
+ * POST /v1/auth/roles/{roleId}/unassign
1016
925
  */
1017
- async registerPasskey(request) {
1018
- 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
+ );
1019
934
  }
1020
935
  /**
1021
- * Authenticate with passkey
936
+ * List sessions
937
+ * GET /v1/auth/sessions
1022
938
  */
1023
- async authenticatePasskey(request) {
1024
- try {
1025
- this.setLoading();
1026
- const response = await this.provider.authenticatePasskey(request);
1027
- this.updateState({
1028
- state: "authenticated" /* AUTHENTICATED */,
1029
- user: response.user,
1030
- session: response.session,
1031
- error: null,
1032
- isAuthenticated: true,
1033
- isLoading: false
1034
- });
1035
- if (this.autoRefresh) {
1036
- this.startAutoRefresh();
1037
- }
1038
- } catch (error) {
1039
- this.handleError(error);
1040
- }
939
+ async listSessions(token) {
940
+ const path = "/v1/auth/sessions";
941
+ return this.request(
942
+ "GET",
943
+ path,
944
+ void 0,
945
+ token
946
+ );
1041
947
  }
1042
948
  /**
1043
- * List passkeys
949
+ * Revoke session
950
+ * DELETE /v1/auth/sessions/{sessionId}
1044
951
  */
1045
- async listPasskeys() {
1046
- 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
+ );
1047
960
  }
1048
961
  /**
1049
- * Delete passkey
962
+ * Sign in
963
+ * POST /v1/auth/signin
1050
964
  */
1051
- async deletePasskey(credentialId) {
1052
- 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
+ );
1053
972
  }
1054
973
  /**
1055
- * Get all organizations the user belongs to
1056
- * 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
1057
989
  */
1058
- async getOrganizations() {
1059
- if (!this.provider.getOrganizations) {
1060
- throw this.createUnsupportedError("Organization support");
1061
- }
1062
- 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
+ );
1063
997
  }
1064
998
  /**
1065
- * Get the currently active organization
1066
- * Only available if the provider supports organizations
999
+ * Start OAuth flow
1000
+ * POST /v1/auth/social/{provider}
1067
1001
  */
1068
- async getActiveOrganization() {
1069
- if (!this.provider.getActiveOrganization) {
1070
- throw this.createUnsupportedError("Organization support");
1071
- }
1072
- 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
+ );
1073
1009
  }
1074
1010
  /**
1075
- * Set the active organization and refresh user state
1076
- * Only available if the provider supports organizations
1011
+ * OAuth callback
1012
+ * GET /v1/auth/social/{provider}/callback
1077
1013
  */
1078
- async setActiveOrganization(organizationId) {
1079
- if (!this.provider.setActiveOrganization) {
1080
- throw this.createUnsupportedError("Organization support");
1081
- }
1082
- await this.provider.setActiveOrganization(organizationId);
1083
- 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
+ );
1084
1021
  }
1085
1022
  /**
1086
- * Get organization memberships with roles and permissions
1087
- * Only available if the provider supports organizations
1023
+ * SSO SAML ACS endpoint
1024
+ * POST /v1/auth/sso/{provider}/acs
1088
1025
  */
1089
- async getOrganizationMemberships() {
1090
- if (!this.provider.getOrganizationMemberships) {
1091
- throw this.createUnsupportedError("Organization memberships");
1092
- }
1093
- 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
+ );
1094
1033
  }
1095
1034
  /**
1096
- * Check if the provider supports organizations
1035
+ * SSO callback (OIDC)
1036
+ * POST /v1/auth/sso/{provider}/callback
1097
1037
  */
1098
- supportsOrganizations() {
1099
- 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
+ );
1100
1045
  }
1101
1046
  /**
1102
- * Refresh session
1047
+ * Start SSO login flow
1048
+ * POST /v1/auth/sso/{provider}/login
1103
1049
  */
1104
- async refreshSession() {
1105
- try {
1106
- const session = await this.provider.refreshSession();
1107
- const currentState = this.state.getValue();
1108
- this.updateState({
1109
- ...currentState,
1110
- session
1111
- });
1112
- } catch (error) {
1113
- console.warn("[AuthClient] Session refresh failed:", error);
1114
- }
1050
+ async startSSOLogin(provider, body) {
1051
+ const path = `/v1/auth/sso/${provider}/login`;
1052
+ return this.request(
1053
+ "POST",
1054
+ path,
1055
+ body
1056
+ );
1115
1057
  }
1116
1058
  /**
1117
- * Get current user
1059
+ * List user roles
1060
+ * GET /v1/auth/users/{userId}/roles
1118
1061
  */
1119
- getUser() {
1120
- 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
+ );
1121
1070
  }
1122
1071
  /**
1123
- * Get current session
1072
+ * Verify email
1073
+ * POST /v1/auth/verify-email
1124
1074
  */
1125
- getSession() {
1126
- 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
+ );
1127
1082
  }
1128
1083
  /**
1129
- * Check if authenticated
1084
+ * List webhooks
1085
+ * GET /v1/auth/webhooks
1130
1086
  */
1131
- isAuthenticated() {
1132
- 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
+ );
1133
1095
  }
1134
1096
  /**
1135
- * Get current error
1097
+ * Create webhook
1098
+ * POST /v1/auth/webhooks
1136
1099
  */
1137
- getError() {
1138
- 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
+ );
1139
1108
  }
1140
1109
  /**
1141
- * Clear error
1110
+ * Get webhook
1111
+ * GET /v1/auth/webhooks/{webhookId}
1142
1112
  */
1143
- clearError() {
1144
- const currentState = this.state.getValue();
1145
- this.updateState({
1146
- ...currentState,
1147
- error: null
1148
- });
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
+ );
1149
1121
  }
1150
1122
  /**
1151
- * Subscribe to auth state changes
1123
+ * Update webhook
1124
+ * PATCH /v1/auth/webhooks/{webhookId}
1152
1125
  */
1153
- subscribe(listener) {
1154
- 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
+ );
1155
1134
  }
1156
1135
  /**
1157
- * Cleanup resources
1136
+ * Delete webhook
1137
+ * DELETE /v1/auth/webhooks/{webhookId}
1158
1138
  */
1159
- destroy() {
1160
- this.stopAutoRefresh();
1161
- this.state.clearListeners();
1162
- }
1163
- // Private methods
1164
- updateState(newState) {
1165
- this.state.setValue(newState);
1166
- }
1167
- setLoading() {
1168
- const currentState = this.state.getValue();
1169
- this.updateState({
1170
- ...currentState,
1171
- state: "loading" /* LOADING */,
1172
- isLoading: true,
1173
- error: null
1174
- });
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
+ );
1175
1147
  }
1176
- handleError(error) {
1177
- const authError = this.provider.normalizeError(error);
1178
- const currentState = this.state.getValue();
1179
- this.updateState({
1180
- ...currentState,
1181
- state: "error" /* ERROR */,
1182
- error: authError,
1183
- 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
1184
1163
  });
1185
- throw authError;
1186
- }
1187
- startAutoRefresh() {
1188
- this.stopAutoRefresh();
1189
- this.refreshTimer = setInterval(() => {
1190
- this.refreshSession();
1191
- }, this.refreshInterval);
1192
- }
1193
- stopAutoRefresh() {
1194
- if (this.refreshTimer) {
1195
- clearInterval(this.refreshTimer);
1196
- 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
+ );
1197
1174
  }
1175
+ if (response.status === 204) {
1176
+ return void 0;
1177
+ }
1178
+ return response.json();
1198
1179
  }
1199
- createUnsupportedError(feature) {
1200
- return {
1201
- name: "AuthError",
1202
- message: `${feature} is not available with this auth provider`,
1203
- type: "unknown_error" /* UNKNOWN_ERROR */
1204
- };
1180
+ };
1181
+ var AuthClientError = class extends Error {
1182
+ code;
1183
+ constructor(message, code) {
1184
+ super(message);
1185
+ this.name = "AuthClientError";
1186
+ this.code = code;
1205
1187
  }
1206
1188
  };
1207
1189
 
1208
- // src/flows/types.ts
1209
- var FlowStep = /* @__PURE__ */ ((FlowStep2) => {
1210
- FlowStep2["SIGN_IN"] = "sign_in";
1211
- FlowStep2["SIGN_UP"] = "sign_up";
1212
- FlowStep2["EMAIL_PASSWORD_SIGN_IN"] = "email_password_sign_in";
1213
- FlowStep2["EMAIL_PASSWORD_SIGN_UP"] = "email_password_sign_up";
1214
- FlowStep2["OAUTH_SELECT"] = "oauth_select";
1215
- FlowStep2["OAUTH_CALLBACK"] = "oauth_callback";
1216
- FlowStep2["MAGIC_LINK_REQUEST"] = "magic_link_request";
1217
- FlowStep2["MAGIC_LINK_VERIFY"] = "magic_link_verify";
1218
- FlowStep2["MAGIC_LINK_SENT"] = "magic_link_sent";
1219
- FlowStep2["PHONE_REQUEST"] = "phone_request";
1220
- FlowStep2["PHONE_VERIFY"] = "phone_verify";
1221
- FlowStep2["USERNAME_SIGN_IN"] = "username_sign_in";
1222
- FlowStep2["USERNAME_SIGN_UP"] = "username_sign_up";
1223
- FlowStep2["PASSKEY_REGISTER"] = "passkey_register";
1224
- FlowStep2["PASSKEY_AUTHENTICATE"] = "passkey_authenticate";
1225
- FlowStep2["MFA_REQUIRED"] = "mfa_required";
1226
- FlowStep2["MFA_SETUP"] = "mfa_setup";
1227
- FlowStep2["MFA_VERIFY"] = "mfa_verify";
1228
- FlowStep2["MFA_SELECT_METHOD"] = "mfa_select_method";
1229
- FlowStep2["EMAIL_VERIFICATION_REQUIRED"] = "email_verification_required";
1230
- FlowStep2["EMAIL_VERIFICATION_SENT"] = "email_verification_sent";
1231
- FlowStep2["PHONE_VERIFICATION_REQUIRED"] = "phone_verification_required";
1232
- FlowStep2["PASSWORD_RESET_REQUEST"] = "password_reset_request";
1233
- FlowStep2["PASSWORD_RESET_SENT"] = "password_reset_sent";
1234
- FlowStep2["PASSWORD_RESET_CONFIRM"] = "password_reset_confirm";
1235
- FlowStep2["PASSWORD_CHANGE"] = "password_change";
1236
- FlowStep2["PROFILE_UPDATE"] = "profile_update";
1237
- FlowStep2["PROFILE_COMPLETE"] = "profile_complete";
1238
- FlowStep2["SUCCESS"] = "success";
1239
- FlowStep2["ERROR"] = "error";
1240
- FlowStep2["CANCELLED"] = "cancelled";
1241
- return FlowStep2;
1242
- })(FlowStep || {});
1243
- var FlowConfigType = /* @__PURE__ */ ((FlowConfigType2) => {
1244
- FlowConfigType2["SIMPLE_SIGN_IN"] = "simple_sign_in";
1245
- FlowConfigType2["SIMPLE_SIGN_UP"] = "simple_sign_up";
1246
- FlowConfigType2["SIGN_UP_WITH_EMAIL_VERIFICATION"] = "sign_up_with_email_verification";
1247
- FlowConfigType2["SIGN_IN_WITH_MFA"] = "sign_in_with_mfa";
1248
- FlowConfigType2["OAUTH_SIGN_IN"] = "oauth_sign_in";
1249
- FlowConfigType2["MAGIC_LINK_FLOW"] = "magic_link_flow";
1250
- FlowConfigType2["PHONE_AUTH_FLOW"] = "phone_auth_flow";
1251
- FlowConfigType2["COMPLETE_SIGN_UP_FLOW"] = "complete_sign_up_flow";
1252
- FlowConfigType2["SECURE_SIGN_IN_FLOW"] = "secure_sign_in_flow";
1253
- FlowConfigType2["PASSWORD_RESET_FLOW"] = "password_reset_flow";
1254
- FlowConfigType2["EMAIL_VERIFICATION_FLOW"] = "email_verification_flow";
1255
- FlowConfigType2["CUSTOM"] = "custom";
1256
- return FlowConfigType2;
1257
- })(FlowConfigType || {});
1258
- var FlowAction = /* @__PURE__ */ ((FlowAction2) => {
1259
- FlowAction2["START"] = "start";
1260
- FlowAction2["NEXT"] = "next";
1261
- FlowAction2["BACK"] = "back";
1262
- FlowAction2["CANCEL"] = "cancel";
1263
- FlowAction2["ERROR"] = "error";
1264
- FlowAction2["RESET"] = "reset";
1265
- return FlowAction2;
1266
- })(FlowAction || {});
1267
-
1268
- // src/flows/engine.ts
1269
- var FlowEngine = class {
1270
- constructor(config, initialState) {
1271
- this.history = [];
1272
- this.config = config;
1273
- this.state = {
1274
- currentStep: config.initialStep,
1275
- ...initialState
1276
- };
1277
- 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);
1278
1201
  }
1279
1202
  /**
1280
- * 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.
1281
1207
  */
1282
- getState() {
1283
- 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);
1284
1213
  }
1285
1214
  /**
1286
- * 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`.
1287
1219
  */
1288
- getCurrentStep() {
1289
- return this.state.currentStep;
1220
+ async mfaChallenge(body) {
1221
+ return super.challengeMFA(body);
1290
1222
  }
1291
1223
  /**
1292
- * 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.
1293
1227
  */
1294
- isStepAllowed(step) {
1295
- return this.config.allowedSteps.includes(step);
1228
+ async verifyRecoveryCode(body) {
1229
+ const req = typeof body === "string" ? { code: body } : body;
1230
+ return super.verifyRecoveryCode(req);
1296
1231
  }
1297
1232
  /**
1298
- * 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.
1299
1236
  */
1300
- async transition(event) {
1301
- const { action, data, error } = event;
1302
- switch (action) {
1303
- case "start":
1304
- return this.handleStart(data);
1305
- case "next":
1306
- return this.handleNext(data);
1307
- case "back":
1308
- return this.handleBack();
1309
- case "cancel":
1310
- return this.handleCancel();
1311
- case "error":
1312
- return this.handleError(error);
1313
- case "reset":
1314
- return this.handleReset();
1315
- default:
1316
- throw new AuthError(
1317
- `Unknown flow action: ${action}`,
1318
- "validation_error" /* VALIDATION_ERROR */
1319
- );
1320
- }
1237
+ async sendSMSCodeForMFA(token) {
1238
+ return super.sendSMSCode({}, token);
1321
1239
  }
1322
1240
  /**
1323
- * 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.
1324
1244
  */
1325
- handleStart(data) {
1326
- this.state = {
1327
- currentStep: this.config.initialStep,
1328
- ...data
1329
- };
1330
- this.history = [this.state.currentStep];
1331
- if (this.config.onStepChange) {
1332
- this.config.onStepChange(this.state.currentStep, this.state);
1333
- }
1334
- return this.getState();
1245
+ async verifySMSCodeForMFA(code, token) {
1246
+ return super.verifySMSCode({ code }, token);
1335
1247
  }
1336
1248
  /**
1337
- * 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.
1338
1253
  */
1339
- handleNext(data) {
1340
- this.state = {
1341
- ...this.state,
1342
- ...data,
1343
- previousStep: this.state.currentStep
1344
- };
1345
- const transitionConfig = this.config.transitions[this.state.currentStep];
1346
- if (!transitionConfig) {
1347
- throw new AuthError(
1348
- `No transition configured for step: ${this.state.currentStep}`,
1349
- "validation_error" /* VALIDATION_ERROR */
1350
- );
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);
1351
1258
  }
1352
- if (transitionConfig.conditions) {
1353
- for (const condition of transitionConfig.conditions) {
1354
- if (condition.when(this.state)) {
1355
- return this.moveToStep(condition.then);
1356
- }
1357
- }
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);
1358
1266
  }
1359
- if (transitionConfig.onSuccess) {
1360
- return this.moveToStep(transitionConfig.onSuccess);
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);
1361
1285
  }
1362
- throw new AuthError(
1363
- `No valid transition found for step: ${this.state.currentStep}`,
1364
- "validation_error" /* VALIDATION_ERROR */
1365
- );
1286
+ };
1287
+ })();
1288
+ function defaultStorage() {
1289
+ try {
1290
+ if (typeof window !== "undefined" && window.localStorage) {
1291
+ return window.localStorage;
1292
+ }
1293
+ } catch {
1366
1294
  }
1367
- /**
1368
- * Go back to previous step
1369
- */
1370
- handleBack() {
1371
- if (this.history.length < 2) {
1372
- throw new AuthError(
1373
- "Cannot go back - already at first step",
1374
- "validation_error" /* VALIDATION_ERROR */
1375
- );
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;
1315
+ }
1316
+ if (config.onStateChange) {
1317
+ this.listeners.add(config.onStateChange);
1376
1318
  }
1377
- this.history.pop();
1378
- const previousStep = this.history[this.history.length - 1];
1379
- const transitionConfig = this.config.transitions[this.state.currentStep];
1380
- const targetStep = transitionConfig?.onBack || previousStep;
1381
- return this.moveToStep(targetStep, false);
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;
1382
1335
  }
1383
1336
  /**
1384
- * 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.
1385
1340
  */
1386
- handleCancel() {
1387
- const transitionConfig = this.config.transitions[this.state.currentStep];
1388
- const targetStep = transitionConfig?.onCancel;
1389
- if (this.config.onCancel) {
1390
- this.config.onCancel(this.state);
1341
+ async initialize() {
1342
+ if (this.publishableKey && !this.clientConfig) {
1343
+ void this.fetchClientConfig();
1391
1344
  }
1392
- if (targetStep) {
1393
- 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" });
1394
1364
  }
1395
- this.state.currentStep = "cancelled";
1396
- return this.getState();
1397
1365
  }
1398
- /**
1399
- * Handle error in flow
1400
- */
1401
- handleError(error) {
1402
- this.state.error = error;
1403
- const transitionConfig = this.config.transitions[this.state.currentStep];
1404
- const targetStep = transitionConfig?.onError;
1405
- if (this.config.onError) {
1406
- 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;
1407
1381
  }
1408
- if (targetStep) {
1409
- 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;
1410
1397
  }
1411
- return this.getState();
1412
1398
  }
1413
- /**
1414
- * Reset flow to initial state
1415
- */
1416
- handleReset() {
1417
- 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" });
1418
1411
  }
1419
- /**
1420
- * Move to a specific step
1421
- */
1422
- moveToStep(step, addToHistory = true) {
1423
- if (!this.isStepAllowed(step)) {
1424
- throw new AuthError(
1425
- `Step ${step} is not allowed in this flow`,
1426
- "validation_error" /* VALIDATION_ERROR */
1427
- );
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);
1428
1425
  }
1429
- this.state.currentStep = step;
1430
- if (addToHistory) {
1431
- this.history.push(step);
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);
1432
1440
  }
1433
- if (this.config.onStepChange) {
1434
- this.config.onStepChange(step, this.state);
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);
1435
1463
  }
1436
- if (step === "success" && this.state.user && this.state.session) {
1437
- if (this.config.onComplete) {
1438
- this.config.onComplete(this.state.user, this.state.session);
1439
- }
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;
1440
1475
  }
1441
- return this.getState();
1476
+ if (this.state.status === "mfa_required") {
1477
+ return this.state.session.session_token;
1478
+ }
1479
+ return null;
1442
1480
  }
1443
- /**
1444
- * Get flow history
1445
- */
1446
- getHistory() {
1447
- 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
+ };
1448
1499
  }
1449
1500
  /**
1450
- * Check if can go back
1501
+ * Fetch client config from the backend.
1502
+ * Deduplicates concurrent calls and caches the result with a TTL.
1451
1503
  */
1452
- canGoBack() {
1453
- return this.history.length > 1;
1454
- }
1455
- };
1456
-
1457
- // src/flows/configs.ts
1458
- var simpleSignInFlow = {
1459
- name: "Simple Sign In",
1460
- description: "Basic email/password sign-in",
1461
- initialStep: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1462
- allowedSteps: [
1463
- "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1464
- "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1465
- "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1466
- "password_reset_request" /* PASSWORD_RESET_REQUEST */,
1467
- "password_reset_sent" /* PASSWORD_RESET_SENT */,
1468
- "success" /* SUCCESS */,
1469
- "error" /* ERROR */
1470
- ],
1471
- transitions: {
1472
- ["email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */]: {
1473
- onSuccess: "success" /* SUCCESS */,
1474
- onError: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1475
- },
1476
- ["email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */]: {
1477
- onSuccess: "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1478
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1479
- },
1480
- ["email_verification_sent" /* EMAIL_VERIFICATION_SENT */]: {
1481
- onSuccess: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1482
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1483
- },
1484
- ["password_reset_request" /* PASSWORD_RESET_REQUEST */]: {
1485
- onSuccess: "password_reset_sent" /* PASSWORD_RESET_SENT */,
1486
- onBack: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1487
- },
1488
- ["password_reset_sent" /* PASSWORD_RESET_SENT */]: {
1489
- onSuccess: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1504
+ async fetchClientConfig() {
1505
+ if (this.configFetchPromise) {
1506
+ return this.configFetchPromise;
1490
1507
  }
1491
- }
1492
- };
1493
- var signInWithMFAFlow = {
1494
- name: "Sign In with MFA",
1495
- description: "Sign-in that handles MFA if enabled",
1496
- initialStep: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1497
- allowedSteps: [
1498
- "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1499
- "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1500
- "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1501
- "mfa_required" /* MFA_REQUIRED */,
1502
- "mfa_select_method" /* MFA_SELECT_METHOD */,
1503
- "mfa_verify" /* MFA_VERIFY */,
1504
- "password_reset_request" /* PASSWORD_RESET_REQUEST */,
1505
- "password_reset_sent" /* PASSWORD_RESET_SENT */,
1506
- "success" /* SUCCESS */,
1507
- "error" /* ERROR */
1508
- ],
1509
- transitions: {
1510
- ["email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */]: {
1511
- onSuccess: "success" /* SUCCESS */,
1512
- onError: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1513
- conditions: [
1514
- {
1515
- when: (state) => state.mfaRequired === true,
1516
- then: "mfa_required" /* MFA_REQUIRED */
1517
- }
1518
- ]
1519
- },
1520
- ["email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */]: {
1521
- onSuccess: "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1522
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1523
- },
1524
- ["email_verification_sent" /* EMAIL_VERIFICATION_SENT */]: {
1525
- onSuccess: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */,
1526
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1527
- },
1528
- ["mfa_required" /* MFA_REQUIRED */]: {
1529
- onSuccess: "mfa_verify" /* MFA_VERIFY */,
1530
- conditions: [
1531
- {
1532
- when: (state) => (state.mfaMethods?.length || 0) > 1,
1533
- 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;
1534
1515
  }
1535
- ]
1536
- },
1537
- ["mfa_select_method" /* MFA_SELECT_METHOD */]: {
1538
- onSuccess: "mfa_verify" /* MFA_VERIFY */,
1539
- onBack: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1540
- },
1541
- ["mfa_verify" /* MFA_VERIFY */]: {
1542
- onSuccess: "success" /* SUCCESS */,
1543
- onError: "mfa_verify" /* MFA_VERIFY */,
1544
- onBack: "mfa_select_method" /* MFA_SELECT_METHOD */
1545
- },
1546
- ["password_reset_request" /* PASSWORD_RESET_REQUEST */]: {
1547
- onSuccess: "password_reset_sent" /* PASSWORD_RESET_SENT */,
1548
- onBack: "email_password_sign_in" /* EMAIL_PASSWORD_SIGN_IN */
1516
+ }
1517
+ } catch {
1549
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;
1550
1533
  }
1551
- };
1552
- var completeSignUpFlow = {
1553
- name: "Complete Sign Up",
1554
- description: "Sign-up with email verification and profile completion",
1555
- initialStep: "email_password_sign_up" /* EMAIL_PASSWORD_SIGN_UP */,
1556
- allowedSteps: [
1557
- "email_password_sign_up" /* EMAIL_PASSWORD_SIGN_UP */,
1558
- "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1559
- "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1560
- "profile_complete" /* PROFILE_COMPLETE */,
1561
- "success" /* SUCCESS */,
1562
- "error" /* ERROR */
1563
- ],
1564
- transitions: {
1565
- ["email_password_sign_up" /* EMAIL_PASSWORD_SIGN_UP */]: {
1566
- onSuccess: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1567
- onError: "email_password_sign_up" /* EMAIL_PASSWORD_SIGN_UP */,
1568
- conditions: [
1569
- {
1570
- when: (state) => state.verificationRequired === false,
1571
- then: "profile_complete" /* PROFILE_COMPLETE */
1572
- }
1573
- ]
1574
- },
1575
- ["email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */]: {
1576
- onSuccess: "email_verification_sent" /* EMAIL_VERIFICATION_SENT */
1577
- },
1578
- ["email_verification_sent" /* EMAIL_VERIFICATION_SENT */]: {
1579
- onSuccess: "profile_complete" /* PROFILE_COMPLETE */
1580
- },
1581
- ["profile_complete" /* PROFILE_COMPLETE */]: {
1582
- onSuccess: "success" /* SUCCESS */,
1583
- 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" });
1584
1556
  }
1585
1557
  }
1586
- };
1587
- var magicLinkFlow = {
1588
- name: "Magic Link",
1589
- description: "Passwordless authentication via email",
1590
- initialStep: "magic_link_request" /* MAGIC_LINK_REQUEST */,
1591
- allowedSteps: [
1592
- "magic_link_request" /* MAGIC_LINK_REQUEST */,
1593
- "magic_link_sent" /* MAGIC_LINK_SENT */,
1594
- "magic_link_verify" /* MAGIC_LINK_VERIFY */,
1595
- "success" /* SUCCESS */,
1596
- "error" /* ERROR */
1597
- ],
1598
- transitions: {
1599
- ["magic_link_request" /* MAGIC_LINK_REQUEST */]: {
1600
- onSuccess: "magic_link_sent" /* MAGIC_LINK_SENT */,
1601
- onError: "magic_link_request" /* MAGIC_LINK_REQUEST */
1602
- },
1603
- ["magic_link_sent" /* MAGIC_LINK_SENT */]: {
1604
- onSuccess: "magic_link_verify" /* MAGIC_LINK_VERIFY */
1605
- },
1606
- ["magic_link_verify" /* MAGIC_LINK_VERIFY */]: {
1607
- onSuccess: "success" /* SUCCESS */,
1608
- 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;
1609
1574
  }
1610
1575
  }
1611
- };
1612
- var phoneAuthFlow = {
1613
- name: "Phone Authentication",
1614
- description: "SMS-based authentication",
1615
- initialStep: "phone_request" /* PHONE_REQUEST */,
1616
- allowedSteps: [
1617
- "phone_request" /* PHONE_REQUEST */,
1618
- "phone_verify" /* PHONE_VERIFY */,
1619
- "success" /* SUCCESS */,
1620
- "error" /* ERROR */
1621
- ],
1622
- transitions: {
1623
- ["phone_request" /* PHONE_REQUEST */]: {
1624
- onSuccess: "phone_verify" /* PHONE_VERIFY */,
1625
- onError: "phone_request" /* PHONE_REQUEST */
1626
- },
1627
- ["phone_verify" /* PHONE_VERIFY */]: {
1628
- onSuccess: "success" /* SUCCESS */,
1629
- onError: "phone_verify" /* PHONE_VERIFY */,
1630
- 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
+ }
1631
1589
  }
1632
1590
  }
1633
- };
1634
- var oauthSignInFlow = {
1635
- name: "OAuth Sign In",
1636
- description: "Third-party OAuth authentication",
1637
- initialStep: "oauth_select" /* OAUTH_SELECT */,
1638
- allowedSteps: [
1639
- "oauth_select" /* OAUTH_SELECT */,
1640
- "oauth_callback" /* OAUTH_CALLBACK */,
1641
- "success" /* SUCCESS */,
1642
- "error" /* ERROR */
1643
- ],
1644
- transitions: {
1645
- ["oauth_select" /* OAUTH_SELECT */]: {
1646
- onSuccess: "oauth_callback" /* OAUTH_CALLBACK */,
1647
- onError: "oauth_select" /* OAUTH_SELECT */
1648
- },
1649
- ["oauth_callback" /* OAUTH_CALLBACK */]: {
1650
- onSuccess: "success" /* SUCCESS */,
1651
- 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
+ }
1652
1598
  }
1653
1599
  }
1654
- };
1655
- var passwordResetFlow = {
1656
- name: "Password Reset",
1657
- description: "Reset forgotten password",
1658
- initialStep: "password_reset_request" /* PASSWORD_RESET_REQUEST */,
1659
- allowedSteps: [
1660
- "password_reset_request" /* PASSWORD_RESET_REQUEST */,
1661
- "password_reset_sent" /* PASSWORD_RESET_SENT */,
1662
- "password_reset_confirm" /* PASSWORD_RESET_CONFIRM */,
1663
- "success" /* SUCCESS */,
1664
- "error" /* ERROR */
1665
- ],
1666
- transitions: {
1667
- ["password_reset_request" /* PASSWORD_RESET_REQUEST */]: {
1668
- onSuccess: "password_reset_sent" /* PASSWORD_RESET_SENT */,
1669
- onError: "password_reset_request" /* PASSWORD_RESET_REQUEST */
1670
- },
1671
- ["password_reset_sent" /* PASSWORD_RESET_SENT */]: {
1672
- onSuccess: "password_reset_confirm" /* PASSWORD_RESET_CONFIRM */
1673
- },
1674
- ["password_reset_confirm" /* PASSWORD_RESET_CONFIRM */]: {
1675
- onSuccess: "success" /* SUCCESS */,
1676
- 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
+ }
1677
1616
  }
1617
+ this.setState({ status: "error", error: message });
1618
+ this.onError?.({ error: message, code });
1678
1619
  }
1679
1620
  };
1680
- var emailVerificationFlow = {
1681
- name: "Email Verification",
1682
- description: "Verify email address with code or link",
1683
- initialStep: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1684
- allowedSteps: [
1685
- "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */,
1686
- "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1687
- "success" /* SUCCESS */,
1688
- "error" /* ERROR */
1689
- ],
1690
- transitions: {
1691
- ["email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */]: {
1692
- onSuccess: "email_verification_sent" /* EMAIL_VERIFICATION_SENT */,
1693
- onError: "email_verification_required" /* EMAIL_VERIFICATION_REQUIRED */
1694
- },
1695
- ["email_verification_sent" /* EMAIL_VERIFICATION_SENT */]: {
1696
- onSuccess: "success" /* SUCCESS */,
1697
- 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);
1698
1651
  }
1652
+ out.user = user;
1699
1653
  }
1700
- };
1701
- function getFlowConfig(type) {
1702
- switch (type) {
1703
- case "simple_sign_in" /* SIMPLE_SIGN_IN */:
1704
- return simpleSignInFlow;
1705
- case "sign_in_with_mfa" /* SIGN_IN_WITH_MFA */:
1706
- return signInWithMFAFlow;
1707
- case "complete_sign_up_flow" /* COMPLETE_SIGN_UP_FLOW */:
1708
- return completeSignUpFlow;
1709
- case "magic_link_flow" /* MAGIC_LINK_FLOW */:
1710
- return magicLinkFlow;
1711
- case "phone_auth_flow" /* PHONE_AUTH_FLOW */:
1712
- return phoneAuthFlow;
1713
- case "oauth_sign_in" /* OAUTH_SIGN_IN */:
1714
- return oauthSignInFlow;
1715
- case "password_reset_flow" /* PASSWORD_RESET_FLOW */:
1716
- return passwordResetFlow;
1717
- case "email_verification_flow" /* EMAIL_VERIFICATION_FLOW */:
1718
- return emailVerificationFlow;
1719
- default:
1720
- throw new Error(`Unknown flow type: ${type}`);
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);
1706
+ }
1721
1707
  }
1708
+ result.response = serializedResponse;
1709
+ if (cred.authenticatorAttachment) {
1710
+ result.authenticatorAttachment = cred.authenticatorAttachment;
1711
+ }
1712
+ return result;
1722
1713
  }
1723
- var predefinedFlows = {
1724
- ["simple_sign_in" /* SIMPLE_SIGN_IN */]: simpleSignInFlow,
1725
- ["sign_in_with_mfa" /* SIGN_IN_WITH_MFA */]: signInWithMFAFlow,
1726
- ["complete_sign_up_flow" /* COMPLETE_SIGN_UP_FLOW */]: completeSignUpFlow,
1727
- ["magic_link_flow" /* MAGIC_LINK_FLOW */]: magicLinkFlow,
1728
- ["phone_auth_flow" /* PHONE_AUTH_FLOW */]: phoneAuthFlow,
1729
- ["oauth_sign_in" /* OAUTH_SIGN_IN */]: oauthSignInFlow,
1730
- ["password_reset_flow" /* PASSWORD_RESET_FLOW */]: passwordResetFlow,
1731
- ["email_verification_flow" /* EMAIL_VERIFICATION_FLOW */]: emailVerificationFlow
1714
+ export {
1715
+ AuthClient2 as AuthClient,
1716
+ AuthClientError,
1717
+ AuthManager,
1718
+ base64urlToBuffer,
1719
+ bufferToBase64url,
1720
+ prepareCreationOptions,
1721
+ prepareRequestOptions,
1722
+ serializeCredential
1732
1723
  };
1733
-
1734
- exports.AuthClient = AuthClient;
1735
- exports.AuthError = AuthError;
1736
- exports.AuthErrorType = AuthErrorType;
1737
- exports.AuthState = AuthState;
1738
- exports.BaseAuthProvider = BaseAuthProvider;
1739
- exports.FlowAction = FlowAction;
1740
- exports.FlowConfigType = FlowConfigType;
1741
- exports.FlowEngine = FlowEngine;
1742
- exports.FlowStep = FlowStep;
1743
- exports.LocalStorageAdapter = LocalStorageAdapter;
1744
- exports.MemoryStorageAdapter = MemoryStorageAdapter;
1745
- exports.OAuthProvider = OAuthProvider;
1746
- exports.Observable = Observable;
1747
- exports.SessionStorageAdapter = SessionStorageAdapter;
1748
- exports.TokenManager = TokenManager;
1749
- exports.TwoFactorMethod = TwoFactorMethod;
1750
- exports.completeSignUpFlow = completeSignUpFlow;
1751
- exports.createAuthError = createAuthError;
1752
- exports.createLocale = createLocale;
1753
- exports.defaultLocale = defaultLocale;
1754
- exports.emailVerificationFlow = emailVerificationFlow;
1755
- exports.extractCookiesFromHeaders = extractCookiesFromHeaders;
1756
- exports.getFlowConfig = getFlowConfig;
1757
- exports.interpolate = interpolate;
1758
- exports.isAuthError = isAuthError;
1759
- exports.isMFARequiredError = isMFARequiredError;
1760
- exports.isNetworkError = isNetworkError;
1761
- exports.isUnauthenticatedError = isUnauthenticatedError;
1762
- exports.magicLinkFlow = magicLinkFlow;
1763
- exports.oauthSignInFlow = oauthSignInFlow;
1764
- exports.parseCookie = parseCookie;
1765
- exports.parseCookieOptions = parseCookieOptions;
1766
- exports.passwordResetFlow = passwordResetFlow;
1767
- exports.phoneAuthFlow = phoneAuthFlow;
1768
- exports.predefinedFlows = predefinedFlows;
1769
- exports.serializeCookie = serializeCookie;
1770
- exports.serializeCookies = serializeCookies;
1771
- exports.signInWithMFAFlow = signInWithMFAFlow;
1772
- exports.simpleSignInFlow = simpleSignInFlow;
1773
- exports.toAuthError = toAuthError;
1774
- exports.validate2FACode = validate2FACode;
1775
- exports.validateEmail = validateEmail;
1776
- exports.validatePassword = validatePassword;
1777
- exports.validatePhone = validatePhone;
1778
- exports.validateRequired = validateRequired;
1779
- exports.validateUsername = validateUsername;
1780
- //# sourceMappingURL=index.js.map
1781
1724
  //# sourceMappingURL=index.js.map