@authyon/auth 0.2.0-beta.2 → 0.2.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -35,10 +35,42 @@ __export(index_exports, {
35
35
  createDefaultStorage: () => createDefaultStorage,
36
36
  createLocalStorage: () => createLocalStorage,
37
37
  createMemoryStorage: () => createMemoryStorage,
38
- hasPermission: () => hasPermission
38
+ hasPermission: () => hasPermission,
39
+ hasPermissionGroup: () => hasPermissionGroup
39
40
  });
40
41
  module.exports = __toCommonJS(index_exports);
41
42
 
43
+ // ../../internal/core/security/approvals.ts
44
+ function path(id, suffix = "") {
45
+ if (typeof id !== "string" || !id.trim())
46
+ throw new TypeError("Authyon: an approval id is required.");
47
+ return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
48
+ }
49
+ var NO_METHODS = {
50
+ password: false,
51
+ authenticator: false,
52
+ emailCode: false,
53
+ passkey: false,
54
+ passkeyCount: 0,
55
+ recoveryCodes: 0,
56
+ sso: [],
57
+ twoFactor: false
58
+ };
59
+ function subjectSecurity(request) {
60
+ return {
61
+ methods: async () => {
62
+ const me = await request("/auth/me");
63
+ return me.security ?? NO_METHODS;
64
+ },
65
+ approvals: {
66
+ get: (id) => request(path(id)),
67
+ webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
68
+ confirm: (id, input) => request(path(id, "/confirm"), { method: "POST", body: input }),
69
+ reject: (id) => request(path(id, "/reject"), { method: "POST" })
70
+ }
71
+ };
72
+ }
73
+
42
74
  // ../../internal/core/errors/authyonError.ts
43
75
  var ErrorCodes = {
44
76
  Unknown: "unknown",
@@ -51,16 +83,45 @@ var ErrorCodes = {
51
83
  EmailTaken: "user.email_taken",
52
84
  PasswordWeak: "user.password_weak",
53
85
  PasswordPwned: "user.password_pwned",
54
- RateLimited: "rate_limited"
86
+ RateLimited: "rate_limited",
87
+ StepUpRequired: "step_up_required",
88
+ InvalidSecondFactorCode: "invalid_code",
89
+ VerificationAttemptsExhausted: "verification_attempts_exhausted",
90
+ MethodNotEnrolled: "method_not_enrolled",
91
+ InvalidApprovalState: "invalid_authorization_state",
92
+ PayloadMismatch: "payload_mismatch",
93
+ ApprovalNotConsumable: "authorization_not_consumable",
94
+ IdempotencyConflict: "idempotency_conflict",
95
+ UserDisabled: "user_disabled",
96
+ UserNotFound: "user_not_found",
97
+ TemporarilyUnavailable: "temporarily_unavailable",
98
+ InsufficientScope: "insufficient_scope",
99
+ CredentialThrottled: "credential_throttled",
100
+ ApprovalNotFound: "authorization_not_found",
101
+ SessionRevoked: "session_revoked",
102
+ TwoFactorTooManyFailures: "user.2fa.too_many_failures"
55
103
  };
104
+ var STANDARD_ERROR_FIELDS = /* @__PURE__ */ new Set([
105
+ "type",
106
+ "status",
107
+ "title",
108
+ "detail",
109
+ "code",
110
+ "error",
111
+ "error_description"
112
+ ]);
56
113
  var AuthyonError = class extends Error {
57
114
  constructor(status, body, options = {}) {
58
- super(body.detail ?? body.title ?? `Authyon request failed with status ${status}`);
115
+ const detail = body.detail ?? body.error_description;
116
+ super(detail ?? body.title ?? `Authyon request failed with status ${status}`);
59
117
  this.name = "AuthyonError";
60
118
  this.status = status;
61
- this.code = body.code ?? "unknown";
119
+ this.code = body.code ?? body.error ?? "unknown";
62
120
  this.title = body.title ?? "Error";
63
- this.detail = body.detail;
121
+ this.detail = detail;
122
+ this.extensions = Object.fromEntries(
123
+ Object.entries(body).filter(([key]) => !STANDARD_ERROR_FIELDS.has(key))
124
+ );
64
125
  this.requestId = options.requestId;
65
126
  this.retryAfter = options.retryAfter;
66
127
  this.cause = options.cause;
@@ -110,6 +171,7 @@ var AuthyonError = class extends Error {
110
171
  };
111
172
  function classifyError(status, code) {
112
173
  if (code === ErrorCodes.NetworkError) return "network";
174
+ if (code === ErrorCodes.StepUpRequired) return "authentication";
113
175
  if (code === ErrorCodes.Timeout || status === 408) return "timeout";
114
176
  if (code === ErrorCodes.RateLimited || status === 429) return "rate_limit";
115
177
  if (code === ErrorCodes.EmailTaken || status === 409) return "conflict";
@@ -203,14 +265,21 @@ var DEFAULT_BASE_URL = "https://api.authyon.com";
203
265
  var DEFAULT_EXPIRY_SKEW_MS = 3e4;
204
266
 
205
267
  // ../../internal/core/http/query.ts
206
- function appendQuery(path, params) {
207
- if (!params) return path;
268
+ function appendQuery(path2, params) {
269
+ if (!params) return path2;
208
270
  const query = new URLSearchParams();
209
271
  for (const [key, value2] of Object.entries(params)) {
210
- if (value2 !== void 0) query.set(key, String(value2));
272
+ if (value2 === void 0) continue;
273
+ if (Array.isArray(value2)) {
274
+ for (const item of value2) {
275
+ if (item !== void 0) query.append(key, String(item));
276
+ }
277
+ continue;
278
+ }
279
+ query.set(key, String(value2));
211
280
  }
212
281
  const value = query.toString();
213
- return value ? `${path}${path.includes("?") ? "&" : "?"}${value}` : path;
282
+ return value ? `${path2}${path2.includes("?") ? "&" : "?"}${value}` : path2;
214
283
  }
215
284
 
216
285
  // ../../internal/core/http/httpAdapter.ts
@@ -223,7 +292,8 @@ var FetchHttpAdapter = class {
223
292
  method: request.method,
224
293
  headers: request.headers,
225
294
  body: request.body,
226
- signal: request.signal
295
+ signal: request.signal,
296
+ redirect: "error"
227
297
  });
228
298
  }
229
299
  };
@@ -275,6 +345,9 @@ function defaultHttpLogger(event) {
275
345
  }
276
346
  function sanitizeUrl(value) {
277
347
  const url = new URL(value);
348
+ url.username = "";
349
+ url.password = "";
350
+ url.hash = "";
278
351
  const queryKeys = /* @__PURE__ */ new Set();
279
352
  url.searchParams.forEach((_value, key) => queryKeys.add(key));
280
353
  url.search = queryKeys.size > 0 ? [...queryKeys].map((key) => `${encodeURIComponent(key)}=REDACTED`).join("&") : "";
@@ -304,12 +377,12 @@ function createSharedTransport(options) {
304
377
  const httpAdapter = options.httpLogger ? new LoggingHttpAdapter(baseAdapter, options.httpLogger) : baseAdapter;
305
378
  return {
306
379
  baseUrl,
307
- async request(path, init) {
380
+ async request(path2, init) {
308
381
  const controller = new AbortController();
309
382
  const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
310
383
  try {
311
384
  return await httpAdapter.request({
312
- url: `${baseUrl}${path}`,
385
+ url: `${baseUrl}${path2}`,
313
386
  method: init.method ?? "GET",
314
387
  headers: normalizeHeaders(init.headers),
315
388
  body: init.body,
@@ -367,11 +440,11 @@ var JsonHttpClient = class {
367
440
  constructor(transport) {
368
441
  this.transport = transport;
369
442
  }
370
- async send(path, options = {}) {
443
+ async send(path2, options = {}) {
371
444
  const headers = { ...options.headers };
372
445
  if (options.body !== void 0) headers["Content-Type"] = "application/json";
373
446
  try {
374
- return await this.transport.request(appendQuery(path, options.query), {
447
+ return await this.transport.request(appendQuery(path2, options.query), {
375
448
  method: options.method ?? "GET",
376
449
  headers,
377
450
  body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
@@ -385,7 +458,9 @@ var JsonHttpClient = class {
385
458
  if (!response.ok) {
386
459
  let body = {};
387
460
  try {
388
- body = await response.json();
461
+ const parsed = await response.json();
462
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
463
+ body = parsed;
389
464
  } catch {
390
465
  }
391
466
  throw new AuthyonError(response.status, body, responseMetadata(response));
@@ -393,11 +468,33 @@ var JsonHttpClient = class {
393
468
  if (response.status === 204) return void 0;
394
469
  return await response.json();
395
470
  }
396
- async request(path, options = {}) {
397
- return this.parse(await this.send(path, options));
471
+ async request(path2, options = {}) {
472
+ return this.parse(await this.send(path2, options));
398
473
  }
399
474
  };
400
475
 
476
+ // ../../internal/core/http/clientIp.ts
477
+ function clientIpHeaders(context) {
478
+ if (!context?.clientIp) return {};
479
+ return { "X-Forwarded-For": normalizeClientIp(context.clientIp) };
480
+ }
481
+ function normalizeClientIp(value) {
482
+ let ip = value.trim();
483
+ if (ip.startsWith("[") && ip.endsWith("]")) ip = ip.slice(1, -1);
484
+ if (!ip || ip.length > 45 || ip.includes(",") || /[\r\n\s]/.test(ip) || !/^[0-9a-f:.]+$/i.test(ip) || !ip.includes(".") && !ip.includes(":")) {
485
+ throw invalidClientIp();
486
+ }
487
+ try {
488
+ new URL(ip.includes(":") ? `http://[${ip}]` : `http://${ip}`);
489
+ } catch {
490
+ throw invalidClientIp();
491
+ }
492
+ return ip;
493
+ }
494
+ function invalidClientIp() {
495
+ return new Error("Authyon: `clientIp` must be a single valid IPv4 or IPv6 address");
496
+ }
497
+
401
498
  // src/client/authyonClient.ts
402
499
  var FALLBACK_EXPIRES_IN = 1800;
403
500
  function readTokens(raw) {
@@ -475,18 +572,41 @@ var AuthyonClient = class {
475
572
  method: "DELETE",
476
573
  bearer: true
477
574
  }),
478
- /** POST /auth/password-reset/request — always resolves (no account enumeration). */
479
- requestPasswordReset: (email) => this.request("/auth/password-reset/request", { method: "POST", body: { email } }),
480
- /** POST /auth/password-reset/confirm — sets a new password and revokes all refresh tokens. */
481
- confirmPasswordReset: (token, newPassword) => this.request("/auth/password-reset/confirm", {
575
+ /**
576
+ * POST /auth/password-reset/request — resolves whether or not the address
577
+ * has an account (no account enumeration). `redirectUri` is where the
578
+ * person lands after changing the password; it must be one of the
579
+ * environment's registered redirect URIs, or the call rejects with
580
+ * `user.password_reset.redirect_uri.not_allowed`.
581
+ */
582
+ requestPasswordReset: (email, options = {}) => this.request("/auth/password-reset/request", {
482
583
  method: "POST",
483
- body: { token, newPassword }
484
- })
584
+ body: { email, ...options }
585
+ }),
586
+ /**
587
+ * POST /auth/password-reset/validate — checks a reset token without
588
+ * spending it, so the reset page can refuse a dead link before asking for
589
+ * a password. Rejects with `user.password_reset.invalid` (401) when the
590
+ * token is unknown, used or expired.
591
+ */
592
+ validatePasswordReset: (token) => this.request("/auth/password-reset/validate", { method: "POST", body: { token } }),
593
+ /**
594
+ * POST /auth/password-reset/confirm — sets a new password and revokes all
595
+ * refresh tokens. Resolves with the `redirectUri` the reset was requested
596
+ * with (`null` when there was none); following it is up to the caller.
597
+ */
598
+ confirmPasswordReset: async (token, newPassword) => {
599
+ const done = await this.request(
600
+ "/auth/password-reset/confirm",
601
+ { method: "POST", body: { token, newPassword } }
602
+ );
603
+ return { redirectUri: done?.redirectUri ?? null };
604
+ }
485
605
  };
486
606
  // ── Organization ─────────────────────────────────────────────────────────
487
607
  this.organization = {
488
- /** GET /auth/tenants — all organization memberships. */
489
- list: () => this.request("/auth/tenants", { bearer: true }),
608
+ /** GET /auth/tenants — filterable list of organization memberships. */
609
+ list: (params = {}) => this.request(appendQuery("/auth/tenants", params), { bearer: true }),
490
610
  /**
491
611
  * POST /auth/tenants — creates an organization owned by the signed-in
492
612
  * user (only available when self-service organization creation is
@@ -523,7 +643,11 @@ var AuthyonClient = class {
523
643
  appendQuery(`/auth/tenants/${encodeURIComponent(organizationId)}/members`, params),
524
644
  { bearer: true }
525
645
  ),
526
- /** POST /auth/tenants/{organizationId}/members — invite a member by e-mail. */
646
+ /**
647
+ * POST /auth/tenants/{organizationId}/members — add an existing
648
+ * environment user by e-mail (no e-mail is sent). To invite an address
649
+ * that may not have an account yet, use `organization.invites.create`.
650
+ */
527
651
  invite: (organizationId, params) => this.request(`/auth/tenants/${encodeURIComponent(organizationId)}/members`, {
528
652
  method: "POST",
529
653
  bearer: true,
@@ -535,6 +659,59 @@ var AuthyonClient = class {
535
659
  { method: "DELETE", bearer: true }
536
660
  )
537
661
  },
662
+ /**
663
+ * Invites by e-mail or by link. Managing them requires the
664
+ * `tenants:members:invite` permission on the organization; `preview` and
665
+ * `accept` are public — the token in the link is the credential.
666
+ */
667
+ invites: {
668
+ /** GET /auth/tenants/{organizationId}/invites — every invite with its status, newest first. */
669
+ list: (organizationId) => this.request(`/auth/tenants/${encodeURIComponent(organizationId)}/invites`, {
670
+ bearer: true
671
+ }),
672
+ /**
673
+ * POST /auth/tenants/{organizationId}/invites — invite an address.
674
+ * Always returns `acceptUrl`; with `sendEmail: false` Authyon does not
675
+ * mail it and you deliver the link yourself. The link is valid for 7
676
+ * days, once, and can't be read again later.
677
+ */
678
+ create: (organizationId, params) => this.request(`/auth/tenants/${encodeURIComponent(organizationId)}/invites`, {
679
+ method: "POST",
680
+ bearer: true,
681
+ body: {
682
+ email: params.email,
683
+ roles: params.roles,
684
+ sendEmail: params.sendEmail ?? true,
685
+ redirectUri: params.redirectUri
686
+ }
687
+ }),
688
+ /**
689
+ * POST /auth/tenants/{organizationId}/invites/{inviteId}/resend — issue
690
+ * a new link (the previous one stops working), mailing it unless
691
+ * `sendEmail` is `false`.
692
+ */
693
+ resend: (organizationId, inviteId, params = {}) => this.request(
694
+ `/auth/tenants/${encodeURIComponent(organizationId)}/invites/${encodeURIComponent(inviteId)}/resend`,
695
+ { method: "POST", bearer: true, body: { sendEmail: params.sendEmail ?? true } }
696
+ ),
697
+ /** DELETE /auth/tenants/{organizationId}/invites/{inviteId} — revoke a pending invite. */
698
+ revoke: (organizationId, inviteId) => this.request(
699
+ `/auth/tenants/${encodeURIComponent(organizationId)}/invites/${encodeURIComponent(inviteId)}`,
700
+ { method: "DELETE", bearer: true }
701
+ ),
702
+ /**
703
+ * POST /auth/tenant-invites/preview — public. Read the `token` query
704
+ * parameter of the invite link and pick the form: one click when
705
+ * `accountExists`, sign-up otherwise.
706
+ */
707
+ preview: (token) => this.request("/auth/tenant-invites/preview", { method: "POST", body: { token } }),
708
+ /**
709
+ * POST /auth/tenant-invites/accept — public. Joins the organization; for
710
+ * an address with no account, also creates it (password required) with
711
+ * the e-mail already confirmed. Does not sign the user in.
712
+ */
713
+ accept: (params) => this.request("/auth/tenant-invites/accept", { method: "POST", body: params })
714
+ },
538
715
  roles: {
539
716
  /** GET /auth/tenants/{organizationId}/roles — roles available in the organization. */
540
717
  list: (organizationId) => this.request(`/auth/tenants/${encodeURIComponent(organizationId)}/roles`, {
@@ -610,9 +787,20 @@ var AuthyonClient = class {
610
787
  })
611
788
  }
612
789
  };
790
+ // ── Security (customer side) ─────────────────────────────────────────────
791
+ /**
792
+ * `security.approvals`: approve or reject what your backend asked the
793
+ * customer to confirm (`@authyon/server` → `security.approvals.create`).
794
+ * Show the payload with `get()`, then `confirm()` with the customer's
795
+ * authenticator code or passkey, or `reject()`.
796
+ */
797
+ this.security = subjectSecurity(
798
+ (path2, options) => this.request(path2, { ...options, bearer: true })
799
+ );
613
800
  if (!options.envKey)
614
801
  throw new Error("Authyon: `envKey` is required (pk_live_... / pk_test_...)");
615
802
  this.envKey = options.envKey;
803
+ this.clientIp = options.clientIp;
616
804
  this.transport = createSharedTransport({
617
805
  baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
618
806
  allowInsecureHttp: options.allowInsecureHttp,
@@ -722,9 +910,10 @@ var AuthyonClient = class {
722
910
  }
723
911
  }
724
912
  // ── HTTP core ────────────────────────────────────────────────────────────
725
- async request(path, options = {}, isRetry = false) {
913
+ async request(path2, options = {}, isRetry = false) {
726
914
  const headers = {
727
915
  "X-Authyon-Environment": this.envKey,
916
+ ...clientIpHeaders({ clientIp: this.clientIp }),
728
917
  ...options.headers
729
918
  };
730
919
  if (options.bearer) {
@@ -736,7 +925,7 @@ var AuthyonClient = class {
736
925
  });
737
926
  headers.Authorization = `Bearer ${token}`;
738
927
  }
739
- const response = await this.http.send(path, { ...options, headers });
928
+ const response = await this.http.send(path2, { ...options, headers });
740
929
  if (response.status === 401 && options.bearer && this.autoRefresh && !isRetry && this.getSession()) {
741
930
  try {
742
931
  await this.refresh();
@@ -744,7 +933,7 @@ var AuthyonClient = class {
744
933
  this.clearSession();
745
934
  return this.http.parse(response);
746
935
  }
747
- return this.request(path, options, true);
936
+ return this.request(path2, options, true);
748
937
  }
749
938
  return this.http.parse(response);
750
939
  }
@@ -889,6 +1078,10 @@ var AuthyonClientBuilder = class {
889
1078
  this.options.autoRefresh = enabled;
890
1079
  return this;
891
1080
  }
1081
+ withClientIp(clientIp) {
1082
+ this.options.clientIp = clientIp;
1083
+ return this;
1084
+ }
892
1085
  withTimeout(timeoutMs) {
893
1086
  this.options.timeoutMs = timeoutMs;
894
1087
  return this;
@@ -1109,6 +1302,11 @@ function hasPermission(source, requiredPermission) {
1109
1302
  const permissionSource = isPermissionList(source) ? { permissions: source } : source;
1110
1303
  return createAuthyonAbility(permissionSource).can(requirement.action, requirement.subject);
1111
1304
  }
1305
+ function hasPermissionGroup(source, group) {
1306
+ const hasAll = (group.allOf ?? []).every((permission) => hasPermission(source, permission));
1307
+ const hasAny = !group.anyOf?.length || group.anyOf.some((permission) => hasPermission(source, permission));
1308
+ return hasAll && hasAny;
1309
+ }
1112
1310
  function isPermissionList(source) {
1113
1311
  return Array.isArray(source);
1114
1312
  }
@@ -1154,18 +1352,18 @@ function matchesField(pattern, field) {
1154
1352
  return pattern.endsWith(".*") && field.startsWith(pattern.slice(0, -1));
1155
1353
  }
1156
1354
  function matchesConditions(subject, conditions) {
1157
- return Object.entries(conditions).every(([path, expected]) => {
1158
- if (path === "$and" && Array.isArray(expected)) {
1355
+ return Object.entries(conditions).every(([path2, expected]) => {
1356
+ if (path2 === "$and" && Array.isArray(expected)) {
1159
1357
  return expected.every(
1160
1358
  (condition) => matchesConditions(subject, condition)
1161
1359
  );
1162
1360
  }
1163
- if (path === "$or" && Array.isArray(expected)) {
1361
+ if (path2 === "$or" && Array.isArray(expected)) {
1164
1362
  return expected.some(
1165
1363
  (condition) => matchesConditions(subject, condition)
1166
1364
  );
1167
1365
  }
1168
- return matchesValue(readPath(subject, path), expected);
1366
+ return matchesValue(readPath(subject, path2), expected);
1169
1367
  });
1170
1368
  }
1171
1369
  function matchesValue(actual, expected) {
@@ -1197,8 +1395,8 @@ function matchesValue(actual, expected) {
1197
1395
  }
1198
1396
  });
1199
1397
  }
1200
- function readPath(value, path) {
1201
- return path.split(".").reduce((current, part) => isRecord(current) ? current[part] : void 0, value);
1398
+ function readPath(value, path2) {
1399
+ return path2.split(".").reduce((current, part) => isRecord(current) ? current[part] : void 0, value);
1202
1400
  }
1203
1401
  function defaultSubjectType(subject) {
1204
1402
  const explicit = subject.__type ?? subject.type ?? subject.kind;
@@ -1237,5 +1435,6 @@ function isAbilityRule(value) {
1237
1435
  createDefaultStorage,
1238
1436
  createLocalStorage,
1239
1437
  createMemoryStorage,
1240
- hasPermission
1438
+ hasPermission,
1439
+ hasPermissionGroup
1241
1440
  });
package/dist/index.d.cts CHANGED
@@ -1,18 +1,5 @@
1
- import { T as TokenStorage, H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonClient } from './ability-g6nBpOQM.cjs';
2
- export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRule, f as AbilitySubject, g as Activity, h as AuthEvent, i as AuthState, j as AuthStateListener, k as AuthenticatorSetup, l as AuthyonAbility, m as AuthyonAbilityBuilder, n as AuthyonAbilityOptions, o as AuthyonClientOptions, p as AuthyonPermissionSource, q as AuthyonSessionController, C as CreateOrganizationInput, F as FetchHttpAdapter, r as HttpAdapterRequest, s as HttpLogEvent, t as HttpLogger, I as IntrospectResult, u as InviteMemberInput, L as LoggingHttpAdapter, v as LoginInput, w as LoginResult, O as Organization, x as OrganizationMember, P as Paged, y as PaginationOptions, R as RegisterInput, z as Role, S as Session, B as SessionControllerOptions, D as SessionInfo, E as SessionSnapshot, G as SessionSnapshotListener, J as SessionStatus, K as SsoProvider, M as TwoFactorChallenge, N as TwoFactorMethod, Q as TwoFactorStatus, U as User, V as ValidateResult, W as VerifyTwoFactorInput, X as WebAuthnAssertion, Y as WebAuthnCeremonyStart, Z as WebAuthnCredential, _ as createAuthyonAbility, $ as createAuthyonRules, a0 as createClient, a1 as hasPermission } from './ability-g6nBpOQM.cjs';
3
-
4
- /** Builds an Authyon browser client through explicit, progressive configuration. */
5
- declare class AuthyonClientBuilder {
6
- private readonly options;
7
- constructor(envKey: string);
8
- withBaseUrl(baseUrl: string, allowInsecureHttp?: boolean): this;
9
- withStorage(storage: TokenStorage): this;
10
- withAutomaticRefresh(enabled?: boolean): this;
11
- withTimeout(timeoutMs: number): this;
12
- withHttpAdapter(httpAdapter: HttpAdapter): this;
13
- withHttpLogger(httpLogger: HttpLoggerOptions): this;
14
- build(): AuthyonClient;
15
- }
1
+ import { T as TokenStorage, H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonClient } from './ability-BTcayvkM.cjs';
2
+ export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRule, f as AbilitySubject, g as AcceptOrganizationInviteInput, h as Activity, i as Approval, j as ApprovalAssurance, k as ApprovalPayload, l as ApprovalStatus, m as ApprovalWebAuthnOptions, n as AuthEvent, o as AuthState, p as AuthStateListener, q as AuthenticatorSetup, r as AuthyonAbility, s as AuthyonAbilityBuilder, t as AuthyonAbilityOptions, u as AuthyonClientOptions, v as AuthyonPermissionSource, w as AuthyonSessionController, C as ConfirmApprovalInput, x as CreateOrganizationInput, F as FetchHttpAdapter, y as HttpAdapterRequest, z as HttpLogEvent, B as HttpLogger, I as IntrospectResult, D as InviteMemberInput, L as LoggingHttpAdapter, E as LoginInput, G as LoginResult, O as Organization, J as OrganizationInvite, K as OrganizationInviteAccepted, M as OrganizationInviteInput, N as OrganizationInviteIssued, P as OrganizationInvitePreview, Q as OrganizationInviteStatus, R as OrganizationMember, S as Paged, U as PaginationOptions, V as PasswordResetCompleted, W as PasswordResetPreview, X as PasswordResetRequestOptions, Y as PermissionGroup, Z as RegisterInput, _ as Role, $ as SecurityMethods, a0 as Session, a1 as SessionControllerOptions, a2 as SessionInfo, a3 as SessionSnapshot, a4 as SessionSnapshotListener, a5 as SessionStatus, a6 as SsoProvider, a7 as SubjectApprovals, a8 as SubjectSecurity, a9 as TwoFactorChallenge, aa as TwoFactorMethod, ab as TwoFactorStatus, ac as User, ad as ValidateResult, ae as VerifyTwoFactorInput, af as WebAuthnAssertion, ag as WebAuthnCeremonyStart, ah as WebAuthnCredential, ai as createAuthyonAbility, aj as createAuthyonRules, ak as createClient, al as hasPermission, am as hasPermissionGroup } from './ability-BTcayvkM.cjs';
16
3
 
17
4
  declare const ErrorCodes: {
18
5
  readonly Unknown: "unknown";
@@ -26,6 +13,22 @@ declare const ErrorCodes: {
26
13
  readonly PasswordWeak: "user.password_weak";
27
14
  readonly PasswordPwned: "user.password_pwned";
28
15
  readonly RateLimited: "rate_limited";
16
+ readonly StepUpRequired: "step_up_required";
17
+ readonly InvalidSecondFactorCode: "invalid_code";
18
+ readonly VerificationAttemptsExhausted: "verification_attempts_exhausted";
19
+ readonly MethodNotEnrolled: "method_not_enrolled";
20
+ readonly InvalidApprovalState: "invalid_authorization_state";
21
+ readonly PayloadMismatch: "payload_mismatch";
22
+ readonly ApprovalNotConsumable: "authorization_not_consumable";
23
+ readonly IdempotencyConflict: "idempotency_conflict";
24
+ readonly UserDisabled: "user_disabled";
25
+ readonly UserNotFound: "user_not_found";
26
+ readonly TemporarilyUnavailable: "temporarily_unavailable";
27
+ readonly InsufficientScope: "insufficient_scope";
28
+ readonly CredentialThrottled: "credential_throttled";
29
+ readonly ApprovalNotFound: "authorization_not_found";
30
+ readonly SessionRevoked: "session_revoked";
31
+ readonly TwoFactorTooManyFailures: "user.2fa.too_many_failures";
29
32
  };
30
33
  type KnownErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
31
34
  type AuthyonErrorCategory = "network" | "timeout" | "authentication" | "authorization" | "validation" | "not_found" | "conflict" | "rate_limit" | "server" | "unknown";
@@ -37,6 +40,14 @@ interface AuthyonErrorInterpretation {
37
40
  retryAfter?: number;
38
41
  requestId?: string;
39
42
  }
43
+ /** Error body as sent by the API: RFC 7807, or OAuth-style `error`/`error_description`. */
44
+ type AuthyonErrorBody = Partial<{
45
+ title: string;
46
+ detail: string;
47
+ code: string;
48
+ error: string;
49
+ error_description: string;
50
+ }> & Record<string, unknown>;
40
51
  /** Shared RFC 7807 error implementation used by both public SDKs. */
41
52
  declare class AuthyonError extends Error {
42
53
  readonly status: number;
@@ -46,11 +57,13 @@ declare class AuthyonError extends Error {
46
57
  readonly requestId?: string;
47
58
  readonly retryAfter?: number;
48
59
  readonly cause?: unknown;
49
- constructor(status: number, body: Partial<{
50
- title: string;
51
- detail: string;
52
- code: string;
53
- }>, options?: {
60
+ /**
61
+ * Extra fields from the error body beyond code/title/detail — e.g.
62
+ * `attemptsRemaining` on `invalid_code` or `requiredMethods` on
63
+ * `step_up_required`. Not included in {@link toJSON}.
64
+ */
65
+ readonly extensions: Readonly<Record<string, unknown>>;
66
+ constructor(status: number, body: AuthyonErrorBody, options?: {
54
67
  requestId?: string;
55
68
  retryAfter?: number;
56
69
  cause?: unknown;
@@ -66,10 +79,24 @@ declare class AuthyonError extends Error {
66
79
  toJSON(): Record<string, unknown>;
67
80
  }
68
81
 
82
+ /** Builds an Authyon browser client through explicit, progressive configuration. */
83
+ declare class AuthyonClientBuilder {
84
+ private readonly options;
85
+ constructor(envKey: string);
86
+ withBaseUrl(baseUrl: string, allowInsecureHttp?: boolean): this;
87
+ withStorage(storage: TokenStorage): this;
88
+ withAutomaticRefresh(enabled?: boolean): this;
89
+ withClientIp(clientIp: string): this;
90
+ withTimeout(timeoutMs: number): this;
91
+ withHttpAdapter(httpAdapter: HttpAdapter): this;
92
+ withHttpLogger(httpLogger: HttpLoggerOptions): this;
93
+ build(): AuthyonClient;
94
+ }
95
+
69
96
  /** Keeps the session in memory only (lost on page reload). */
70
97
  declare function createMemoryStorage(): TokenStorage;
71
98
  /** Persists the session in `localStorage` under a namespaced key. */
72
99
  declare function createLocalStorage(key?: string): TokenStorage;
73
100
  declare function createDefaultStorage(): TokenStorage;
74
101
 
75
- export { AuthyonClient, AuthyonClientBuilder, AuthyonError, type AuthyonErrorAction, type AuthyonErrorCategory, type AuthyonErrorInterpretation, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode, TokenStorage, createDefaultStorage, createLocalStorage, createMemoryStorage };
102
+ export { AuthyonClient, AuthyonClientBuilder, AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode, TokenStorage, createDefaultStorage, createLocalStorage, createMemoryStorage };