@passflow/core 0.0.1 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +3230 -639
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/lib/api/app.d.ts +4 -1
  6. package/dist/lib/api/app.d.ts.map +1 -1
  7. package/dist/lib/api/auth.d.ts +6 -4
  8. package/dist/lib/api/auth.d.ts.map +1 -1
  9. package/dist/lib/api/axios-client.d.ts +26 -4
  10. package/dist/lib/api/axios-client.d.ts.map +1 -1
  11. package/dist/lib/api/index.d.ts +4 -3
  12. package/dist/lib/api/index.d.ts.map +1 -1
  13. package/dist/lib/api/invitation.d.ts +4 -1
  14. package/dist/lib/api/invitation.d.ts.map +1 -1
  15. package/dist/lib/api/model.d.ts +180 -11
  16. package/dist/lib/api/model.d.ts.map +1 -1
  17. package/dist/lib/api/setting.d.ts +4 -1
  18. package/dist/lib/api/setting.d.ts.map +1 -1
  19. package/dist/lib/api/tenant.d.ts +4 -1
  20. package/dist/lib/api/tenant.d.ts.map +1 -1
  21. package/dist/lib/api/two-factor.d.ts +75 -0
  22. package/dist/lib/api/two-factor.d.ts.map +1 -0
  23. package/dist/lib/api/user.d.ts +4 -1
  24. package/dist/lib/api/user.d.ts.map +1 -1
  25. package/dist/lib/constants/index.d.ts +25 -0
  26. package/dist/lib/constants/index.d.ts.map +1 -1
  27. package/dist/lib/device/index.d.ts +17 -0
  28. package/dist/lib/device/index.d.ts.map +1 -0
  29. package/dist/lib/index.d.ts +10 -3
  30. package/dist/lib/index.d.ts.map +1 -1
  31. package/dist/lib/m2m/client.d.ts +196 -0
  32. package/dist/lib/m2m/client.d.ts.map +1 -0
  33. package/dist/lib/m2m/errors.d.ts +107 -0
  34. package/dist/lib/m2m/errors.d.ts.map +1 -0
  35. package/dist/lib/m2m/index.d.ts +27 -0
  36. package/dist/lib/m2m/index.d.ts.map +1 -0
  37. package/dist/lib/m2m/types.d.ts +217 -0
  38. package/dist/lib/m2m/types.d.ts.map +1 -0
  39. package/dist/lib/passflow.d.ts +972 -11
  40. package/dist/lib/passflow.d.ts.map +1 -1
  41. package/dist/lib/services/auth-service.d.ts +29 -4
  42. package/dist/lib/services/auth-service.d.ts.map +1 -1
  43. package/dist/lib/services/index.d.ts +2 -1
  44. package/dist/lib/services/index.d.ts.map +1 -1
  45. package/dist/lib/services/invitation-service.d.ts +2 -2
  46. package/dist/lib/services/tenant-service.d.ts +2 -2
  47. package/dist/lib/services/token-cache-service.d.ts +14 -6
  48. package/dist/lib/services/token-cache-service.d.ts.map +1 -1
  49. package/dist/lib/services/two-factor-service.d.ts +120 -0
  50. package/dist/lib/services/two-factor-service.d.ts.map +1 -0
  51. package/dist/lib/services/user-service.d.ts +1 -1
  52. package/dist/lib/services/user-service.d.ts.map +1 -1
  53. package/dist/lib/storage/index.d.ts +96 -0
  54. package/dist/lib/storage/index.d.ts.map +1 -0
  55. package/dist/lib/store.d.ts +67 -1
  56. package/dist/lib/store.d.ts.map +1 -1
  57. package/dist/lib/token/delivery-manager.d.ts +121 -0
  58. package/dist/lib/token/delivery-manager.d.ts.map +1 -0
  59. package/dist/lib/{token-service → token}/index.d.ts +1 -1
  60. package/dist/lib/token/index.d.ts.map +1 -0
  61. package/dist/lib/token/membership.d.ts.map +1 -0
  62. package/dist/lib/{token-service → token}/service.d.ts +15 -3
  63. package/dist/lib/token/service.d.ts.map +1 -0
  64. package/dist/lib/token/token.d.ts +55 -0
  65. package/dist/lib/token/token.d.ts.map +1 -0
  66. package/dist/lib/types/index.d.ts +5 -3
  67. package/dist/lib/types/index.d.ts.map +1 -1
  68. package/dist/lib/utils/validation.d.ts +54 -0
  69. package/dist/lib/utils/validation.d.ts.map +1 -0
  70. package/dist/tsconfig.build.tsbuildinfo +1 -0
  71. package/package.json +13 -15
  72. package/dist/lib/device-service/index.d.ts +0 -7
  73. package/dist/lib/device-service/index.d.ts.map +0 -1
  74. package/dist/lib/storage-manager/index.d.ts +0 -37
  75. package/dist/lib/storage-manager/index.d.ts.map +0 -1
  76. package/dist/lib/token-service/index.d.ts.map +0 -1
  77. package/dist/lib/token-service/membership.d.ts.map +0 -1
  78. package/dist/lib/token-service/service.d.ts.map +0 -1
  79. package/dist/lib/token-service/token.d.ts +0 -34
  80. package/dist/lib/token-service/token.d.ts.map +0 -1
  81. package/dist/tests/storage-manager/fake-storage.d.ts +0 -7
  82. package/dist/tests/storage-manager/fake-storage.d.ts.map +0 -1
  83. package/dist/tests/storage-manager/storage-manager.test.d.ts +0 -2
  84. package/dist/tests/storage-manager/storage-manager.test.d.ts.map +0 -1
  85. package/dist/tsconfig.tsbuildinfo +0 -1
  86. /package/dist/lib/{token-service → token}/membership.d.ts +0 -0
package/dist/index.mjs CHANGED
@@ -1,7 +1,9 @@
1
- import T from "axios";
2
- import { v4 as R } from "uuid";
3
- import { startRegistration as _, startAuthentication as U } from "@simplewebauthn/browser";
4
- const P = "X-Passflow-Clientid", m = "Authorization", D = "X-Passflow-DeviceId", x = "X-Passflow-DeviceType", F = ["id", "offline", "tenant", "email", "oidc", "openid", "access:tenant:all"], A = "https://auth.passflow.cloud", re = "default", M = (i) => {
1
+ import D from "axios";
2
+ import { v4 as H } from "uuid";
3
+ import { startRegistration as K, startAuthentication as j } from "@simplewebauthn/browser";
4
+ const z = "0.2.8", X = {
5
+ version: z
6
+ }, C = "X-Passflow-Clientid", _ = "Authorization", W = "X-Passflow-DeviceId", J = "X-Passflow-DeviceType", Z = X.version, Ne = ["id", "offline", "openid"], Q = ["id", "offline", "tenant", "email", "oidc", "openid", "access:tenant:all"], G = "https://auth.passflow.cloud", Ke = "default", ee = 500, te = 600, se = 100, re = 6e4, V = 30, ie = 3, ne = 30, oe = 200, ae = (i) => {
5
7
  const e = [];
6
8
  let t;
7
9
  for (t in i) {
@@ -9,16 +11,23 @@ const P = "X-Passflow-Clientid", m = "Authorization", D = "X-Passflow-DeviceId",
9
11
  if (s === void 0)
10
12
  continue;
11
13
  const r = { tenant: { id: s.tenant_id, name: s.tenant_name } };
12
- r.groups = s.groups ? Object.keys(s.groups).map((o) => {
13
- const n = s.groups[o] || [];
14
- return { group: { id: o, name: s.group_names?.[o] ?? "unknown" }, roles: n };
15
- }) : [], r.tenantRoles = r.groups?.find((o) => o.group.id === s.root_group_id), e.push(r);
14
+ r.groups = s.groups ? Object.keys(s.groups).map((n) => {
15
+ const o = s.groups[n] || [];
16
+ return { group: { id: n, name: s.group_names?.[n] ?? "unknown" }, roles: o };
17
+ }) : [], r.tenantRoles = r.groups?.find((n) => n.group.id === s.root_group_id), e.push(r);
16
18
  }
17
19
  return { raw: i, tenants: e };
18
20
  };
19
- class G {
20
- constructor() {
21
- this.storageManager = new b();
21
+ function ce(i) {
22
+ if (typeof window < "u" && typeof window.atob == "function")
23
+ return window.atob(i);
24
+ if (typeof Buffer < "u")
25
+ return Buffer.from(i, "base64").toString("utf-8");
26
+ throw new Error("No Base64 decoding method available in this environment");
27
+ }
28
+ class he {
29
+ constructor(e) {
30
+ this.storageManager = e;
22
31
  }
23
32
  /**
24
33
  * Checks if a token is not exists or expired.
@@ -29,8 +38,8 @@ class G {
29
38
  isTokenTypeExpired(e) {
30
39
  const t = this.storageManager.getToken(e);
31
40
  if (!t) return !0;
32
- const s = d(t);
33
- return s ? f(s) : !0;
41
+ const s = y(t);
42
+ return s ? m(s) : !0;
34
43
  }
35
44
  /**
36
45
  * Parse token from storage by type.
@@ -42,40 +51,209 @@ class G {
42
51
  parseTokenType(e) {
43
52
  const t = this.storageManager.getToken(e);
44
53
  if (t)
45
- return d(t);
54
+ return y(t);
46
55
  }
47
56
  }
48
- function f(i) {
49
- return Math.floor(Date.now() / 1e3) > i.exp;
57
+ function m(i, e = V) {
58
+ return Math.floor(Date.now() / 1e3) + e > i.exp;
50
59
  }
51
- function d(i) {
60
+ function y(i) {
52
61
  const e = i.split(".")[1];
53
62
  if (!e) throw new Error("Invalid token string");
54
- const t = e.replace(/-/g, "+").replace(/_/g, "/"), s = decodeURIComponent(
55
- window.atob(t).split("").map((o) => "%" + ("00" + o.charCodeAt(0).toString(16)).slice(-2)).join("")
56
- ), r = JSON.parse(s);
57
- return r.membership = r.passflow_tm && r.type !== "invite" ? M(r.passflow_tm) : void 0, r;
63
+ const t = e.replace(/-/g, "+").replace(/_/g, "/"), s = t + "=".repeat((4 - t.length % 4) % 4), r = ce(s), n = decodeURIComponent(
64
+ r.split("").map((d) => "%" + ("00" + d.charCodeAt(0).toString(16)).slice(-2)).join("")
65
+ ), o = JSON.parse(n);
66
+ return o.membership = o.passflow_tm && o.type !== "invite" ? ae(o.passflow_tm) : void 0, o;
67
+ }
68
+ var k = /* @__PURE__ */ ((i) => (i.id_token = "id_token", i.access_token = "access", i.refresh_token = "refresh", i.invite_token = "invite", i.reset_token = "reset", i.web_cookie = "web-cookie", i.management = "management", i.signin = "signin", i.actor = "actor", i.two_factor = "2fa", i))(k || {}), v = /* @__PURE__ */ ((i) => (i.JsonBody = "json_body", i.Cookie = "cookie", i.Mobile = "mobile", i.BFF = "bff", i))(v || {}), q = /* @__PURE__ */ ((i) => (i.Unknown = "unknown", i.Valid = "valid", i.Invalid = "invalid", i))(q || {});
69
+ class Y {
70
+ constructor(e) {
71
+ this.storageManager = e, this.mode = "json_body", this.sessionState = "unknown", this.isInitializedFlag = !1, this.STORAGE_PREFIX = "passflow_", this.DELIVERY_MODE_KEY = `${this.STORAGE_PREFIX}delivery_mode`, this.SESSION_STATE_KEY = `${this.STORAGE_PREFIX}session_state`, this.loadPersistedMode(), this.loadPersistedSessionState();
72
+ }
73
+ /**
74
+ * Set the token delivery mode
75
+ */
76
+ setMode(e) {
77
+ this.mode = e, this.isInitializedFlag = !0, this.persistMode();
78
+ }
79
+ /**
80
+ * Get the current token delivery mode
81
+ */
82
+ getMode() {
83
+ return this.mode;
84
+ }
85
+ /**
86
+ * Check if currently in cookie mode
87
+ */
88
+ isCookieMode() {
89
+ return this.mode === "cookie";
90
+ }
91
+ /**
92
+ * Check if currently in JSON body mode
93
+ */
94
+ isJsonMode() {
95
+ return this.mode === "json_body";
96
+ }
97
+ /**
98
+ * Check if currently in mobile mode
99
+ */
100
+ isMobileMode() {
101
+ return this.mode === "mobile";
102
+ }
103
+ /**
104
+ * Check if currently in BFF mode
105
+ */
106
+ isBFFMode() {
107
+ return this.mode === "bff";
108
+ }
109
+ /**
110
+ * Check if delivery mode has been initialized from a server response
111
+ */
112
+ isInitialized() {
113
+ return this.isInitializedFlag;
114
+ }
115
+ /**
116
+ * Mark session as valid (successful authentication or token refresh)
117
+ */
118
+ setSessionValid() {
119
+ this.sessionState = "valid", this.persistSessionState();
120
+ }
121
+ /**
122
+ * Mark session as invalid (received 401 or logout)
123
+ */
124
+ setSessionInvalid() {
125
+ this.sessionState = "invalid", this.persistSessionState();
126
+ }
127
+ /**
128
+ * Reset session state to unknown (used during authentication flows)
129
+ */
130
+ setSessionUnknown() {
131
+ this.sessionState = "unknown", this.persistSessionState();
132
+ }
133
+ /**
134
+ * Check if session is valid
135
+ */
136
+ isSessionValid() {
137
+ return this.sessionState === "valid";
138
+ }
139
+ /**
140
+ * Check if session state is unknown (not yet determined)
141
+ */
142
+ isSessionUnknown() {
143
+ return this.sessionState === "unknown";
144
+ }
145
+ /**
146
+ * Check if session is invalid
147
+ */
148
+ isSessionInvalid() {
149
+ return this.sessionState === "invalid";
150
+ }
151
+ /**
152
+ * Get current session state
153
+ */
154
+ getSessionState() {
155
+ return this.sessionState;
156
+ }
157
+ /**
158
+ * Reset delivery manager to initial state
159
+ */
160
+ reset() {
161
+ this.mode = "json_body", this.sessionState = "unknown", this.isInitializedFlag = !1, this.clearPersistedMode(), this.clearPersistedSessionState();
162
+ }
163
+ /**
164
+ * Load persisted delivery mode from storage
165
+ */
166
+ loadPersistedMode() {
167
+ try {
168
+ const e = this.storageManager.storage.getItem(this.DELIVERY_MODE_KEY);
169
+ e && Object.values(v).includes(e) && (this.mode = e, this.isInitializedFlag = !0);
170
+ } catch {
171
+ }
172
+ }
173
+ /**
174
+ * Load persisted session state from storage
175
+ */
176
+ loadPersistedSessionState() {
177
+ try {
178
+ const e = this.storageManager.storage.getItem(this.SESSION_STATE_KEY);
179
+ e && Object.values(q).includes(e) && (this.sessionState = e);
180
+ } catch {
181
+ }
182
+ }
183
+ /**
184
+ * Persist delivery mode to storage
185
+ */
186
+ persistMode() {
187
+ try {
188
+ this.storageManager.storage.setItem(this.DELIVERY_MODE_KEY, this.mode);
189
+ } catch {
190
+ }
191
+ }
192
+ /**
193
+ * Persist session state to storage
194
+ */
195
+ persistSessionState() {
196
+ try {
197
+ this.storageManager.storage.setItem(this.SESSION_STATE_KEY, this.sessionState);
198
+ } catch {
199
+ }
200
+ }
201
+ /**
202
+ * Clear persisted delivery mode from storage
203
+ */
204
+ clearPersistedMode() {
205
+ try {
206
+ this.storageManager.storage.removeItem(this.DELIVERY_MODE_KEY);
207
+ } catch {
208
+ }
209
+ }
210
+ /**
211
+ * Clear persisted session state from storage
212
+ */
213
+ clearPersistedSessionState() {
214
+ try {
215
+ this.storageManager.storage.removeItem(this.SESSION_STATE_KEY);
216
+ } catch {
217
+ }
218
+ }
58
219
  }
59
- var g = /* @__PURE__ */ ((i) => (i.id_token = "id_token", i.access_token = "access", i.refresh_token = "refresh", i.invite_token = "invite", i.reset_token = "reset", i.web_cookie = "web-cookie", i.management = "management", i.signin = "signin", i.actor = "actor", i))(g || {});
60
- class b {
220
+ class $ {
61
221
  constructor({ storage: e, prefix: t } = {}) {
62
- this.keyStoragePrefix = "", this.scopes = `${this.keyStoragePrefix}tokens_scopes`, this.deviceId = `${this.keyStoragePrefix}passflowDeviceId`, this.invitationToken = `${this.keyStoragePrefix}passflowInvitationToken`, this.previousRedirectUrl = `${this.keyStoragePrefix}passflowPreviousRedirectUrl`, this.storage = e ?? localStorage, this.keyStoragePrefix = t ? `${t}_` : "";
222
+ this.keyStoragePrefix = "", this.scopes = `${this.keyStoragePrefix}tokens_scopes`, this.deviceId = `${this.keyStoragePrefix}passflowDeviceId`, this.invitationToken = `${this.keyStoragePrefix}passflowInvitationToken`, this.previousRedirectUrl = `${this.keyStoragePrefix}passflowPreviousRedirectUrl`, this.STORAGE_PREFIX = "passflow_", this.ID_TOKEN_KEY = `${this.STORAGE_PREFIX}id_token`, this.CSRF_TOKEN_KEY = `${this.STORAGE_PREFIX}csrf_token`, this.DELIVERY_MODE_KEY = `${this.STORAGE_PREFIX}delivery_mode`, this.storage = e ?? localStorage, this.keyStoragePrefix = t ? `${t}_` : "";
63
223
  }
64
- saveTokens(e) {
65
- const { id_token: t, access_token: s, refresh_token: r, scopes: o } = e;
66
- t && this.storage.setItem(this.getKeyForTokenType(g.id_token), t), s && this.storage.setItem(this.getKeyForTokenType(g.access_token), s), r && this.storage.setItem(this.getKeyForTokenType(g.refresh_token), r), o && this.storage.setItem(this.scopes, o.join(","));
224
+ /**
225
+ * Save tokens to storage with conditional logic based on delivery mode
226
+ * In cookie/BFF mode: ONLY save ID token (not access/refresh tokens)
227
+ * In JSON mode: save all tokens (existing behavior)
228
+ */
229
+ saveTokens(e, t) {
230
+ const { id_token: s, access_token: r, refresh_token: n, scopes: o } = e;
231
+ t === v.Cookie || t === v.BFF ? s && this.storage.setItem(this.ID_TOKEN_KEY, s) : (s && this.storage.setItem(this.getKeyForTokenType(k.id_token), s), r && this.storage.setItem(this.getKeyForTokenType(k.access_token), r), n && this.storage.setItem(this.getKeyForTokenType(k.refresh_token), n), o && this.storage.setItem(this.scopes, o.join(",")));
67
232
  }
68
233
  getToken(e) {
69
234
  const t = this.getKeyForTokenType(e);
70
235
  return this.storage.getItem(t) ?? void 0;
71
236
  }
237
+ /**
238
+ * Get tokens from storage with conditional logic based on delivery mode
239
+ * In cookie/BFF mode: return ID token only (access/refresh in HttpOnly cookies)
240
+ * In JSON mode: return all stored tokens (existing behavior)
241
+ */
72
242
  getTokens() {
73
- const e = this.storage.getItem(this.getKeyForTokenType(g.access_token));
74
- if (e)
243
+ const e = this.getDeliveryMode();
244
+ if (e === v.Cookie || e === v.BFF) {
245
+ const s = this.storage.getItem(this.ID_TOKEN_KEY);
246
+ return s ? {
247
+ id_token: s
248
+ // access_token and refresh_token are in HttpOnly cookies, not localStorage
249
+ } : void 0;
250
+ }
251
+ const t = this.storage.getItem(this.getKeyForTokenType(k.access_token));
252
+ if (t)
75
253
  return {
76
- access_token: e,
77
- id_token: this.storage.getItem(this.getKeyForTokenType(g.id_token)) ?? void 0,
78
- refresh_token: this.storage.getItem(this.getKeyForTokenType(g.refresh_token)) ?? void 0,
254
+ access_token: t,
255
+ id_token: this.storage.getItem(this.getKeyForTokenType(k.id_token)) ?? void 0,
256
+ refresh_token: this.storage.getItem(this.getKeyForTokenType(k.refresh_token)) ?? void 0,
79
257
  scopes: this.storage.getItem(this.scopes)?.split(",") ?? void 0
80
258
  };
81
259
  }
@@ -87,7 +265,7 @@ class b {
87
265
  this.storage.removeItem(t);
88
266
  }
89
267
  deleteTokens() {
90
- this.storage.removeItem(this.getKeyForTokenType(g.id_token)), this.storage.removeItem(this.getKeyForTokenType(g.access_token)), this.storage.removeItem(this.getKeyForTokenType(g.refresh_token)), this.storage.removeItem(this.scopes);
268
+ this.storage.removeItem(this.getKeyForTokenType(k.id_token)), this.storage.removeItem(this.getKeyForTokenType(k.access_token)), this.storage.removeItem(this.getKeyForTokenType(k.refresh_token)), this.storage.removeItem(this.scopes), this.clearIdToken();
91
269
  }
92
270
  getDeviceId() {
93
271
  return this.storage.getItem(this.deviceId) ?? void 0;
@@ -116,13 +294,101 @@ class b {
116
294
  deletePreviousRedirectUrl() {
117
295
  this.storage.removeItem(this.previousRedirectUrl);
118
296
  }
297
+ // Delivery mode storage methods
298
+ /**
299
+ * Set the token delivery mode in storage
300
+ */
301
+ setDeliveryMode(e) {
302
+ try {
303
+ this.storage.setItem(this.DELIVERY_MODE_KEY, e);
304
+ } catch {
305
+ }
306
+ }
307
+ /**
308
+ * Get the token delivery mode from storage
309
+ */
310
+ getDeliveryMode() {
311
+ try {
312
+ const e = this.storage.getItem(this.DELIVERY_MODE_KEY);
313
+ if (e && Object.values(v).includes(e))
314
+ return e;
315
+ } catch {
316
+ }
317
+ }
318
+ /**
319
+ * Clear the delivery mode from storage
320
+ */
321
+ clearDeliveryMode() {
322
+ try {
323
+ this.storage.removeItem(this.DELIVERY_MODE_KEY);
324
+ } catch {
325
+ }
326
+ }
327
+ // ID token storage methods (for cookie mode)
328
+ /**
329
+ * Get the ID token from storage (cookie mode)
330
+ */
331
+ getIdToken() {
332
+ try {
333
+ return this.storage.getItem(this.ID_TOKEN_KEY) ?? void 0;
334
+ } catch {
335
+ return;
336
+ }
337
+ }
338
+ /**
339
+ * Set the ID token in storage (cookie mode)
340
+ */
341
+ setIdToken(e) {
342
+ try {
343
+ this.storage.setItem(this.ID_TOKEN_KEY, e);
344
+ } catch {
345
+ }
346
+ }
347
+ /**
348
+ * Clear the ID token from storage
349
+ */
350
+ clearIdToken() {
351
+ try {
352
+ this.storage.removeItem(this.ID_TOKEN_KEY);
353
+ } catch {
354
+ }
355
+ }
356
+ // CSRF token storage methods
357
+ /**
358
+ * Get the CSRF token from storage
359
+ */
360
+ getCsrfToken() {
361
+ try {
362
+ return this.storage.getItem(this.CSRF_TOKEN_KEY) ?? void 0;
363
+ } catch {
364
+ return;
365
+ }
366
+ }
367
+ /**
368
+ * Set the CSRF token in storage
369
+ */
370
+ setCsrfToken(e) {
371
+ try {
372
+ this.storage.setItem(this.CSRF_TOKEN_KEY, e);
373
+ } catch {
374
+ }
375
+ }
376
+ /**
377
+ * Clear the CSRF token from storage
378
+ */
379
+ clearCsrfToken() {
380
+ try {
381
+ this.storage.removeItem(this.CSRF_TOKEN_KEY);
382
+ } catch {
383
+ }
384
+ }
119
385
  getKeyForTokenType(e) {
120
386
  return `${this.keyStoragePrefix}${e}`;
121
387
  }
122
388
  }
123
- class $ {
124
- constructor() {
125
- this.storageManager = new b();
389
+ class B {
390
+ constructor(e) {
391
+ this.storageManager = e ?? new $();
126
392
  }
127
393
  getDeviceId() {
128
394
  const e = this.storageManager.getDeviceId();
@@ -133,84 +399,85 @@ class $ {
133
399
  return e;
134
400
  }
135
401
  generateUniqueDeviceId() {
136
- return R();
402
+ return H();
137
403
  }
138
404
  }
139
- var S = /* @__PURE__ */ ((i) => (i.GET = "get", i.POST = "post", i.PUT = "put", i.PATCH = "patch", i.DELETE = "delete", i))(S || {}), c = /* @__PURE__ */ ((i) => (i.signin = "/auth/login", i.signup = "/auth/register", i.signInWithProvider = "/auth/federated/start/", i.passwordless = "/auth/passwordless/start", i.passwordlessComplete = "/auth/passwordless/complete", i.logout = "/user/logout", i.refresh = "/auth/refresh", i.sendPasswordResetEmail = "/auth/password/reset", i.resetPassword = "/auth/password/change", i.appSettings = "/app/settings", i.passkeyRegisterStart = "/auth/passkey/register/start", i.passkeyRegisterComplete = "/auth/passkey/register/complete", i.passkeyAuthenticateStart = "/auth/passkey/authenticate/start", i.passkeyAuthenticateComplete = "/auth/passkey/authenticate/complete", i.passkeyValidate = "/auth/validate", i.settingsAll = "/settings", i.settingsPasswordPolicy = "/settings/password", i.settingsPasskey = "/settings/passkey", i.userPasskey = "/user/passkey", i.addUserPasskey = "/user/passkey/add/start", i.completeAddUserPasskey = "/user/passkey/add/complete", i.joinInvitation = "/user/tenant/join", i.tenantPath = "/user/tenant", i.invitationsPath = "/user/tenant/:tenantID/invitations", i.requestInvitation = "/user/invite", i.invitationDelete = "/user/invite/:invitationID", i.invitationResend = "/user/invite/:invitationID/resend", i.invitationGetLink = "/user/invite/:invitationID/link", i))(c || {}), y = /* @__PURE__ */ ((i) => (i.passkeyRegisterStart = "/admin/auth/passkey/register/start", i.passkeyRegisterComplete = "/admin/auth/passkey/register/complete", i.passkeyAuthenticateStart = "/admin/auth/passkey/authenticate/start", i.passkeyAuthenticateComplete = "/admin/auth/passkey/authenticate/complete", i.passkeyValidate = "/admin/auth/validate", i.logout = "/admin/auth/logout", i))(y || {});
405
+ var E = /* @__PURE__ */ ((i) => (i.GET = "get", i.POST = "post", i.PUT = "put", i.PATCH = "patch", i.DELETE = "delete", i))(E || {}), h = /* @__PURE__ */ ((i) => (i.signin = "/auth/login", i.signup = "/auth/register", i.signInWithProvider = "/auth/federated/start/", i.passwordless = "/auth/passwordless/start", i.passwordlessComplete = "/auth/passwordless/complete", i.logout = "/user/logout", i.refresh = "/auth/refresh", i.validateSession = "/user/me", i.sendPasswordResetEmail = "/auth/password/reset", i.resetPassword = "/auth/password/change", i.appSettings = "/app/settings", i.passkeyRegisterStart = "/auth/passkey/register/start", i.passkeyRegisterComplete = "/auth/passkey/register/complete", i.passkeyAuthenticateStart = "/auth/passkey/authenticate/start", i.passkeyAuthenticateComplete = "/auth/passkey/authenticate/complete", i.passkeyValidate = "/auth/validate", i.settingsAll = "/settings", i.settingsPasswordPolicy = "/settings/password", i.settingsPasskey = "/settings/passkey", i.userPasskey = "/user/passkey", i.addUserPasskey = "/user/passkey/add/start", i.completeAddUserPasskey = "/user/passkey/add/complete", i.joinInvitation = "/user/tenant/join", i.tenantPath = "/user/tenant", i.invitationsPath = "/user/tenant/:tenantID/invitations", i.requestInvitation = "/user/invite", i.invitationDelete = "/user/invite/:invitationID", i.invitationResend = "/user/invite/:invitationID/resend", i.invitationGetLink = "/user/invite/:invitationID/link", i.twoFactor = "/user/2fa", i.twoFactorStatus = "/user/2fa/status", i.twoFactorSetupBegin = "/user/2fa/setup/begin", i.twoFactorSetupConfirm = "/user/2fa/setup/confirm", i.twoFactorVerify = "/auth/2fa/verify", i.twoFactorRecovery = "/auth/2fa/recovery", i.twoFactorRegenerateCodes = "/user/2fa/recovery-codes/regenerate", i.twoFactorSetupMagicLink = "/auth/2fa-setup", i))(h || {}), w = /* @__PURE__ */ ((i) => (i.passkeyRegisterStart = "/admin/auth/passkey/register/start", i.passkeyRegisterComplete = "/admin/auth/passkey/register/complete", i.passkeyAuthenticateStart = "/admin/auth/passkey/authenticate/start", i.passkeyAuthenticateComplete = "/admin/auth/passkey/authenticate/complete", i.passkeyValidate = "/admin/auth/validate", i.logout = "/admin/auth/logout", i))(w || {});
140
406
  class u extends Error {
141
407
  constructor(e) {
142
408
  super(), this.id = e?.id ?? "unknown", this.message = e?.message ?? e ?? "Something went wrong", this.status = e?.status ?? 500, this.location = e?.location ?? "unknown", this.time = e?.time ?? (/* @__PURE__ */ new Date()).toISOString();
143
409
  }
144
410
  }
145
- var L = /* @__PURE__ */ ((i) => (i.google = "google", i.facebook = "facebook", i))(L || {}), w = /* @__PURE__ */ ((i) => (i.web = "web", i))(w || {});
146
- function C(i, e) {
411
+ var de = /* @__PURE__ */ ((i) => (i.google = "google", i.facebook = "facebook", i))(de || {}), I = /* @__PURE__ */ ((i) => (i.web = "web", i))(I || {});
412
+ function A(i, e) {
147
413
  let t = i;
148
414
  return Object.entries(e).forEach(([s, r]) => {
149
415
  t = t.replace(`:${s}`, r);
150
416
  }), t;
151
417
  }
152
- class I {
153
- constructor(e) {
154
- this.refreshPromise = null, this.origin = window.location.origin, this.defaultHeaders = {
418
+ var ue = /* @__PURE__ */ ((i) => (i.Disabled = "disabled", i.Optional = "optional", i.Required = "required", i))(ue || {});
419
+ const le = 3, ge = 1e3;
420
+ class T {
421
+ constructor(e, t, s) {
422
+ this.refreshPromise = null, this.isRefreshing = !1, this.origin = typeof window < "u" ? window.location.origin : "", this.defaultHeaders = {
155
423
  Accept: "application/json",
156
424
  "Content-Type": "application/json"
157
425
  }, this.nonAccessTokenEndpoints = ["/auth/", "/settings", "/settings/"], this.protectedEndpoints = ["logout", "refresh"];
158
- const { url: t, appId: s, keyStoragePrefix: r } = e;
159
- this.url = t || A, this.storageManager = new b({
160
- prefix: r ?? ""
161
- }), this.deviceService = new $(), this.tokenService = new G(), s && (this.appId = s, this.defaultHeaders = {
426
+ const { url: r, appId: n, keyStoragePrefix: o } = e;
427
+ this.url = r || G, this.storageManager = t ?? new $({
428
+ prefix: o ?? ""
429
+ }), this.deviceService = s ?? new B(this.storageManager), this.tokenService = new he(this.storageManager), this.tokenDeliveryManager = new Y(this.storageManager), n && (this.appId = n, this.defaultHeaders = {
162
430
  ...this.defaultHeaders,
163
- [P]: s
431
+ [C]: n
164
432
  });
165
- const o = this.deviceService.getDeviceId();
433
+ const d = this.deviceService.getDeviceId();
166
434
  this.defaultHeaders = {
167
435
  ...this.defaultHeaders,
168
- [D]: o,
169
- [x]: "web"
170
- }, this.instance = T.create({
436
+ [W]: d,
437
+ [J]: "web"
438
+ }, this.detectCookieSupport(), this.instance = D.create({
171
439
  baseURL: this.url,
172
440
  headers: { ...this.defaultHeaders }
173
- }), this.instance.interceptors.request.use(async (n) => {
174
- if (this.isNonAuthEndpoint(n.url))
175
- return n;
176
- if (n.url?.includes("refresh")) {
177
- if (this.refreshPromise) {
441
+ }), this.instance.interceptors.request.use(async (c) => {
442
+ if (this.isNonAuthEndpoint(c.url))
443
+ return c;
444
+ if (this.tokenDeliveryManager.isCookieMode()) {
445
+ c.withCredentials = !0;
446
+ const p = this.storageManager.getCsrfToken();
447
+ return p && (c.headers["X-CSRF-Token"] = p), c;
448
+ }
449
+ if (c.url?.includes("refresh")) {
450
+ if (this.isRefreshing) {
178
451
  const p = new AbortController();
179
- return p.abort(), n.signal = p.signal, n;
452
+ return p.abort(), c.signal = p.signal, c;
180
453
  }
181
- return n;
454
+ return c;
182
455
  }
183
- const h = this.storageManager.getTokens(), l = this.storageManager.getScopes();
184
- if (h?.access_token) {
185
- const p = d(h.access_token);
186
- if (f(p) && h.refresh_token)
456
+ const g = this.storageManager.getTokens();
457
+ if (g?.access_token) {
458
+ const p = y(g.access_token);
459
+ if (m(p, V) && g.refresh_token)
187
460
  try {
188
461
  if (this.refreshPromise) {
189
- const E = await this.refreshPromise;
190
- return E.data && (n.headers[m] = `Bearer ${E.data.access_token}`), n;
462
+ const f = await this.refreshPromise;
463
+ return f?.data?.access_token && (c.headers[_] = `Bearer ${f.data.access_token}`), c;
464
+ }
465
+ this.refreshPromise = this.refreshTokens();
466
+ try {
467
+ const f = await this.refreshPromise;
468
+ return f?.data?.access_token && (c.headers[_] = `Bearer ${f.data.access_token}`), c;
469
+ } finally {
470
+ this.refreshPromise = null;
191
471
  }
192
- const v = {
193
- refresh_token: h.refresh_token,
194
- scopes: l
195
- };
196
- this.refreshPromise = this.instance.post(c.refresh, v, {
197
- headers: {
198
- [m]: `Bearer ${h.refresh_token}`
199
- }
200
- });
201
- const k = await this.refreshPromise;
202
- return k.data && (this.storageManager.saveTokens(k.data), n.headers[m] = `Bearer ${k.data.access_token}`), n;
203
- } catch (v) {
204
- return this.refreshPromise = null, Promise.reject(v);
205
- } finally {
206
- this.refreshPromise = null;
472
+ } catch (f) {
473
+ return this.refreshPromise = null, this.isRefreshing = !1, this.storageManager.deleteTokens(), Promise.reject(f);
207
474
  }
208
- return n.headers[m] = `Bearer ${h.access_token}`, n;
475
+ return c.headers[_] = `Bearer ${g.access_token}`, c;
209
476
  }
210
- return n;
477
+ return c;
211
478
  }), this.instance.interceptors.response.use(
212
- (n) => n,
213
- (n) => this.handleAxiosError(n)
479
+ (c) => c,
480
+ async (c) => (c.response?.status === 401 && this.tokenDeliveryManager.setSessionInvalid(), c.response?.status === 429 ? await this.handleRateLimitError(c) : this.handleAxiosError(c))
214
481
  );
215
482
  }
216
483
  isProtectedEndpoint(e) {
@@ -219,6 +486,71 @@ class I {
219
486
  isNonAuthEndpoint(e) {
220
487
  return this.nonAccessTokenEndpoints.some((t) => e?.includes(t)) && !this.isProtectedEndpoint(e);
221
488
  }
489
+ /**
490
+ * Detect if cookies are supported/enabled in the browser
491
+ * Falls back to JSON mode if cookies are blocked
492
+ */
493
+ detectCookieSupport() {
494
+ if (!(typeof document > "u"))
495
+ try {
496
+ document.cookie = "passflow_test=1; SameSite=Lax";
497
+ const e = document.cookie.indexOf("passflow_test=1") !== -1;
498
+ document.cookie = "passflow_test=; expires=Thu, 01 Jan 1970 00:00:00 UTC", !e && this.tokenDeliveryManager.isCookieMode();
499
+ } catch {
500
+ }
501
+ }
502
+ /**
503
+ * Refresh tokens using single-flight pattern to prevent race conditions
504
+ * Supports both cookie mode and JSON mode
505
+ */
506
+ async refreshTokens() {
507
+ if (this.tokenDeliveryManager.isCookieMode()) {
508
+ const e = await this.instance.post(
509
+ h.refresh,
510
+ {},
511
+ // Empty body
512
+ { withCredentials: !0 }
513
+ );
514
+ return this.tokenDeliveryManager.setSessionValid(), e.data.csrf_token && this.storageManager.setCsrfToken(e.data.csrf_token), e.data.id_token && this.storageManager.setIdToken(e.data.id_token), e;
515
+ } else {
516
+ const e = this.storageManager.getTokens(), t = this.storageManager.getScopes();
517
+ if (!e?.refresh_token)
518
+ throw new Error("No refresh token available");
519
+ this.isRefreshing = !0;
520
+ const s = {
521
+ refresh_token: e.refresh_token,
522
+ scopes: t
523
+ }, r = await this.instance.post(h.refresh, s, {
524
+ headers: {
525
+ [_]: `Bearer ${e.refresh_token}`
526
+ }
527
+ });
528
+ return r.data && this.storageManager.saveTokens(r.data), this.isRefreshing = !1, r;
529
+ }
530
+ }
531
+ async handleRateLimitError(e) {
532
+ const t = e.config;
533
+ if (!t)
534
+ return Promise.reject(e);
535
+ const s = t.method?.toUpperCase();
536
+ if (!["GET", "HEAD", "OPTIONS"].includes(s || ""))
537
+ return Promise.reject(e);
538
+ const n = t._retryCount || 0;
539
+ if (n >= le)
540
+ return Promise.reject(e);
541
+ let o = ge * Math.pow(2, n);
542
+ const d = e.response?.headers?.["retry-after"];
543
+ if (d) {
544
+ const c = Number.parseInt(d, 10);
545
+ if (!Number.isNaN(c))
546
+ o = c * 1e3;
547
+ else {
548
+ const g = new Date(d);
549
+ Number.isNaN(g.getTime()) || (o = Math.max(0, g.getTime() - Date.now()));
550
+ }
551
+ }
552
+ return await new Promise((c) => setTimeout(c, o)), t._retryCount = n + 1, this.instance.request(t);
553
+ }
222
554
  // eslint-disable-next-line complexity
223
555
  // biome-ignore lint/suspicious/useAwait: <explanation>
224
556
  async handleAxiosError(e) {
@@ -247,33 +579,59 @@ class I {
247
579
  })).data;
248
580
  }
249
581
  get(e, t) {
250
- return this.send(S.GET, e, t);
582
+ return this.send(E.GET, e, t);
251
583
  }
252
584
  post(e, t, s) {
253
- return this.send(S.POST, e, { data: t, ...s });
585
+ return this.send(E.POST, e, { data: t, ...s });
254
586
  }
255
587
  put(e, t, s) {
256
- return this.send(S.PUT, e, { data: t, ...s });
588
+ return this.send(E.PUT, e, { data: t, ...s });
257
589
  }
258
590
  patch(e, t, s) {
259
- return this.send(S.PATCH, e, { data: t, ...s });
591
+ return this.send(E.PATCH, e, { data: t, ...s });
260
592
  }
261
593
  delete(e, t) {
262
- return this.send(S.DELETE, e, t);
594
+ return this.send(E.DELETE, e, t);
595
+ }
596
+ /**
597
+ * Update the appId and propagate it to axios headers.
598
+ * This ensures that the APP_ID_HEADER_KEY is updated in all future requests.
599
+ *
600
+ * @param appId - The new application ID to set
601
+ */
602
+ setAppId(e) {
603
+ this.appId = e, this.defaultHeaders = {
604
+ ...this.defaultHeaders,
605
+ [C]: e
606
+ }, this.instance.defaults.headers.common[C] = e;
263
607
  }
264
608
  }
265
- class O {
266
- constructor(e) {
267
- this.storageManager = new b(), this.axiosClient = new I(e);
609
+ class pe {
610
+ constructor(e, t, s) {
611
+ this.axiosClient = new T(e, t, s);
612
+ }
613
+ setAppId(e) {
614
+ this.axiosClient.setAppId(e);
615
+ }
616
+ getAppSettings() {
617
+ return this.axiosClient.get(h.appSettings);
618
+ }
619
+ }
620
+ class fe {
621
+ constructor(e, t, s) {
622
+ this.axiosClient = new T(e, t, s);
623
+ }
624
+ setAppId(e) {
625
+ this.axiosClient.setAppId(e);
268
626
  }
269
627
  refreshToken(e, t, s) {
270
628
  const r = {
271
629
  access: s,
272
630
  scopes: t
273
631
  };
274
- return this.axiosClient.post(c.refresh, r, {
632
+ return this.axiosClient.post(h.refresh, r, {
275
633
  headers: {
276
- [m]: `Bearer ${e}`
634
+ [_]: `Bearer ${e}`
277
635
  }
278
636
  });
279
637
  }
@@ -284,7 +642,7 @@ class O {
284
642
  os: s
285
643
  };
286
644
  return this.axiosClient.post(
287
- c.signin,
645
+ h.signin,
288
646
  r
289
647
  );
290
648
  }
@@ -295,35 +653,38 @@ class O {
295
653
  anonymous: s ?? !1
296
654
  };
297
655
  return this.axiosClient.post(
298
- c.signup,
656
+ h.signup,
299
657
  r
300
658
  );
301
659
  }
302
660
  passwordlessSignIn(e, t, s) {
303
- const { create_tenant: r } = e, o = {
661
+ const { create_tenant: r } = e, n = {
304
662
  ...e,
305
663
  create_tenant: r ?? !1,
306
664
  device: t,
307
665
  os: s
308
666
  };
309
667
  return this.axiosClient.post(
310
- c.passwordless,
311
- o
668
+ h.passwordless,
669
+ n
312
670
  );
313
671
  }
314
672
  passwordlessSignInComplete(e) {
315
673
  return this.axiosClient.post(
316
- c.passwordlessComplete,
674
+ h.passwordlessComplete,
317
675
  e
318
676
  );
319
677
  }
320
678
  logOut(e, t, s = !1) {
321
- const r = s ? void 0 : { refresh_token: t, device: e }, o = s ? y.logout : c.logout;
322
- return this.axiosClient.post(o, r);
679
+ const r = s ? void 0 : { refresh_token: t, device: e }, n = s ? w.logout : h.logout;
680
+ return this.axiosClient.post(n, r);
681
+ }
682
+ validateSession() {
683
+ return this.axiosClient.get(h.validateSession);
323
684
  }
324
685
  sendPasswordResetEmail(e) {
325
686
  return this.axiosClient.post(
326
- c.sendPasswordResetEmail,
687
+ h.sendPasswordResetEmail,
327
688
  e
328
689
  );
329
690
  }
@@ -332,129 +693,153 @@ class O {
332
693
  password: e,
333
694
  scopes: t
334
695
  };
335
- return this.axiosClient.post(c.resetPassword, r, {
696
+ return this.axiosClient.post(h.resetPassword, r, {
336
697
  headers: {
337
- [m]: `Bearer ${s}`,
338
- [P]: void 0
698
+ [_]: `Bearer ${s}`,
699
+ [C]: void 0
339
700
  }
340
701
  });
341
702
  }
342
703
  passkeyRegisterStart(e, t, s, r = !1) {
343
- const { create_tenant: o } = e, n = {
704
+ const { create_tenant: n } = e, o = {
344
705
  ...e,
345
- create_tenant: o ?? !1,
706
+ create_tenant: n ?? !1,
346
707
  device: t,
347
708
  os: s
348
- }, h = r ? y.passkeyRegisterStart : c.passkeyRegisterStart;
349
- return this.axiosClient.post(h, n);
709
+ }, d = r ? w.passkeyRegisterStart : h.passkeyRegisterStart;
710
+ return this.axiosClient.post(d, o);
350
711
  }
351
712
  passkeyRegisterComplete(e, t, s, r = !1) {
352
- const o = {
713
+ const n = {
353
714
  challenge_id: s,
354
715
  device: t,
355
716
  passkey_data: e
356
- }, n = r ? y.passkeyRegisterComplete : c.passkeyRegisterComplete;
357
- return this.axiosClient.post(n, o);
717
+ }, o = r ? w.passkeyRegisterComplete : h.passkeyRegisterComplete;
718
+ return this.axiosClient.post(o, n);
358
719
  }
359
720
  passkeyAuthenticateStart(e, t, s, r = !1) {
360
- const o = {
721
+ const n = {
361
722
  ...e,
362
723
  user_id: e.user_id ?? "",
363
724
  device: t,
364
725
  os: s
365
- }, n = r ? y.passkeyAuthenticateStart : c.passkeyAuthenticateStart;
726
+ }, o = r ? w.passkeyAuthenticateStart : h.passkeyAuthenticateStart;
366
727
  return this.axiosClient.post(
367
- n,
368
- o
728
+ o,
729
+ n
369
730
  );
370
731
  }
371
732
  passkeyAuthenticateComplete(e, t, s, r = !1) {
372
- const o = {
733
+ const n = {
373
734
  challenge_id: s,
374
735
  device: t,
375
736
  passkey_data: e
376
- }, n = r ? y.passkeyAuthenticateComplete : c.passkeyAuthenticateComplete;
377
- return this.axiosClient.post(n, o);
737
+ }, o = r ? w.passkeyAuthenticateComplete : h.passkeyAuthenticateComplete;
738
+ return this.axiosClient.post(o, n);
378
739
  }
379
- passkeyValidate(e, t, s, r = !1, o) {
380
- const n = {
740
+ passkeyValidate(e, t, s, r = !1, n) {
741
+ const o = {
381
742
  otp: e,
382
743
  device: t,
383
744
  challenge_id: s
384
745
  };
385
- let h = c.passkeyValidate;
386
- !o && r && (h = y.passkeyValidate);
387
- const l = o ? { [P]: o } : {};
388
- return this.axiosClient.post(h, n, { headers: l });
746
+ let d = h.passkeyValidate;
747
+ !n && r && (d = w.passkeyValidate);
748
+ const c = n ? { [C]: n } : {};
749
+ return this.axiosClient.post(d, o, { headers: c });
389
750
  }
390
751
  }
391
- class j {
392
- constructor(e) {
393
- this.axiosClient = new I(e);
752
+ class ke {
753
+ constructor(e, t, s) {
754
+ this.axiosClient = new T(e, t, s);
394
755
  }
395
- getAppSettings() {
396
- return this.axiosClient.get(c.appSettings);
756
+ setAppId(e) {
757
+ this.axiosClient.setAppId(e);
758
+ }
759
+ /**
760
+ * Requests an invitation link that can be used to invite users
761
+ * @param payload Request invitation payload
762
+ * @returns Promise with invitation link and token
763
+ */
764
+ requestInviteLink(e) {
765
+ return this.axiosClient.post(
766
+ h.requestInvitation,
767
+ e
768
+ );
769
+ }
770
+ /**
771
+ * Gets a list of active invitations
772
+ * @param options Optional parameters for filtering and pagination
773
+ * @returns Promise with paginated list of invitations
774
+ */
775
+ getInvitations(e) {
776
+ const t = {};
777
+ e.groupID && (t.group_id = e.groupID.toString()), e.skip !== void 0 && (t.skip = e.skip.toString()), e.limit !== void 0 && (t.limit = e.limit.toString());
778
+ const s = A(h.invitationsPath, {
779
+ tenantID: e.tenantID
780
+ });
781
+ return this.axiosClient.get(s, { params: t }).then((r) => ({
782
+ invites: r.invites,
783
+ nextPageSkip: r.next_page_skip
784
+ }));
785
+ }
786
+ /**
787
+ * Deletes an invitation by token
788
+ * @param invitationID The invitation ID to delete
789
+ * @returns Promise with success response
790
+ */
791
+ deleteInvitation(e) {
792
+ const t = A(h.invitationDelete, {
793
+ invitationID: e
794
+ });
795
+ return this.axiosClient.delete(t);
796
+ }
797
+ /**
798
+ * Resend an invitation by token
799
+ * @param invitationID The invitation ID to resend
800
+ * @returns Promise with success response
801
+ */
802
+ resendInvitation(e) {
803
+ const t = A(h.invitationResend, {
804
+ invitationID: e
805
+ });
806
+ return this.axiosClient.post(t, {});
807
+ }
808
+ /**
809
+ * Get a link to an invitation by id
810
+ * @param invitationID The invitation ID to get link
811
+ * @returns Promise with the link
812
+ */
813
+ getInvitationLink(e) {
814
+ const t = A(h.invitationGetLink, {
815
+ invitationID: e
816
+ });
817
+ return this.axiosClient.get(t);
397
818
  }
398
819
  }
399
- class K {
400
- constructor(e) {
401
- this.axiosClient = new I(e);
820
+ class ye {
821
+ constructor(e, t, s) {
822
+ this.axiosClient = new T(e, t, s);
823
+ }
824
+ setAppId(e) {
825
+ this.axiosClient.setAppId(e);
402
826
  }
403
827
  getSettingsAll() {
404
- return this.axiosClient.get(c.settingsAll);
828
+ return this.axiosClient.get(h.settingsAll);
405
829
  }
406
830
  getPasswordPolicySettings() {
407
- return this.axiosClient.get(c.settingsPasswordPolicy);
831
+ return this.axiosClient.get(h.settingsPasswordPolicy);
408
832
  }
409
833
  getPasskeySettings() {
410
- return this.axiosClient.get(c.settingsPasskey);
834
+ return this.axiosClient.get(h.settingsPasskey);
411
835
  }
412
836
  }
413
- class N {
414
- constructor(e) {
415
- this.axiosClient = new I(e);
416
- }
417
- getUserPasskeys() {
418
- return this.axiosClient.get(c.userPasskey);
419
- }
420
- renameUserPasskey(e, t) {
421
- return this.axiosClient.patch(
422
- `${c.userPasskey}/${t}`,
423
- {
424
- name: e
425
- }
426
- );
427
- }
428
- deleteUserPasskey(e) {
429
- return this.axiosClient.delete(`${c.userPasskey}/${e}`);
430
- }
431
- addUserPasskeyStart({
432
- relyingPartyId: e,
433
- deviceId: t,
434
- os: s,
435
- passkeyDisplayName: r,
436
- passkeyUsername: o
437
- }) {
438
- const n = {
439
- passkey_display_name: r,
440
- passkey_username: o,
441
- relying_party_id: e,
442
- deviceId: t,
443
- os: s
444
- };
445
- return this.axiosClient.post(c.addUserPasskey, n);
446
- }
447
- addUserPasskeyComplete(e, t, s) {
448
- return this.axiosClient.post(c.completeAddUserPasskey, {
449
- challenge_id: s,
450
- device: t,
451
- passkey_data: e
452
- });
837
+ class ve {
838
+ constructor(e, t, s) {
839
+ this.axiosClient = new T(e, t, s);
453
840
  }
454
- }
455
- class B {
456
- constructor(e) {
457
- this.axiosClient = new I(e);
841
+ setAppId(e) {
842
+ this.axiosClient.setAppId(e);
458
843
  }
459
844
  joinInvitation(e, t) {
460
845
  const s = {
@@ -462,7 +847,7 @@ class B {
462
847
  scopes: t
463
848
  };
464
849
  return this.axiosClient.post(
465
- c.joinInvitation,
850
+ h.joinInvitation,
466
851
  s
467
852
  );
468
853
  }
@@ -471,7 +856,7 @@ class B {
471
856
  name: e
472
857
  };
473
858
  return this.axiosClient.post(
474
- c.tenantPath,
859
+ h.tenantPath,
475
860
  t
476
861
  );
477
862
  }
@@ -481,7 +866,7 @@ class B {
481
866
  * @param tenantId Tenant ID
482
867
  */
483
868
  getTenantDetails(e) {
484
- const t = `${c.tenantPath}/${e}`;
869
+ const t = `${h.tenantPath}/${e}`;
485
870
  return this.axiosClient.get(t);
486
871
  }
487
872
  /**
@@ -490,7 +875,7 @@ class B {
490
875
  * @param name New tenant name
491
876
  */
492
877
  updateTenant(e, t) {
493
- const s = `${c.tenantPath}/${e}`, r = { name: t };
878
+ const s = `${h.tenantPath}/${e}`, r = { name: t };
494
879
  return this.axiosClient.put(s, r);
495
880
  }
496
881
  /**
@@ -498,14 +883,14 @@ class B {
498
883
  * @param tenantId Tenant ID
499
884
  */
500
885
  deleteTenant(e) {
501
- const t = `${c.tenantPath}/${e}`;
886
+ const t = `${h.tenantPath}/${e}`;
502
887
  return this.axiosClient.delete(t);
503
888
  }
504
889
  /**
505
890
  * Get user's tenant memberships
506
891
  */
507
892
  getUserTenantMembership() {
508
- return this.axiosClient.get(c.tenantPath);
893
+ return this.axiosClient.get(h.tenantPath);
509
894
  }
510
895
  // 2. Group Management
511
896
  /**
@@ -514,7 +899,7 @@ class B {
514
899
  * @param name Group name
515
900
  */
516
901
  createGroup(e, t) {
517
- const s = `${c.tenantPath}/${e}/group`, r = { name: t };
902
+ const s = `${h.tenantPath}/${e}/group`, r = { name: t };
518
903
  return this.axiosClient.post(s, r);
519
904
  }
520
905
  /**
@@ -523,7 +908,7 @@ class B {
523
908
  * @param groupId Group ID
524
909
  */
525
910
  getGroupInfo(e, t) {
526
- const s = `${c.tenantPath}/${e}/group/${t}`;
911
+ const s = `${h.tenantPath}/${e}/group/${t}`;
527
912
  return this.axiosClient.get(s);
528
913
  }
529
914
  /**
@@ -533,8 +918,8 @@ class B {
533
918
  * @param name New group name
534
919
  */
535
920
  updateGroup(e, t, s) {
536
- const r = `${c.tenantPath}/${e}/group/${t}`, o = { name: s };
537
- return this.axiosClient.put(r, o);
921
+ const r = `${h.tenantPath}/${e}/group/${t}`, n = { name: s };
922
+ return this.axiosClient.put(r, n);
538
923
  }
539
924
  /**
540
925
  * Delete a group
@@ -542,7 +927,7 @@ class B {
542
927
  * @param groupId Group ID
543
928
  */
544
929
  deleteGroup(e, t) {
545
- const s = `${c.tenantPath}/${e}/group/${t}`;
930
+ const s = `${h.tenantPath}/${e}/group/${t}`;
546
931
  return this.axiosClient.delete(s);
547
932
  }
548
933
  /**
@@ -553,8 +938,8 @@ class B {
553
938
  * @param role Role to assign
554
939
  */
555
940
  addUserToGroup(e, t, s, r) {
556
- const o = `${c.tenantPath}/${e}/group/${t}/add`, n = { user_id: s, role: r };
557
- return this.axiosClient.post(o, n);
941
+ const n = `${h.tenantPath}/${e}/group/${t}/add`, o = { user_id: s, role: r };
942
+ return this.axiosClient.post(n, o);
558
943
  }
559
944
  /**
560
945
  * Remove user roles from a group
@@ -564,8 +949,8 @@ class B {
564
949
  * @param roles Roles to remove
565
950
  */
566
951
  removeUserRolesFromGroup(e, t, s, r) {
567
- const o = `${c.tenantPath}/${e}/group/${t}/remove_roles`, n = { user_id: s, roles: r };
568
- return this.axiosClient.post(o, n);
952
+ const n = `${h.tenantPath}/${e}/group/${t}/remove_roles`, o = { user_id: s, roles: r };
953
+ return this.axiosClient.post(n, o);
569
954
  }
570
955
  /**
571
956
  * Change user roles in a group
@@ -575,8 +960,8 @@ class B {
575
960
  * @param roles New roles to assign
576
961
  */
577
962
  changeUserRoles(e, t, s, r) {
578
- const o = `${c.tenantPath}/${e}/group/${t}/change`, n = { user_id: s, roles: r };
579
- return this.axiosClient.post(o, n);
963
+ const n = `${h.tenantPath}/${e}/group/${t}/change`, o = { user_id: s, roles: r };
964
+ return this.axiosClient.post(n, o);
580
965
  }
581
966
  /**
582
967
  * Delete a user from a group
@@ -585,7 +970,7 @@ class B {
585
970
  * @param userId User ID
586
971
  */
587
972
  deleteUserFromGroup(e, t, s) {
588
- const r = `${c.tenantPath}/${e}/group/${t}/${s}`;
973
+ const r = `${h.tenantPath}/${e}/group/${t}/${s}`;
589
974
  return this.axiosClient.delete(r);
590
975
  }
591
976
  // 3. Role Management
@@ -594,7 +979,7 @@ class B {
594
979
  * @param tenantId Tenant ID
595
980
  */
596
981
  getRolesForTenant(e) {
597
- const t = `${c.tenantPath}/${e}/role`;
982
+ const t = `${h.tenantPath}/${e}/role`;
598
983
  return this.axiosClient.get(t);
599
984
  }
600
985
  /**
@@ -603,7 +988,7 @@ class B {
603
988
  * @param name Role name
604
989
  */
605
990
  createRoleForTenant(e, t) {
606
- const s = `${c.tenantPath}/${e}/role`, r = { name: t };
991
+ const s = `${h.tenantPath}/${e}/role`, r = { name: t };
607
992
  return this.axiosClient.post(s, r);
608
993
  }
609
994
  /**
@@ -613,8 +998,8 @@ class B {
613
998
  * @param name New role name
614
999
  */
615
1000
  updateRole(e, t, s) {
616
- const r = `${c.tenantPath}/${e}/role/${t}`, o = { name: s };
617
- return this.axiosClient.put(r, o);
1001
+ const r = `${h.tenantPath}/${e}/role/${t}`, n = { name: s };
1002
+ return this.axiosClient.put(r, n);
618
1003
  }
619
1004
  /**
620
1005
  * Delete a role
@@ -622,7 +1007,7 @@ class B {
622
1007
  * @param roleId Role ID
623
1008
  */
624
1009
  deleteRole(e, t) {
625
- const s = `${c.tenantPath}/${e}/role/${t}`;
1010
+ const s = `${h.tenantPath}/${e}/role/${t}`;
626
1011
  return this.axiosClient.delete(s);
627
1012
  }
628
1013
  // 4. User Management in Tenants
@@ -632,7 +1017,7 @@ class B {
632
1017
  * @param userId User ID
633
1018
  */
634
1019
  deleteUserFromTenant(e, t) {
635
- const s = `${c.tenantPath}/${e}/user/${t}`;
1020
+ const s = `${h.tenantPath}/${e}/user/${t}`;
636
1021
  return this.axiosClient.delete(s);
637
1022
  }
638
1023
  // 5. Invitation Management
@@ -644,8 +1029,8 @@ class B {
644
1029
  * @param skip Number of invitations to skip
645
1030
  */
646
1031
  getGroupInvitations(e, t, s, r) {
647
- const o = `${c.tenantPath}/${e}/group/${t}/invitations`;
648
- return this.axiosClient.get(o, {
1032
+ const n = `${h.tenantPath}/${e}/group/${t}/invitations`;
1033
+ return this.axiosClient.get(n, {
649
1034
  params: { limit: s, skip: r }
650
1035
  });
651
1036
  }
@@ -656,7 +1041,7 @@ class B {
656
1041
  * @param skip Number of invitations to skip
657
1042
  */
658
1043
  getTenantInvitations(e, t, s) {
659
- const r = `${c.tenantPath}/${e}/invitations`;
1044
+ const r = `${h.tenantPath}/${e}/invitations`;
660
1045
  return this.axiosClient.get(r, {
661
1046
  params: { limit: t, skip: s }
662
1047
  });
@@ -668,7 +1053,7 @@ class B {
668
1053
  * @param inviteId Invitation ID
669
1054
  */
670
1055
  invalidateInviteById(e, t, s) {
671
- const r = `${c.tenantPath}/${e}/group/${t}/invite/${s}`;
1056
+ const r = `${h.tenantPath}/${e}/group/${t}/invite/${s}`;
672
1057
  return this.axiosClient.delete(r);
673
1058
  }
674
1059
  /**
@@ -678,77 +1063,227 @@ class B {
678
1063
  * @param email Email address
679
1064
  */
680
1065
  invalidateInviteByEmail(e, t, s) {
681
- const r = `${c.tenantPath}/${e}/group/${t}/invite/email/${s}`;
1066
+ const r = `${h.tenantPath}/${e}/group/${t}/invite/email/${s}`;
682
1067
  return this.axiosClient.delete(r);
683
1068
  }
684
1069
  }
685
- class W {
686
- constructor(e) {
687
- this.axiosClient = new I(e);
1070
+ class me {
1071
+ constructor(e, t, s) {
1072
+ this.axiosClient = new T(e, t, s);
1073
+ }
1074
+ setAppId(e) {
1075
+ this.axiosClient.setAppId(e);
688
1076
  }
689
1077
  /**
690
- * Requests an invitation link that can be used to invite users
691
- * @param payload Request invitation payload
692
- * @returns Promise with invitation link and token
1078
+ * Get current 2FA enrollment status
1079
+ * GET /user/2fa/status
693
1080
  */
694
- requestInviteLink(e) {
1081
+ getStatus() {
1082
+ return this.axiosClient.get(h.twoFactorStatus);
1083
+ }
1084
+ /**
1085
+ * Begin 2FA setup process
1086
+ * POST /user/2fa/setup/begin
1087
+ * Returns secret and QR code for authenticator app
1088
+ */
1089
+ beginSetup() {
1090
+ return this.axiosClient.post(h.twoFactorSetupBegin, {});
1091
+ }
1092
+ /**
1093
+ * Confirm 2FA setup with TOTP code
1094
+ * POST /user/2fa/setup/confirm
1095
+ * Returns recovery codes on success
1096
+ */
1097
+ confirmSetup(e) {
695
1098
  return this.axiosClient.post(
696
- c.requestInvitation,
1099
+ h.twoFactorSetupConfirm,
697
1100
  e
698
1101
  );
699
1102
  }
700
1103
  /**
701
- * Gets a list of active invitations
702
- * @param options Optional parameters for filtering and pagination
703
- * @returns Promise with paginated list of invitations
1104
+ * Verify TOTP code during login
1105
+ * POST /auth/2fa/verify
1106
+ * Uses tfa_token as Bearer token for authentication
704
1107
  */
705
- getInvitations(e) {
706
- const t = {};
707
- e.groupID && (t.group_id = e.groupID.toString()), e.skip !== void 0 && (t.skip = e.skip.toString()), e.limit !== void 0 && (t.limit = e.limit.toString());
708
- const s = C(c.invitationsPath, {
709
- tenantID: e.tenantID
710
- });
711
- return this.axiosClient.get(s, { params: t }).then((r) => ({
712
- invites: r.invites,
713
- nextPageSkip: r.next_page_skip
714
- }));
1108
+ verify(e) {
1109
+ const { tfa_token: t, code: s } = e;
1110
+ return this.axiosClient.post(
1111
+ h.twoFactorVerify,
1112
+ { code: s },
1113
+ {
1114
+ headers: {
1115
+ Authorization: `Bearer ${t}`
1116
+ }
1117
+ }
1118
+ );
715
1119
  }
716
1120
  /**
717
- * Deletes an invitation by token
718
- * @param invitationID The invitation ID to delete
719
- * @returns Promise with success response
1121
+ * Use recovery code for authentication
1122
+ * POST /auth/2fa/recovery
1123
+ * Uses tfa_token as Bearer token for authentication
720
1124
  */
721
- deleteInvitation(e) {
722
- const t = C(c.invitationDelete, {
723
- invitationID: e
724
- });
725
- return this.axiosClient.delete(t);
1125
+ useRecoveryCode(e) {
1126
+ const { tfa_token: t, recovery_code: s } = e;
1127
+ return this.axiosClient.post(
1128
+ h.twoFactorRecovery,
1129
+ { recovery_code: s },
1130
+ {
1131
+ headers: {
1132
+ Authorization: `Bearer ${t}`
1133
+ }
1134
+ }
1135
+ );
726
1136
  }
727
1137
  /**
728
- * Resend an invitation by token
729
- * @param invitationID The invitation ID to resend
730
- * @returns Promise with success response
1138
+ * Disable 2FA (requires TOTP verification)
1139
+ * DELETE /user/2fa
731
1140
  */
732
- resendInvitation(e) {
733
- const t = C(c.invitationResend, {
734
- invitationID: e
1141
+ disable(e) {
1142
+ return this.axiosClient.delete(h.twoFactor, { data: e });
1143
+ }
1144
+ /**
1145
+ * Regenerate recovery codes
1146
+ * POST /user/2fa/recovery-codes/regenerate
1147
+ */
1148
+ regenerateRecoveryCodes(e) {
1149
+ return this.axiosClient.post(
1150
+ h.twoFactorRegenerateCodes,
1151
+ e
1152
+ );
1153
+ }
1154
+ /**
1155
+ * Validate magic link token for 2FA setup
1156
+ * GET /auth/2fa-setup/:token
1157
+ *
1158
+ * This endpoint validates an admin-generated magic link token
1159
+ * and returns a scoped session (scope: "2fa_setup") that can ONLY
1160
+ * be used for completing 2FA setup operations.
1161
+ *
1162
+ * This method never throws - it always returns a TwoFactorSetupMagicLinkValidationResponse
1163
+ * with either success=true and session data, or success=false and error details.
1164
+ *
1165
+ * @param token - Magic link token from URL parameter
1166
+ * @returns Validation response with scoped session token or error
1167
+ */
1168
+ validateTwoFactorSetupMagicLink(e) {
1169
+ const t = `${h.twoFactorSetupMagicLink}/${e}`;
1170
+ return this.axiosClient.get(t, {
1171
+ // Override default auth headers (this is a public endpoint)
1172
+ transformRequest: [
1173
+ (s, r) => (r && delete r.Authorization, s)
1174
+ ]
1175
+ }).then((s) => {
1176
+ const r = s;
1177
+ return {
1178
+ success: !0,
1179
+ sessionToken: r.session_token,
1180
+ userId: r.user_id,
1181
+ expiresIn: r.expires_in,
1182
+ appId: r.app_id
1183
+ };
1184
+ }).catch((s) => {
1185
+ if (s.response) {
1186
+ const r = s.response.status, n = s.response.data || {}, o = s.response.headers?.["retry-after"] ? parseInt(s.response.headers["retry-after"], 10) : void 0;
1187
+ return {
1188
+ success: !1,
1189
+ error: {
1190
+ code: n.error || this.mapStatusToErrorCode(r),
1191
+ message: n.message || this.getDefaultErrorMessage(r),
1192
+ retryAfter: o
1193
+ }
1194
+ };
1195
+ }
1196
+ return {
1197
+ success: !1,
1198
+ error: {
1199
+ code: "SERVER_ERROR",
1200
+ message: s instanceof Error ? s.message : "Unable to connect to the server. Please check your connection."
1201
+ }
1202
+ };
735
1203
  });
736
- return this.axiosClient.post(t, {});
737
1204
  }
738
1205
  /**
739
- * Get a link to an invitation by id
740
- * @param invitationID The invitation ID to get link
741
- * @returns Promise with the link
1206
+ * Map HTTP status code to magic link error code
742
1207
  */
743
- getInvitationLink(e) {
744
- const t = C(c.invitationGetLink, {
745
- invitationID: e
1208
+ mapStatusToErrorCode(e) {
1209
+ switch (e) {
1210
+ case 400:
1211
+ return "INVALID_TOKEN";
1212
+ case 404:
1213
+ return "REVOKED_TOKEN";
1214
+ case 410:
1215
+ return "EXPIRED_TOKEN";
1216
+ case 429:
1217
+ return "RATE_LIMITED";
1218
+ default:
1219
+ return "SERVER_ERROR";
1220
+ }
1221
+ }
1222
+ /**
1223
+ * Get default error message for HTTP status code
1224
+ */
1225
+ getDefaultErrorMessage(e) {
1226
+ switch (e) {
1227
+ case 400:
1228
+ return "The provided magic link is invalid or malformed.";
1229
+ case 404:
1230
+ return "This magic link has been revoked or does not exist.";
1231
+ case 410:
1232
+ return "This magic link has expired. Please request a new one from your administrator.";
1233
+ case 429:
1234
+ return "Too many validation attempts. Please try again later.";
1235
+ default:
1236
+ return "An error occurred while validating the magic link.";
1237
+ }
1238
+ }
1239
+ }
1240
+ class Se {
1241
+ constructor(e, t, s) {
1242
+ this.axiosClient = new T(e, t, s);
1243
+ }
1244
+ setAppId(e) {
1245
+ this.axiosClient.setAppId(e);
1246
+ }
1247
+ getUserPasskeys() {
1248
+ return this.axiosClient.get(h.userPasskey);
1249
+ }
1250
+ renameUserPasskey(e, t) {
1251
+ return this.axiosClient.patch(
1252
+ `${h.userPasskey}/${t}`,
1253
+ {
1254
+ name: e
1255
+ }
1256
+ );
1257
+ }
1258
+ deleteUserPasskey(e) {
1259
+ return this.axiosClient.delete(`${h.userPasskey}/${e}`);
1260
+ }
1261
+ addUserPasskeyStart({
1262
+ relyingPartyId: e,
1263
+ deviceId: t,
1264
+ os: s,
1265
+ passkeyDisplayName: r,
1266
+ passkeyUsername: n
1267
+ }) {
1268
+ const o = {
1269
+ passkey_display_name: r,
1270
+ passkey_username: n,
1271
+ relying_party_id: e,
1272
+ deviceId: t,
1273
+ os: s
1274
+ };
1275
+ return this.axiosClient.post(h.addUserPasskey, o);
1276
+ }
1277
+ addUserPasskeyComplete(e, t, s) {
1278
+ return this.axiosClient.post(h.completeAddUserPasskey, {
1279
+ challenge_id: s,
1280
+ device: t,
1281
+ passkey_data: e
746
1282
  });
747
- return this.axiosClient.get(t);
748
1283
  }
749
1284
  }
750
- var a = /* @__PURE__ */ ((i) => (i.SignIn = "signin", i.SignInStart = "signin:start", i.Register = "register", i.RegisterStart = "register:start", i.SignOut = "signout", i.Error = "error", i.Refresh = "refresh", i.RefreshStart = "refresh:start", i.TokenCacheExpired = "token-cache-expired", i))(a || {});
751
- class H {
1285
+ var a = /* @__PURE__ */ ((i) => (i.SignIn = "signin", i.SignInStart = "signin:start", i.Register = "register", i.RegisterStart = "register:start", i.SignOut = "signout", i.SessionRestored = "session:restored", i.Error = "error", i.Refresh = "refresh", i.RefreshStart = "refresh:start", i.TokenCacheExpired = "token-cache-expired", i.TwoFactorRequired = "2fa:required", i.TwoFactorSetupStarted = "2fa:setup_started", i.TwoFactorEnabled = "2fa:enabled", i.TwoFactorDisabled = "2fa:disabled", i.TwoFactorVerified = "2fa:verified", i.TwoFactorRecoveryUsed = "2fa:recovery_used", i.TwoFactorRecoveryCodesLow = "2fa:recovery_low", i.TwoFactorRecoveryCodesExhausted = "2fa:recovery_exhausted", i.TwoFactorSetupMagicLinkValidated = "2fa:magic_link_validated", i.TwoFactorSetupMagicLinkFailed = "2fa:magic_link_failed", i))(a || {});
1286
+ class we {
752
1287
  constructor() {
753
1288
  this.subscribers = /* @__PURE__ */ new Map();
754
1289
  }
@@ -788,36 +1323,179 @@ class H {
788
1323
  });
789
1324
  }
790
1325
  }
791
- class q {
792
- constructor(e, t, s, r, o, n, h, l, p, v, k) {
793
- this.authApi = e, this.deviceService = t, this.storageManager = s, this.subscribeStore = r, this.tokenCacheService = o, this.scopes = n, this.createTenantForNewUser = h, this.origin = l, this.url = p, this.sessionCallbacks = v, this.appId = k;
1326
+ function M(i) {
1327
+ if (!i || typeof i != "string") return !1;
1328
+ const e = i.split(".");
1329
+ if (e.length !== 3) return !1;
1330
+ const t = /^[A-Za-z0-9_-]+$/;
1331
+ return e.every((s) => t.test(s) && s.length > 0);
1332
+ }
1333
+ function Te(i) {
1334
+ return i.replace(/<[^>]*>/g, "").substring(0, oe);
1335
+ }
1336
+ function F(i) {
1337
+ if (!i || typeof i != "string") return !1;
1338
+ const e = i.trim();
1339
+ return e.length === 0 ? !1 : /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e);
1340
+ }
1341
+ function x(i) {
1342
+ if (!i || typeof i != "string") return !1;
1343
+ const e = i.trim();
1344
+ return /^\+[1-9]\d{1,14}$/.test(e);
1345
+ }
1346
+ function Ee(i) {
1347
+ if (!i || typeof i != "string") return !1;
1348
+ const e = i.trim();
1349
+ return e.length < ie || e.length > ne ? !1 : /^[a-zA-Z0-9_-]+$/.test(e);
1350
+ }
1351
+ function R(i, e = 6) {
1352
+ return !i || typeof i != "string" ? !1 : (e === 8 ? /^\d{8}$/ : /^\d{6}$/).test(i);
1353
+ }
1354
+ function _e(i) {
1355
+ if (!i || typeof i != "string") return null;
1356
+ const e = i.toUpperCase().replace(/\s+/g, "");
1357
+ return /^[A-Z0-9-]{4,16}$/.test(e) ? e : null;
1358
+ }
1359
+ class Ie {
1360
+ constructor(e, t, s, r, n, o, d, c, g, p, f, b) {
1361
+ this.authApi = e, this.deviceService = t, this.storageManager = s, this.subscribeStore = r, this.tokenCacheService = n, this.scopes = o, this.createTenantForNewUser = d, this.origin = c, this.url = g, this.sessionCallbacks = p, this.appId = f, this.tokenExchangeConfig = b, this.tokenDeliveryManager = new Y(s), b?.enabled && this.tokenDeliveryManager.setMode(v.BFF), this.initializeSession();
1362
+ }
1363
+ /**
1364
+ * Initialize session state on page load for cookie/BFF mode
1365
+ */
1366
+ async initializeSession() {
1367
+ (this.tokenDeliveryManager.isCookieMode() || this.tokenDeliveryManager.isBFFMode()) && await this.restoreSession();
1368
+ }
1369
+ /**
1370
+ * Restore session for cookie/BFF mode on page load
1371
+ * Validates that HttpOnly cookies are still valid
1372
+ * @returns true if session is valid, false otherwise
1373
+ */
1374
+ async restoreSession() {
1375
+ if (this.tokenDeliveryManager.isBFFMode() && this.tokenExchangeConfig?.statusUrl)
1376
+ try {
1377
+ const e = await fetch(this.tokenExchangeConfig.statusUrl, {
1378
+ method: "GET",
1379
+ credentials: "include"
1380
+ // Include httpOnly cookies
1381
+ });
1382
+ return e.ok && (await e.json()).authenticated ? (this.tokenDeliveryManager.setSessionValid(), !0) : (this.tokenDeliveryManager.setSessionInvalid(), !1);
1383
+ } catch {
1384
+ return this.tokenDeliveryManager.setSessionInvalid(), !1;
1385
+ }
1386
+ if (!this.tokenDeliveryManager.isCookieMode())
1387
+ return !1;
1388
+ try {
1389
+ const e = await this.authApi.validateSession();
1390
+ return e.valid ? (this.tokenDeliveryManager.setSessionValid(), e.user && this.subscribeStore.notify(a.SessionRestored, e.user), !0) : (this.tokenDeliveryManager.setSessionInvalid(), !1);
1391
+ } catch {
1392
+ return this.tokenDeliveryManager.setSessionInvalid(), !1;
1393
+ }
1394
+ }
1395
+ /**
1396
+ * Process successful authentication response
1397
+ * Handles token storage, session state, CSRF tokens
1398
+ * In BFF mode, forwards tokens to BFF server
1399
+ */
1400
+ async processAuthResponse(e, t) {
1401
+ this.tokenExchangeConfig?.enabled || "token_delivery" in e && e.token_delivery && this.tokenDeliveryManager.setMode(e.token_delivery), this.tokenDeliveryManager.setSessionValid(), this.tokenDeliveryManager.isBFFMode() && this.tokenExchangeConfig?.callbackUrl && await this.forwardTokensToBFF(e), e.scopes = t, this.storageManager.saveTokens(e, this.tokenDeliveryManager.getMode()), this.tokenCacheService.setTokensCache(e), e.csrf_token && this.storageManager.setCsrfToken(e.csrf_token);
1402
+ }
1403
+ /**
1404
+ * Forward tokens to BFF server for httpOnly cookie storage
1405
+ */
1406
+ async forwardTokensToBFF(e) {
1407
+ if (!this.tokenExchangeConfig?.callbackUrl)
1408
+ return;
1409
+ const t = await fetch(this.tokenExchangeConfig.callbackUrl, {
1410
+ method: "POST",
1411
+ credentials: "include",
1412
+ // Include/set httpOnly cookies
1413
+ headers: {
1414
+ "Content-Type": "application/json"
1415
+ },
1416
+ body: JSON.stringify({
1417
+ access_token: e.access_token,
1418
+ refresh_token: e.refresh_token,
1419
+ id_token: e.id_token,
1420
+ // expires_in is returned by the server but not typed in the SDK
1421
+ expires_in: e.expires_in
1422
+ })
1423
+ });
1424
+ if (!t.ok)
1425
+ throw new Error(`BFF token storage failed: ${t.status}`);
794
1426
  }
795
1427
  async signIn(e) {
1428
+ if ("email" in e && e.email && !F(e.email)) {
1429
+ const r = new Error("Invalid email format"), n = {
1430
+ message: "Invalid email format",
1431
+ originalError: r,
1432
+ code: "VALIDATION_ERROR"
1433
+ };
1434
+ throw this.subscribeStore.notify(a.Error, n), r;
1435
+ }
1436
+ if ("username" in e && e.username && !Ee(e.username)) {
1437
+ const r = new Error(
1438
+ "Invalid username format. Username must be 3-30 characters and contain only letters, numbers, underscores, and hyphens"
1439
+ ), n = {
1440
+ message: "Invalid username format. Username must be 3-30 characters and contain only letters, numbers, underscores, and hyphens",
1441
+ originalError: r,
1442
+ code: "VALIDATION_ERROR"
1443
+ };
1444
+ throw this.subscribeStore.notify(a.Error, n), r;
1445
+ }
1446
+ if ("phone" in e && e.phone && !x(e.phone)) {
1447
+ const r = new Error("Invalid phone number format. Phone must be in E.164 format (e.g., +12345678901)"), n = {
1448
+ message: "Invalid phone number format. Phone must be in E.164 format (e.g., +12345678901)",
1449
+ originalError: r,
1450
+ code: "VALIDATION_ERROR"
1451
+ };
1452
+ throw this.subscribeStore.notify(a.Error, n), r;
1453
+ }
796
1454
  this.subscribeStore.notify(a.SignInStart, { email: e.email });
797
- const t = this.deviceService.getDeviceId(), s = w.web;
1455
+ const t = this.deviceService.getDeviceId(), s = I.web;
798
1456
  e.scopes = e.scopes ?? this.scopes;
799
1457
  try {
800
1458
  const r = await this.authApi.signIn(e, t, s);
801
- return r.scopes = e.scopes, this.storageManager.saveTokens(r), this.tokenCacheService.setTokensCache(r), this.subscribeStore.notify(a.SignIn, {
1459
+ return "requires_2fa" in r && r.requires_2fa === !0 || "tfa_token" in r && r.tfa_token ? (this.subscribeStore.notify(a.TwoFactorRequired, {
1460
+ email: e.email || "",
1461
+ challengeId: r.challenge_id || "",
1462
+ tfaToken: r.tfa_token || ""
1463
+ }), r) : (await this.processAuthResponse(r, e.scopes), this.subscribeStore.notify(a.SignIn, {
802
1464
  tokens: r,
803
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
804
- }), await this.submitSessionCheck(), r;
1465
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1466
+ }), await this.submitSessionCheck(), r);
805
1467
  } catch (r) {
806
- const o = {
1468
+ const n = {
807
1469
  message: r instanceof Error ? r.message : "Sign in failed",
808
1470
  originalError: r,
809
1471
  code: r instanceof u ? r.id : void 0
810
1472
  };
811
- throw this.subscribeStore.notify(a.Error, o), r;
1473
+ throw this.subscribeStore.notify(a.Error, n), r;
812
1474
  }
813
1475
  }
814
1476
  async signUp(e) {
1477
+ if (e.user.email && !F(e.user.email)) {
1478
+ const t = new Error("Invalid email format"), s = {
1479
+ message: "Invalid email format",
1480
+ originalError: t,
1481
+ code: "VALIDATION_ERROR"
1482
+ };
1483
+ throw this.subscribeStore.notify(a.Error, s), t;
1484
+ }
1485
+ if (e.user.phone_number && !x(e.user.phone_number)) {
1486
+ const t = new Error("Invalid phone number format. Phone must be in E.164 format (e.g., +12345678901)"), s = {
1487
+ message: "Invalid phone number format. Phone must be in E.164 format (e.g., +12345678901)",
1488
+ originalError: t,
1489
+ code: "VALIDATION_ERROR"
1490
+ };
1491
+ throw this.subscribeStore.notify(a.Error, s), t;
1492
+ }
815
1493
  this.subscribeStore.notify(a.RegisterStart, { email: e.user.email }), e.scopes = e.scopes ?? this.scopes, e.create_tenant = this.createTenantForNewUser;
816
1494
  try {
817
1495
  const t = await this.authApi.signUp(e);
818
- return t.scopes = e.scopes, this.storageManager.saveTokens(t), this.tokenCacheService.setTokensCache(t), this.subscribeStore.notify(a.Register, {
1496
+ return await this.processAuthResponse(t, e.scopes), this.subscribeStore.notify(a.Register, {
819
1497
  tokens: t,
820
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
1498
+ parsedTokens: this.tokenCacheService.getParsedTokens()
821
1499
  }), await this.submitSessionCheck(), t;
822
1500
  } catch (t) {
823
1501
  const s = {
@@ -829,26 +1507,42 @@ class q {
829
1507
  }
830
1508
  }
831
1509
  async passwordlessSignIn(e) {
1510
+ if (e.email && !F(e.email)) {
1511
+ const r = new Error("Invalid email format"), n = {
1512
+ message: "Invalid email format",
1513
+ originalError: r,
1514
+ code: "VALIDATION_ERROR"
1515
+ };
1516
+ throw this.subscribeStore.notify(a.Error, n), r;
1517
+ }
1518
+ if (e.phone && !x(e.phone)) {
1519
+ const r = new Error("Invalid phone number format. Phone must be in E.164 format (e.g., +12345678901)"), n = {
1520
+ message: "Invalid phone number format. Phone must be in E.164 format (e.g., +12345678901)",
1521
+ originalError: r,
1522
+ code: "VALIDATION_ERROR"
1523
+ };
1524
+ throw this.subscribeStore.notify(a.Error, n), r;
1525
+ }
832
1526
  this.subscribeStore.notify(a.SignInStart, { email: e.email }), e.scopes = e.scopes ?? this.scopes;
833
- const t = this.deviceService.getDeviceId(), s = w.web;
1527
+ const t = this.deviceService.getDeviceId(), s = I.web;
834
1528
  try {
835
1529
  return await this.authApi.passwordlessSignIn(e, t, s);
836
1530
  } catch (r) {
837
- const o = {
1531
+ const n = {
838
1532
  message: r instanceof Error ? r.message : "Failed to send passwordless sign-in link",
839
1533
  originalError: r,
840
1534
  code: r instanceof u ? r.id : void 0
841
1535
  };
842
- throw this.subscribeStore.notify(a.Error, o), r;
1536
+ throw this.subscribeStore.notify(a.Error, n), r;
843
1537
  }
844
1538
  }
845
1539
  async passwordlessSignInComplete(e) {
846
1540
  this.subscribeStore.notify(a.SignInStart, {}), e.scopes = e.scopes ?? this.scopes, e.device = this.deviceService.getDeviceId();
847
1541
  try {
848
1542
  const t = await this.authApi.passwordlessSignInComplete(e);
849
- return t.scopes = e.scopes, this.storageManager.saveTokens(t), this.tokenCacheService.setTokensCache(t), this.subscribeStore.notify(a.SignIn, {
1543
+ return await this.processAuthResponse(t, e.scopes), this.subscribeStore.notify(a.SignIn, {
850
1544
  tokens: t,
851
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
1545
+ parsedTokens: this.tokenCacheService.getParsedTokens()
852
1546
  }), await this.submitSessionCheck(), t;
853
1547
  } catch (t) {
854
1548
  const s = {
@@ -860,17 +1554,64 @@ class q {
860
1554
  }
861
1555
  }
862
1556
  async logOut() {
863
- const e = this.storageManager.getToken(g.refresh_token), t = this.storageManager.getDeviceId();
864
- try {
865
- if ((await this.authApi.logOut(t, e, !this.appId)).status !== "ok")
866
- throw new Error("Logout failed");
867
- this.storageManager.deleteTokens(), this.subscribeStore.notify(a.SignOut, {});
868
- } catch (s) {
869
- throw console.error(s), s;
1557
+ if (this.tokenDeliveryManager.isBFFMode() && this.tokenExchangeConfig?.logoutUrl)
1558
+ try {
1559
+ (await fetch(this.tokenExchangeConfig.logoutUrl, {
1560
+ method: "POST",
1561
+ credentials: "include"
1562
+ // Include httpOnly cookies
1563
+ })).ok;
1564
+ } catch {
1565
+ }
1566
+ else {
1567
+ const e = this.storageManager.getToken(k.refresh_token), t = this.storageManager.getDeviceId();
1568
+ try {
1569
+ if ((await this.authApi.logOut(t, e, !this.appId)).status !== "ok")
1570
+ throw new Error("Logout failed");
1571
+ } catch {
1572
+ }
870
1573
  }
1574
+ this.storageManager.deleteTokens(), this.storageManager.clearIdToken(), this.storageManager.clearCsrfToken(), this.tokenDeliveryManager.reset(), this.subscribeStore.notify(a.SignOut, {});
871
1575
  }
872
1576
  async refreshToken() {
873
- this.subscribeStore.notify(a.RefreshStart, {});
1577
+ if (this.subscribeStore.notify(a.RefreshStart, {}), this.tokenDeliveryManager.isBFFMode() && this.tokenExchangeConfig?.refreshUrl)
1578
+ try {
1579
+ const s = await fetch(this.tokenExchangeConfig.refreshUrl, {
1580
+ method: "POST",
1581
+ credentials: "include"
1582
+ // Include httpOnly cookies
1583
+ });
1584
+ if (!s.ok)
1585
+ throw this.tokenDeliveryManager.setSessionInvalid(), new Error("BFF token refresh failed");
1586
+ const r = await s.json();
1587
+ return this.tokenDeliveryManager.setSessionValid(), r.id_token && this.storageManager.setIdToken(r.id_token), this.subscribeStore.notify(a.Refresh, {
1588
+ tokens: r,
1589
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1590
+ }), this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !1 }), this.tokenCacheService.isRefreshing = !1, this.tokenCacheService.tokenExpiredFlag = !1, r;
1591
+ } catch (s) {
1592
+ this.tokenDeliveryManager.setSessionInvalid();
1593
+ const r = {
1594
+ message: s instanceof Error ? s.message : "Token refresh failed",
1595
+ originalError: s
1596
+ };
1597
+ throw this.subscribeStore.notify(a.Error, r), s;
1598
+ }
1599
+ if (this.tokenDeliveryManager.isCookieMode())
1600
+ try {
1601
+ const s = await this.authApi.refreshToken("", this.scopes);
1602
+ return this.tokenDeliveryManager.setSessionValid(), await this.processAuthResponse(s, this.scopes), this.subscribeStore.notify(a.Refresh, {
1603
+ tokens: s,
1604
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1605
+ }), this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !1 }), this.tokenCacheService.isRefreshing = !1, this.tokenCacheService.tokenExpiredFlag = !1, s;
1606
+ } catch (s) {
1607
+ this.tokenDeliveryManager.setSessionInvalid();
1608
+ const r = {
1609
+ message: s instanceof Error ? s.message : "Token refresh failed",
1610
+ originalError: s,
1611
+ code: s instanceof u ? s.id : void 0
1612
+ };
1613
+ throw this.subscribeStore.notify(a.Error, r), s;
1614
+ }
874
1615
  const e = this.storageManager.getTokens();
875
1616
  if (e) {
876
1617
  if (!e?.refresh_token) {
@@ -892,19 +1633,19 @@ class q {
892
1633
  const s = await this.authApi.refreshToken(e?.refresh_token ?? "", t, e?.access_token);
893
1634
  return s.scopes = t, this.storageManager.saveTokens(s), this.tokenCacheService.setTokensCache(s), this.subscribeStore.notify(a.Refresh, {
894
1635
  tokens: s,
895
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
896
- }), this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !1 }), this.tokenCacheService.isRefreshing = !1, this.tokenCacheService.isExpired = !1, this.tokenCacheService.startTokenCheck(), s;
1636
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1637
+ }), this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !1 }), this.tokenCacheService.isRefreshing = !1, this.tokenCacheService.tokenExpiredFlag = !1, this.tokenCacheService.startTokenCheck(), s;
897
1638
  } catch (s) {
898
1639
  const r = {
899
1640
  message: s instanceof Error ? s.message : "Token refresh failed",
900
1641
  originalError: s,
901
1642
  code: s instanceof u ? s.id : void 0,
902
- details: T.isAxiosError(s) && s.response ? {
1643
+ details: D.isAxiosError(s) && s.response ? {
903
1644
  status: s.response.status,
904
1645
  data: s.response.data
905
1646
  } : void 0
906
1647
  };
907
- throw this.subscribeStore.notify(a.Error, r), s instanceof u ? s : T.isAxiosError(s) && s.response && s.response?.status >= 400 && s.response?.status < 500 ? new Error(`Getting unknown error message from server with code:${s.response.status}`) : s;
1648
+ throw this.subscribeStore.notify(a.Error, r), s instanceof u ? s : D.isAxiosError(s) && s.response && s.response?.status >= 400 && s.response?.status < 500 ? new Error(`Getting unknown error message from server with code:${s.response.status}`) : s;
908
1649
  }
909
1650
  }
910
1651
  async sendPasswordResetEmail(e) {
@@ -921,74 +1662,74 @@ class q {
921
1662
  }
922
1663
  async resetPassword(e, t) {
923
1664
  this.subscribeStore.notify(a.SignInStart, {});
924
- const r = new URLSearchParams(window.location.search).get("token") ?? void 0, o = t ?? this.scopes;
1665
+ const r = new URLSearchParams(window.location.search).get("token") ?? void 0, n = t ?? this.scopes;
925
1666
  try {
926
- const n = await this.authApi.resetPassword(e, o, r);
927
- return n.scopes = o, this.storageManager.saveTokens(n), this.tokenCacheService.setTokensCache(n), this.subscribeStore.notify(a.SignIn, {
928
- tokens: n,
929
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
930
- }), await this.submitSessionCheck(), n;
931
- } catch (n) {
932
- const h = {
933
- message: n instanceof Error ? n.message : "Password reset failed",
934
- originalError: n,
935
- code: n instanceof u ? n.id : void 0
1667
+ const o = await this.authApi.resetPassword(e, n, r);
1668
+ return await this.processAuthResponse(o, n), this.subscribeStore.notify(a.SignIn, {
1669
+ tokens: o,
1670
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1671
+ }), await this.submitSessionCheck(), o;
1672
+ } catch (o) {
1673
+ const d = {
1674
+ message: o instanceof Error ? o.message : "Password reset failed",
1675
+ originalError: o,
1676
+ code: o instanceof u ? o.id : void 0
936
1677
  };
937
- throw this.subscribeStore.notify(a.Error, h), n;
1678
+ throw this.subscribeStore.notify(a.Error, d), o;
938
1679
  }
939
1680
  }
940
1681
  async passkeyRegister(e) {
941
1682
  this.subscribeStore.notify(a.RegisterStart, {});
942
- const t = this.deviceService.getDeviceId(), s = w.web;
1683
+ const t = this.deviceService.getDeviceId(), s = I.web;
943
1684
  e.scopes = e.scopes ?? this.scopes, e.create_tenant = this.createTenantForNewUser;
944
1685
  try {
945
- const { challenge_id: r, publicKey: o } = await this.authApi.passkeyRegisterStart(e, t, s, !this.appId);
946
- o.user.id = btoa(o.user.id);
947
- const n = await _({
948
- optionsJSON: o
949
- }), h = await this.authApi.passkeyRegisterComplete(
950
- n,
1686
+ const { challenge_id: r, publicKey: n } = await this.authApi.passkeyRegisterStart(e, t, s, !this.appId);
1687
+ n.user.id = btoa(n.user.id);
1688
+ const o = await K({
1689
+ optionsJSON: n
1690
+ }), d = await this.authApi.passkeyRegisterComplete(
1691
+ o,
951
1692
  t,
952
1693
  r,
953
1694
  !this.appId
954
1695
  );
955
- return h.scopes = e.scopes, this.storageManager.saveTokens(h), this.tokenCacheService.setTokensCache(h), this.subscribeStore.notify(a.Register, {
956
- tokens: h,
957
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
958
- }), await this.submitSessionCheck(), h;
1696
+ return await this.processAuthResponse(d, e.scopes), this.subscribeStore.notify(a.Register, {
1697
+ tokens: d,
1698
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1699
+ }), await this.submitSessionCheck(), d;
959
1700
  } catch (r) {
960
- const o = {
1701
+ const n = {
961
1702
  message: r instanceof Error ? r.message : "Passkey registration failed",
962
1703
  originalError: r,
963
1704
  code: r instanceof u ? r.id : void 0
964
1705
  };
965
- throw this.subscribeStore.notify(a.Error, o), r;
1706
+ throw this.subscribeStore.notify(a.Error, n), r;
966
1707
  }
967
1708
  }
968
1709
  async passkeyAuthenticate(e) {
969
1710
  this.subscribeStore.notify(a.SignInStart, {});
970
- const t = this.deviceService.getDeviceId(), s = w.web;
1711
+ const t = this.deviceService.getDeviceId(), s = I.web;
971
1712
  e.scopes = e.scopes ?? this.scopes;
972
1713
  try {
973
- const { challenge_id: r, publicKey: o } = await this.authApi.passkeyAuthenticateStart(e, t, s, !this.appId), n = await U({
974
- optionsJSON: o
975
- }), h = await this.authApi.passkeyAuthenticateComplete(
976
- n,
1714
+ const { challenge_id: r, publicKey: n } = await this.authApi.passkeyAuthenticateStart(e, t, s, !this.appId), o = await j({
1715
+ optionsJSON: n
1716
+ }), d = await this.authApi.passkeyAuthenticateComplete(
1717
+ o,
977
1718
  t,
978
1719
  r,
979
1720
  !this.appId
980
1721
  );
981
- return "access_token" in h && (h.scopes = e.scopes, this.storageManager.saveTokens(h), this.tokenCacheService.setTokensCache(h), this.subscribeStore.notify(a.SignIn, {
982
- tokens: h,
983
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
984
- }), await this.submitSessionCheck()), h;
1722
+ return "access_token" in d && (await this.processAuthResponse(d, e.scopes), this.subscribeStore.notify(a.SignIn, {
1723
+ tokens: d,
1724
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1725
+ }), await this.submitSessionCheck()), d;
985
1726
  } catch (r) {
986
- const o = {
1727
+ const n = {
987
1728
  message: r instanceof Error ? r.message : "Passkey authentication failed",
988
1729
  originalError: r,
989
1730
  code: r instanceof u ? r.id : void 0
990
1731
  };
991
- throw this.subscribeStore.notify(a.Error, o), r;
1732
+ throw this.subscribeStore.notify(a.Error, n), r;
992
1733
  }
993
1734
  }
994
1735
  createFederatedAuthUrl(e) {
@@ -1001,30 +1742,53 @@ class q {
1001
1742
  ...e.invite_token ? { invite_token: e.invite_token } : {},
1002
1743
  ...e.create_tenant ? { create_tenant: e.create_tenant.toString() } : {},
1003
1744
  ...e.device ? { device: e.device } : {}
1004
- }, o = new URL(t, this.url), n = new URLSearchParams(r);
1005
- return o.search = n.toString(), o.toString();
1745
+ }, n = new URL(t, this.url), o = new URLSearchParams(r);
1746
+ return n.search = o.toString(), n.toString();
1006
1747
  }
1007
1748
  federatedAuthWithPopup(e) {
1008
1749
  this.subscribeStore.notify(a.SignInStart, { provider: e.provider });
1009
- const t = e.scopes ?? this.scopes, s = this.deviceService.getDeviceId(), r = this.createFederatedAuthUrl({ ...e, scopes: t, device: s }), o = window.open(r, "_blank", "width=500,height=500");
1010
- if (!o)
1750
+ const t = e.scopes ?? this.scopes, s = this.deviceService.getDeviceId(), r = this.createFederatedAuthUrl({ ...e, scopes: t, device: s }), n = window.open(r, "_blank", `width=${ee},height=${te}`);
1751
+ if (!n) {
1011
1752
  this.federatedAuthWithRedirect(e);
1012
- else {
1013
- const n = setInterval(() => {
1014
- if (o.location.href.startsWith(this.origin)) {
1015
- const h = new URLSearchParams(o.location.search), l = h.get("access_token") || "", p = h.get("refresh_token") || "", v = h.get("id_token") || "", k = {
1016
- access_token: l,
1017
- refresh_token: p,
1018
- id_token: v,
1753
+ return;
1754
+ }
1755
+ const o = Date.now(), d = setInterval(() => {
1756
+ if (n.closed) {
1757
+ clearInterval(d);
1758
+ const c = {
1759
+ message: "Authentication popup was closed",
1760
+ code: "POPUP_CLOSED"
1761
+ };
1762
+ this.subscribeStore.notify(a.Error, c);
1763
+ return;
1764
+ }
1765
+ if (Date.now() - o > re) {
1766
+ clearInterval(d), n.close();
1767
+ const c = {
1768
+ message: "Authentication popup timed out",
1769
+ code: "POPUP_TIMEOUT"
1770
+ };
1771
+ this.subscribeStore.notify(a.Error, c);
1772
+ return;
1773
+ }
1774
+ try {
1775
+ if (n.location.href.startsWith(this.origin)) {
1776
+ const c = new URLSearchParams(n.location.search), g = c.get("access_token") || "", p = c.get("refresh_token") || "", f = c.get("id_token") || "", b = {
1777
+ access_token: g,
1778
+ refresh_token: p || void 0,
1779
+ id_token: f || void 0,
1019
1780
  scopes: t
1020
1781
  };
1021
- this.storageManager.saveTokens(k), this.tokenCacheService.setTokensCache(k), this.subscribeStore.notify(a.SignIn, {
1022
- tokens: k,
1023
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
1024
- }), window.location.href = `${this.origin}`, clearInterval(n), o.close();
1782
+ this.processAuthResponse(b, t).then(() => {
1783
+ this.subscribeStore.notify(a.SignIn, {
1784
+ tokens: b,
1785
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1786
+ }), window.location.href = `${this.origin}`;
1787
+ }), clearInterval(d), n.close();
1025
1788
  }
1026
- }, 100);
1027
- }
1789
+ } catch {
1790
+ }
1791
+ }, se);
1028
1792
  }
1029
1793
  federatedAuthWithRedirect(e) {
1030
1794
  this.subscribeStore.notify(a.SignInStart, { provider: e.provider });
@@ -1034,14 +1798,14 @@ class q {
1034
1798
  // Helper methods for authentication UI redirect
1035
1799
  authRedirectUrl(e = {}) {
1036
1800
  try {
1037
- const { url: t, redirectUrl: s, scopes: r, appId: o } = e ?? {}, n = new URL(t ?? this.url);
1038
- n.pathname = (n.pathname.endsWith("/") ? n.pathname : n.pathname + "/") + "web";
1039
- const h = r ?? this.scopes, l = {
1040
- appId: o ?? this.appId ?? "",
1801
+ const { url: t, redirectUrl: s, scopes: r, appId: n } = e ?? {}, o = new URL(t ?? this.url);
1802
+ o.pathname = (o.pathname.endsWith("/") ? o.pathname : o.pathname + "/") + "web";
1803
+ const d = r ?? this.scopes, c = {
1804
+ appId: n ?? this.appId ?? "",
1041
1805
  redirectto: s ?? window.location.href,
1042
- scopes: h.join(",")
1043
- }, p = new URLSearchParams(l);
1044
- return n.search = p.toString(), n.toString();
1806
+ scopes: d.join(",")
1807
+ }, g = new URLSearchParams(c);
1808
+ return o.search = g.toString(), o.toString();
1045
1809
  } catch (t) {
1046
1810
  const s = {
1047
1811
  message: t instanceof Error ? t.message : "Failed to create auth redirect URL",
@@ -1063,10 +1827,15 @@ class q {
1063
1827
  }
1064
1828
  /**
1065
1829
  * Check if user is authenticated
1830
+ * CRITICAL: Cookie/BFF mode checks ID token + session state, NOT access_token
1066
1831
  */
1067
1832
  isAuthenticated(e) {
1068
1833
  try {
1069
- return e ? !f(e.access_token) || !!e.refresh_token && !f(e.refresh_token) : !1;
1834
+ if (this.tokenDeliveryManager.isCookieMode() || this.tokenDeliveryManager.isBFFMode()) {
1835
+ const t = !!e?.id_token || !!this.storageManager.getIdToken(), s = this.tokenDeliveryManager.isSessionValid(), r = this.tokenDeliveryManager.isSessionUnknown();
1836
+ return t && (s || r);
1837
+ }
1838
+ return !e || !e.access_token ? !1 : !m(e.access_token) || e.refresh_token !== void 0 && !m(e.refresh_token);
1070
1839
  } catch (t) {
1071
1840
  const s = {
1072
1841
  message: t instanceof Error ? t.message : "Failed to check authentication status",
@@ -1081,25 +1850,31 @@ class q {
1081
1850
  async submitSessionCheck(e = !1) {
1082
1851
  let t, s;
1083
1852
  try {
1084
- t = await this.getTokens(e), s = this.tokenCacheService.getParsedTokenCache();
1853
+ t = await this.getTokens(e), s = this.tokenCacheService.getParsedTokens();
1085
1854
  } catch (r) {
1086
- const o = {
1855
+ const n = {
1087
1856
  message: r instanceof Error || r instanceof u ? r.message : "Session check failed",
1088
1857
  originalError: r
1089
1858
  };
1090
- this.subscribeStore.notify(a.Error, o), t = void 0;
1859
+ this.subscribeStore.notify(a.Error, n), t = void 0;
1091
1860
  }
1092
1861
  return t && this.sessionCallbacks.createSession && await this.sessionCallbacks.createSession({ tokens: t, parsedTokens: s }), !t && this.sessionCallbacks.expiredSession && await this.sessionCallbacks.expiredSession(), t;
1093
1862
  }
1094
1863
  /**
1095
1864
  * Get tokens and refresh if needed
1865
+ * Cookie/BFF mode: Returns ID token only (access/refresh in HttpOnly cookies)
1866
+ * JSON mode: Returns all tokens from localStorage
1096
1867
  */
1097
1868
  async getTokens(e) {
1098
1869
  try {
1870
+ if (this.tokenDeliveryManager.isCookieMode() || this.tokenDeliveryManager.isBFFMode()) {
1871
+ const r = this.storageManager.getTokens();
1872
+ return r?.id_token ? this.tokenDeliveryManager.isSessionInvalid() && e ? await this.refreshToken() : r : void 0;
1873
+ }
1099
1874
  const t = this.storageManager.getTokens();
1100
1875
  if (!t || !t.access_token) return;
1101
- const s = d(t.access_token);
1102
- return f(s) ? e ? await this.refreshToken() : void 0 : t;
1876
+ const s = y(t.access_token);
1877
+ return m(s) ? e ? await this.refreshToken() : void 0 : t;
1103
1878
  } catch (t) {
1104
1879
  const s = {
1105
1880
  message: t instanceof Error ? t.message : "Failed to get tokens",
@@ -1110,9 +1885,9 @@ class q {
1110
1885
  }
1111
1886
  }
1112
1887
  }
1113
- class V {
1888
+ class be {
1114
1889
  constructor(e) {
1115
- this.invitationAPI = e;
1890
+ this.invitationApi = e;
1116
1891
  }
1117
1892
  /**
1118
1893
  * Requests an invitation link that can be used to invite users
@@ -1120,7 +1895,7 @@ class V {
1120
1895
  * @returns Promise with invitation link and token
1121
1896
  */
1122
1897
  requestInviteLink(e) {
1123
- return this.invitationAPI.requestInviteLink(e);
1898
+ return this.invitationApi.requestInviteLink(e);
1124
1899
  }
1125
1900
  /**
1126
1901
  * Gets a list of active invitations
@@ -1128,7 +1903,7 @@ class V {
1128
1903
  * @returns Promise with paginated list of invitations
1129
1904
  */
1130
1905
  getInvitations(e) {
1131
- return this.invitationAPI.getInvitations(e);
1906
+ return this.invitationApi.getInvitations(e);
1132
1907
  }
1133
1908
  /**
1134
1909
  * Deletes an invitation by token
@@ -1136,7 +1911,7 @@ class V {
1136
1911
  * @returns Promise with success response
1137
1912
  */
1138
1913
  deleteInvitation(e) {
1139
- return this.invitationAPI.deleteInvitation(e);
1914
+ return this.invitationApi.deleteInvitation(e);
1140
1915
  }
1141
1916
  /**
1142
1917
  * Resends an invitation by token
@@ -1144,7 +1919,7 @@ class V {
1144
1919
  * @returns Promise with success response
1145
1920
  */
1146
1921
  resendInvitation(e) {
1147
- return this.invitationAPI.resendInvitation(e);
1922
+ return this.invitationApi.resendInvitation(e);
1148
1923
  }
1149
1924
  /**
1150
1925
  * Gets a link to an invitation by id
@@ -1152,10 +1927,10 @@ class V {
1152
1927
  * @returns Promise with the link
1153
1928
  */
1154
1929
  getInvitationLink(e) {
1155
- return this.invitationAPI.getInvitationLink(e);
1930
+ return this.invitationApi.getInvitationLink(e);
1156
1931
  }
1157
1932
  }
1158
- class z {
1933
+ class Ce {
1159
1934
  error(e, ...t) {
1160
1935
  console.error(e, ...t);
1161
1936
  }
@@ -1169,40 +1944,40 @@ class z {
1169
1944
  console.debug(e, ...t);
1170
1945
  }
1171
1946
  }
1172
- function J() {
1173
- return new z();
1947
+ function Ae() {
1948
+ return new Ce();
1174
1949
  }
1175
- class Y {
1950
+ class Re {
1176
1951
  constructor(e) {
1177
1952
  this.data = this.normalize(e);
1178
1953
  }
1179
1954
  normalize(e) {
1180
- const t = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), o = [];
1181
- return e.groups?.forEach((n) => {
1182
- s.set(n.id, {
1183
- id: n.id,
1184
- name: n.name,
1185
- default: n.default ?? !1,
1186
- updated_at: n.updated_at,
1187
- created_at: n.created_at
1955
+ const t = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), n = [];
1956
+ return e.groups?.forEach((o) => {
1957
+ s.set(o.id, {
1958
+ id: o.id,
1959
+ name: o.name,
1960
+ default: o.default ?? !1,
1961
+ updated_at: o.updated_at,
1962
+ created_at: o.created_at
1188
1963
  });
1189
- }), e.roles?.forEach((n) => {
1190
- r.set(n.id, {
1191
- id: n.id,
1192
- tenant_id: n.tenant_id,
1193
- name: n.name
1964
+ }), e.roles?.forEach((o) => {
1965
+ r.set(o.id, {
1966
+ id: o.id,
1967
+ tenant_id: o.tenant_id,
1968
+ name: o.name
1194
1969
  });
1195
- }), e.users_in_groups?.forEach((n) => {
1196
- const h = n.user;
1197
- h && !t.has(h.id) && t.set(h.id, {
1198
- id: h.id,
1199
- name: h.name ?? null,
1200
- email: h.email ?? null,
1201
- phone: h.phone ?? null
1202
- }), h && n.group_id && s.has(n.group_id) && o.push({
1203
- userId: h.id,
1204
- groupId: n.group_id,
1205
- roleIds: n.roles?.map((l) => l.id) ?? []
1970
+ }), e.users_in_groups?.forEach((o) => {
1971
+ const d = o.user;
1972
+ d && !t.has(d.id) && t.set(d.id, {
1973
+ id: d.id,
1974
+ name: d.name ?? null,
1975
+ email: d.email ?? null,
1976
+ phone: d.phone ?? null
1977
+ }), d && o.group_id && s.has(o.group_id) && n.push({
1978
+ userId: d.id,
1979
+ groupId: o.group_id,
1980
+ roleIds: o.roles?.map((c) => c.id) ?? []
1206
1981
  });
1207
1982
  }), {
1208
1983
  tenant_id: e.tenant_id,
@@ -1210,7 +1985,7 @@ class Y {
1210
1985
  users: Array.from(t.values()),
1211
1986
  groups: Array.from(s.values()),
1212
1987
  roles: Array.from(r.values()),
1213
- memberships: o,
1988
+ memberships: n,
1214
1989
  usersById: t,
1215
1990
  groupsById: s,
1216
1991
  rolesById: r
@@ -1242,9 +2017,9 @@ class Y {
1242
2017
  return this.data;
1243
2018
  }
1244
2019
  }
1245
- class X {
2020
+ class Pe {
1246
2021
  constructor(e, t, s) {
1247
- this.tenantAPI = e, this.scopes = t, this.logger = s || J();
2022
+ this.tenantApi = e, this.scopes = t, this.logger = s || Ae();
1248
2023
  }
1249
2024
  /**
1250
2025
  * Handle Passflow API errors
@@ -1253,7 +2028,7 @@ class X {
1253
2028
  * @throws Formatted error with Passflow API error details
1254
2029
  */
1255
2030
  handlePassflowError(e, t) {
1256
- if (T.isAxiosError(e) && e.response?.data) {
2031
+ if (D.isAxiosError(e) && e.response?.data) {
1257
2032
  const s = e.response.data;
1258
2033
  if (typeof s == "object" && s !== null && "error" in s && typeof s.error == "object" && s.error !== null) {
1259
2034
  const r = s.error;
@@ -1271,7 +2046,7 @@ class X {
1271
2046
  async joinInvitation(e, t) {
1272
2047
  try {
1273
2048
  const s = t ?? this.scopes;
1274
- return await this.tenantAPI.joinInvitation(e, s);
2049
+ return await this.tenantApi.joinInvitation(e, s);
1275
2050
  } catch (s) {
1276
2051
  this.handlePassflowError(s, "Join invitation failed");
1277
2052
  }
@@ -1283,7 +2058,7 @@ class X {
1283
2058
  */
1284
2059
  async createTenant(e) {
1285
2060
  try {
1286
- return await this.tenantAPI.createTenant(e);
2061
+ return await this.tenantApi.createTenant(e);
1287
2062
  } catch (t) {
1288
2063
  this.handlePassflowError(t, "Tenant creation failed");
1289
2064
  }
@@ -1301,7 +2076,7 @@ class X {
1301
2076
  */
1302
2077
  async getTenantDetails(e) {
1303
2078
  try {
1304
- return await this.tenantAPI.getTenantDetails(e);
2079
+ return await this.tenantApi.getTenantDetails(e);
1305
2080
  } catch (t) {
1306
2081
  this.handlePassflowError(t, `Get tenant details failed for tenant ID ${e}`);
1307
2082
  }
@@ -1313,8 +2088,8 @@ class X {
1313
2088
  */
1314
2089
  async getTenantUserMembership(e) {
1315
2090
  try {
1316
- const t = await this.tenantAPI.getTenantDetails(e);
1317
- return new Y(t);
2091
+ const t = await this.tenantApi.getTenantDetails(e);
2092
+ return new Re(t);
1318
2093
  } catch (t) {
1319
2094
  this.handlePassflowError(t, `Get tenant user membership failed for tenant ID ${e}`);
1320
2095
  }
@@ -1327,7 +2102,7 @@ class X {
1327
2102
  */
1328
2103
  async updateTenant(e, t) {
1329
2104
  try {
1330
- return await this.tenantAPI.updateTenant(e, t);
2105
+ return await this.tenantApi.updateTenant(e, t);
1331
2106
  } catch (s) {
1332
2107
  this.handlePassflowError(s, `Update tenant failed for tenant ID ${e}`);
1333
2108
  }
@@ -1339,7 +2114,7 @@ class X {
1339
2114
  */
1340
2115
  async deleteTenant(e) {
1341
2116
  try {
1342
- return await this.tenantAPI.deleteTenant(e);
2117
+ return await this.tenantApi.deleteTenant(e);
1343
2118
  } catch (t) {
1344
2119
  this.handlePassflowError(t, `Delete tenant failed for tenant ID ${e}`);
1345
2120
  }
@@ -1350,7 +2125,7 @@ class X {
1350
2125
  */
1351
2126
  async getUserTenantMembership() {
1352
2127
  try {
1353
- return await this.tenantAPI.getUserTenantMembership();
2128
+ return await this.tenantApi.getUserTenantMembership();
1354
2129
  } catch (e) {
1355
2130
  this.handlePassflowError(e, "Get user tenant memberships failed");
1356
2131
  }
@@ -1364,7 +2139,7 @@ class X {
1364
2139
  */
1365
2140
  async createGroup(e, t) {
1366
2141
  try {
1367
- return await this.tenantAPI.createGroup(e, t);
2142
+ return await this.tenantApi.createGroup(e, t);
1368
2143
  } catch (s) {
1369
2144
  this.handlePassflowError(s, `Group creation failed for tenant ID ${e}`);
1370
2145
  }
@@ -1377,7 +2152,7 @@ class X {
1377
2152
  */
1378
2153
  async getGroupInfo(e, t) {
1379
2154
  try {
1380
- return await this.tenantAPI.getGroupInfo(e, t);
2155
+ return await this.tenantApi.getGroupInfo(e, t);
1381
2156
  } catch (s) {
1382
2157
  this.handlePassflowError(s, `Get group info failed for tenant ID ${e}, group ID ${t}`);
1383
2158
  }
@@ -1391,7 +2166,7 @@ class X {
1391
2166
  */
1392
2167
  async updateGroup(e, t, s) {
1393
2168
  try {
1394
- return await this.tenantAPI.updateGroup(e, t, s);
2169
+ return await this.tenantApi.updateGroup(e, t, s);
1395
2170
  } catch (r) {
1396
2171
  this.handlePassflowError(r, `Update group failed for tenant ID ${e}, group ID ${t}`);
1397
2172
  }
@@ -1404,7 +2179,7 @@ class X {
1404
2179
  */
1405
2180
  async deleteGroup(e, t) {
1406
2181
  try {
1407
- return await this.tenantAPI.deleteGroup(e, t);
2182
+ return await this.tenantApi.deleteGroup(e, t);
1408
2183
  } catch (s) {
1409
2184
  this.handlePassflowError(s, `Delete group failed for tenant ID ${e}, group ID ${t}`);
1410
2185
  }
@@ -1419,10 +2194,10 @@ class X {
1419
2194
  */
1420
2195
  async addUserToGroup(e, t, s, r) {
1421
2196
  try {
1422
- return await this.tenantAPI.addUserToGroup(e, t, s, r);
1423
- } catch (o) {
2197
+ return await this.tenantApi.addUserToGroup(e, t, s, r);
2198
+ } catch (n) {
1424
2199
  this.handlePassflowError(
1425
- o,
2200
+ n,
1426
2201
  `Add user to group failed for tenant ID ${e}, group ID ${t}, user ID ${s}`
1427
2202
  );
1428
2203
  }
@@ -1437,10 +2212,10 @@ class X {
1437
2212
  */
1438
2213
  async removeUserRolesFromGroup(e, t, s, r) {
1439
2214
  try {
1440
- return await this.tenantAPI.removeUserRolesFromGroup(e, t, s, r);
1441
- } catch (o) {
2215
+ return await this.tenantApi.removeUserRolesFromGroup(e, t, s, r);
2216
+ } catch (n) {
1442
2217
  this.handlePassflowError(
1443
- o,
2218
+ n,
1444
2219
  `Remove user roles from group failed for tenant ID ${e}, group ID ${t}, user ID ${s}`
1445
2220
  );
1446
2221
  }
@@ -1455,10 +2230,10 @@ class X {
1455
2230
  */
1456
2231
  async changeUserRoles(e, t, s, r) {
1457
2232
  try {
1458
- return await this.tenantAPI.changeUserRoles(e, t, s, r);
1459
- } catch (o) {
2233
+ return await this.tenantApi.changeUserRoles(e, t, s, r);
2234
+ } catch (n) {
1460
2235
  this.handlePassflowError(
1461
- o,
2236
+ n,
1462
2237
  `Change user roles failed for tenant ID ${e}, group ID ${t}, user ID ${s}`
1463
2238
  );
1464
2239
  }
@@ -1472,7 +2247,7 @@ class X {
1472
2247
  */
1473
2248
  async deleteUserFromGroup(e, t, s) {
1474
2249
  try {
1475
- return await this.tenantAPI.deleteUserFromGroup(e, t, s);
2250
+ return await this.tenantApi.deleteUserFromGroup(e, t, s);
1476
2251
  } catch (r) {
1477
2252
  this.handlePassflowError(
1478
2253
  r,
@@ -1488,7 +2263,7 @@ class X {
1488
2263
  */
1489
2264
  async getRolesForTenant(e) {
1490
2265
  try {
1491
- return await this.tenantAPI.getRolesForTenant(e);
2266
+ return await this.tenantApi.getRolesForTenant(e);
1492
2267
  } catch (t) {
1493
2268
  this.handlePassflowError(t, `Get roles for tenant failed for tenant ID ${e}`);
1494
2269
  }
@@ -1501,7 +2276,7 @@ class X {
1501
2276
  */
1502
2277
  async createRoleForTenant(e, t) {
1503
2278
  try {
1504
- return await this.tenantAPI.createRoleForTenant(e, t);
2279
+ return await this.tenantApi.createRoleForTenant(e, t);
1505
2280
  } catch (s) {
1506
2281
  this.handlePassflowError(s, `Create role for tenant failed for tenant ID ${e}`);
1507
2282
  }
@@ -1515,7 +2290,7 @@ class X {
1515
2290
  */
1516
2291
  async updateRole(e, t, s) {
1517
2292
  try {
1518
- return await this.tenantAPI.updateRole(e, t, s);
2293
+ return await this.tenantApi.updateRole(e, t, s);
1519
2294
  } catch (r) {
1520
2295
  this.handlePassflowError(r, `Update role failed for tenant ID ${e}, role ID ${t}`);
1521
2296
  }
@@ -1528,7 +2303,7 @@ class X {
1528
2303
  */
1529
2304
  async deleteRole(e, t) {
1530
2305
  try {
1531
- return await this.tenantAPI.deleteRole(e, t);
2306
+ return await this.tenantApi.deleteRole(e, t);
1532
2307
  } catch (s) {
1533
2308
  this.handlePassflowError(s, `Delete role failed for tenant ID ${e}, role ID ${t}`);
1534
2309
  }
@@ -1542,7 +2317,7 @@ class X {
1542
2317
  */
1543
2318
  async deleteUserFromTenant(e, t) {
1544
2319
  try {
1545
- return await this.tenantAPI.deleteUserFromTenant(e, t);
2320
+ return await this.tenantApi.deleteUserFromTenant(e, t);
1546
2321
  } catch (s) {
1547
2322
  this.handlePassflowError(s, `Delete user from tenant failed for tenant ID ${e}, user ID ${t}`);
1548
2323
  }
@@ -1558,9 +2333,9 @@ class X {
1558
2333
  */
1559
2334
  async getGroupInvitations(e, t, s, r) {
1560
2335
  try {
1561
- return await this.tenantAPI.getGroupInvitations(e, t, s, r);
1562
- } catch (o) {
1563
- this.handlePassflowError(o, `Get group invitations failed for tenant ID ${e}, group ID ${t}`);
2336
+ return await this.tenantApi.getGroupInvitations(e, t, s, r);
2337
+ } catch (n) {
2338
+ this.handlePassflowError(n, `Get group invitations failed for tenant ID ${e}, group ID ${t}`);
1564
2339
  }
1565
2340
  }
1566
2341
  /**
@@ -1572,7 +2347,7 @@ class X {
1572
2347
  */
1573
2348
  async getTenantInvitations(e, t, s) {
1574
2349
  try {
1575
- return await this.tenantAPI.getTenantInvitations(e, t, s);
2350
+ return await this.tenantApi.getTenantInvitations(e, t, s);
1576
2351
  } catch (r) {
1577
2352
  this.handlePassflowError(r, `Get tenant invitations failed for tenant ID ${e}`);
1578
2353
  }
@@ -1586,7 +2361,7 @@ class X {
1586
2361
  */
1587
2362
  async invalidateInviteById(e, t, s) {
1588
2363
  try {
1589
- return await this.tenantAPI.invalidateInviteById(e, t, s);
2364
+ return await this.tenantApi.invalidateInviteById(e, t, s);
1590
2365
  } catch (r) {
1591
2366
  this.handlePassflowError(
1592
2367
  r,
@@ -1603,7 +2378,7 @@ class X {
1603
2378
  */
1604
2379
  async invalidateInviteByEmail(e, t, s) {
1605
2380
  try {
1606
- return await this.tenantAPI.invalidateInviteByEmail(e, t, s);
2381
+ return await this.tenantApi.invalidateInviteByEmail(e, t, s);
1607
2382
  } catch (r) {
1608
2383
  this.handlePassflowError(
1609
2384
  r,
@@ -1612,69 +2387,23 @@ class X {
1612
2387
  }
1613
2388
  }
1614
2389
  }
1615
- class Q {
1616
- constructor(e, t) {
1617
- this.userAPI = e, this.deviceService = t;
1618
- }
1619
- /**
1620
- * Get user's registered passkeys
1621
- * @returns Promise with passkeys array
1622
- */
1623
- getUserPasskeys() {
1624
- return this.userAPI.getUserPasskeys();
1625
- }
1626
- /**
1627
- * Rename a user passkey
1628
- * @param name The new name for the passkey
1629
- * @param passkeyId The ID of the passkey to rename
1630
- * @returns Promise with success response
1631
- */
1632
- renameUserPasskey(e, t) {
1633
- return this.userAPI.renameUserPasskey(e, t);
1634
- }
1635
- /**
1636
- * Delete a user passkey
1637
- * @param passkeyId The ID of the passkey to delete
1638
- * @returns Promise with success response
1639
- */
1640
- deleteUserPasskey(e) {
1641
- return this.userAPI.deleteUserPasskey(e);
1642
- }
1643
- /**
1644
- * Add a new passkey for the current user
1645
- * @param options Optional parameters for the passkey
1646
- * @returns Promise that resolves when the passkey is added
1647
- */
1648
- async addUserPasskey({
1649
- relyingPartyId: e,
1650
- passkeyUsername: t,
1651
- passkeyDisplayName: s
1652
- } = {}) {
1653
- const r = this.deviceService.getDeviceId(), o = w.web, { challenge_id: n, publicKey: h } = await this.userAPI.addUserPasskeyStart({
1654
- relyingPartyId: e || window?.location?.hostname,
1655
- deviceId: r,
1656
- os: o,
1657
- passkeyDisplayName: s,
1658
- passkeyUsername: t
1659
- });
1660
- h.user.id = btoa(h.user.id);
1661
- const l = await _({ optionsJSON: h });
1662
- return await this.userAPI.addUserPasskeyComplete(l, r, n);
1663
- }
1664
- }
1665
- class Z {
2390
+ class De {
1666
2391
  constructor(e, t, s) {
1667
- this.storageManager = e, this.authApi = t, this.subscribeStore = s, this.checkInterval = null, this.CHECK_INTERVAL = 10, this.isRefreshing = !1, this.isExpired = !1, this.storageManager = e, this.authApi = t;
2392
+ this.storageManager = e, this.authApi = t, this.subscribeStore = s, this.checkInterval = null, this.CHECK_INTERVAL = 6e4, this.visibilityChangeHandler = null, this.isRefreshing = !1, this.tokenExpiredFlag = !1, this.storageManager = e, this.authApi = t, this.setupPageUnloadHandler();
1668
2393
  }
1669
2394
  initialize() {
1670
2395
  try {
1671
2396
  const e = this.storageManager.getTokens();
1672
- if (!e || !e.access_token) {
2397
+ if (!e) {
1673
2398
  this.startTokenCheck();
1674
2399
  return;
1675
2400
  }
1676
- const t = d(e.access_token);
1677
- f(t) ? (this.isExpired = !0, this.stopTokenCheck(), this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !0 })) : (this.setTokensCache(e), this.startTokenCheck());
2401
+ if (!e.access_token) {
2402
+ this.setTokensCache(e), this.startTokenCheck();
2403
+ return;
2404
+ }
2405
+ const t = y(e.access_token);
2406
+ m(t) ? (this.tokenExpiredFlag = !0, this.stopTokenCheck(), this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !0 })) : (this.setTokensCache(e), this.startTokenCheck());
1678
2407
  } catch (e) {
1679
2408
  const t = {
1680
2409
  message: e instanceof Error ? e.message : "Failed to get tokens",
@@ -1688,7 +2417,7 @@ class Z {
1688
2417
  try {
1689
2418
  this.isRefreshing = !0, this.subscribeStore.notify(a.RefreshStart, {});
1690
2419
  const t = await this.authApi.refreshToken(e?.refresh_token ?? "", e.scopes ?? [], e.access_token);
1691
- this.setTokensCache(t), this.subscribeStore.notify(a.Refresh, { tokens: t, parsedTokens: this.getParsedTokenCache() }), this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !1 }), this.isExpired = !1, this.startTokenCheck();
2420
+ this.setTokensCache(t), this.subscribeStore.notify(a.Refresh, { tokens: t, parsedTokens: this.getParsedTokens() }), this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !1 }), this.tokenExpiredFlag = !1, this.startTokenCheck();
1692
2421
  } catch (t) {
1693
2422
  const s = {
1694
2423
  message: t instanceof Error ? t.message : "Failed to get tokens",
@@ -1700,29 +2429,48 @@ class Z {
1700
2429
  }
1701
2430
  }
1702
2431
  startTokenCheck() {
1703
- this.checkInterval && clearInterval(this.checkInterval), !this.isExpired && (this.checkInterval = setInterval(() => {
1704
- this.isRefreshing || this.isExpired || this.tokensCacheIsExpired() && !this.isExpired && (this.isExpired = !0, this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !0 }), this.stopTokenCheck());
2432
+ this.checkInterval && clearInterval(this.checkInterval), !this.tokenExpiredFlag && (this.setupVisibilityListener(), this.checkInterval = setInterval(() => {
2433
+ typeof document < "u" && document.hidden || this.isRefreshing || this.tokenExpiredFlag || this.isExpired() && !this.tokenExpiredFlag && (this.tokenExpiredFlag = !0, this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !0 }), this.stopTokenCheck());
1705
2434
  }, this.CHECK_INTERVAL));
1706
2435
  }
2436
+ setupVisibilityListener() {
2437
+ typeof document > "u" || (this.visibilityChangeHandler && document.removeEventListener("visibilitychange", this.visibilityChangeHandler), this.visibilityChangeHandler = () => {
2438
+ !document.hidden && this.checkInterval && !this.isRefreshing && !this.tokenExpiredFlag && this.isExpired() && (this.tokenExpiredFlag = !0, this.subscribeStore.notify(a.TokenCacheExpired, { isExpired: !0 }), this.stopTokenCheck());
2439
+ }, document.addEventListener("visibilitychange", this.visibilityChangeHandler));
2440
+ }
2441
+ setupPageUnloadHandler() {
2442
+ typeof window > "u" || window.addEventListener("beforeunload", () => {
2443
+ this.destroy();
2444
+ });
2445
+ }
1707
2446
  stopTokenCheck() {
1708
- this.checkInterval && (clearInterval(this.checkInterval), this.checkInterval = null);
2447
+ this.checkInterval && (clearInterval(this.checkInterval), this.checkInterval = null), this.visibilityChangeHandler && typeof document < "u" && (document.removeEventListener("visibilitychange", this.visibilityChangeHandler), this.visibilityChangeHandler = null);
2448
+ }
2449
+ /**
2450
+ * Cleanup method to stop all intervals and remove event listeners.
2451
+ * Should be called when the service is no longer needed.
2452
+ */
2453
+ destroy() {
2454
+ this.stopTokenCheck();
1709
2455
  }
1710
2456
  setTokensCache(e) {
1711
2457
  this.tokensCache = e, e ? this.parsedTokensCache = {
1712
- access_token: d(e.access_token),
1713
- id_token: e.id_token ? d(e.id_token) : void 0,
1714
- refresh_token: e.refresh_token ? d(e.refresh_token) : void 0,
2458
+ access_token: e.access_token ? y(e.access_token) : void 0,
2459
+ id_token: e.id_token ? y(e.id_token) : void 0,
2460
+ refresh_token: e.refresh_token ? y(e.refresh_token) : void 0,
1715
2461
  scopes: e.scopes
1716
2462
  } : this.parsedTokensCache = void 0;
1717
2463
  }
1718
- getTokensCache() {
2464
+ getTokens() {
1719
2465
  return this.tokensCache;
1720
2466
  }
1721
- async getTokensCacheWithRefresh() {
2467
+ async getTokensWithRefresh() {
1722
2468
  try {
1723
2469
  if (!this.tokensCache) return this.tokensCache;
1724
- const e = d(this.tokensCache.access_token);
1725
- return f(e) && !this.isExpired ? (await this.refreshTokensCache(this.tokensCache), this.tokensCache) : this.tokensCache;
2470
+ if (!this.tokensCache.access_token)
2471
+ return this.tokensCache;
2472
+ const e = y(this.tokensCache.access_token);
2473
+ return m(e) && !this.tokenExpiredFlag ? (await this.refreshTokensCache(this.tokensCache), this.tokensCache) : this.tokensCache;
1726
2474
  } catch (e) {
1727
2475
  const t = {
1728
2476
  message: e instanceof Error ? e.message : "Failed to get tokens",
@@ -1732,28 +2480,352 @@ class Z {
1732
2480
  return;
1733
2481
  }
1734
2482
  }
1735
- getParsedTokenCache() {
2483
+ getParsedTokens() {
1736
2484
  return this.parsedTokensCache;
1737
2485
  }
1738
- tokensCacheIsExpired() {
2486
+ isExpired() {
1739
2487
  if (!this.tokensCache) return !0;
1740
- const e = d(this.tokensCache.access_token);
1741
- return f(e);
2488
+ if (!this.tokensCache.access_token)
2489
+ return !1;
2490
+ const e = y(this.tokensCache.access_token);
2491
+ return m(e);
2492
+ }
2493
+ }
2494
+ class Me {
2495
+ constructor(e, t) {
2496
+ this.twoFactorApi = e, this.subscribeStore = t, this.PARTIAL_AUTH_TIMEOUT_MS = 300 * 1e3, this.SESSION_STORAGE_KEY = "passflow_2fa_challenge", this.totpDigits = 6;
2497
+ const s = {
2498
+ onAuthChange: (r, n) => {
2499
+ if (r === a.TwoFactorRequired) {
2500
+ const o = n;
2501
+ this.setPartialAuthState(o.email, o.challengeId, o.tfaToken);
2502
+ }
2503
+ }
2504
+ };
2505
+ this.subscribeStore.subscribe(s, [a.TwoFactorRequired]);
2506
+ }
2507
+ /**
2508
+ * Emit error event and throw the error
2509
+ * Helper method to ensure errors are properly emitted to subscribers
2510
+ */
2511
+ emitErrorAndThrow(e, t) {
2512
+ const s = e, r = {
2513
+ message: e instanceof Error ? e.message : `${t} failed`,
2514
+ originalError: e,
2515
+ code: s?.id || void 0
2516
+ };
2517
+ throw this.subscribeStore.notify(a.Error, r), e;
2518
+ }
2519
+ /**
2520
+ * Get 2FA enrollment status for current user
2521
+ */
2522
+ async getStatus() {
2523
+ try {
2524
+ const e = await this.twoFactorApi.getStatus();
2525
+ return e.totp_digits && (this.totpDigits = e.totp_digits), e;
2526
+ } catch (e) {
2527
+ this.emitErrorAndThrow(e, "Get 2FA status");
2528
+ }
2529
+ }
2530
+ /**
2531
+ * Begin 2FA setup process
2532
+ * Returns secret and QR code for authenticator app
2533
+ */
2534
+ async beginSetup() {
2535
+ try {
2536
+ const e = await this.twoFactorApi.beginSetup();
2537
+ return e.totp_digits && (this.totpDigits = e.totp_digits), this.subscribeStore.notify(a.TwoFactorSetupStarted, { secret: e.secret }), e;
2538
+ } catch (e) {
2539
+ this.emitErrorAndThrow(e, "Begin 2FA setup");
2540
+ }
2541
+ }
2542
+ /**
2543
+ * Confirm 2FA setup with TOTP code
2544
+ * Returns recovery codes that MUST be displayed to user
2545
+ */
2546
+ async confirmSetup(e) {
2547
+ if (!R(e, this.totpDigits))
2548
+ throw new Error(`Invalid TOTP code format. Code must be exactly ${this.totpDigits} digits.`);
2549
+ try {
2550
+ const t = await this.twoFactorApi.confirmSetup({ code: e });
2551
+ return this.subscribeStore.notify(a.TwoFactorEnabled, {
2552
+ recoveryCodes: t.recovery_codes,
2553
+ clearRecoveryCodes: () => {
2554
+ t.recovery_codes.length = 0;
2555
+ }
2556
+ }), t;
2557
+ } catch (t) {
2558
+ this.emitErrorAndThrow(t, "Confirm 2FA setup");
2559
+ }
2560
+ }
2561
+ /**
2562
+ * Verify TOTP code during login
2563
+ * Completes authentication if successful
2564
+ */
2565
+ async verify(e) {
2566
+ if (!R(e, this.totpDigits))
2567
+ throw new Error(`Invalid TOTP code format. Code must be exactly ${this.totpDigits} digits.`);
2568
+ if (this.recoverPartialAuthState(), !this.isVerificationRequired())
2569
+ throw new Error("2FA verification expired or not required. User must sign in first.");
2570
+ if (!this.partialAuthState?.tfaToken)
2571
+ throw new Error("No TFA token found. User must sign in first.");
2572
+ try {
2573
+ const t = await this.twoFactorApi.verify({
2574
+ code: e,
2575
+ tfa_token: this.partialAuthState.tfaToken
2576
+ });
2577
+ return this.clearPartialAuthState(), this.subscribeStore.notify(a.TwoFactorVerified, { tokens: t }), t;
2578
+ } catch (t) {
2579
+ this.emitErrorAndThrow(t, "Verify 2FA code");
2580
+ }
2581
+ }
2582
+ /**
2583
+ * Use recovery code for authentication
2584
+ * Completes authentication if successful
2585
+ */
2586
+ async useRecoveryCode(e) {
2587
+ try {
2588
+ const t = _e(e);
2589
+ if (!t)
2590
+ throw new Error("Invalid recovery code format. Expected format: XXXX-XXXX or XXXXXXXX (alphanumeric).");
2591
+ if (this.recoverPartialAuthState(), !this.isVerificationRequired())
2592
+ throw new Error("2FA verification expired or not required. User must sign in first.");
2593
+ if (!this.partialAuthState?.tfaToken)
2594
+ throw new Error("No TFA token found. User must sign in first.");
2595
+ const s = await this.twoFactorApi.useRecoveryCode({
2596
+ recovery_code: t,
2597
+ tfa_token: this.partialAuthState.tfaToken
2598
+ });
2599
+ return this.clearPartialAuthState(), s.remaining_recovery_codes === 0 ? this.subscribeStore.notify(a.TwoFactorRecoveryCodesExhausted, { tokens: s }) : s.remaining_recovery_codes <= 2 && this.subscribeStore.notify(a.TwoFactorRecoveryCodesLow, {
2600
+ tokens: s,
2601
+ remainingCodes: s.remaining_recovery_codes
2602
+ }), this.subscribeStore.notify(a.TwoFactorRecoveryUsed, {
2603
+ tokens: s,
2604
+ remainingCodes: s.remaining_recovery_codes
2605
+ }), this.subscribeStore.notify(a.TwoFactorVerified, { tokens: s }), s;
2606
+ } catch (t) {
2607
+ this.emitErrorAndThrow(t, "Use recovery code");
2608
+ }
2609
+ }
2610
+ /**
2611
+ * Disable 2FA (requires TOTP verification)
2612
+ */
2613
+ async disable(e) {
2614
+ if (!R(e, this.totpDigits))
2615
+ throw new Error(`Invalid TOTP code format. Code must be exactly ${this.totpDigits} digits.`);
2616
+ try {
2617
+ const t = await this.twoFactorApi.disable({ code: e });
2618
+ return this.subscribeStore.notify(a.TwoFactorDisabled, {}), t;
2619
+ } catch (t) {
2620
+ this.emitErrorAndThrow(t, "Disable 2FA");
2621
+ }
2622
+ }
2623
+ /**
2624
+ * Regenerate recovery codes
2625
+ */
2626
+ async regenerateRecoveryCodes(e) {
2627
+ if (!R(e, this.totpDigits))
2628
+ throw new Error(`Invalid TOTP code format. Code must be exactly ${this.totpDigits} digits.`);
2629
+ try {
2630
+ const t = await this.twoFactorApi.regenerateRecoveryCodes({ code: e }), s = [...t.recovery_codes];
2631
+ return t.recovery_codes = [], t.recovery_codes = s, t;
2632
+ } catch (t) {
2633
+ this.emitErrorAndThrow(t, "Regenerate recovery codes");
2634
+ }
2635
+ }
2636
+ /**
2637
+ * Check if 2FA verification is required (local state check)
2638
+ * Returns true if user has signed in but needs 2FA verification
2639
+ */
2640
+ isVerificationRequired() {
2641
+ return this.recoverPartialAuthState(), this.partialAuthState ? Date.now() > this.partialAuthState.expiresAt ? (this.clearPartialAuthState(), !1) : !0 : !1;
2642
+ }
2643
+ /**
2644
+ * Set partial auth state when login requires 2FA
2645
+ * Called internally via event listener when AuthService emits TwoFactorRequired
2646
+ */
2647
+ setPartialAuthState(e, t, s) {
2648
+ if (this.partialAuthState = {
2649
+ email: e,
2650
+ challengeId: t,
2651
+ tfaToken: s,
2652
+ timestamp: Date.now(),
2653
+ expiresAt: Date.now() + this.PARTIAL_AUTH_TIMEOUT_MS
2654
+ }, typeof sessionStorage < "u")
2655
+ try {
2656
+ sessionStorage.setItem(this.SESSION_STORAGE_KEY, JSON.stringify(this.partialAuthState));
2657
+ } catch {
2658
+ }
2659
+ }
2660
+ /**
2661
+ * Clear partial auth state
2662
+ * Called on logout or successful verification
2663
+ */
2664
+ clearPartialAuthState() {
2665
+ if (this.partialAuthState = void 0, typeof sessionStorage < "u")
2666
+ try {
2667
+ sessionStorage.removeItem(this.SESSION_STORAGE_KEY);
2668
+ } catch {
2669
+ }
2670
+ }
2671
+ /**
2672
+ * Attempt to recover partial auth state from sessionStorage
2673
+ * Called before verification operations to handle page refresh
2674
+ */
2675
+ recoverPartialAuthState() {
2676
+ if (!this.partialAuthState && !(typeof sessionStorage > "u"))
2677
+ try {
2678
+ const e = sessionStorage.getItem(this.SESSION_STORAGE_KEY);
2679
+ if (!e) return;
2680
+ const t = JSON.parse(e);
2681
+ Date.now() < t.expiresAt ? this.partialAuthState = t : sessionStorage.removeItem(this.SESSION_STORAGE_KEY);
2682
+ } catch {
2683
+ try {
2684
+ sessionStorage.removeItem(this.SESSION_STORAGE_KEY);
2685
+ } catch {
2686
+ }
2687
+ }
2688
+ }
2689
+ // ============================================
2690
+ // Magic Link 2FA Setup Methods
2691
+ // ============================================
2692
+ /**
2693
+ * Validate magic link token for 2FA setup
2694
+ *
2695
+ * This method validates an admin-generated magic link token and
2696
+ * creates a scoped session (scope: "2fa_setup") that can ONLY be
2697
+ * used for completing 2FA setup operations.
2698
+ *
2699
+ * Session characteristics:
2700
+ * - Stored in memory only (no persistence across page reloads)
2701
+ * - Short-lived (typically 1 hour expiration)
2702
+ * - Cannot be refreshed
2703
+ * - Cannot be promoted to full authentication
2704
+ * - Only valid for 2FA setup endpoints
2705
+ *
2706
+ * @param token - Magic link token from URL parameter
2707
+ * @returns Validation response with session details
2708
+ */
2709
+ async validateTwoFactorSetupMagicLink(e) {
2710
+ const t = await this.twoFactorApi.validateTwoFactorSetupMagicLink(e);
2711
+ return t.success && t.sessionToken && t.userId ? (this.magicLinkSession = {
2712
+ sessionToken: t.sessionToken,
2713
+ userId: t.userId,
2714
+ appId: t.appId,
2715
+ scope: "2fa_setup",
2716
+ timestamp: Date.now(),
2717
+ expiresAt: Date.now() + (t.expiresIn || 3600) * 1e3
2718
+ }, this.subscribeStore.notify(a.TwoFactorSetupMagicLinkValidated, {
2719
+ userId: t.userId,
2720
+ appId: t.appId,
2721
+ expiresIn: t.expiresIn || 3600,
2722
+ sessionToken: t.sessionToken
2723
+ })) : t.error && this.subscribeStore.notify(a.TwoFactorSetupMagicLinkFailed, {
2724
+ error: t.error
2725
+ }), t;
2726
+ }
2727
+ /**
2728
+ * Get current magic link session (if any)
2729
+ * Used by React SDK to access session token for API calls
2730
+ *
2731
+ * @returns Active magic link session or null if none/expired
2732
+ */
2733
+ getMagicLinkSession() {
2734
+ return this.magicLinkSession ? Date.now() > this.magicLinkSession.expiresAt ? (this.clearMagicLinkSession(), null) : this.magicLinkSession : null;
2735
+ }
2736
+ /**
2737
+ * Clear magic link session
2738
+ * Called after successful setup completion or on error
2739
+ */
2740
+ clearMagicLinkSession() {
2741
+ this.magicLinkSession = void 0;
2742
+ }
2743
+ /**
2744
+ * Check if magic link session is active
2745
+ * Used by React SDK to determine if form can use magic link auth
2746
+ */
2747
+ hasMagicLinkSession() {
2748
+ return this.getMagicLinkSession() !== null;
2749
+ }
2750
+ /**
2751
+ * Get the session token from magic link session (if active)
2752
+ * Used by AxiosClient for injecting auth header on 2FA setup endpoints
2753
+ */
2754
+ getMagicLinkSessionToken() {
2755
+ return this.getMagicLinkSession()?.sessionToken || null;
2756
+ }
2757
+ /**
2758
+ * Get configured TOTP digit count
2759
+ * Returns the number of digits (6 or 8) for TOTP codes
2760
+ * Useful for UI components that need to render the correct number of input fields
2761
+ */
2762
+ getTotpDigits() {
2763
+ return this.totpDigits;
2764
+ }
2765
+ }
2766
+ class Fe {
2767
+ constructor(e, t) {
2768
+ this.userAPI = e, this.deviceService = t;
2769
+ }
2770
+ /**
2771
+ * Get user's registered passkeys
2772
+ * @returns Promise with passkeys array
2773
+ */
2774
+ getUserPasskeys() {
2775
+ return this.userAPI.getUserPasskeys();
2776
+ }
2777
+ /**
2778
+ * Rename a user passkey
2779
+ * @param name The new name for the passkey
2780
+ * @param passkeyId The ID of the passkey to rename
2781
+ * @returns Promise with success response
2782
+ */
2783
+ renameUserPasskey(e, t) {
2784
+ return this.userAPI.renameUserPasskey(e, t);
2785
+ }
2786
+ /**
2787
+ * Delete a user passkey
2788
+ * @param passkeyId The ID of the passkey to delete
2789
+ * @returns Promise with success response
2790
+ */
2791
+ deleteUserPasskey(e) {
2792
+ return this.userAPI.deleteUserPasskey(e);
2793
+ }
2794
+ /**
2795
+ * Add a new passkey for the current user
2796
+ * @param options Optional parameters for the passkey
2797
+ * @returns Promise that resolves when the passkey is added
2798
+ */
2799
+ async addUserPasskey({
2800
+ relyingPartyId: e,
2801
+ passkeyUsername: t,
2802
+ passkeyDisplayName: s
2803
+ } = {}) {
2804
+ const r = this.deviceService.getDeviceId(), n = I.web, { challenge_id: o, publicKey: d } = await this.userAPI.addUserPasskeyStart({
2805
+ relyingPartyId: e || window?.location?.hostname,
2806
+ deviceId: r,
2807
+ os: n,
2808
+ passkeyDisplayName: s,
2809
+ passkeyUsername: t
2810
+ });
2811
+ d.user.id = btoa(d.user.id);
2812
+ const c = await K({ optionsJSON: d });
2813
+ return await this.userAPI.addUserPasskeyComplete(c, r, o);
1742
2814
  }
1743
2815
  }
1744
- class ie {
2816
+ const O = class O {
1745
2817
  constructor(e) {
1746
2818
  this.doRefreshTokens = !1, this.origin = window.location.origin, this.session = async ({
1747
- createSession: o,
1748
- expiredSession: n,
1749
- doRefresh: h = !1
2819
+ createSession: n,
2820
+ expiredSession: o,
2821
+ doRefresh: d = !1
1750
2822
  }) => {
1751
- this.createSessionCallback = o, this.expiredSessionCallback = n, this.doRefreshTokens = h, await this.submitSessionCheck();
2823
+ this.createSessionCallback = n, this.expiredSessionCallback = o, this.doRefreshTokens = d, await this.submitSessionCheck();
1752
2824
  };
1753
2825
  const { url: t, appId: s, scopes: r } = e;
1754
- this.url = t || A, this.appId = s, this.authApi = new O(e), this.appApi = new j(e), this.userApi = new N(e), this.settingApi = new K(e), this.tenantAPI = new B(e), this.invitationAPI = new W(e), this.storageManager = new b({
2826
+ this.url = t || G, this.appId = s, this.storageManager = new $({
1755
2827
  prefix: e.keyStoragePrefix ?? ""
1756
- }), this.deviceService = new $(), this.subscribeStore = new H(), this.tokenCacheService = new Z(this.storageManager, this.authApi, this.subscribeStore), this.scopes = r ?? F, this.createTenantForNewUser = e.createTenantForNewUser ?? !1, this.authService = new q(
2828
+ }), this.deviceService = new B(this.storageManager), this.authApi = new fe(e, this.storageManager, this.deviceService), this.appApi = new pe(e, this.storageManager, this.deviceService), this.userApi = new Se(e, this.storageManager, this.deviceService), this.settingApi = new ye(e, this.storageManager, this.deviceService), this.tenantApi = new ve(e, this.storageManager, this.deviceService), this.invitationApi = new ke(e, this.storageManager, this.deviceService), this.twoFactorApi = new me(e, this.storageManager, this.deviceService), this.subscribeStore = new we(), this.tokenCacheService = new De(this.storageManager, this.authApi, this.subscribeStore), this.scopes = r ?? Q, this.createTenantForNewUser = e.createTenantForNewUser ?? !1, this.authService = new Ie(
1757
2829
  this.authApi,
1758
2830
  this.deviceService,
1759
2831
  this.storageManager,
@@ -1767,13 +2839,29 @@ class ie {
1767
2839
  createSession: this.createSessionCallback,
1768
2840
  expiredSession: this.expiredSessionCallback
1769
2841
  },
1770
- this.appId ?? ""
1771
- ), this.userService = new Q(this.userApi, this.deviceService), this.tenantService = new X(this.tenantAPI, this.scopes), this.tenant = this.tenantService, this.invitationService = new V(this.invitationAPI), e.parseQueryParams && this.checkAndSetTokens(), this.setTokensToCacheFromLocalStorage();
2842
+ this.appId ?? "",
2843
+ e.tokenExchange
2844
+ ), this.userService = new Fe(this.userApi, this.deviceService), this.tenantService = new Pe(this.tenantApi, this.scopes), this.tenant = this.tenantService, this.invitationService = new be(this.invitationApi), this.twoFactorService = new Me(this.twoFactorApi, this.subscribeStore), this.twoFactor = this.twoFactorService, e.parseQueryParams && this.checkAndSetTokens(), this.setTokensToCacheFromLocalStorage();
2845
+ }
2846
+ /**
2847
+ * Update the appId and propagate it to all API clients.
2848
+ * This ensures that all future API requests use the new appId in their headers.
2849
+ *
2850
+ * @param appId - The new application ID to set
2851
+ *
2852
+ * @example
2853
+ * ```typescript
2854
+ * // Update appId after discovery
2855
+ * passflow.setAppId('discovered-app-id-123');
2856
+ * ```
2857
+ */
2858
+ setAppId(e) {
2859
+ this.appId = e, this.authApi.setAppId(e), this.appApi.setAppId(e), this.userApi.setAppId(e), this.settingApi.setAppId(e), this.tenantApi.setAppId(e), this.invitationApi.setAppId(e), this.twoFactorApi.setAppId(e), this.authService;
1772
2860
  }
1773
2861
  async submitSessionCheck() {
1774
2862
  let e, t;
1775
2863
  try {
1776
- e = await this.authService.getTokens(this.doRefreshTokens), t = this.tokenCacheService.getParsedTokenCache();
2864
+ e = await this.authService.getTokens(this.doRefreshTokens), t = this.tokenCacheService.getParsedTokens();
1777
2865
  } catch (s) {
1778
2866
  const r = {
1779
2867
  message: s instanceof Error || s instanceof u ? s.message : "Session check failed",
@@ -1784,89 +2872,424 @@ class ie {
1784
2872
  e && this.createSessionCallback && await this.createSessionCallback({ tokens: e, parsedTokens: t }), !e && this.expiredSessionCallback && await this.expiredSessionCallback();
1785
2873
  }
1786
2874
  // Event subscription
2875
+ /**
2876
+ * Subscribe to Passflow authentication events.
2877
+ *
2878
+ * @param subscriber - Subscriber function that receives event type and payload
2879
+ * @param events - Optional array of specific events to listen for. If omitted, subscribes to all events.
2880
+ *
2881
+ * @example
2882
+ * ```typescript
2883
+ * // Subscribe to all events
2884
+ * passflow.subscribe((event, payload) => {
2885
+ * console.log('Event:', event, payload);
2886
+ * });
2887
+ *
2888
+ * // Subscribe to specific events only
2889
+ * passflow.subscribe(
2890
+ * (event, payload) => {
2891
+ * if (event === PassflowEvent.SignIn) {
2892
+ * console.log('User signed in', payload.tokens);
2893
+ * }
2894
+ * },
2895
+ * [PassflowEvent.SignIn, PassflowEvent.SignOut]
2896
+ * );
2897
+ * ```
2898
+ */
1787
2899
  subscribe(e, t) {
1788
2900
  this.subscribeStore.subscribe(e, t), this.tokenCacheService.initialize();
1789
2901
  }
2902
+ /**
2903
+ * Unsubscribe from Passflow authentication events.
2904
+ *
2905
+ * @param subscriber - The subscriber function to remove
2906
+ * @param events - Optional array of specific events to unsubscribe from. If omitted, unsubscribes from all events.
2907
+ *
2908
+ * @example
2909
+ * ```typescript
2910
+ * const subscriber = (event, payload) => console.log(event, payload);
2911
+ *
2912
+ * // Subscribe
2913
+ * passflow.subscribe(subscriber);
2914
+ *
2915
+ * // Later, unsubscribe
2916
+ * passflow.unsubscribe(subscriber);
2917
+ * ```
2918
+ */
1790
2919
  unsubscribe(e, t) {
1791
2920
  this.subscribeStore.unsubscribe(e, t);
1792
2921
  }
1793
2922
  // Token handling
2923
+ /**
2924
+ * Handle OAuth redirect callback and extract tokens from URL query parameters.
2925
+ * This method should be called on the redirect page after authentication.
2926
+ *
2927
+ * @returns Tokens object if found in URL, undefined otherwise
2928
+ *
2929
+ * @example
2930
+ * ```typescript
2931
+ * // On your redirect page (e.g., /auth/callback)
2932
+ * const tokens = passflow.handleTokensRedirect();
2933
+ * if (tokens) {
2934
+ * console.log('Authentication successful', tokens.access_token);
2935
+ * // Tokens are automatically saved to storage
2936
+ * }
2937
+ * ```
2938
+ */
1794
2939
  handleTokensRedirect() {
1795
2940
  return this.checkAndSetTokens();
1796
2941
  }
1797
2942
  checkAndSetTokens() {
1798
- const e = new URLSearchParams(window.location.search), t = e.get("access_token"), s = e.get("refresh_token"), r = e.get("id_token"), o = e.get("scopes")?.split(",") ?? this.scopes;
1799
- let n;
1800
- if (t)
1801
- return n = {
1802
- access_token: t,
1803
- refresh_token: s ?? void 0,
1804
- id_token: r ?? void 0,
2943
+ let e = new URLSearchParams(window.location.search), t = !1;
2944
+ if (!e.get("access_token") && window.location.hash) {
2945
+ const c = new URLSearchParams(window.location.hash.substring(1));
2946
+ c.get("access_token") && (e = c, t = !0);
2947
+ }
2948
+ const s = e.get("access_token"), r = e.get("refresh_token"), n = e.get("id_token"), o = e.get("scopes")?.split(",") ?? this.scopes;
2949
+ let d;
2950
+ if (s) {
2951
+ if (!M(s)) {
2952
+ const c = {
2953
+ message: "Invalid access token format received",
2954
+ code: "INVALID_TOKEN_FORMAT"
2955
+ };
2956
+ this.subscribeStore.notify(a.Error, c), this.cleanupUrlParams(t);
2957
+ return;
2958
+ }
2959
+ if (r && !M(r)) {
2960
+ const c = {
2961
+ message: "Invalid refresh token format received",
2962
+ code: "INVALID_TOKEN_FORMAT"
2963
+ };
2964
+ this.subscribeStore.notify(a.Error, c), this.cleanupUrlParams(t);
2965
+ return;
2966
+ }
2967
+ if (n && !M(n)) {
2968
+ const c = {
2969
+ message: "Invalid ID token format received",
2970
+ code: "INVALID_TOKEN_FORMAT"
2971
+ };
2972
+ this.subscribeStore.notify(a.Error, c), this.cleanupUrlParams(t);
2973
+ return;
2974
+ }
2975
+ return d = {
2976
+ access_token: s,
2977
+ refresh_token: r ?? void 0,
2978
+ id_token: n ?? void 0,
1805
2979
  scopes: o
1806
- }, this.storageManager.saveTokens(n), this.tokenCacheService.setTokensCache(n), this.subscribeStore.notify(a.SignIn, { tokens: n, parsedTokens: this.getParsedTokenCache() }), this.submitSessionCheck(), e.delete("access_token"), e.delete("refresh_token"), e.delete("id_token"), e.delete("client_challenge"), e.size > 0 ? window.history.replaceState({}, document.title, `${window.location.pathname}?${e.toString()}`) : window.history.replaceState({}, document.title, window.location.pathname), this.error = void 0, n;
1807
- this.error = this.checkErrorsFromURL();
2980
+ }, this.storageManager.saveTokens(d), this.tokenCacheService.setTokensCache(d), this.subscribeStore.notify(a.SignIn, { tokens: d, parsedTokens: this.getParsedTokens() }), this.submitSessionCheck(), this.cleanupUrlParams(t), this.error = void 0, d;
2981
+ } else
2982
+ this.error = this.checkErrorsFromURL();
1808
2983
  }
1809
2984
  checkErrorsFromURL() {
1810
2985
  const t = new URLSearchParams(window.location.search).get("error");
1811
- if (t)
1812
- return new Error(t);
2986
+ if (t) {
2987
+ const s = Te(t);
2988
+ return new Error(s);
2989
+ }
2990
+ }
2991
+ cleanupUrlParams(e = !1) {
2992
+ if (e)
2993
+ window.history.replaceState({}, document.title, window.location.pathname + window.location.search);
2994
+ else {
2995
+ const t = new URLSearchParams(window.location.search);
2996
+ t.delete("access_token"), t.delete("refresh_token"), t.delete("id_token"), t.delete("client_challenge"), t.size > 0 ? window.history.replaceState({}, document.title, `${window.location.pathname}?${t.toString()}`) : window.history.replaceState({}, document.title, window.location.pathname);
2997
+ }
1813
2998
  }
1814
2999
  setTokensToCacheFromLocalStorage() {
1815
3000
  const e = this.storageManager.getTokens();
1816
3001
  e && this.tokenCacheService.setTokensCache(e);
1817
3002
  }
1818
- getTokensCache() {
1819
- return this.tokenCacheService.getTokensCache();
3003
+ /**
3004
+ * Get cached tokens from memory without triggering a refresh.
3005
+ *
3006
+ * @returns Cached tokens or undefined if not cached
3007
+ *
3008
+ * @example
3009
+ * ```typescript
3010
+ * const tokens = passflow.getCachedTokens();
3011
+ * if (tokens) {
3012
+ * console.log('Access token:', tokens.access_token);
3013
+ * }
3014
+ * ```
3015
+ */
3016
+ getCachedTokens() {
3017
+ return this.tokenCacheService.getTokens();
1820
3018
  }
1821
- getTokensCacheWithRefresh() {
1822
- return this.tokenCacheService.getTokensCacheWithRefresh();
3019
+ /**
3020
+ * Get cached tokens from memory and automatically refresh if expired.
3021
+ *
3022
+ * @returns Promise resolving to tokens or undefined
3023
+ *
3024
+ * @example
3025
+ * ```typescript
3026
+ * const tokens = await passflow.getTokensWithRefresh();
3027
+ * // Tokens are guaranteed to be valid or undefined
3028
+ * ```
3029
+ */
3030
+ getTokensWithRefresh() {
3031
+ return this.tokenCacheService.getTokensWithRefresh();
1823
3032
  }
1824
- getParsedTokenCache() {
1825
- return this.tokenCacheService.getParsedTokenCache();
3033
+ /**
3034
+ * Get parsed JWT tokens with decoded claims.
3035
+ *
3036
+ * @returns Parsed token objects with decoded payloads
3037
+ *
3038
+ * @example
3039
+ * ```typescript
3040
+ * const parsed = passflow.getParsedTokens();
3041
+ * if (parsed?.access_token) {
3042
+ * console.log('User ID:', parsed.access_token.sub);
3043
+ * console.log('Expires at:', new Date(parsed.access_token.exp * 1000));
3044
+ * }
3045
+ * ```
3046
+ */
3047
+ getParsedTokens() {
3048
+ return this.tokenCacheService.getParsedTokens();
1826
3049
  }
1827
- tokensCacheIsExpired() {
1828
- return this.tokenCacheService.tokensCacheIsExpired();
3050
+ /**
3051
+ * Check if the cached tokens are expired.
3052
+ *
3053
+ * @returns True if tokens are expired, false otherwise
3054
+ *
3055
+ * @example
3056
+ * ```typescript
3057
+ * if (passflow.areTokensExpired()) {
3058
+ * await passflow.refreshToken();
3059
+ * }
3060
+ * ```
3061
+ */
3062
+ areTokensExpired() {
3063
+ return this.tokenCacheService.isExpired();
1829
3064
  }
1830
3065
  // Auth delegation methods
3066
+ /**
3067
+ * Check if the user is currently authenticated with valid tokens.
3068
+ *
3069
+ * @returns True if user has valid, non-expired tokens
3070
+ *
3071
+ * @example
3072
+ * ```typescript
3073
+ * if (passflow.isAuthenticated()) {
3074
+ * console.log('User is logged in');
3075
+ * } else {
3076
+ * console.log('User needs to sign in');
3077
+ * }
3078
+ * ```
3079
+ */
1831
3080
  isAuthenticated() {
1832
3081
  const e = this.storageManager.getTokens();
1833
3082
  if (!e || !e.access_token) return !1;
1834
- const t = {
1835
- access_token: d(e.access_token),
1836
- refresh_token: e.refresh_token ? d(e.refresh_token) : void 0
1837
- };
1838
- return this.authService.isAuthenticated(t);
3083
+ const t = this.tokenCacheService.getParsedTokens();
3084
+ return t ? this.authService.isAuthenticated(t) : !1;
1839
3085
  }
3086
+ /**
3087
+ * Sign in a user with email/username and password.
3088
+ *
3089
+ * @param payload - Sign-in credentials and options
3090
+ * @param payload.email - User's email or username
3091
+ * @param payload.password - User's password
3092
+ * @param payload.scopes - Optional scopes to request (defaults to SDK scopes)
3093
+ * @returns Promise with authorization response containing tokens
3094
+ * @throws {PassflowError} If authentication fails
3095
+ *
3096
+ * @example
3097
+ * ```typescript
3098
+ * try {
3099
+ * const response = await passflow.signIn({
3100
+ * email: 'user@example.com',
3101
+ * password: 'secure-password'
3102
+ * });
3103
+ * console.log('Signed in successfully', response.access_token);
3104
+ * } catch (error) {
3105
+ * console.error('Sign in failed', error.message);
3106
+ * }
3107
+ * ```
3108
+ */
1840
3109
  async signIn(e) {
1841
3110
  return await this.authService.signIn(e);
1842
3111
  }
3112
+ /**
3113
+ * Register a new user account with email and password.
3114
+ *
3115
+ * @param payload - Registration details
3116
+ * @param payload.email - User's email address
3117
+ * @param payload.password - User's password
3118
+ * @param payload.username - Optional username
3119
+ * @param payload.scopes - Optional scopes to request
3120
+ * @returns Promise with authorization response containing tokens
3121
+ * @throws {PassflowError} If registration fails
3122
+ *
3123
+ * @example
3124
+ * ```typescript
3125
+ * try {
3126
+ * const response = await passflow.signUp({
3127
+ * email: 'newuser@example.com',
3128
+ * password: 'secure-password',
3129
+ * username: 'newuser'
3130
+ * });
3131
+ * console.log('Account created', response.access_token);
3132
+ * } catch (error) {
3133
+ * console.error('Sign up failed', error.message);
3134
+ * }
3135
+ * ```
3136
+ */
1843
3137
  async signUp(e) {
1844
3138
  return await this.authService.signUp(e);
1845
3139
  }
3140
+ /**
3141
+ * Initiate passwordless authentication by sending a magic link or OTP.
3142
+ *
3143
+ * @param payload - Passwordless sign-in configuration
3144
+ * @param payload.email - User's email address
3145
+ * @param payload.method - Delivery method ('email' or 'sms')
3146
+ * @returns Promise with response indicating if the code was sent
3147
+ * @throws {PassflowError} If request fails
3148
+ *
3149
+ * @example
3150
+ * ```typescript
3151
+ * // Send magic link via email
3152
+ * const response = await passflow.passwordlessSignIn({
3153
+ * email: 'user@example.com',
3154
+ * method: 'email'
3155
+ * });
3156
+ * console.log('Magic link sent:', response.success);
3157
+ * ```
3158
+ */
1846
3159
  passwordlessSignIn(e) {
1847
3160
  return this.authService.passwordlessSignIn(e);
1848
3161
  }
3162
+ /**
3163
+ * Complete passwordless authentication by verifying the OTP or token.
3164
+ *
3165
+ * @param payload - Verification payload
3166
+ * @param payload.email - User's email address
3167
+ * @param payload.code - Verification code from email/SMS
3168
+ * @param payload.scopes - Optional scopes to request
3169
+ * @returns Promise with validation response containing tokens
3170
+ * @throws {PassflowError} If verification fails
3171
+ *
3172
+ * @example
3173
+ * ```typescript
3174
+ * try {
3175
+ * const response = await passflow.passwordlessSignInComplete({
3176
+ * email: 'user@example.com',
3177
+ * code: '123456'
3178
+ * });
3179
+ * console.log('Passwordless sign-in complete', response.access_token);
3180
+ * } catch (error) {
3181
+ * console.error('Invalid code', error.message);
3182
+ * }
3183
+ * ```
3184
+ */
1849
3185
  async passwordlessSignInComplete(e) {
1850
3186
  return await this.authService.passwordlessSignInComplete(e);
1851
3187
  }
3188
+ /**
3189
+ * Centralized error handler for all public methods.
3190
+ * Creates proper ErrorPayload, distinguishes PassflowError from generic Error,
3191
+ * notifies error event, and re-throws the error.
3192
+ *
3193
+ * @param error - The error to handle
3194
+ * @param context - Context description for the error
3195
+ * @throws The original error after handling
3196
+ */
3197
+ handleError(e, t) {
3198
+ const s = {
3199
+ message: e instanceof Error ? e.message : `${t} failed`,
3200
+ originalError: e,
3201
+ code: e instanceof u ? e.id : void 0
3202
+ };
3203
+ throw this.subscribeStore.notify(a.Error, s), e;
3204
+ }
3205
+ /**
3206
+ * Sign out the current user and clear all tokens.
3207
+ *
3208
+ * @returns Promise that resolves when sign-out is complete
3209
+ * @throws {PassflowError} If sign-out request fails
3210
+ *
3211
+ * @example
3212
+ * ```typescript
3213
+ * try {
3214
+ * await passflow.logOut();
3215
+ * console.log('User signed out successfully');
3216
+ * // Redirect to login page
3217
+ * } catch (error) {
3218
+ * console.error('Sign out failed', error.message);
3219
+ * }
3220
+ * ```
3221
+ */
1852
3222
  async logOut() {
1853
3223
  try {
1854
- await this.authService.logOut(), this.storageManager.deleteTokens(), await this.submitSessionCheck();
3224
+ await this.authService.logOut(), this.storageManager.deleteTokens(), this.tokenCacheService.setTokensCache(void 0), this.twoFactorService.clearPartialAuthState(), await this.submitSessionCheck(), this.subscribeStore.notify(a.SignOut, {});
1855
3225
  } catch (e) {
1856
- const t = {
1857
- message: e instanceof Error ? e.message : "Failed to log out",
1858
- originalError: e
1859
- };
1860
- this.subscribeStore.notify(a.Error, t);
3226
+ this.handleError(e, "Log out");
1861
3227
  }
1862
- this.tokenCacheService.setTokensCache(void 0), this.subscribeStore.notify(a.SignOut, {});
1863
3228
  }
3229
+ /**
3230
+ * Initiate federated authentication (OAuth) with a popup window.
3231
+ *
3232
+ * @param payload - Federated authentication configuration
3233
+ * @param payload.provider - OAuth provider (e.g., 'google', 'github', 'microsoft')
3234
+ * @param payload.scopes - Optional scopes to request
3235
+ *
3236
+ * @example
3237
+ * ```typescript
3238
+ * // Sign in with Google using a popup
3239
+ * passflow.federatedAuthWithPopup({
3240
+ * provider: 'google'
3241
+ * });
3242
+ *
3243
+ * // Listen for the result via subscribe
3244
+ * passflow.subscribe((event, payload) => {
3245
+ * if (event === PassflowEvent.SignIn) {
3246
+ * console.log('OAuth sign-in successful', payload.tokens);
3247
+ * }
3248
+ * });
3249
+ * ```
3250
+ */
1864
3251
  federatedAuthWithPopup(e) {
1865
3252
  this.authService.federatedAuthWithPopup(e);
1866
3253
  }
3254
+ /**
3255
+ * Initiate federated authentication (OAuth) with a full-page redirect.
3256
+ *
3257
+ * @param payload - Federated authentication configuration
3258
+ * @param payload.provider - OAuth provider (e.g., 'google', 'github', 'microsoft')
3259
+ * @param payload.scopes - Optional scopes to request
3260
+ * @param payload.redirectUrl - URL to redirect to after authentication
3261
+ *
3262
+ * @example
3263
+ * ```typescript
3264
+ * // Sign in with GitHub using redirect
3265
+ * passflow.federatedAuthWithRedirect({
3266
+ * provider: 'github',
3267
+ * redirectUrl: window.location.origin + '/auth/callback'
3268
+ * });
3269
+ * ```
3270
+ */
1867
3271
  federatedAuthWithRedirect(e) {
1868
3272
  this.authService.federatedAuthWithRedirect(e);
1869
3273
  }
3274
+ /**
3275
+ * Reset the SDK state by clearing all tokens and optionally throwing an error.
3276
+ *
3277
+ * @param error - Optional error message to throw after reset
3278
+ * @throws {Error} If error message is provided
3279
+ *
3280
+ * @example
3281
+ * ```typescript
3282
+ * // Clear tokens without error
3283
+ * passflow.reset();
3284
+ *
3285
+ * // Clear tokens and throw error
3286
+ * try {
3287
+ * passflow.reset('Session expired');
3288
+ * } catch (error) {
3289
+ * console.error('Reset error:', error.message);
3290
+ * }
3291
+ * ```
3292
+ */
1870
3293
  reset(e) {
1871
3294
  if (this.storageManager.deleteTokens(), this.tokenCacheService.setTokensCache(void 0), this.subscribeStore.notify(a.SignOut, {}), e) {
1872
3295
  this.error = new Error(e);
@@ -1877,6 +3300,24 @@ class ie {
1877
3300
  throw this.subscribeStore.notify(a.Error, t), this.error;
1878
3301
  }
1879
3302
  }
3303
+ /**
3304
+ * Refresh the access token using the refresh token.
3305
+ *
3306
+ * @returns Promise with new authorization response containing refreshed tokens
3307
+ * @throws {Error} If no refresh token is found
3308
+ * @throws {PassflowError} If refresh request fails
3309
+ *
3310
+ * @example
3311
+ * ```typescript
3312
+ * try {
3313
+ * const response = await passflow.refreshToken();
3314
+ * console.log('Token refreshed', response.access_token);
3315
+ * } catch (error) {
3316
+ * console.error('Failed to refresh token', error.message);
3317
+ * // Redirect to login
3318
+ * }
3319
+ * ```
3320
+ */
1880
3321
  async refreshToken() {
1881
3322
  if (!this.tokenCacheService.parsedTokensCache?.refresh_token)
1882
3323
  throw new Error("No refresh token found");
@@ -1889,122 +3330,337 @@ class ie {
1889
3330
  }), e;
1890
3331
  }
1891
3332
  }
3333
+ /**
3334
+ * Send a password reset email to the user.
3335
+ *
3336
+ * @param payload - Password reset request
3337
+ * @param payload.email - User's email address
3338
+ * @returns Promise with success response
3339
+ * @throws {PassflowError} If request fails
3340
+ *
3341
+ * @example
3342
+ * ```typescript
3343
+ * try {
3344
+ * await passflow.sendPasswordResetEmail({
3345
+ * email: 'user@example.com'
3346
+ * });
3347
+ * console.log('Password reset email sent');
3348
+ * } catch (error) {
3349
+ * console.error('Failed to send reset email', error.message);
3350
+ * }
3351
+ * ```
3352
+ */
1892
3353
  sendPasswordResetEmail(e) {
1893
3354
  return this.authService.sendPasswordResetEmail(e);
1894
3355
  }
3356
+ /**
3357
+ * Reset password using a reset token (typically from URL after clicking email link).
3358
+ *
3359
+ * @param newPassword - The new password to set
3360
+ * @param scopes - Optional scopes to request after reset
3361
+ * @returns Promise with authorization response containing new tokens
3362
+ * @throws {PassflowError} If reset fails
3363
+ *
3364
+ * @example
3365
+ * ```typescript
3366
+ * // On password reset page (e.g., /reset-password?token=xyz)
3367
+ * try {
3368
+ * const response = await passflow.resetPassword('new-secure-password');
3369
+ * console.log('Password reset successful', response.access_token);
3370
+ * } catch (error) {
3371
+ * console.error('Password reset failed', error.message);
3372
+ * }
3373
+ * ```
3374
+ */
1895
3375
  async resetPassword(e, t) {
1896
3376
  return await this.authService.resetPassword(e, t);
1897
3377
  }
1898
3378
  // App settings
3379
+ /**
3380
+ * Get application settings and configuration.
3381
+ *
3382
+ * @returns Promise with app settings including branding, features, and config
3383
+ * @throws {PassflowError} If request fails
3384
+ *
3385
+ * @example
3386
+ * ```typescript
3387
+ * const settings = await passflow.getAppSettings();
3388
+ * console.log('App name:', settings.name);
3389
+ * console.log('Passwordless enabled:', settings.passwordless_enabled);
3390
+ * ```
3391
+ */
1899
3392
  async getAppSettings() {
1900
3393
  try {
1901
3394
  return await this.appApi.getAppSettings();
1902
3395
  } catch (e) {
1903
- const t = {
1904
- message: e instanceof Error ? e.message : "Failed to get app settings",
1905
- originalError: e
1906
- };
1907
- throw this.subscribeStore.notify(a.Error, t), e;
3396
+ this.handleError(e, "Get app settings");
1908
3397
  }
1909
3398
  }
3399
+ /**
3400
+ * Get all Passflow settings including password policy, passkey settings, etc.
3401
+ *
3402
+ * @returns Promise with all settings
3403
+ * @throws {PassflowError} If request fails
3404
+ *
3405
+ * @example
3406
+ * ```typescript
3407
+ * const settings = await passflow.getSettingsAll();
3408
+ * console.log('Password policy:', settings.password_policy);
3409
+ * console.log('Passkey settings:', settings.passkey);
3410
+ * ```
3411
+ */
1910
3412
  async getSettingsAll() {
1911
3413
  try {
1912
3414
  return await this.settingApi.getSettingsAll();
1913
3415
  } catch (e) {
1914
- const t = {
1915
- message: e instanceof Error ? e.message : "Failed to get all settings",
1916
- originalError: e
1917
- };
1918
- throw this.subscribeStore.notify(a.Error, t), e;
3416
+ this.handleError(e, "Get all settings");
1919
3417
  }
1920
3418
  }
3419
+ /**
3420
+ * Get password policy settings (min length, complexity requirements, etc.).
3421
+ *
3422
+ * @returns Promise with password policy configuration
3423
+ * @throws {PassflowError} If request fails
3424
+ *
3425
+ * @example
3426
+ * ```typescript
3427
+ * const policy = await passflow.getPasswordPolicySettings();
3428
+ * console.log('Min length:', policy.min_length);
3429
+ * console.log('Require uppercase:', policy.require_uppercase);
3430
+ * ```
3431
+ */
1921
3432
  async getPasswordPolicySettings() {
1922
3433
  try {
1923
3434
  return await this.settingApi.getPasswordPolicySettings();
1924
3435
  } catch (e) {
1925
- const t = {
1926
- message: e instanceof Error ? e.message : "Failed to get password policy settings",
1927
- originalError: e
1928
- };
1929
- throw this.subscribeStore.notify(a.Error, t), e;
3436
+ this.handleError(e, "Get password policy settings");
1930
3437
  }
1931
3438
  }
3439
+ /**
3440
+ * Get passkey (WebAuthn) configuration settings.
3441
+ *
3442
+ * @returns Promise with passkey settings
3443
+ * @throws {PassflowError} If request fails
3444
+ *
3445
+ * @example
3446
+ * ```typescript
3447
+ * const passkeySettings = await passflow.getPasskeySettings();
3448
+ * console.log('Passkeys enabled:', passkeySettings.enabled);
3449
+ * console.log('User verification:', passkeySettings.user_verification);
3450
+ * ```
3451
+ */
1932
3452
  async getPasskeySettings() {
1933
3453
  try {
1934
3454
  return await this.settingApi.getPasskeySettings();
1935
3455
  } catch (e) {
1936
- const t = {
1937
- message: e instanceof Error ? e.message : "Failed to get passkey settings",
1938
- originalError: e
1939
- };
1940
- throw this.subscribeStore.notify(a.Error, t), e;
3456
+ this.handleError(e, "Get passkey settings");
1941
3457
  }
1942
3458
  }
1943
3459
  // Passkey methods
3460
+ /**
3461
+ * Register a new user with a passkey (WebAuthn).
3462
+ *
3463
+ * @param payload - Passkey registration configuration
3464
+ * @param payload.email - User's email address
3465
+ * @param payload.username - Optional username
3466
+ * @param payload.scopes - Optional scopes to request
3467
+ * @returns Promise with authorization response containing tokens
3468
+ * @throws {PassflowError} If passkey registration fails
3469
+ *
3470
+ * @example
3471
+ * ```typescript
3472
+ * try {
3473
+ * const response = await passflow.passkeyRegister({
3474
+ * email: 'user@example.com',
3475
+ * username: 'myusername'
3476
+ * });
3477
+ * console.log('Passkey registered', response.access_token);
3478
+ * } catch (error) {
3479
+ * console.error('Passkey registration failed', error.message);
3480
+ * }
3481
+ * ```
3482
+ */
1944
3483
  async passkeyRegister(e) {
1945
3484
  return await this.authService.passkeyRegister(e);
1946
3485
  }
3486
+ /**
3487
+ * Authenticate a user with a passkey (WebAuthn).
3488
+ *
3489
+ * @param payload - Passkey authentication configuration
3490
+ * @param payload.email - Optional user email to pre-fill
3491
+ * @param payload.scopes - Optional scopes to request
3492
+ * @returns Promise with authorization response containing tokens
3493
+ * @throws {PassflowError} If passkey authentication fails
3494
+ *
3495
+ * @example
3496
+ * ```typescript
3497
+ * try {
3498
+ * // Let user select from available passkeys
3499
+ * const response = await passflow.passkeyAuthenticate({});
3500
+ * console.log('Passkey sign-in successful', response.access_token);
3501
+ * } catch (error) {
3502
+ * console.error('Passkey authentication failed', error.message);
3503
+ * }
3504
+ * ```
3505
+ */
1947
3506
  async passkeyAuthenticate(e) {
1948
3507
  return await this.authService.passkeyAuthenticate(e);
1949
3508
  }
1950
3509
  // Token management
3510
+ /**
3511
+ * Manually set tokens (useful after custom authentication flows).
3512
+ * This will save tokens to storage, update cache, and trigger SignIn event.
3513
+ *
3514
+ * @param tokensData - Tokens object to set
3515
+ * @param tokensData.access_token - JWT access token
3516
+ * @param tokensData.refresh_token - Optional refresh token
3517
+ * @param tokensData.id_token - Optional ID token
3518
+ * @param tokensData.scopes - Token scopes
3519
+ *
3520
+ * @example
3521
+ * ```typescript
3522
+ * // Set tokens from a custom auth flow
3523
+ * passflow.setTokens({
3524
+ * access_token: 'eyJhbGci...',
3525
+ * refresh_token: 'eyJhbGci...',
3526
+ * id_token: 'eyJhbGci...',
3527
+ * scopes: ['id', 'offline', 'email']
3528
+ * });
3529
+ * ```
3530
+ */
1951
3531
  setTokens(e) {
1952
3532
  this.storageManager.saveTokens(e), this.tokenCacheService.setTokensCache(e), this.subscribeStore.notify(a.SignIn, {
1953
3533
  tokens: e,
1954
- parsedTokens: this.tokenCacheService.getParsedTokenCache()
3534
+ parsedTokens: this.tokenCacheService.getParsedTokens()
1955
3535
  });
1956
3536
  }
1957
- // Add getTokens method
3537
+ /**
3538
+ * Get current tokens from storage, optionally refreshing if expired.
3539
+ *
3540
+ * @param doRefresh - If true, automatically refresh expired tokens (default: false)
3541
+ * @returns Promise with tokens or undefined if not authenticated
3542
+ *
3543
+ * @example
3544
+ * ```typescript
3545
+ * // Get tokens without refresh
3546
+ * const tokens = await passflow.getTokens();
3547
+ *
3548
+ * // Get tokens and auto-refresh if expired
3549
+ * const freshTokens = await passflow.getTokens(true);
3550
+ * ```
3551
+ */
1958
3552
  async getTokens(e = !1) {
1959
3553
  return await this.authService.getTokens(e);
1960
3554
  }
1961
- // Get token from storage by key
3555
+ /**
3556
+ * Get a specific token from storage by type.
3557
+ *
3558
+ * @param tokenType - Type of token to retrieve ('access_token', 'refresh_token', 'id_token')
3559
+ * @returns Token string or undefined if not found
3560
+ *
3561
+ * @example
3562
+ * ```typescript
3563
+ * const accessToken = passflow.getToken('access_token');
3564
+ * if (accessToken) {
3565
+ * // Use token for API calls
3566
+ * fetch('/api/data', {
3567
+ * headers: { Authorization: `Bearer ${accessToken}` }
3568
+ * });
3569
+ * }
3570
+ * ```
3571
+ */
1962
3572
  getToken(e) {
1963
3573
  return this.storageManager.getToken(e);
1964
3574
  }
1965
3575
  // User passkey methods delegated to UserService
3576
+ /**
3577
+ * Get list of passkeys registered for the current user.
3578
+ *
3579
+ * @returns Promise with array of user's passkeys
3580
+ * @throws {PassflowError} If request fails
3581
+ *
3582
+ * @example
3583
+ * ```typescript
3584
+ * const passkeys = await passflow.getUserPasskeys();
3585
+ * passkeys.forEach(passkey => {
3586
+ * console.log('Passkey:', passkey.name, passkey.id);
3587
+ * });
3588
+ * ```
3589
+ */
1966
3590
  async getUserPasskeys() {
1967
3591
  try {
1968
3592
  return await this.userService.getUserPasskeys();
1969
3593
  } catch (e) {
1970
- const t = {
1971
- message: e instanceof Error ? e.message : "Failed to get user passkeys",
1972
- originalError: e
1973
- };
1974
- throw this.subscribeStore.notify(a.Error, t), e;
3594
+ this.handleError(e, "Get user passkeys");
1975
3595
  }
1976
3596
  }
3597
+ /**
3598
+ * Rename a user's passkey to a friendly name.
3599
+ *
3600
+ * @param name - New friendly name for the passkey
3601
+ * @param passkeyId - ID of the passkey to rename
3602
+ * @returns Promise with success response
3603
+ * @throws {PassflowError} If request fails
3604
+ *
3605
+ * @example
3606
+ * ```typescript
3607
+ * await passflow.renameUserPasskey('My MacBook Pro', 'passkey-123');
3608
+ * console.log('Passkey renamed successfully');
3609
+ * ```
3610
+ */
1977
3611
  async renameUserPasskey(e, t) {
1978
3612
  try {
1979
3613
  return await this.userService.renameUserPasskey(e, t);
1980
3614
  } catch (s) {
1981
- const r = {
1982
- message: s instanceof Error ? s.message : "Failed to rename user passkey",
1983
- originalError: s
1984
- };
1985
- throw this.subscribeStore.notify(a.Error, r), s;
3615
+ this.handleError(s, "Rename user passkey");
1986
3616
  }
1987
3617
  }
3618
+ /**
3619
+ * Delete a passkey from the user's account.
3620
+ *
3621
+ * @param passkeyId - ID of the passkey to delete
3622
+ * @returns Promise with success response
3623
+ * @throws {PassflowError} If request fails
3624
+ *
3625
+ * @example
3626
+ * ```typescript
3627
+ * await passflow.deleteUserPasskey('passkey-123');
3628
+ * console.log('Passkey deleted successfully');
3629
+ * ```
3630
+ */
1988
3631
  async deleteUserPasskey(e) {
1989
3632
  try {
1990
3633
  return await this.userService.deleteUserPasskey(e);
1991
3634
  } catch (t) {
1992
- const s = {
1993
- message: t instanceof Error ? t.message : "Failed to delete user passkey",
1994
- originalError: t
1995
- };
1996
- throw this.subscribeStore.notify(a.Error, s), t;
3635
+ this.handleError(t, "Delete user passkey");
1997
3636
  }
1998
3637
  }
3638
+ /**
3639
+ * Add a new passkey to the current user's account (requires active session).
3640
+ *
3641
+ * @param options - Optional passkey configuration
3642
+ * @param options.relyingPartyId - Optional RP ID for the passkey
3643
+ * @param options.passkeyUsername - Optional username to associate with passkey
3644
+ * @param options.passkeyDisplayName - Optional display name for the passkey
3645
+ * @returns Promise that resolves when passkey is added
3646
+ * @throws {PassflowError} If request fails
3647
+ *
3648
+ * @example
3649
+ * ```typescript
3650
+ * // Add passkey with default settings
3651
+ * await passflow.addUserPasskey();
3652
+ *
3653
+ * // Add passkey with custom display name
3654
+ * await passflow.addUserPasskey({
3655
+ * passkeyDisplayName: 'My iPhone'
3656
+ * });
3657
+ * ```
3658
+ */
1999
3659
  async addUserPasskey(e) {
2000
3660
  try {
2001
3661
  return await this.userService.addUserPasskey(e);
2002
3662
  } catch (t) {
2003
- const s = {
2004
- message: t instanceof Error ? t.message : "Failed to add user passkey",
2005
- originalError: t
2006
- };
2007
- throw this.subscribeStore.notify(a.Error, s), t;
3663
+ this.handleError(t, "Add user passkey");
2008
3664
  }
2009
3665
  }
2010
3666
  // Tenant methods delegated to TenantService
@@ -2019,11 +3675,7 @@ class ie {
2019
3675
  const s = await this.tenant.joinInvitation(e, t);
2020
3676
  return s.scopes = t ?? this.scopes, this.storageManager.saveTokens(s), this.tokenCacheService.setTokensCache(s), s;
2021
3677
  } catch (s) {
2022
- const r = {
2023
- message: s instanceof Error ? s.message : "Failed to join invitation",
2024
- originalError: s
2025
- };
2026
- throw this.subscribeStore.notify(a.Error, r), s;
3678
+ this.handleError(s, "Join invitation");
2027
3679
  }
2028
3680
  }
2029
3681
  /**
@@ -2037,23 +3689,35 @@ class ie {
2037
3689
  const s = await this.tenant.createTenant(e);
2038
3690
  return t && await this.refreshToken(), s;
2039
3691
  } catch (s) {
2040
- const r = {
2041
- message: s instanceof Error ? s.message : "Failed to create tenant",
2042
- originalError: s
2043
- };
2044
- throw this.subscribeStore.notify(a.Error, r), s;
3692
+ this.handleError(s, "Create tenant");
2045
3693
  }
2046
3694
  }
2047
3695
  // Invitation methods delegated to InvitationService
3696
+ /**
3697
+ * Request an invitation link for a user to join a tenant.
3698
+ *
3699
+ * @param payload - Invitation request configuration
3700
+ * @param payload.email - Email address to send invitation to
3701
+ * @param payload.tenantID - Tenant ID for the invitation
3702
+ * @param payload.send_to_email - Whether to send email automatically (default: true)
3703
+ * @returns Promise with invitation link response
3704
+ * @throws {PassflowError} If request fails
3705
+ *
3706
+ * @example
3707
+ * ```typescript
3708
+ * const invitation = await passflow.requestInviteLink({
3709
+ * email: 'newuser@example.com',
3710
+ * tenantID: 'tenant-123',
3711
+ * send_to_email: true
3712
+ * });
3713
+ * console.log('Invitation link:', invitation.link);
3714
+ * ```
3715
+ */
2048
3716
  async requestInviteLink(e) {
2049
3717
  try {
2050
3718
  return e.send_to_email === void 0 && (e.send_to_email = !0), await this.invitationService.requestInviteLink(e);
2051
3719
  } catch (t) {
2052
- const s = {
2053
- message: t instanceof Error ? t.message : "Failed to request invite link",
2054
- originalError: t
2055
- };
2056
- throw this.subscribeStore.notify(a.Error, s), t;
3720
+ this.handleError(t, "Request invite link");
2057
3721
  }
2058
3722
  }
2059
3723
  /**
@@ -2065,85 +3729,1012 @@ class ie {
2065
3729
  try {
2066
3730
  return await this.invitationService.getInvitations(e);
2067
3731
  } catch (t) {
2068
- const s = {
2069
- message: t instanceof Error ? t.message : "Failed to get invitations",
2070
- originalError: t
2071
- };
2072
- throw this.subscribeStore.notify(a.Error, s), t;
3732
+ this.handleError(t, "Get invitations");
2073
3733
  }
2074
3734
  }
3735
+ /**
3736
+ * Delete an invitation by its token.
3737
+ *
3738
+ * @param token - Invitation token to delete
3739
+ * @returns Promise with success response
3740
+ * @throws {PassflowError} If request fails
3741
+ *
3742
+ * @example
3743
+ * ```typescript
3744
+ * await passflow.deleteInvitation('invitation-token-123');
3745
+ * console.log('Invitation deleted');
3746
+ * ```
3747
+ */
2075
3748
  async deleteInvitation(e) {
2076
3749
  try {
2077
3750
  return await this.invitationService.deleteInvitation(e);
2078
3751
  } catch (t) {
2079
- const s = {
2080
- message: t instanceof Error ? t.message : "Failed to delete invitation",
2081
- originalError: t
2082
- };
2083
- throw this.subscribeStore.notify(a.Error, s), t;
3752
+ this.handleError(t, "Delete invitation");
2084
3753
  }
2085
3754
  }
3755
+ /**
3756
+ * Resend an invitation email.
3757
+ *
3758
+ * @param token - Invitation token to resend
3759
+ * @returns Promise with success response
3760
+ * @throws {PassflowError} If request fails
3761
+ *
3762
+ * @example
3763
+ * ```typescript
3764
+ * await passflow.resendInvitation('invitation-token-123');
3765
+ * console.log('Invitation email resent');
3766
+ * ```
3767
+ */
2086
3768
  async resendInvitation(e) {
2087
3769
  try {
2088
3770
  return await this.invitationService.resendInvitation(e);
2089
3771
  } catch (t) {
2090
- const s = {
2091
- message: t instanceof Error ? t.message : "Failed to resend invitation",
2092
- originalError: t
2093
- };
2094
- throw this.subscribeStore.notify(a.Error, s), t;
3772
+ this.handleError(t, "Resend invitation");
2095
3773
  }
2096
3774
  }
3775
+ /**
3776
+ * Get invitation details and link by invitation ID.
3777
+ *
3778
+ * @param invitationID - Invitation ID to retrieve
3779
+ * @returns Promise with invitation link response
3780
+ * @throws {PassflowError} If request fails
3781
+ *
3782
+ * @example
3783
+ * ```typescript
3784
+ * const invitation = await passflow.getInvitationLink('invitation-123');
3785
+ * console.log('Invitation link:', invitation.link);
3786
+ * ```
3787
+ */
2097
3788
  async getInvitationLink(e) {
2098
3789
  try {
2099
3790
  return await this.invitationService.getInvitationLink(e);
2100
3791
  } catch (t) {
2101
- const s = {
2102
- message: t instanceof Error ? t.message : "Failed to get invitation link",
2103
- originalError: t
2104
- };
2105
- throw this.subscribeStore.notify(a.Error, s), t;
3792
+ this.handleError(t, "Get invitation link");
2106
3793
  }
2107
3794
  }
2108
3795
  // Auth redirect helpers
3796
+ /**
3797
+ * Generate an authentication redirect URL for hosted login.
3798
+ *
3799
+ * @param options - Redirect URL configuration
3800
+ * @param options.url - Optional custom Passflow server URL
3801
+ * @param options.redirectUrl - URL to redirect to after authentication
3802
+ * @param options.scopes - Optional scopes to request
3803
+ * @param options.appId - Optional app ID to use
3804
+ * @returns Authentication redirect URL
3805
+ *
3806
+ * @example
3807
+ * ```typescript
3808
+ * const authUrl = passflow.authRedirectUrl({
3809
+ * redirectUrl: window.location.origin + '/auth/callback',
3810
+ * scopes: ['id', 'email', 'offline']
3811
+ * });
3812
+ * console.log('Auth URL:', authUrl);
3813
+ * // Use this URL for custom navigation logic
3814
+ * ```
3815
+ */
2109
3816
  authRedirectUrl(e = {}) {
2110
3817
  return this.authService.authRedirectUrl(e);
2111
3818
  }
3819
+ /**
3820
+ * Redirect to the Passflow hosted login page.
3821
+ *
3822
+ * @param options - Redirect configuration
3823
+ * @param options.url - Optional custom Passflow server URL
3824
+ * @param options.redirectUrl - URL to redirect to after authentication
3825
+ * @param options.scopes - Optional scopes to request
3826
+ * @param options.appId - Optional app ID to use
3827
+ *
3828
+ * @example
3829
+ * ```typescript
3830
+ * // Redirect to hosted login page
3831
+ * passflow.authRedirect({
3832
+ * redirectUrl: window.location.origin + '/auth/callback'
3833
+ * });
3834
+ * ```
3835
+ */
2112
3836
  authRedirect(e = {}) {
2113
3837
  this.authService.authRedirect(e);
2114
3838
  }
3839
+ /**
3840
+ * Get the current token delivery mode.
3841
+ * Returns the mode determined by the server (json_body, cookie, or mobile).
3842
+ *
3843
+ * @returns The current token delivery mode
3844
+ *
3845
+ * @example
3846
+ * ```typescript
3847
+ * import { TokenDeliveryMode } from '@passflow/core';
3848
+ *
3849
+ * const mode = passflow.getDeliveryMode();
3850
+ * if (mode === TokenDeliveryMode.Cookie) {
3851
+ * console.log('Using cookie-based authentication');
3852
+ * } else {
3853
+ * console.log('Using JSON body authentication');
3854
+ * }
3855
+ * ```
3856
+ */
3857
+ getDeliveryMode() {
3858
+ return this.authService.tokenDeliveryManager.getMode();
3859
+ }
3860
+ /**
3861
+ * Restore and validate session for cookie mode on page load.
3862
+ * Only applicable when using cookie-based token delivery.
3863
+ * Validates that HttpOnly cookies are still valid with the server.
3864
+ *
3865
+ * This method is automatically called on SDK initialization for cookie mode,
3866
+ * but can be called manually to re-validate the session.
3867
+ *
3868
+ * @returns Promise resolving to true if session is valid, false otherwise
3869
+ *
3870
+ * @example
3871
+ * ```typescript
3872
+ * // Check if session is valid (useful after page reload)
3873
+ * const isValid = await passflow.restoreSession();
3874
+ * if (isValid) {
3875
+ * console.log('Session restored successfully');
3876
+ * } else {
3877
+ * console.log('Session expired, please sign in again');
3878
+ * }
3879
+ * ```
3880
+ */
3881
+ async restoreSession() {
3882
+ return await this.authService.restoreSession();
3883
+ }
3884
+ // Two-Factor Authentication methods
3885
+ /**
3886
+ * Get the current 2FA enrollment status for the authenticated user.
3887
+ *
3888
+ * @returns Promise with 2FA status including enabled state and policy
3889
+ * @throws {PassflowError} If request fails
3890
+ *
3891
+ * @example
3892
+ * ```typescript
3893
+ * const status = await passflow.getTwoFactorStatus();
3894
+ * console.log('2FA enabled:', status.enabled);
3895
+ * console.log('Recovery codes remaining:', status.recovery_codes_remaining);
3896
+ * ```
3897
+ */
3898
+ async getTwoFactorStatus() {
3899
+ try {
3900
+ return await this.twoFactorService.getStatus();
3901
+ } catch (e) {
3902
+ this.handleError(e, "Get 2FA status");
3903
+ }
3904
+ }
3905
+ /**
3906
+ * Begin the 2FA setup process for the authenticated user.
3907
+ * Returns a secret and QR code to scan with an authenticator app.
3908
+ *
3909
+ * @returns Promise with setup response containing secret and QR code
3910
+ * @throws {PassflowError} If request fails
3911
+ *
3912
+ * @example
3913
+ * ```typescript
3914
+ * const setup = await passflow.beginTwoFactorSetup();
3915
+ * console.log('Scan this QR code:', setup.qr_code);
3916
+ * console.log('Or enter this secret:', setup.secret);
3917
+ * ```
3918
+ */
3919
+ async beginTwoFactorSetup() {
3920
+ try {
3921
+ return await this.twoFactorService.beginSetup();
3922
+ } catch (e) {
3923
+ this.handleError(e, "Begin 2FA setup");
3924
+ }
3925
+ }
3926
+ /**
3927
+ * Confirm 2FA setup by verifying a TOTP code from the authenticator app.
3928
+ * Returns recovery codes that MUST be saved by the user.
3929
+ *
3930
+ * @param code - 6-digit TOTP code from authenticator app
3931
+ * @returns Promise with confirmation response including recovery codes
3932
+ * @throws {PassflowError} If verification fails
3933
+ *
3934
+ * @example
3935
+ * ```typescript
3936
+ * const result = await passflow.confirmTwoFactorSetup('123456');
3937
+ * console.log('SAVE THESE RECOVERY CODES:', result.recovery_codes);
3938
+ * // Display recovery codes to user for safekeeping
3939
+ * ```
3940
+ */
3941
+ async confirmTwoFactorSetup(e) {
3942
+ try {
3943
+ return await this.twoFactorService.confirmSetup(e);
3944
+ } catch (t) {
3945
+ this.handleError(t, "Confirm 2FA setup");
3946
+ }
3947
+ }
3948
+ /**
3949
+ * Verify a TOTP code during login when 2FA is required.
3950
+ * Completes the authentication process and saves tokens.
3951
+ *
3952
+ * @param code - 6-digit TOTP code from authenticator app
3953
+ * @returns Promise with verification response containing tokens
3954
+ * @throws {PassflowError} If verification fails
3955
+ *
3956
+ * @example
3957
+ * ```typescript
3958
+ * // After signIn returns requires_2fa: true
3959
+ * if (passflow.isTwoFactorVerificationRequired()) {
3960
+ * const response = await passflow.verifyTwoFactor('123456');
3961
+ * console.log('Authentication complete', response.access_token);
3962
+ * }
3963
+ * ```
3964
+ */
3965
+ async verifyTwoFactor(e) {
3966
+ try {
3967
+ const t = await this.twoFactorService.verify(e);
3968
+ return this.storageManager.saveTokens(t), this.tokenCacheService.setTokensCache(t), this.subscribeStore.notify(a.SignIn, {
3969
+ tokens: t,
3970
+ parsedTokens: this.tokenCacheService.getParsedTokens()
3971
+ }), await this.submitSessionCheck(), t;
3972
+ } catch (t) {
3973
+ this.handleError(t, "Verify 2FA");
3974
+ }
3975
+ }
3976
+ /**
3977
+ * Use a recovery code for authentication when TOTP is unavailable.
3978
+ * Completes the authentication process and saves tokens.
3979
+ *
3980
+ * @param code - Recovery code from the list provided during setup
3981
+ * @returns Promise with recovery response containing tokens and remaining codes count
3982
+ * @throws {PassflowError} If recovery code is invalid
3983
+ *
3984
+ * @example
3985
+ * ```typescript
3986
+ * // After signIn returns requires_2fa: true
3987
+ * const result = await passflow.useTwoFactorRecoveryCode('ABCD-1234');
3988
+ * console.log('Authenticated with recovery code');
3989
+ * console.log(`${result.remaining_recovery_codes} recovery codes remaining`);
3990
+ * ```
3991
+ */
3992
+ async useTwoFactorRecoveryCode(e) {
3993
+ try {
3994
+ const t = await this.twoFactorService.useRecoveryCode(e);
3995
+ return this.storageManager.saveTokens(t), this.tokenCacheService.setTokensCache(t), this.subscribeStore.notify(a.SignIn, {
3996
+ tokens: t,
3997
+ parsedTokens: this.tokenCacheService.getParsedTokens()
3998
+ }), await this.submitSessionCheck(), t;
3999
+ } catch (t) {
4000
+ this.handleError(t, "Use 2FA recovery code");
4001
+ }
4002
+ }
4003
+ /**
4004
+ * Disable 2FA for the authenticated user.
4005
+ * Requires verification with a current TOTP code.
4006
+ *
4007
+ * @param code - Current 6-digit TOTP code for verification
4008
+ * @returns Promise with success response
4009
+ * @throws {PassflowError} If verification fails
4010
+ *
4011
+ * @example
4012
+ * ```typescript
4013
+ * await passflow.disableTwoFactor('123456');
4014
+ * console.log('2FA disabled successfully');
4015
+ * ```
4016
+ */
4017
+ async disableTwoFactor(e) {
4018
+ try {
4019
+ return await this.twoFactorService.disable(e);
4020
+ } catch (t) {
4021
+ this.handleError(t, "Disable 2FA");
4022
+ }
4023
+ }
4024
+ /**
4025
+ * Regenerate recovery codes for the authenticated user.
4026
+ * Old recovery codes will be invalidated. Requires verification with a current TOTP code.
4027
+ *
4028
+ * @param code - Current 6-digit TOTP code for verification
4029
+ * @returns Promise with response containing new recovery codes
4030
+ * @throws {PassflowError} If verification fails
4031
+ *
4032
+ * @example
4033
+ * ```typescript
4034
+ * const result = await passflow.regenerateTwoFactorRecoveryCodes('123456');
4035
+ * console.log('New recovery codes:', result.recovery_codes);
4036
+ * // Display new recovery codes to user for safekeeping
4037
+ * ```
4038
+ */
4039
+ async regenerateTwoFactorRecoveryCodes(e) {
4040
+ try {
4041
+ return await this.twoFactorService.regenerateRecoveryCodes(e);
4042
+ } catch (t) {
4043
+ this.handleError(t, "Regenerate 2FA recovery codes");
4044
+ }
4045
+ }
4046
+ /**
4047
+ * Check if 2FA verification is currently required (local state check).
4048
+ * Returns true if user has signed in but needs to complete 2FA verification.
4049
+ *
4050
+ * @returns True if 2FA verification is pending, false otherwise
4051
+ *
4052
+ * @example
4053
+ * ```typescript
4054
+ * if (passflow.isTwoFactorVerificationRequired()) {
4055
+ * // Show 2FA code input UI
4056
+ * console.log('Please enter your 2FA code');
4057
+ * }
4058
+ * ```
4059
+ */
4060
+ isTwoFactorVerificationRequired() {
4061
+ return this.twoFactorService.isVerificationRequired();
4062
+ }
4063
+ /**
4064
+ * Get configured TOTP digit count for the current app
4065
+ * @returns Number of digits (6 or 8) configured for TOTP codes
4066
+ *
4067
+ * @example
4068
+ * ```typescript
4069
+ * const digits = passflow.getTotpDigits();
4070
+ * console.log(`TOTP codes should be ${digits} digits`);
4071
+ * ```
4072
+ */
4073
+ getTotpDigits() {
4074
+ return this.twoFactorService.getTotpDigits();
4075
+ }
4076
+ // Magic Link 2FA Setup Methods
4077
+ /**
4078
+ * Validate a magic link token for 2FA setup.
4079
+ * Used when a user clicks on an admin-generated magic link to set up 2FA.
4080
+ *
4081
+ * The magic link creates a scoped session that can ONLY be used for 2FA setup,
4082
+ * not for regular authentication.
4083
+ *
4084
+ * @param token - Magic link token from URL parameter
4085
+ * @returns Promise with validation response containing scoped session or error
4086
+ *
4087
+ * @example
4088
+ * ```typescript
4089
+ * // On the magic link landing page (e.g., /2fa-setup/:token)
4090
+ * const urlToken = extractTokenFromUrl();
4091
+ * const result = await passflow.validateTwoFactorSetupMagicLink(urlToken);
4092
+ *
4093
+ * if (result.success) {
4094
+ * console.log('Magic link validated');
4095
+ * console.log('User ID:', result.userId);
4096
+ * console.log('Session expires in:', result.expiresIn, 'seconds');
4097
+ * // Show 2FA setup form
4098
+ * } else {
4099
+ * console.error('Validation failed:', result.error?.message);
4100
+ * // Show error UI
4101
+ * }
4102
+ * ```
4103
+ */
4104
+ async validateTwoFactorSetupMagicLink(e) {
4105
+ return await this.twoFactorService.validateTwoFactorSetupMagicLink(e);
4106
+ }
4107
+ /**
4108
+ * Get the current magic link session (if any).
4109
+ * Used by React SDK components to access session data.
4110
+ *
4111
+ * @returns Active magic link session or null if none/expired
4112
+ *
4113
+ * @example
4114
+ * ```typescript
4115
+ * const session = passflow.getMagicLinkSession();
4116
+ * if (session) {
4117
+ * console.log('Active session for user:', session.userId);
4118
+ * console.log('Expires at:', new Date(session.expiresAt));
4119
+ * }
4120
+ * ```
4121
+ */
4122
+ getMagicLinkSession() {
4123
+ return this.twoFactorService.getMagicLinkSession();
4124
+ }
4125
+ /**
4126
+ * Check if a magic link session is currently active.
4127
+ *
4128
+ * @returns True if magic link session is active and not expired
4129
+ *
4130
+ * @example
4131
+ * ```typescript
4132
+ * if (passflow.hasMagicLinkSession()) {
4133
+ * // User can proceed with 2FA setup
4134
+ * } else {
4135
+ * // Redirect to error page or request new link
4136
+ * }
4137
+ * ```
4138
+ */
4139
+ hasMagicLinkSession() {
4140
+ return this.twoFactorService.hasMagicLinkSession();
4141
+ }
4142
+ /**
4143
+ * Clear the magic link session.
4144
+ * Called after successful 2FA setup or on error.
4145
+ *
4146
+ * @example
4147
+ * ```typescript
4148
+ * // After 2FA setup is complete
4149
+ * passflow.clearMagicLinkSession();
4150
+ * // Redirect to sign-in
4151
+ * ```
4152
+ */
4153
+ clearMagicLinkSession() {
4154
+ this.twoFactorService.clearMagicLinkSession();
4155
+ }
4156
+ };
4157
+ O.version = Z;
4158
+ let L = O;
4159
+ class l extends Error {
4160
+ constructor(e) {
4161
+ super(e.message), this.name = "M2MError", this.code = e.code, this.status = e.status ?? 400, this.errorUri = e.errorUri, this.rateLimitInfo = e.rateLimitInfo, this.headers = e.headers, this.cause = e.cause, this.timestamp = (/* @__PURE__ */ new Date()).toISOString(), Error.captureStackTrace && Error.captureStackTrace(this, l);
4162
+ }
4163
+ /**
4164
+ * Create an M2MError from an OAuth 2.0 error response
4165
+ */
4166
+ static fromOAuthError(e, t, s) {
4167
+ const r = s ? l.parseRateLimitHeaders(s) : void 0;
4168
+ return new l({
4169
+ code: e.error,
4170
+ message: e.error_description ?? l.getDefaultMessage(e.error),
4171
+ status: t,
4172
+ errorUri: e.error_uri,
4173
+ rateLimitInfo: r,
4174
+ headers: s
4175
+ });
4176
+ }
4177
+ /**
4178
+ * Create an M2MError from a network or other error
4179
+ */
4180
+ static fromError(e, t = "server_error") {
4181
+ return new l({
4182
+ code: t,
4183
+ message: e.message || "An unexpected error occurred",
4184
+ status: 500,
4185
+ cause: e
4186
+ });
4187
+ }
4188
+ /**
4189
+ * Parse rate limit headers from response
4190
+ */
4191
+ static parseRateLimitHeaders(e) {
4192
+ const t = e["x-ratelimit-limit"], s = e["x-ratelimit-remaining"], r = e["x-ratelimit-reset"] || e["retry-after"];
4193
+ if (t && s && r)
4194
+ return {
4195
+ limit: parseInt(t, 10),
4196
+ remaining: parseInt(s, 10),
4197
+ reset: parseInt(r, 10)
4198
+ };
4199
+ }
4200
+ /**
4201
+ * Get default error message for an error code
4202
+ */
4203
+ static getDefaultMessage(e) {
4204
+ return {
4205
+ invalid_request: "The request is missing a required parameter or is otherwise malformed.",
4206
+ invalid_client: "Client authentication failed. Verify your client credentials.",
4207
+ invalid_grant: "The provided authorization grant is invalid or expired.",
4208
+ invalid_scope: "The requested scope is invalid, unknown, or exceeds the allowed scopes.",
4209
+ unauthorized_client: "The client is not authorized to use this grant type.",
4210
+ unsupported_grant_type: "The authorization grant type is not supported.",
4211
+ rate_limit_exceeded: "Too many requests. Please retry after the rate limit window resets.",
4212
+ server_error: "The authorization server encountered an unexpected error.",
4213
+ temporarily_unavailable: "The authorization server is temporarily unavailable. Please try again later."
4214
+ }[e] || "An unknown error occurred.";
4215
+ }
4216
+ /**
4217
+ * Check if the error is retryable
4218
+ */
4219
+ isRetryable() {
4220
+ return this.code === "server_error" || this.code === "temporarily_unavailable" || this.code === "rate_limit_exceeded" || this.status >= 500;
4221
+ }
4222
+ /**
4223
+ * Get suggested wait time before retry (in milliseconds)
4224
+ */
4225
+ getRetryAfter() {
4226
+ if (this.rateLimitInfo?.reset) {
4227
+ const e = Math.floor(Date.now() / 1e3), t = this.rateLimitInfo.reset - e;
4228
+ return Math.max(t * 1e3, 1e3);
4229
+ }
4230
+ return 1e3;
4231
+ }
4232
+ /**
4233
+ * Convert to JSON-serializable object
4234
+ */
4235
+ toJSON() {
4236
+ return {
4237
+ name: this.name,
4238
+ code: this.code,
4239
+ message: this.message,
4240
+ status: this.status,
4241
+ errorUri: this.errorUri,
4242
+ rateLimitInfo: this.rateLimitInfo,
4243
+ timestamp: this.timestamp
4244
+ };
4245
+ }
4246
+ /**
4247
+ * Create a human-readable string representation
4248
+ */
4249
+ toString() {
4250
+ let e = `M2MError [${this.code}]: ${this.message}`;
4251
+ return this.status && (e += ` (HTTP ${this.status})`), e;
4252
+ }
4253
+ }
4254
+ class N extends l {
4255
+ constructor(e, t) {
4256
+ super({
4257
+ code: "temporarily_unavailable",
4258
+ message: e,
4259
+ status: 0,
4260
+ cause: t
4261
+ }), this.name = "M2MNetworkError";
4262
+ }
4263
+ }
4264
+ class P extends l {
4265
+ constructor(e, t) {
4266
+ super({
4267
+ code: "invalid_request",
4268
+ message: e,
4269
+ status: 400,
4270
+ cause: t
4271
+ }), this.name = "M2MTokenParseError";
4272
+ }
4273
+ }
4274
+ class U extends l {
4275
+ constructor(e) {
4276
+ super({
4277
+ code: "invalid_request",
4278
+ message: e,
4279
+ status: 400
4280
+ }), this.name = "M2MConfigError";
4281
+ }
4282
+ }
4283
+ const Ge = {
4284
+ InvalidRequest: "invalid_request",
4285
+ InvalidClient: "invalid_client",
4286
+ InvalidGrant: "invalid_grant",
4287
+ InvalidScope: "invalid_scope",
4288
+ UnauthorizedClient: "unauthorized_client",
4289
+ UnsupportedGrantType: "unsupported_grant_type",
4290
+ RateLimitExceeded: "rate_limit_exceeded",
4291
+ ServerError: "server_error",
4292
+ TemporarilyUnavailable: "temporarily_unavailable"
4293
+ }, S = {
4294
+ /** Default token endpoint path */
4295
+ TOKEN_ENDPOINT: "/oauth2/token",
4296
+ /** Default request timeout in milliseconds */
4297
+ TIMEOUT: 1e4,
4298
+ /** Default number of retry attempts */
4299
+ RETRIES: 3,
4300
+ /** Default delay between retries in milliseconds */
4301
+ RETRY_DELAY: 1e3,
4302
+ /** Default refresh threshold in seconds */
4303
+ REFRESH_THRESHOLD: 30,
4304
+ /** Content-Type for token requests */
4305
+ CONTENT_TYPE: "application/x-www-form-urlencoded"
4306
+ };
4307
+ class xe {
4308
+ constructor() {
4309
+ this.cache = /* @__PURE__ */ new Map();
4310
+ }
4311
+ get(e) {
4312
+ const t = this.cache.get(e);
4313
+ return t ? Date.now() >= t.expiresAt ? (this.cache.delete(e), Promise.resolve(null)) : Promise.resolve(t.token) : Promise.resolve(null);
4314
+ }
4315
+ set(e, t, s) {
4316
+ return this.cache.set(e, {
4317
+ token: t,
4318
+ expiresAt: Date.now() + s * 1e3
4319
+ }), Promise.resolve();
4320
+ }
4321
+ delete(e) {
4322
+ return this.cache.delete(e), Promise.resolve();
4323
+ }
4324
+ }
4325
+ const Ue = {
4326
+ shouldRetry(i, e) {
4327
+ return e >= 3 ? !1 : i.code === "server_error" || i.code === "temporarily_unavailable" || i.code === "rate_limit_exceeded" || i.status !== void 0 && i.status >= 500;
4328
+ },
4329
+ getDelay(i) {
4330
+ return Math.pow(2, i - 1) * 1e3;
4331
+ }
4332
+ };
4333
+ class Ve {
4334
+ /**
4335
+ * Create a new M2M client
4336
+ *
4337
+ * @param config - Client configuration
4338
+ * @throws {M2MConfigError} If required configuration is missing
4339
+ *
4340
+ * @example
4341
+ * ```typescript
4342
+ * const m2m = new M2MClient({
4343
+ * url: 'https://auth.yourapp.com',
4344
+ * clientId: 'your-client-id',
4345
+ * clientSecret: 'your-client-secret',
4346
+ * });
4347
+ * ```
4348
+ */
4349
+ constructor(e) {
4350
+ if (!e.url)
4351
+ throw new U("M2M client requires a URL");
4352
+ if (!e.clientId)
4353
+ throw new U("M2M client requires a clientId");
4354
+ if (!e.clientSecret)
4355
+ throw new U("M2M client requires a clientSecret");
4356
+ const t = e.url.replace(/\/$/, "");
4357
+ this.config = {
4358
+ url: t,
4359
+ clientId: e.clientId,
4360
+ clientSecret: e.clientSecret,
4361
+ scopes: e.scopes,
4362
+ audience: e.audience,
4363
+ autoRefresh: e.autoRefresh ?? !1,
4364
+ refreshThreshold: e.refreshThreshold ?? S.REFRESH_THRESHOLD,
4365
+ timeout: e.timeout ?? S.TIMEOUT,
4366
+ retries: e.retries ?? S.RETRIES,
4367
+ retryDelay: e.retryDelay ?? S.RETRY_DELAY,
4368
+ retryStrategy: e.retryStrategy,
4369
+ cache: e.cache,
4370
+ onTokenRequest: e.onTokenRequest,
4371
+ onTokenResponse: e.onTokenResponse,
4372
+ onError: e.onError
4373
+ }, this.cache = e.cache ?? new xe(), this.retryStrategy = e.retryStrategy ?? Ue, this.tokenEndpoint = `${t}${S.TOKEN_ENDPOINT}`;
4374
+ }
4375
+ /**
4376
+ * Get the cache key for this client
4377
+ */
4378
+ getCacheKey(e, t) {
4379
+ const s = e?.sort().join(",") || "", r = t?.sort().join(",") || "";
4380
+ return `m2m:${this.config.clientId}:${s}:${r}`;
4381
+ }
4382
+ /**
4383
+ * Request an access token from the authorization server
4384
+ *
4385
+ * @param options - Optional request overrides
4386
+ * @returns Token response
4387
+ * @throws {M2MError} On authentication failure
4388
+ *
4389
+ * @example
4390
+ * ```typescript
4391
+ * // Basic usage
4392
+ * const token = await m2m.getToken();
4393
+ *
4394
+ * // With options
4395
+ * const token = await m2m.getToken({
4396
+ * scopes: ['users:read'],
4397
+ * forceRefresh: true,
4398
+ * });
4399
+ * ```
4400
+ */
4401
+ async getToken(e) {
4402
+ const t = e?.scopes ?? this.config.scopes, s = e?.audience ?? this.config.audience, r = this.getCacheKey(t, s);
4403
+ if (!e?.forceRefresh) {
4404
+ const n = await this.cache.get(r);
4405
+ if (n && !this.isTokenExpired(n))
4406
+ return n;
4407
+ }
4408
+ return this.requestToken(t, s, r);
4409
+ }
4410
+ /**
4411
+ * Get a valid token, automatically refreshing if needed
4412
+ *
4413
+ * When autoRefresh is enabled, this will proactively refresh tokens
4414
+ * that are about to expire (within refreshThreshold seconds).
4415
+ *
4416
+ * @returns Valid token response
4417
+ * @throws {M2MError} On authentication failure
4418
+ *
4419
+ * @example
4420
+ * ```typescript
4421
+ * // Always returns a valid, non-expired token
4422
+ * const token = await m2m.getValidToken();
4423
+ * ```
4424
+ */
4425
+ async getValidToken() {
4426
+ const e = this.config.scopes, t = this.config.audience, s = this.getCacheKey(e, t), r = await this.cache.get(s);
4427
+ if (r) {
4428
+ if (this.config.autoRefresh && this.isTokenExpired(r, this.config.refreshThreshold))
4429
+ return this.requestToken(e, t, s);
4430
+ if (!this.isTokenExpired(r))
4431
+ return r;
4432
+ }
4433
+ return this.requestToken(e, t, s);
4434
+ }
4435
+ /**
4436
+ * Request a new token from the authorization server
4437
+ */
4438
+ async requestToken(e, t, s) {
4439
+ const r = {
4440
+ grant_type: "client_credentials",
4441
+ client_id: this.config.clientId,
4442
+ client_secret: this.config.clientSecret
4443
+ };
4444
+ e && e.length > 0 && (r.scope = e.join(" ")), t && t.length > 0 && (r.audience = t.join(" ")), this.config.onTokenRequest && this.config.onTokenRequest({
4445
+ clientId: this.config.clientId,
4446
+ scopes: e ?? [],
4447
+ audience: t ?? [],
4448
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4449
+ });
4450
+ const n = await this.executeWithRetry(() => this.doTokenRequest(r));
4451
+ return n.issued_at = Math.floor(Date.now() / 1e3), s && await this.cache.set(s, n, n.expires_in), this.config.onTokenResponse && this.config.onTokenResponse(n), n;
4452
+ }
4453
+ /**
4454
+ * Execute the actual HTTP request to the token endpoint
4455
+ */
4456
+ async doTokenRequest(e) {
4457
+ const t = new URLSearchParams();
4458
+ t.append("grant_type", e.grant_type), t.append("client_id", e.client_id), t.append("client_secret", e.client_secret), e.scope && t.append("scope", e.scope), e.audience && t.append("audience", e.audience);
4459
+ const s = new AbortController(), r = setTimeout(() => s.abort(), this.config.timeout);
4460
+ try {
4461
+ const n = await fetch(this.tokenEndpoint, {
4462
+ method: "POST",
4463
+ headers: {
4464
+ "Content-Type": S.CONTENT_TYPE,
4465
+ Accept: "application/json"
4466
+ },
4467
+ body: t.toString(),
4468
+ signal: s.signal
4469
+ });
4470
+ clearTimeout(r);
4471
+ const o = {};
4472
+ n.headers.forEach((c, g) => {
4473
+ o[g.toLowerCase()] = c;
4474
+ });
4475
+ const d = await n.json();
4476
+ if (!n.ok) {
4477
+ const c = l.fromOAuthError(
4478
+ {
4479
+ error: d.error || "server_error",
4480
+ error_description: d.error_description || d.message,
4481
+ error_uri: d.error_uri
4482
+ },
4483
+ n.status,
4484
+ o
4485
+ );
4486
+ throw this.config.onError && this.config.onError({
4487
+ error: c.code,
4488
+ error_description: c.message
4489
+ }), c;
4490
+ }
4491
+ return d;
4492
+ } catch (n) {
4493
+ throw clearTimeout(r), n instanceof Error && n.name === "AbortError" ? new N(`Request timed out after ${this.config.timeout}ms`) : n instanceof TypeError && n.message.includes("fetch") ? new N(`Network error: ${n.message}`, n) : n instanceof l ? n : l.fromError(n instanceof Error ? n : new Error(String(n)));
4494
+ }
4495
+ }
4496
+ /**
4497
+ * Execute a request with retry logic
4498
+ */
4499
+ async executeWithRetry(e) {
4500
+ let t;
4501
+ for (let s = 1; s <= this.config.retries; s++)
4502
+ try {
4503
+ return await e();
4504
+ } catch (r) {
4505
+ if (!(r instanceof l))
4506
+ throw r;
4507
+ if (t = r, s < this.config.retries && this.retryStrategy.shouldRetry({ code: r.code, status: r.status }, s)) {
4508
+ const n = this.retryStrategy.getDelay(s);
4509
+ await this.sleep(n);
4510
+ continue;
4511
+ }
4512
+ throw r;
4513
+ }
4514
+ throw t ?? new l({ code: "server_error", message: "Request failed after retries" });
4515
+ }
4516
+ /**
4517
+ * Sleep for a given duration
4518
+ */
4519
+ sleep(e) {
4520
+ return new Promise((t) => setTimeout(t, e));
4521
+ }
4522
+ /**
4523
+ * Get the currently cached token without making a request
4524
+ *
4525
+ * @returns Cached token or null if not cached
4526
+ *
4527
+ * @example
4528
+ * ```typescript
4529
+ * const token = m2m.getCachedToken();
4530
+ * if (token && !m2m.isTokenExpired(token)) {
4531
+ * console.log('Using cached token');
4532
+ * }
4533
+ * ```
4534
+ */
4535
+ getCachedToken() {
4536
+ const e = this.cache;
4537
+ if ("cache" in e) {
4538
+ const t = this.getCacheKey(this.config.scopes, this.config.audience);
4539
+ return e.cache.get(
4540
+ t
4541
+ )?.token ?? null;
4542
+ }
4543
+ return null;
4544
+ }
4545
+ /**
4546
+ * Check if a token is expired or about to expire
4547
+ *
4548
+ * @param token - Token to check (uses issued_at + expires_in if available)
4549
+ * @param threshold - Seconds before actual expiry to consider expired (default: 0)
4550
+ * @returns true if expired or about to expire
4551
+ *
4552
+ * @example
4553
+ * ```typescript
4554
+ * if (m2m.isTokenExpired(token)) {
4555
+ * console.log('Token is expired');
4556
+ * }
4557
+ *
4558
+ * // Check if expiring within 5 minutes
4559
+ * if (m2m.isTokenExpired(token, 300)) {
4560
+ * console.log('Token expires soon');
4561
+ * }
4562
+ * ```
4563
+ */
4564
+ isTokenExpired(e, t = 0) {
4565
+ if (!e) return !0;
4566
+ const s = Math.floor(Date.now() / 1e3), n = (e.issued_at ?? s - e.expires_in) + e.expires_in;
4567
+ return s >= n - t;
4568
+ }
4569
+ /**
4570
+ * Parse token claims from a JWT access token
4571
+ *
4572
+ * @param token - JWT access token string
4573
+ * @returns Decoded token claims
4574
+ * @throws {M2MTokenParseError} If token format is invalid
4575
+ *
4576
+ * @example
4577
+ * ```typescript
4578
+ * const token = await m2m.getToken();
4579
+ * const claims = m2m.parseToken(token.access_token);
4580
+ * console.log('Client ID:', claims.client_id);
4581
+ * console.log('Scopes:', claims.scopes);
4582
+ * ```
4583
+ */
4584
+ parseToken(e) {
4585
+ try {
4586
+ const t = e.split(".");
4587
+ if (t.length !== 3)
4588
+ throw new P("Invalid JWT format: expected 3 parts");
4589
+ const s = t[1];
4590
+ if (!s)
4591
+ throw new P("Invalid JWT format: missing payload");
4592
+ const r = atob(s.replace(/-/g, "+").replace(/_/g, "/")), n = JSON.parse(r);
4593
+ return n.scopes && typeof n.scopes == "string" ? n.scopes = n.scopes.split(" ") : n.scopes || (n.scopes = []), n;
4594
+ } catch (t) {
4595
+ throw t instanceof P ? t : new P(`Failed to parse token: ${t instanceof Error ? t.message : "Unknown error"}`);
4596
+ }
4597
+ }
4598
+ /**
4599
+ * Clear the token cache, forcing a new request on next getToken()
4600
+ *
4601
+ * @example
4602
+ * ```typescript
4603
+ * m2m.clearCache();
4604
+ * // Next getToken() will request a new token
4605
+ * const token = await m2m.getToken();
4606
+ * ```
4607
+ */
4608
+ clearCache() {
4609
+ const e = this.getCacheKey(this.config.scopes, this.config.audience);
4610
+ this.cache.delete(e);
4611
+ }
4612
+ /**
4613
+ * Revoke the current token
4614
+ *
4615
+ * Note: Requires the server to support token revocation (RFC 7009).
4616
+ * Not all Passflow deployments may support this endpoint.
4617
+ *
4618
+ * @throws {M2MError} If revocation fails
4619
+ *
4620
+ * @example
4621
+ * ```typescript
4622
+ * await m2m.revokeToken();
4623
+ * console.log('Token revoked');
4624
+ * ```
4625
+ */
4626
+ async revokeToken() {
4627
+ const e = this.getCachedToken();
4628
+ if (!e)
4629
+ return;
4630
+ const t = `${this.config.url}/oauth2/revoke`, s = new URLSearchParams();
4631
+ s.append("token", e.access_token), s.append("client_id", this.config.clientId), s.append("client_secret", this.config.clientSecret);
4632
+ try {
4633
+ const r = await fetch(t, {
4634
+ method: "POST",
4635
+ headers: {
4636
+ "Content-Type": S.CONTENT_TYPE
4637
+ },
4638
+ body: s.toString()
4639
+ });
4640
+ if (!r.ok && r.status !== 200) {
4641
+ const n = await r.json().catch(() => ({}));
4642
+ throw l.fromOAuthError(
4643
+ {
4644
+ error: n.error || "server_error",
4645
+ error_description: n.error_description || "Token revocation failed"
4646
+ },
4647
+ r.status
4648
+ );
4649
+ }
4650
+ this.clearCache();
4651
+ } catch (r) {
4652
+ throw r instanceof l ? r : l.fromError(r instanceof Error ? r : new Error(String(r)));
4653
+ }
4654
+ }
4655
+ /**
4656
+ * Get the configured URL
4657
+ */
4658
+ get url() {
4659
+ return this.config.url;
4660
+ }
4661
+ /**
4662
+ * Get the configured client ID
4663
+ */
4664
+ get clientId() {
4665
+ return this.config.clientId;
4666
+ }
4667
+ /**
4668
+ * Get the configured scopes
4669
+ */
4670
+ get scopes() {
4671
+ return this.config.scopes;
4672
+ }
4673
+ /**
4674
+ * Get the configured audience
4675
+ */
4676
+ get audience() {
4677
+ return this.config.audience;
4678
+ }
2115
4679
  }
2116
4680
  export {
2117
- P as APP_ID_HEADER_KEY,
2118
- m as AUTHORIZATION_HEADER_KEY,
2119
- j as AppAPI,
2120
- O as AuthAPI,
2121
- q as AuthService,
2122
- re as DEFAULT_GROUP_NAME,
2123
- F as DEFAULT_SCOPES,
2124
- D as DEVICE_ID_HEADER_KEY,
2125
- x as DEVICE_TYPE_HEADER_KEY,
2126
- W as InvitationAPI,
2127
- V as InvitationService,
2128
- w as OS,
2129
- A as PASSFLOW_CLOUD_URL,
2130
- ie as Passflow,
2131
- y as PassflowAdminEndpointPaths,
2132
- c as PassflowEndpointPaths,
4681
+ C as APP_ID_HEADER_KEY,
4682
+ _ as AUTHORIZATION_HEADER_KEY,
4683
+ pe as AppAPI,
4684
+ fe as AuthAPI,
4685
+ Ie as AuthService,
4686
+ Ke as DEFAULT_GROUP_NAME,
4687
+ Q as DEFAULT_SCOPES,
4688
+ W as DEVICE_ID_HEADER_KEY,
4689
+ J as DEVICE_TYPE_HEADER_KEY,
4690
+ oe as ERROR_MESSAGE_MAX_LENGTH,
4691
+ ke as InvitationAPI,
4692
+ be as InvitationService,
4693
+ Ve as M2MClient,
4694
+ U as M2MConfigError,
4695
+ l as M2MError,
4696
+ Ge as M2MErrorCodes,
4697
+ N as M2MNetworkError,
4698
+ P as M2MTokenParseError,
4699
+ S as M2M_DEFAULTS,
4700
+ Ne as MINIMAL_DEFAULT_SCOPES,
4701
+ I as OS,
4702
+ G as PASSFLOW_CLOUD_URL,
4703
+ te as POPUP_HEIGHT,
4704
+ se as POPUP_POLL_INTERVAL_MS,
4705
+ re as POPUP_TIMEOUT_MS,
4706
+ ee as POPUP_WIDTH,
4707
+ L as Passflow,
4708
+ w as PassflowAdminEndpointPaths,
4709
+ h as PassflowEndpointPaths,
2133
4710
  u as PassflowError,
2134
4711
  a as PassflowEvent,
2135
- L as Providers,
2136
- S as RequestMethod,
2137
- K as SettingAPI,
2138
- B as TenantAPI,
2139
- X as TenantService,
2140
- Y as TenantUserMembership,
2141
- Z as TokenCacheService,
2142
- g as TokenType,
2143
- N as UserAPI,
2144
- Q as UserService,
2145
- f as isTokenExpired,
2146
- d as parseToken,
2147
- C as pathWithParams
4712
+ de as Providers,
4713
+ E as RequestMethod,
4714
+ Z as SDK_VERSION,
4715
+ q as SessionState,
4716
+ ye as SettingAPI,
4717
+ V as TOKEN_EXPIRY_BUFFER_SECONDS,
4718
+ ve as TenantAPI,
4719
+ Pe as TenantService,
4720
+ Re as TenantUserMembership,
4721
+ De as TokenCacheService,
4722
+ v as TokenDeliveryMode,
4723
+ k as TokenType,
4724
+ me as TwoFactorApiClient,
4725
+ ue as TwoFactorPolicy,
4726
+ Me as TwoFactorService,
4727
+ ne as USERNAME_MAX_LENGTH,
4728
+ ie as USERNAME_MIN_LENGTH,
4729
+ Se as UserAPI,
4730
+ Fe as UserService,
4731
+ m as isTokenExpired,
4732
+ F as isValidEmail,
4733
+ M as isValidJWTFormat,
4734
+ x as isValidPhoneNumber,
4735
+ Ee as isValidUsername,
4736
+ y as parseToken,
4737
+ A as pathWithParams,
4738
+ Te as sanitizeErrorMessage
2148
4739
  };
2149
4740
  //# sourceMappingURL=index.mjs.map