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

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,14 @@ 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
272
  if (value2 !== void 0) query.set(key, String(value2));
211
273
  }
212
274
  const value = query.toString();
213
- return value ? `${path}${path.includes("?") ? "&" : "?"}${value}` : path;
275
+ return value ? `${path2}${path2.includes("?") ? "&" : "?"}${value}` : path2;
214
276
  }
215
277
 
216
278
  // ../../internal/core/http/httpAdapter.ts
@@ -223,7 +285,8 @@ var FetchHttpAdapter = class {
223
285
  method: request.method,
224
286
  headers: request.headers,
225
287
  body: request.body,
226
- signal: request.signal
288
+ signal: request.signal,
289
+ redirect: "error"
227
290
  });
228
291
  }
229
292
  };
@@ -275,6 +338,9 @@ function defaultHttpLogger(event) {
275
338
  }
276
339
  function sanitizeUrl(value) {
277
340
  const url = new URL(value);
341
+ url.username = "";
342
+ url.password = "";
343
+ url.hash = "";
278
344
  const queryKeys = /* @__PURE__ */ new Set();
279
345
  url.searchParams.forEach((_value, key) => queryKeys.add(key));
280
346
  url.search = queryKeys.size > 0 ? [...queryKeys].map((key) => `${encodeURIComponent(key)}=REDACTED`).join("&") : "";
@@ -304,12 +370,12 @@ function createSharedTransport(options) {
304
370
  const httpAdapter = options.httpLogger ? new LoggingHttpAdapter(baseAdapter, options.httpLogger) : baseAdapter;
305
371
  return {
306
372
  baseUrl,
307
- async request(path, init) {
373
+ async request(path2, init) {
308
374
  const controller = new AbortController();
309
375
  const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
310
376
  try {
311
377
  return await httpAdapter.request({
312
- url: `${baseUrl}${path}`,
378
+ url: `${baseUrl}${path2}`,
313
379
  method: init.method ?? "GET",
314
380
  headers: normalizeHeaders(init.headers),
315
381
  body: init.body,
@@ -367,11 +433,11 @@ var JsonHttpClient = class {
367
433
  constructor(transport) {
368
434
  this.transport = transport;
369
435
  }
370
- async send(path, options = {}) {
436
+ async send(path2, options = {}) {
371
437
  const headers = { ...options.headers };
372
438
  if (options.body !== void 0) headers["Content-Type"] = "application/json";
373
439
  try {
374
- return await this.transport.request(appendQuery(path, options.query), {
440
+ return await this.transport.request(appendQuery(path2, options.query), {
375
441
  method: options.method ?? "GET",
376
442
  headers,
377
443
  body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
@@ -385,7 +451,9 @@ var JsonHttpClient = class {
385
451
  if (!response.ok) {
386
452
  let body = {};
387
453
  try {
388
- body = await response.json();
454
+ const parsed = await response.json();
455
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
456
+ body = parsed;
389
457
  } catch {
390
458
  }
391
459
  throw new AuthyonError(response.status, body, responseMetadata(response));
@@ -393,11 +461,33 @@ var JsonHttpClient = class {
393
461
  if (response.status === 204) return void 0;
394
462
  return await response.json();
395
463
  }
396
- async request(path, options = {}) {
397
- return this.parse(await this.send(path, options));
464
+ async request(path2, options = {}) {
465
+ return this.parse(await this.send(path2, options));
398
466
  }
399
467
  };
400
468
 
469
+ // ../../internal/core/http/clientIp.ts
470
+ function clientIpHeaders(context) {
471
+ if (!context?.clientIp) return {};
472
+ return { "X-Forwarded-For": normalizeClientIp(context.clientIp) };
473
+ }
474
+ function normalizeClientIp(value) {
475
+ let ip = value.trim();
476
+ if (ip.startsWith("[") && ip.endsWith("]")) ip = ip.slice(1, -1);
477
+ if (!ip || ip.length > 45 || ip.includes(",") || /[\r\n\s]/.test(ip) || !/^[0-9a-f:.]+$/i.test(ip) || !ip.includes(".") && !ip.includes(":")) {
478
+ throw invalidClientIp();
479
+ }
480
+ try {
481
+ new URL(ip.includes(":") ? `http://[${ip}]` : `http://${ip}`);
482
+ } catch {
483
+ throw invalidClientIp();
484
+ }
485
+ return ip;
486
+ }
487
+ function invalidClientIp() {
488
+ return new Error("Authyon: `clientIp` must be a single valid IPv4 or IPv6 address");
489
+ }
490
+
401
491
  // src/client/authyonClient.ts
402
492
  var FALLBACK_EXPIRES_IN = 1800;
403
493
  function readTokens(raw) {
@@ -475,18 +565,41 @@ var AuthyonClient = class {
475
565
  method: "DELETE",
476
566
  bearer: true
477
567
  }),
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", {
568
+ /**
569
+ * POST /auth/password-reset/request — resolves whether or not the address
570
+ * has an account (no account enumeration). `redirectUri` is where the
571
+ * person lands after changing the password; it must be one of the
572
+ * environment's registered redirect URIs, or the call rejects with
573
+ * `user.password_reset.redirect_uri.not_allowed`.
574
+ */
575
+ requestPasswordReset: (email, options = {}) => this.request("/auth/password-reset/request", {
482
576
  method: "POST",
483
- body: { token, newPassword }
484
- })
577
+ body: { email, ...options }
578
+ }),
579
+ /**
580
+ * POST /auth/password-reset/validate — checks a reset token without
581
+ * spending it, so the reset page can refuse a dead link before asking for
582
+ * a password. Rejects with `user.password_reset.invalid` (401) when the
583
+ * token is unknown, used or expired.
584
+ */
585
+ validatePasswordReset: (token) => this.request("/auth/password-reset/validate", { method: "POST", body: { token } }),
586
+ /**
587
+ * POST /auth/password-reset/confirm — sets a new password and revokes all
588
+ * refresh tokens. Resolves with the `redirectUri` the reset was requested
589
+ * with (`null` when there was none); following it is up to the caller.
590
+ */
591
+ confirmPasswordReset: async (token, newPassword) => {
592
+ const done = await this.request(
593
+ "/auth/password-reset/confirm",
594
+ { method: "POST", body: { token, newPassword } }
595
+ );
596
+ return { redirectUri: done?.redirectUri ?? null };
597
+ }
485
598
  };
486
599
  // ── Organization ─────────────────────────────────────────────────────────
487
600
  this.organization = {
488
- /** GET /auth/tenants — all organization memberships. */
489
- list: () => this.request("/auth/tenants", { bearer: true }),
601
+ /** GET /auth/tenants — filterable list of organization memberships. */
602
+ list: (params = {}) => this.request(appendQuery("/auth/tenants", params), { bearer: true }),
490
603
  /**
491
604
  * POST /auth/tenants — creates an organization owned by the signed-in
492
605
  * user (only available when self-service organization creation is
@@ -523,7 +636,11 @@ var AuthyonClient = class {
523
636
  appendQuery(`/auth/tenants/${encodeURIComponent(organizationId)}/members`, params),
524
637
  { bearer: true }
525
638
  ),
526
- /** POST /auth/tenants/{organizationId}/members — invite a member by e-mail. */
639
+ /**
640
+ * POST /auth/tenants/{organizationId}/members — add an existing
641
+ * environment user by e-mail (no e-mail is sent). To invite an address
642
+ * that may not have an account yet, use `organization.invites.create`.
643
+ */
527
644
  invite: (organizationId, params) => this.request(`/auth/tenants/${encodeURIComponent(organizationId)}/members`, {
528
645
  method: "POST",
529
646
  bearer: true,
@@ -535,6 +652,59 @@ var AuthyonClient = class {
535
652
  { method: "DELETE", bearer: true }
536
653
  )
537
654
  },
655
+ /**
656
+ * Invites by e-mail or by link. Managing them requires the
657
+ * `tenants:members:invite` permission on the organization; `preview` and
658
+ * `accept` are public — the token in the link is the credential.
659
+ */
660
+ invites: {
661
+ /** GET /auth/tenants/{organizationId}/invites — every invite with its status, newest first. */
662
+ list: (organizationId) => this.request(`/auth/tenants/${encodeURIComponent(organizationId)}/invites`, {
663
+ bearer: true
664
+ }),
665
+ /**
666
+ * POST /auth/tenants/{organizationId}/invites — invite an address.
667
+ * Always returns `acceptUrl`; with `sendEmail: false` Authyon does not
668
+ * mail it and you deliver the link yourself. The link is valid for 7
669
+ * days, once, and can't be read again later.
670
+ */
671
+ create: (organizationId, params) => this.request(`/auth/tenants/${encodeURIComponent(organizationId)}/invites`, {
672
+ method: "POST",
673
+ bearer: true,
674
+ body: {
675
+ email: params.email,
676
+ roles: params.roles,
677
+ sendEmail: params.sendEmail ?? true,
678
+ redirectUri: params.redirectUri
679
+ }
680
+ }),
681
+ /**
682
+ * POST /auth/tenants/{organizationId}/invites/{inviteId}/resend — issue
683
+ * a new link (the previous one stops working), mailing it unless
684
+ * `sendEmail` is `false`.
685
+ */
686
+ resend: (organizationId, inviteId, params = {}) => this.request(
687
+ `/auth/tenants/${encodeURIComponent(organizationId)}/invites/${encodeURIComponent(inviteId)}/resend`,
688
+ { method: "POST", bearer: true, body: { sendEmail: params.sendEmail ?? true } }
689
+ ),
690
+ /** DELETE /auth/tenants/{organizationId}/invites/{inviteId} — revoke a pending invite. */
691
+ revoke: (organizationId, inviteId) => this.request(
692
+ `/auth/tenants/${encodeURIComponent(organizationId)}/invites/${encodeURIComponent(inviteId)}`,
693
+ { method: "DELETE", bearer: true }
694
+ ),
695
+ /**
696
+ * POST /auth/tenant-invites/preview — public. Read the `token` query
697
+ * parameter of the invite link and pick the form: one click when
698
+ * `accountExists`, sign-up otherwise.
699
+ */
700
+ preview: (token) => this.request("/auth/tenant-invites/preview", { method: "POST", body: { token } }),
701
+ /**
702
+ * POST /auth/tenant-invites/accept — public. Joins the organization; for
703
+ * an address with no account, also creates it (password required) with
704
+ * the e-mail already confirmed. Does not sign the user in.
705
+ */
706
+ accept: (params) => this.request("/auth/tenant-invites/accept", { method: "POST", body: params })
707
+ },
538
708
  roles: {
539
709
  /** GET /auth/tenants/{organizationId}/roles — roles available in the organization. */
540
710
  list: (organizationId) => this.request(`/auth/tenants/${encodeURIComponent(organizationId)}/roles`, {
@@ -610,9 +780,20 @@ var AuthyonClient = class {
610
780
  })
611
781
  }
612
782
  };
783
+ // ── Security (customer side) ─────────────────────────────────────────────
784
+ /**
785
+ * `security.approvals`: approve or reject what your backend asked the
786
+ * customer to confirm (`@authyon/server` → `security.approvals.create`).
787
+ * Show the payload with `get()`, then `confirm()` with the customer's
788
+ * authenticator code or passkey, or `reject()`.
789
+ */
790
+ this.security = subjectSecurity(
791
+ (path2, options) => this.request(path2, { ...options, bearer: true })
792
+ );
613
793
  if (!options.envKey)
614
794
  throw new Error("Authyon: `envKey` is required (pk_live_... / pk_test_...)");
615
795
  this.envKey = options.envKey;
796
+ this.clientIp = options.clientIp;
616
797
  this.transport = createSharedTransport({
617
798
  baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
618
799
  allowInsecureHttp: options.allowInsecureHttp,
@@ -722,9 +903,10 @@ var AuthyonClient = class {
722
903
  }
723
904
  }
724
905
  // ── HTTP core ────────────────────────────────────────────────────────────
725
- async request(path, options = {}, isRetry = false) {
906
+ async request(path2, options = {}, isRetry = false) {
726
907
  const headers = {
727
908
  "X-Authyon-Environment": this.envKey,
909
+ ...clientIpHeaders({ clientIp: this.clientIp }),
728
910
  ...options.headers
729
911
  };
730
912
  if (options.bearer) {
@@ -736,7 +918,7 @@ var AuthyonClient = class {
736
918
  });
737
919
  headers.Authorization = `Bearer ${token}`;
738
920
  }
739
- const response = await this.http.send(path, { ...options, headers });
921
+ const response = await this.http.send(path2, { ...options, headers });
740
922
  if (response.status === 401 && options.bearer && this.autoRefresh && !isRetry && this.getSession()) {
741
923
  try {
742
924
  await this.refresh();
@@ -744,7 +926,7 @@ var AuthyonClient = class {
744
926
  this.clearSession();
745
927
  return this.http.parse(response);
746
928
  }
747
- return this.request(path, options, true);
929
+ return this.request(path2, options, true);
748
930
  }
749
931
  return this.http.parse(response);
750
932
  }
@@ -889,6 +1071,10 @@ var AuthyonClientBuilder = class {
889
1071
  this.options.autoRefresh = enabled;
890
1072
  return this;
891
1073
  }
1074
+ withClientIp(clientIp) {
1075
+ this.options.clientIp = clientIp;
1076
+ return this;
1077
+ }
892
1078
  withTimeout(timeoutMs) {
893
1079
  this.options.timeoutMs = timeoutMs;
894
1080
  return this;
@@ -1109,6 +1295,11 @@ function hasPermission(source, requiredPermission) {
1109
1295
  const permissionSource = isPermissionList(source) ? { permissions: source } : source;
1110
1296
  return createAuthyonAbility(permissionSource).can(requirement.action, requirement.subject);
1111
1297
  }
1298
+ function hasPermissionGroup(source, group) {
1299
+ const hasAll = (group.allOf ?? []).every((permission) => hasPermission(source, permission));
1300
+ const hasAny = !group.anyOf?.length || group.anyOf.some((permission) => hasPermission(source, permission));
1301
+ return hasAll && hasAny;
1302
+ }
1112
1303
  function isPermissionList(source) {
1113
1304
  return Array.isArray(source);
1114
1305
  }
@@ -1154,18 +1345,18 @@ function matchesField(pattern, field) {
1154
1345
  return pattern.endsWith(".*") && field.startsWith(pattern.slice(0, -1));
1155
1346
  }
1156
1347
  function matchesConditions(subject, conditions) {
1157
- return Object.entries(conditions).every(([path, expected]) => {
1158
- if (path === "$and" && Array.isArray(expected)) {
1348
+ return Object.entries(conditions).every(([path2, expected]) => {
1349
+ if (path2 === "$and" && Array.isArray(expected)) {
1159
1350
  return expected.every(
1160
1351
  (condition) => matchesConditions(subject, condition)
1161
1352
  );
1162
1353
  }
1163
- if (path === "$or" && Array.isArray(expected)) {
1354
+ if (path2 === "$or" && Array.isArray(expected)) {
1164
1355
  return expected.some(
1165
1356
  (condition) => matchesConditions(subject, condition)
1166
1357
  );
1167
1358
  }
1168
- return matchesValue(readPath(subject, path), expected);
1359
+ return matchesValue(readPath(subject, path2), expected);
1169
1360
  });
1170
1361
  }
1171
1362
  function matchesValue(actual, expected) {
@@ -1197,8 +1388,8 @@ function matchesValue(actual, expected) {
1197
1388
  }
1198
1389
  });
1199
1390
  }
1200
- function readPath(value, path) {
1201
- return path.split(".").reduce((current, part) => isRecord(current) ? current[part] : void 0, value);
1391
+ function readPath(value, path2) {
1392
+ return path2.split(".").reduce((current, part) => isRecord(current) ? current[part] : void 0, value);
1202
1393
  }
1203
1394
  function defaultSubjectType(subject) {
1204
1395
  const explicit = subject.__type ?? subject.type ?? subject.kind;
@@ -1237,5 +1428,6 @@ function isAbilityRule(value) {
1237
1428
  createDefaultStorage,
1238
1429
  createLocalStorage,
1239
1430
  createMemoryStorage,
1240
- hasPermission
1431
+ hasPermission,
1432
+ hasPermissionGroup
1241
1433
  });
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 };
package/dist/index.d.ts CHANGED
@@ -1,18 +1,5 @@
1
- import { T as TokenStorage, H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonClient } from './ability-g6nBpOQM.js';
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.js';
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.js';
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.js';
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 };