@authyon/server 0.2.0-beta.12 → 0.2.0-beta.14

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
@@ -37,11 +37,9 @@ __export(index_exports, {
37
37
  FetchHttpAdapter: () => FetchHttpAdapter,
38
38
  JwksTokenVerifier: () => JwksTokenVerifier,
39
39
  LoggingHttpAdapter: () => LoggingHttpAdapter,
40
- PlatformScopedClient: () => PlatformScopedClient,
41
40
  TenantScopedClient: () => TenantScopedClient,
42
41
  TokenVerificationError: () => TokenVerificationError,
43
42
  UserScopedClient: () => UserScopedClient,
44
- WorkspaceInvitesClient: () => WorkspaceInvitesClient,
45
43
  authorizeRequest: () => authorizeRequest,
46
44
  authorizeToken: () => authorizeToken,
47
45
  createAuthorizationErrorResponse: () => createAuthorizationErrorResponse,
@@ -126,9 +124,9 @@ function credentialDetail(value) {
126
124
  accessTokenLifetimeSeconds: value.accessTokenLifetimeSeconds
127
125
  };
128
126
  }
129
- async function credentialPage(request, path, options = {}) {
127
+ async function credentialPage(request, path2, options = {}) {
130
128
  const query = credentialQuery(options);
131
- const page = await request(path, { query });
129
+ const page = await request(path2, { query });
132
130
  if (!page || !Array.isArray(page.data))
133
131
  throw new TypeError("Authyon: expected a paginated credential response.");
134
132
  return {
@@ -141,13 +139,13 @@ async function credentialPage(request, path, options = {}) {
141
139
  hasPrev: page.hasPrev
142
140
  };
143
141
  }
144
- async function allCredentials(request, path) {
142
+ async function allCredentials(request, path2) {
145
143
  const result = [];
146
144
  const seen = /* @__PURE__ */ new Set();
147
145
  let skip = 0;
148
146
  for (let iteration = 0; iteration < 1e3; iteration++) {
149
147
  const page = await request(
150
- path,
148
+ path2,
151
149
  iteration === 0 ? {} : { query: { skip, take: 100 } }
152
150
  );
153
151
  if (Array.isArray(page)) {
@@ -170,134 +168,67 @@ async function allCredentials(request, path) {
170
168
  throw new Error("Authyon: use listPage for more than 1000 credential pages.");
171
169
  }
172
170
 
171
+ // ../../internal/core/financial/subjectFinancialAuthorizations.ts
172
+ function path(id, suffix = "") {
173
+ if (typeof id !== "string" || !id.trim())
174
+ throw new TypeError("Authyon: a financial authorization id is required.");
175
+ return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
176
+ }
177
+ function subjectFinancialAuthorizations(request) {
178
+ return {
179
+ /** GET /auth/authorizations/{id} — the pending transaction, to show before asking for the code. */
180
+ get: (id) => request(path(id)),
181
+ /** POST /auth/authorizations/{id}/webauthn/options — passkey options for approving this authorization. */
182
+ webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
183
+ /**
184
+ * POST /auth/authorizations/{id}/confirm — approves the transaction.
185
+ *
186
+ * Pass the authenticator code or passkey assertion to verify the second
187
+ * factor inline (recommended). Without `input`, the session itself must
188
+ * have used a passkey or authenticator code within the last 5 minutes,
189
+ * otherwise the API answers `step_up_required`.
190
+ */
191
+ confirm: (id, input) => request(path(id, "/confirm"), { method: "POST", body: input }),
192
+ /** POST /auth/authorizations/{id}/reject — the customer declines the transaction. */
193
+ reject: (id) => request(path(id, "/reject"), { method: "POST" })
194
+ };
195
+ }
196
+
173
197
  // src/client/scopedManagementClient.ts
174
198
  function scopedRequest(request, source) {
175
- return async (path, options = {}) => {
199
+ return async (path2, options = {}) => {
176
200
  const token = typeof source === "function" ? await source() : source;
177
201
  if (typeof token !== "string" || !token.trim() || /\s/u.test(token))
178
202
  throw new TypeError("Authyon: a valid access token is required.");
179
- return request(path, {
203
+ return request(path2, {
180
204
  ...options,
181
205
  headers: { ...options.headers, Authorization: `Bearer ${token}` }
182
206
  });
183
207
  };
184
208
  }
185
- function environmentPath(scope) {
186
- return `/platform/workspaces/${segment(scope.workspaceId)}/environments/${segment(scope.environmentId)}`;
187
- }
188
- function tenantPath(scope) {
189
- return `${environmentPath(scope)}/tenants/${segment(scope.tenantId)}`;
190
- }
191
- function credentialPath(scope) {
192
- return `${scope.tenantId === void 0 ? environmentPath(scope) : tenantPath(scope)}/credentials`;
193
- }
194
- function workspacePath(id) {
195
- return `/platform/workspaces/${segment(id)}`;
196
- }
197
- function workspaceRole(role) {
198
- if (role !== "admin" && role !== "auditor")
199
- throw new TypeError("Authyon: workspace role must be admin or auditor.");
200
- return role;
201
- }
202
209
  var _request;
203
- var PlatformScopedClient = class {
204
- /** @hidden */
205
- constructor(request, token) {
206
- __privateAdd(this, _request);
207
- this.credentials = {
208
- list: (scope, options = {}) => credentialPage(__privateGet(this, _request), credentialPath(scope), options),
209
- get: async (scope, credentialId) => credentialDetail(await __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}`)),
210
- create: (scope, input) => __privateGet(this, _request).call(this, credentialPath(scope), {
211
- method: "POST",
212
- body: { description: input.description, ...lifetimeBody(input), ...permissionsBody(input) }
213
- }),
214
- updatePermissions: (scope, credentialId, input) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}/permissions`, {
215
- method: "PUT",
216
- body: permissionsBody(input)
217
- }),
218
- updateScopes: (scope, credentialId, scopes) => this.credentials.updatePermissions(scope, credentialId, { scopes }),
219
- /** Returns a new secret once. API may require an explicit step-up first. */
220
- rotate: (scope, credentialId) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}/rotate`, { method: "POST" }),
221
- revoke: (scope, credentialId) => __privateGet(this, _request).call(this, `${credentialPath(scope)}/${segment(credentialId)}`, { method: "DELETE" })
222
- };
223
- this.workspaces = {
224
- team: (workspaceId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/team`),
225
- members: {
226
- invite: (workspaceId, input) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/invites`, {
227
- method: "POST",
228
- body: { email: input.email, role: workspaceRole(input.role) }
229
- }),
230
- /** memberId comes from team.members; it is not the platform userId. */
231
- remove: (workspaceId, memberId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/members/${segment(memberId)}`, {
232
- method: "DELETE"
233
- }),
234
- changeRole: (workspaceId, memberId, role) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/members/${segment(memberId)}`, {
235
- method: "PATCH",
236
- body: { role: workspaceRole(role) }
237
- })
238
- },
239
- invites: {
240
- create: (workspaceId, input) => this.workspaces.members.invite(workspaceId, input),
241
- revoke: (workspaceId, inviteId) => __privateGet(this, _request).call(this, `${workspacePath(workspaceId)}/invites/${segment(inviteId)}`, {
242
- method: "DELETE"
243
- })
244
- }
245
- };
246
- this.tenants = {
247
- members: {
248
- list: (scope, options = {}) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members`, { query: options }),
249
- add: (scope, userId, roles) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members`, { method: "POST", body: { userId, roles } }),
250
- remove: (scope, userId) => __privateGet(this, _request).call(this, `${tenantPath(scope)}/members/${segment(userId)}`, { method: "DELETE" })
251
- }
252
- };
253
- this.auth = {
254
- /** Explicitly confirms the current platform session; passwords are not retained. */
255
- stepUp: (currentPassword) => __privateGet(this, _request).call(this, "/platform/auth/step-up", { method: "POST", body: { currentPassword } })
256
- };
257
- __privateSet(this, _request, scopedRequest(request, token));
258
- }
259
- };
260
- _request = new WeakMap();
261
- var _request2;
262
210
  var UserScopedClient = class {
263
211
  /** @hidden */
264
212
  constructor(request, token) {
265
- __privateAdd(this, _request2);
213
+ __privateAdd(this, _request);
266
214
  this.tenants = {
267
215
  members: {
268
- list: (tenantId, options = {}) => __privateGet(this, _request2).call(this, `/auth/tenants/${segment(tenantId)}/members`, { query: options }),
216
+ list: (tenantId, options = {}) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members`, { query: options }),
269
217
  /** Adds an existing environment user by email; does not send an invitation email. */
270
- invite: (tenantId, input) => __privateGet(this, _request2).call(this, `/auth/tenants/${segment(tenantId)}/members`, {
218
+ invite: (tenantId, input) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members`, {
271
219
  method: "POST",
272
220
  body: { email: input.email, roles: input.roles }
273
221
  }),
274
- remove: (tenantId, userId) => __privateGet(this, _request2).call(this, `/auth/tenants/${segment(tenantId)}/members/${segment(userId)}`, {
222
+ remove: (tenantId, userId) => __privateGet(this, _request).call(this, `/auth/tenants/${segment(tenantId)}/members/${segment(userId)}`, {
275
223
  method: "DELETE"
276
224
  })
277
225
  }
278
226
  };
279
- __privateSet(this, _request2, scopedRequest(request, token));
280
- }
281
- };
282
- _request2 = new WeakMap();
283
- var _request3;
284
- var WorkspaceInvitesClient = class {
285
- /** @hidden */
286
- constructor(request) {
287
- __privateAdd(this, _request3);
288
- __privateSet(this, _request3, request);
289
- }
290
- preview(token) {
291
- return __privateGet(this, _request3).call(this, `/platform/workspace-invites/${segment(token)}`);
292
- }
293
- accept(token, input = {}) {
294
- return __privateGet(this, _request3).call(this, `/platform/workspace-invites/${segment(token)}/accept`, {
295
- method: "POST",
296
- body: { name: input.name, password: input.password }
297
- });
227
+ __privateSet(this, _request, scopedRequest(request, token));
228
+ this.financialAuthorizations = subjectFinancialAuthorizations(__privateGet(this, _request));
298
229
  }
299
230
  };
300
- _request3 = new WeakMap();
231
+ _request = new WeakMap();
301
232
 
302
233
  // ../../internal/core/config/defaults.ts
303
234
  var DEFAULT_BASE_URL = "https://api.authyon.com";
@@ -344,16 +275,37 @@ var ErrorCodes = {
344
275
  EmailTaken: "user.email_taken",
345
276
  PasswordWeak: "user.password_weak",
346
277
  PasswordPwned: "user.password_pwned",
347
- RateLimited: "rate_limited"
278
+ RateLimited: "rate_limited",
279
+ StepUpRequired: "step_up_required",
280
+ InvalidSecondFactorCode: "invalid_code",
281
+ VerificationAttemptsExhausted: "verification_attempts_exhausted",
282
+ MethodNotEnrolled: "method_not_enrolled",
283
+ InvalidAuthorizationState: "invalid_authorization_state",
284
+ TransactionMismatch: "transaction_mismatch",
285
+ AuthorizationNotConsumable: "authorization_not_consumable",
286
+ IdempotencyConflict: "idempotency_conflict"
348
287
  };
288
+ var STANDARD_ERROR_FIELDS = /* @__PURE__ */ new Set([
289
+ "type",
290
+ "status",
291
+ "title",
292
+ "detail",
293
+ "code",
294
+ "error",
295
+ "error_description"
296
+ ]);
349
297
  var AuthyonError = class extends Error {
350
298
  constructor(status, body, options = {}) {
351
- super(body.detail ?? body.title ?? `Authyon request failed with status ${status}`);
299
+ const detail = body.detail ?? body.error_description;
300
+ super(detail ?? body.title ?? `Authyon request failed with status ${status}`);
352
301
  this.name = "AuthyonError";
353
302
  this.status = status;
354
- this.code = body.code ?? "unknown";
303
+ this.code = body.code ?? body.error ?? "unknown";
355
304
  this.title = body.title ?? "Error";
356
- this.detail = body.detail;
305
+ this.detail = detail;
306
+ this.extensions = Object.fromEntries(
307
+ Object.entries(body).filter(([key]) => !STANDARD_ERROR_FIELDS.has(key))
308
+ );
357
309
  this.requestId = options.requestId;
358
310
  this.retryAfter = options.retryAfter;
359
311
  this.cause = options.cause;
@@ -403,6 +355,7 @@ var AuthyonError = class extends Error {
403
355
  };
404
356
  function classifyError(status, code) {
405
357
  if (code === ErrorCodes.NetworkError) return "network";
358
+ if (code === ErrorCodes.StepUpRequired) return "authentication";
406
359
  if (code === ErrorCodes.Timeout || status === 408) return "timeout";
407
360
  if (code === ErrorCodes.RateLimited || status === 429) return "rate_limit";
408
361
  if (code === ErrorCodes.EmailTaken || status === 409) return "conflict";
@@ -441,14 +394,14 @@ function isRetryable(category) {
441
394
  }
442
395
 
443
396
  // ../../internal/core/http/query.ts
444
- function appendQuery(path, params) {
445
- if (!params) return path;
397
+ function appendQuery(path2, params) {
398
+ if (!params) return path2;
446
399
  const query = new URLSearchParams();
447
400
  for (const [key, value2] of Object.entries(params)) {
448
401
  if (value2 !== void 0) query.set(key, String(value2));
449
402
  }
450
403
  const value = query.toString();
451
- return value ? `${path}${path.includes("?") ? "&" : "?"}${value}` : path;
404
+ return value ? `${path2}${path2.includes("?") ? "&" : "?"}${value}` : path2;
452
405
  }
453
406
 
454
407
  // ../../internal/core/http/httpAdapter.ts
@@ -517,7 +470,6 @@ function sanitizeUrl(value) {
517
470
  url.username = "";
518
471
  url.password = "";
519
472
  url.hash = "";
520
- url.pathname = url.pathname.replace(/(\/platform\/workspace-invites\/)[^/]+/u, "$1REDACTED");
521
473
  const queryKeys = /* @__PURE__ */ new Set();
522
474
  url.searchParams.forEach((_value, key) => queryKeys.add(key));
523
475
  url.search = queryKeys.size > 0 ? [...queryKeys].map((key) => `${encodeURIComponent(key)}=REDACTED`).join("&") : "";
@@ -547,12 +499,12 @@ function createSharedTransport(options) {
547
499
  const httpAdapter = options.httpLogger ? new LoggingHttpAdapter(baseAdapter, options.httpLogger) : baseAdapter;
548
500
  return {
549
501
  baseUrl,
550
- async request(path, init) {
502
+ async request(path2, init) {
551
503
  const controller = new AbortController();
552
504
  const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
553
505
  try {
554
506
  return await httpAdapter.request({
555
- url: `${baseUrl}${path}`,
507
+ url: `${baseUrl}${path2}`,
556
508
  method: init.method ?? "GET",
557
509
  headers: normalizeHeaders(init.headers),
558
510
  body: init.body,
@@ -610,11 +562,11 @@ var JsonHttpClient = class {
610
562
  constructor(transport) {
611
563
  this.transport = transport;
612
564
  }
613
- async send(path, options = {}) {
565
+ async send(path2, options = {}) {
614
566
  const headers = { ...options.headers };
615
567
  if (options.body !== void 0) headers["Content-Type"] = "application/json";
616
568
  try {
617
- return await this.transport.request(appendQuery(path, options.query), {
569
+ return await this.transport.request(appendQuery(path2, options.query), {
618
570
  method: options.method ?? "GET",
619
571
  headers,
620
572
  body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
@@ -628,7 +580,9 @@ var JsonHttpClient = class {
628
580
  if (!response.ok) {
629
581
  let body = {};
630
582
  try {
631
- body = await response.json();
583
+ const parsed = await response.json();
584
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
585
+ body = parsed;
632
586
  } catch {
633
587
  }
634
588
  throw new AuthyonError(response.status, body, responseMetadata(response));
@@ -636,8 +590,8 @@ var JsonHttpClient = class {
636
590
  if (response.status === 204) return void 0;
637
591
  return await response.json();
638
592
  }
639
- async request(path, options = {}) {
640
- return this.parse(await this.send(path, options));
593
+ async request(path2, options = {}) {
594
+ return this.parse(await this.send(path2, options));
641
595
  }
642
596
  };
643
597
 
@@ -846,9 +800,6 @@ var AuthyonServerClient = class {
846
800
  }
847
801
  })
848
802
  };
849
- this.workspaceInvites = new WorkspaceInvitesClient(
850
- (path, options) => this.http.request(path, options)
851
- );
852
803
  // ── Environment management (users, tenants, roles, permissions, audit) ───
853
804
  this.environment = {
854
805
  users: {
@@ -943,12 +894,12 @@ var AuthyonServerClient = class {
943
894
  credentials: {
944
895
  /** GET /env/tenants/{tenantId}/credentials. Returns metadata only, including revoked credentials. */
945
896
  list: (tenantId) => allCredentials(
946
- (path, options) => this.request(path, { ...options, envBearer: true }),
897
+ (path2, options) => this.request(path2, { ...options, envBearer: true }),
947
898
  `/env/tenants/${segment(tenantId)}/credentials`
948
899
  ),
949
900
  /** Paginated searchable listing. Prefer this over loading every credential. */
950
901
  listPage: (tenantId, options = {}) => credentialPage(
951
- (path, requestOptions) => this.request(path, { ...requestOptions, envBearer: true }),
902
+ (path2, requestOptions) => this.request(path2, { ...requestOptions, envBearer: true }),
952
903
  `/env/tenants/${segment(tenantId)}/credentials`,
953
904
  options
954
905
  ),
@@ -1119,6 +1070,41 @@ var AuthyonServerClient = class {
1119
1070
  /** GET /permissions/reserved — reserved permission names you can't redefine. */
1120
1071
  reserved: () => this.request("/permissions/reserved", { envBearer: true })
1121
1072
  },
1073
+ /**
1074
+ * Transaction-bound step-up for financial operations. The environment
1075
+ * credential needs the `authyon:financial:authorize` scope.
1076
+ *
1077
+ * 1. `create()` the authorization for the transaction and the customer.
1078
+ * 2. The customer approves it with their authenticator code or passkey
1079
+ * (`@authyon/auth` → `financialAuthorizations.confirm`).
1080
+ * 3. `consume()` it with the same transaction right before executing it.
1081
+ */
1082
+ financialAuthorizations: {
1083
+ /** POST /env/authorizations — registers a transaction awaiting the customer's approval. */
1084
+ create: (input) => {
1085
+ const { idempotencyKey, ...body } = input;
1086
+ if (typeof idempotencyKey !== "string" || !idempotencyKey.trim())
1087
+ throw new TypeError("Authyon: `idempotencyKey` is required.");
1088
+ return this.request("/env/authorizations", {
1089
+ method: "POST",
1090
+ envBearer: true,
1091
+ headers: { "Idempotency-Key": idempotencyKey },
1092
+ body
1093
+ });
1094
+ },
1095
+ /** GET /env/authorizations/{id} — current status and, once approved, the assurance evidence. */
1096
+ get: (id) => this.request(`/env/authorizations/${segment(id)}`, { envBearer: true }),
1097
+ /**
1098
+ * POST /env/authorizations/{id}/consume — redeems an approved
1099
+ * authorization exactly once. Resend the same transaction given to
1100
+ * `create()`; any difference fails with `transaction_mismatch`.
1101
+ */
1102
+ consume: (id, transaction) => this.request(`/env/authorizations/${segment(id)}/consume`, {
1103
+ method: "POST",
1104
+ envBearer: true,
1105
+ body: transaction
1106
+ })
1107
+ },
1122
1108
  audit: {
1123
1109
  /** GET /env/audit — paginated list of the environment's audit events. */
1124
1110
  list: (params = {}) => this.request("/env/audit", { envBearer: true, query: params }),
@@ -1169,7 +1155,7 @@ var AuthyonServerClient = class {
1169
1155
  };
1170
1156
  });
1171
1157
  }
1172
- async request(path, options = {}) {
1158
+ async request(path2, options = {}) {
1173
1159
  const headers = {
1174
1160
  ...clientIpHeaders({ clientIp: this.clientIp }),
1175
1161
  ...options.headers
@@ -1178,7 +1164,7 @@ var AuthyonServerClient = class {
1178
1164
  headers.Authorization = `Bearer ${await this.getEnvironmentAccessToken()}`;
1179
1165
  }
1180
1166
  if (this.envKey) headers["X-Authyon-Environment"] = this.envKey;
1181
- return this.http.request(path, { ...options, headers });
1167
+ return this.http.request(path2, { ...options, headers });
1182
1168
  }
1183
1169
  /** Mints (and caches) an environment access token from `clientId`/`clientSecret`. */
1184
1170
  async getEnvironmentAccessToken() {
@@ -1233,17 +1219,13 @@ var AuthyonServerClient = class {
1233
1219
  tenant(credentials) {
1234
1220
  return new TenantScopedClient(this, credentials);
1235
1221
  }
1236
- /** Uses only the supplied platform-user access token. */
1237
- platform(token) {
1238
- return new PlatformScopedClient((path, options) => this.http.request(path, options), token);
1239
- }
1240
1222
  /** Uses an end-user token; the configured environment key selects the environment. */
1241
1223
  user(token) {
1242
- return new UserScopedClient((path, options) => this.request(path, options), token);
1224
+ return new UserScopedClient((path2, options) => this.request(path2, options), token);
1243
1225
  }
1244
1226
  /** @internal used by {@link TenantScopedClient} to share the base URL/fetch/error handling. */
1245
- _requestAsTenant(accessToken, path, options = {}) {
1246
- return this.request(path, {
1227
+ _requestAsTenant(accessToken, path2, options = {}) {
1228
+ return this.request(path2, {
1247
1229
  ...options,
1248
1230
  headers: { ...options.headers, Authorization: `Bearer ${accessToken}` },
1249
1231
  envBearer: false
@@ -1320,8 +1302,8 @@ var TenantScopedClient = class {
1320
1302
  async getAccessToken() {
1321
1303
  return this.tokenProvider.getAccessToken();
1322
1304
  }
1323
- async request(path, options = {}) {
1324
- return this.server._requestAsTenant(await this.getAccessToken(), path, options);
1305
+ async request(path2, options = {}) {
1306
+ return this.server._requestAsTenant(await this.getAccessToken(), path2, options);
1325
1307
  }
1326
1308
  /** POST /tenant/auth/validate — validates this tenant client's current bearer token. */
1327
1309
  async validate(context) {
@@ -1494,18 +1476,18 @@ function matchesField(pattern, field) {
1494
1476
  return pattern.endsWith(".*") && field.startsWith(pattern.slice(0, -1));
1495
1477
  }
1496
1478
  function matchesConditions(subject, conditions) {
1497
- return Object.entries(conditions).every(([path, expected]) => {
1498
- if (path === "$and" && Array.isArray(expected)) {
1479
+ return Object.entries(conditions).every(([path2, expected]) => {
1480
+ if (path2 === "$and" && Array.isArray(expected)) {
1499
1481
  return expected.every(
1500
1482
  (condition) => matchesConditions(subject, condition)
1501
1483
  );
1502
1484
  }
1503
- if (path === "$or" && Array.isArray(expected)) {
1485
+ if (path2 === "$or" && Array.isArray(expected)) {
1504
1486
  return expected.some(
1505
1487
  (condition) => matchesConditions(subject, condition)
1506
1488
  );
1507
1489
  }
1508
- return matchesValue(readPath(subject, path), expected);
1490
+ return matchesValue(readPath(subject, path2), expected);
1509
1491
  });
1510
1492
  }
1511
1493
  function matchesValue(actual, expected) {
@@ -1537,8 +1519,8 @@ function matchesValue(actual, expected) {
1537
1519
  }
1538
1520
  });
1539
1521
  }
1540
- function readPath(value, path) {
1541
- return path.split(".").reduce((current, part) => isRecord2(current) ? current[part] : void 0, value);
1522
+ function readPath(value, path2) {
1523
+ return path2.split(".").reduce((current, part) => isRecord2(current) ? current[part] : void 0, value);
1542
1524
  }
1543
1525
  function defaultSubjectType(subject) {
1544
1526
  const explicit = subject.__type ?? subject.type ?? subject.kind;
@@ -1692,11 +1674,9 @@ function unauthenticated() {
1692
1674
  FetchHttpAdapter,
1693
1675
  JwksTokenVerifier,
1694
1676
  LoggingHttpAdapter,
1695
- PlatformScopedClient,
1696
1677
  TenantScopedClient,
1697
1678
  TokenVerificationError,
1698
1679
  UserScopedClient,
1699
- WorkspaceInvitesClient,
1700
1680
  authorizeRequest,
1701
1681
  authorizeToken,
1702
1682
  createAuthorizationErrorResponse,
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-t82mwTws.cjs';
2
- export { b as AcceptWorkspaceInviteInput, c as AccessTokenSource, d as AuditEvent, e as AuthyonJwksDiscoveryOptions, f as AuthyonJwtClaims, g as AuthyonServerClientOptions, C as ClientCredentials, h as ClientRequestContext, i as CreateCredentialInput, j as CreateOrganizationInput, k as CreatePermissionInput, l as CreateTenantCredentialInput, m as CreateUserInput, n as CredentialCreator, o as CredentialDetail, p as CredentialListOptions, q as CredentialPermissionsInput, r as CredentialScope, E as EnvironmentUser, F as FetchHttpAdapter, s as HttpAdapterRequest, t as HttpLogEvent, u as HttpLogger, I as IntrospectResult, v as InviteTenantMemberInput, w as InviteWorkspaceMemberInput, J as JsonWebKeySet, x as JwksTokenVerifier, y as JwksTokenVerifierOptions, L as LoggingHttpAdapter, z as LoginActivity, O as OpenIdConfiguration, B as Organization, P as Paged, D as PaginationOptions, G as Permission, K as PermissionsByRole, M as PlatformScopedClient, R as ReservedPermissions, N as Role, Q as RoleGrant, S as RoleInput, T as RoleList, U as RolePermissions, V as SafeJwtAlgorithm, W as TenantClientValidationResult, X as TenantCredentialIssued, Y as TenantCredentialSummary, Z as TenantManagementScope, _ as TenantMember, $ as TenantMemberPage, a0 as TenantMembership, a1 as TenantScopedClient, a2 as TokenResult, a3 as TokenVerificationError, a4 as TokenVerificationErrorCode, a5 as UpdateOrganizationInput, a6 as User, a7 as UserScopedClient, a8 as ValidateResult, a9 as VerifiedAccessToken, aa as WorkspaceInvite, ab as WorkspaceInviteAccepted, ac as WorkspaceInviteIssued, ad as WorkspaceInvitePreview, ae as WorkspaceInvitesClient, af as WorkspaceMember, ag as WorkspaceRole, ah as WorkspaceTeam, ai as createClient, aj as normalizeClientIp } from './authyonServerClient-t82mwTws.cjs';
3
- export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRequirement, f as AbilityRule, A as AbilitySubject, g as AuthorizationContext, a as AuthorizationError, h as AuthorizationOptions, i as AuthyonAbility, j as AuthyonAbilityBuilder, k as AuthyonAbilityOptions, l as AuthyonPermissionSource, E as ExpressAuthorizationMiddlewareOptions, m as ExpressNext, n as ExpressRequestLike, o as ExpressResponseLike, P as PermissionGroup, R as RequestAuthorizationOptions, p as authorizeRequest, q as authorizeToken, r as createAuthorizationErrorResponse, s as createAuthyonAbility, t as createAuthyonRules, u as createExpressAuthorizationMiddleware, v as hasPermission, w as hasPermissionGroup } from './authorization-DWlLfYQJ.cjs';
1
+ import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-DmNnjw4z.cjs';
2
+ export { b as AccessTokenSource, c as AuditEvent, d as AuthyonJwksDiscoveryOptions, e as AuthyonJwtClaims, f as AuthyonServerClientOptions, C as ClientCredentials, g as ClientRequestContext, h as ConfirmFinancialAuthorizationInput, i as ConsumedFinancialAuthorization, j as CreateCredentialInput, k as CreateFinancialAuthorizationInput, l as CreateOrganizationInput, m as CreatePermissionInput, n as CreateTenantCredentialInput, o as CreateUserInput, p as CredentialCreator, q as CredentialDetail, r as CredentialListOptions, s as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, t as FinancialAssurance, u as FinancialAuthorization, v as FinancialAuthorizationStatus, w as FinancialTransaction, x as FinancialWebAuthnOptions, y as HttpAdapterRequest, z as HttpLogEvent, B as HttpLogger, I as IntrospectResult, D as InviteTenantMemberInput, J as JsonWebKeySet, G as JwksTokenVerifier, K as JwksTokenVerifierOptions, L as LoggingHttpAdapter, M as LoginActivity, O as OpenIdConfiguration, N as Organization, P as Paged, Q as PaginationOptions, R as Permission, S as PermissionsByRole, T as ReservedPermissions, U as Role, V as RoleGrant, W as RoleInput, X as RoleList, Y as RolePermissions, Z as SafeJwtAlgorithm, _ as TenantClientValidationResult, $ as TenantCredentialIssued, a0 as TenantCredentialSummary, a1 as TenantMember, a2 as TenantMemberPage, a3 as TenantMembership, a4 as TenantScopedClient, a5 as TokenResult, a6 as TokenVerificationError, a7 as TokenVerificationErrorCode, a8 as UpdateOrganizationInput, a9 as User, aa as UserScopedClient, ab as ValidateResult, ac as VerifiedAccessToken, ad as createClient, ae as normalizeClientIp } from './authyonServerClient-DmNnjw4z.cjs';
3
+ export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRequirement, f as AbilityRule, A as AbilitySubject, g as AuthorizationContext, a as AuthorizationError, h as AuthorizationOptions, i as AuthyonAbility, j as AuthyonAbilityBuilder, k as AuthyonAbilityOptions, l as AuthyonPermissionSource, E as ExpressAuthorizationMiddlewareOptions, m as ExpressNext, n as ExpressRequestLike, o as ExpressResponseLike, P as PermissionGroup, R as RequestAuthorizationOptions, p as authorizeRequest, q as authorizeToken, r as createAuthorizationErrorResponse, s as createAuthyonAbility, t as createAuthyonRules, u as createExpressAuthorizationMiddleware, v as hasPermission, w as hasPermissionGroup } from './authorization-B7ynKAud.cjs';
4
4
  import 'jose';
5
5
 
6
6
  declare const ErrorCodes: {
@@ -15,6 +15,14 @@ declare const ErrorCodes: {
15
15
  readonly PasswordWeak: "user.password_weak";
16
16
  readonly PasswordPwned: "user.password_pwned";
17
17
  readonly RateLimited: "rate_limited";
18
+ readonly StepUpRequired: "step_up_required";
19
+ readonly InvalidSecondFactorCode: "invalid_code";
20
+ readonly VerificationAttemptsExhausted: "verification_attempts_exhausted";
21
+ readonly MethodNotEnrolled: "method_not_enrolled";
22
+ readonly InvalidAuthorizationState: "invalid_authorization_state";
23
+ readonly TransactionMismatch: "transaction_mismatch";
24
+ readonly AuthorizationNotConsumable: "authorization_not_consumable";
25
+ readonly IdempotencyConflict: "idempotency_conflict";
18
26
  };
19
27
  type KnownErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
20
28
  type AuthyonErrorCategory = "network" | "timeout" | "authentication" | "authorization" | "validation" | "not_found" | "conflict" | "rate_limit" | "server" | "unknown";
@@ -26,6 +34,14 @@ interface AuthyonErrorInterpretation {
26
34
  retryAfter?: number;
27
35
  requestId?: string;
28
36
  }
37
+ /** Error body as sent by the API: RFC 7807, or OAuth-style `error`/`error_description`. */
38
+ type AuthyonErrorBody = Partial<{
39
+ title: string;
40
+ detail: string;
41
+ code: string;
42
+ error: string;
43
+ error_description: string;
44
+ }> & Record<string, unknown>;
29
45
  /** Shared RFC 7807 error implementation used by both public SDKs. */
30
46
  declare class AuthyonError extends Error {
31
47
  readonly status: number;
@@ -35,11 +51,13 @@ declare class AuthyonError extends Error {
35
51
  readonly requestId?: string;
36
52
  readonly retryAfter?: number;
37
53
  readonly cause?: unknown;
38
- constructor(status: number, body: Partial<{
39
- title: string;
40
- detail: string;
41
- code: string;
42
- }>, options?: {
54
+ /**
55
+ * Extra fields from the error body beyond code/title/detail — e.g.
56
+ * `attemptsRemaining` on `invalid_code` or `requiredMethods` on
57
+ * `step_up_required`. Not included in {@link toJSON}.
58
+ */
59
+ readonly extensions: Readonly<Record<string, unknown>>;
60
+ constructor(status: number, body: AuthyonErrorBody, options?: {
43
61
  requestId?: string;
44
62
  retryAfter?: number;
45
63
  cause?: unknown;
@@ -68,4 +86,4 @@ declare class AuthyonServerClientBuilder {
68
86
  build(): AuthyonServerClient;
69
87
  }
70
88
 
71
- export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
89
+ export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-t82mwTws.js';
2
- export { b as AcceptWorkspaceInviteInput, c as AccessTokenSource, d as AuditEvent, e as AuthyonJwksDiscoveryOptions, f as AuthyonJwtClaims, g as AuthyonServerClientOptions, C as ClientCredentials, h as ClientRequestContext, i as CreateCredentialInput, j as CreateOrganizationInput, k as CreatePermissionInput, l as CreateTenantCredentialInput, m as CreateUserInput, n as CredentialCreator, o as CredentialDetail, p as CredentialListOptions, q as CredentialPermissionsInput, r as CredentialScope, E as EnvironmentUser, F as FetchHttpAdapter, s as HttpAdapterRequest, t as HttpLogEvent, u as HttpLogger, I as IntrospectResult, v as InviteTenantMemberInput, w as InviteWorkspaceMemberInput, J as JsonWebKeySet, x as JwksTokenVerifier, y as JwksTokenVerifierOptions, L as LoggingHttpAdapter, z as LoginActivity, O as OpenIdConfiguration, B as Organization, P as Paged, D as PaginationOptions, G as Permission, K as PermissionsByRole, M as PlatformScopedClient, R as ReservedPermissions, N as Role, Q as RoleGrant, S as RoleInput, T as RoleList, U as RolePermissions, V as SafeJwtAlgorithm, W as TenantClientValidationResult, X as TenantCredentialIssued, Y as TenantCredentialSummary, Z as TenantManagementScope, _ as TenantMember, $ as TenantMemberPage, a0 as TenantMembership, a1 as TenantScopedClient, a2 as TokenResult, a3 as TokenVerificationError, a4 as TokenVerificationErrorCode, a5 as UpdateOrganizationInput, a6 as User, a7 as UserScopedClient, a8 as ValidateResult, a9 as VerifiedAccessToken, aa as WorkspaceInvite, ab as WorkspaceInviteAccepted, ac as WorkspaceInviteIssued, ad as WorkspaceInvitePreview, ae as WorkspaceInvitesClient, af as WorkspaceMember, ag as WorkspaceRole, ah as WorkspaceTeam, ai as createClient, aj as normalizeClientIp } from './authyonServerClient-t82mwTws.js';
3
- export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRequirement, f as AbilityRule, A as AbilitySubject, g as AuthorizationContext, a as AuthorizationError, h as AuthorizationOptions, i as AuthyonAbility, j as AuthyonAbilityBuilder, k as AuthyonAbilityOptions, l as AuthyonPermissionSource, E as ExpressAuthorizationMiddlewareOptions, m as ExpressNext, n as ExpressRequestLike, o as ExpressResponseLike, P as PermissionGroup, R as RequestAuthorizationOptions, p as authorizeRequest, q as authorizeToken, r as createAuthorizationErrorResponse, s as createAuthyonAbility, t as createAuthyonRules, u as createExpressAuthorizationMiddleware, v as hasPermission, w as hasPermissionGroup } from './authorization-wrZ5ull7.js';
1
+ import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-DmNnjw4z.js';
2
+ export { b as AccessTokenSource, c as AuditEvent, d as AuthyonJwksDiscoveryOptions, e as AuthyonJwtClaims, f as AuthyonServerClientOptions, C as ClientCredentials, g as ClientRequestContext, h as ConfirmFinancialAuthorizationInput, i as ConsumedFinancialAuthorization, j as CreateCredentialInput, k as CreateFinancialAuthorizationInput, l as CreateOrganizationInput, m as CreatePermissionInput, n as CreateTenantCredentialInput, o as CreateUserInput, p as CredentialCreator, q as CredentialDetail, r as CredentialListOptions, s as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, t as FinancialAssurance, u as FinancialAuthorization, v as FinancialAuthorizationStatus, w as FinancialTransaction, x as FinancialWebAuthnOptions, y as HttpAdapterRequest, z as HttpLogEvent, B as HttpLogger, I as IntrospectResult, D as InviteTenantMemberInput, J as JsonWebKeySet, G as JwksTokenVerifier, K as JwksTokenVerifierOptions, L as LoggingHttpAdapter, M as LoginActivity, O as OpenIdConfiguration, N as Organization, P as Paged, Q as PaginationOptions, R as Permission, S as PermissionsByRole, T as ReservedPermissions, U as Role, V as RoleGrant, W as RoleInput, X as RoleList, Y as RolePermissions, Z as SafeJwtAlgorithm, _ as TenantClientValidationResult, $ as TenantCredentialIssued, a0 as TenantCredentialSummary, a1 as TenantMember, a2 as TenantMemberPage, a3 as TenantMembership, a4 as TenantScopedClient, a5 as TokenResult, a6 as TokenVerificationError, a7 as TokenVerificationErrorCode, a8 as UpdateOrganizationInput, a9 as User, aa as UserScopedClient, ab as ValidateResult, ac as VerifiedAccessToken, ad as createClient, ae as normalizeClientIp } from './authyonServerClient-DmNnjw4z.js';
3
+ export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRequirement, f as AbilityRule, A as AbilitySubject, g as AuthorizationContext, a as AuthorizationError, h as AuthorizationOptions, i as AuthyonAbility, j as AuthyonAbilityBuilder, k as AuthyonAbilityOptions, l as AuthyonPermissionSource, E as ExpressAuthorizationMiddlewareOptions, m as ExpressNext, n as ExpressRequestLike, o as ExpressResponseLike, P as PermissionGroup, R as RequestAuthorizationOptions, p as authorizeRequest, q as authorizeToken, r as createAuthorizationErrorResponse, s as createAuthyonAbility, t as createAuthyonRules, u as createExpressAuthorizationMiddleware, v as hasPermission, w as hasPermissionGroup } from './authorization-BF015NDJ.js';
4
4
  import 'jose';
5
5
 
6
6
  declare const ErrorCodes: {
@@ -15,6 +15,14 @@ declare const ErrorCodes: {
15
15
  readonly PasswordWeak: "user.password_weak";
16
16
  readonly PasswordPwned: "user.password_pwned";
17
17
  readonly RateLimited: "rate_limited";
18
+ readonly StepUpRequired: "step_up_required";
19
+ readonly InvalidSecondFactorCode: "invalid_code";
20
+ readonly VerificationAttemptsExhausted: "verification_attempts_exhausted";
21
+ readonly MethodNotEnrolled: "method_not_enrolled";
22
+ readonly InvalidAuthorizationState: "invalid_authorization_state";
23
+ readonly TransactionMismatch: "transaction_mismatch";
24
+ readonly AuthorizationNotConsumable: "authorization_not_consumable";
25
+ readonly IdempotencyConflict: "idempotency_conflict";
18
26
  };
19
27
  type KnownErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
20
28
  type AuthyonErrorCategory = "network" | "timeout" | "authentication" | "authorization" | "validation" | "not_found" | "conflict" | "rate_limit" | "server" | "unknown";
@@ -26,6 +34,14 @@ interface AuthyonErrorInterpretation {
26
34
  retryAfter?: number;
27
35
  requestId?: string;
28
36
  }
37
+ /** Error body as sent by the API: RFC 7807, or OAuth-style `error`/`error_description`. */
38
+ type AuthyonErrorBody = Partial<{
39
+ title: string;
40
+ detail: string;
41
+ code: string;
42
+ error: string;
43
+ error_description: string;
44
+ }> & Record<string, unknown>;
29
45
  /** Shared RFC 7807 error implementation used by both public SDKs. */
30
46
  declare class AuthyonError extends Error {
31
47
  readonly status: number;
@@ -35,11 +51,13 @@ declare class AuthyonError extends Error {
35
51
  readonly requestId?: string;
36
52
  readonly retryAfter?: number;
37
53
  readonly cause?: unknown;
38
- constructor(status: number, body: Partial<{
39
- title: string;
40
- detail: string;
41
- code: string;
42
- }>, options?: {
54
+ /**
55
+ * Extra fields from the error body beyond code/title/detail — e.g.
56
+ * `attemptsRemaining` on `invalid_code` or `requiredMethods` on
57
+ * `step_up_required`. Not included in {@link toJSON}.
58
+ */
59
+ readonly extensions: Readonly<Record<string, unknown>>;
60
+ constructor(status: number, body: AuthyonErrorBody, options?: {
43
61
  requestId?: string;
44
62
  retryAfter?: number;
45
63
  cause?: unknown;
@@ -68,4 +86,4 @@ declare class AuthyonServerClientBuilder {
68
86
  build(): AuthyonServerClient;
69
87
  }
70
88
 
71
- export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
89
+ export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };