@authyon/server 0.2.0-beta.20 → 0.2.0-beta.22

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
@@ -33,10 +33,16 @@ __export(index_exports, {
33
33
  AuthyonError: () => AuthyonError,
34
34
  AuthyonServerClient: () => AuthyonServerClient,
35
35
  AuthyonServerClientBuilder: () => AuthyonServerClientBuilder,
36
+ CLIENT_IP_HEADER: () => CLIENT_IP_HEADER,
36
37
  ErrorCodes: () => ErrorCodes,
37
38
  FetchHttpAdapter: () => FetchHttpAdapter,
38
39
  JwksTokenVerifier: () => JwksTokenVerifier,
39
40
  LoggingHttpAdapter: () => LoggingHttpAdapter,
41
+ SubtenantPermissions: () => SubtenantPermissions,
42
+ TENANT_FILTER_MAX_DEPTH: () => TENANT_FILTER_MAX_DEPTH,
43
+ TENANT_FILTER_MAX_VALUES: () => TENANT_FILTER_MAX_VALUES,
44
+ TENANT_FILTER_MAX_VALUE_LENGTH: () => TENANT_FILTER_MAX_VALUE_LENGTH,
45
+ TenantPermissions: () => TenantPermissions,
40
46
  TenantScopedClient: () => TenantScopedClient,
41
47
  TokenVerificationError: () => TokenVerificationError,
42
48
  UserScopedClient: () => UserScopedClient,
@@ -49,7 +55,8 @@ __export(index_exports, {
49
55
  createExpressAuthorizationMiddleware: () => createExpressAuthorizationMiddleware,
50
56
  hasPermission: () => hasPermission,
51
57
  hasPermissionGroup: () => hasPermissionGroup,
52
- normalizeClientIp: () => normalizeClientIp
58
+ normalizeClientIp: () => normalizeClientIp,
59
+ tenantFilter: () => tenantFilter
53
60
  });
54
61
  module.exports = __toCommonJS(index_exports);
55
62
 
@@ -436,7 +443,14 @@ function appendQuery(path2, params) {
436
443
  if (!params) return path2;
437
444
  const query = new URLSearchParams();
438
445
  for (const [key, value2] of Object.entries(params)) {
439
- if (value2 !== void 0) query.set(key, String(value2));
446
+ if (value2 === void 0) continue;
447
+ if (Array.isArray(value2)) {
448
+ for (const item of value2) {
449
+ if (item !== void 0) query.append(key, String(item));
450
+ }
451
+ continue;
452
+ }
453
+ query.set(key, String(value2));
440
454
  }
441
455
  const value = query.toString();
442
456
  return value ? `${path2}${path2.includes("?") ? "&" : "?"}${value}` : path2;
@@ -634,9 +648,11 @@ var JsonHttpClient = class {
634
648
  };
635
649
 
636
650
  // ../../internal/core/http/clientIp.ts
651
+ var CLIENT_IP_HEADER = "X-Authyon-Client-Ip";
637
652
  function clientIpHeaders(context) {
638
653
  if (!context?.clientIp) return {};
639
- return { "X-Forwarded-For": normalizeClientIp(context.clientIp) };
654
+ const ip = normalizeClientIp(context.clientIp);
655
+ return { "X-Forwarded-For": ip, [CLIENT_IP_HEADER]: ip };
640
656
  }
641
657
  function normalizeClientIp(value) {
642
658
  let ip = value.trim();
@@ -791,6 +807,11 @@ function isRecord(value) {
791
807
  }
792
808
 
793
809
  // src/client/authyonServerClient.ts
810
+ var ROOT_PARENT_ID = "00000000-0000-0000-0000-000000000000";
811
+ function tenantListQuery({ parentId, ...rest }) {
812
+ if (parentId === void 0) return rest;
813
+ return { ...rest, parentId: parentId === null ? ROOT_PARENT_ID : parentId };
814
+ }
794
815
  var _clientSecret;
795
816
  var AuthyonServerClient = class {
796
817
  constructor(options = {}) {
@@ -1016,13 +1037,64 @@ var AuthyonServerClient = class {
1016
1037
  * is found by the number, and `cnpj` alone finds every tenant carrying
1017
1038
  * that key. `take` defaults to 25 and is capped at 100.
1018
1039
  *
1040
+ * `filter` is the structured half, and the one to reach for when more
1041
+ * than one condition has to hold: each entry is a condition on a JSON
1042
+ * document, they are ANDed with each other and with `search`, and they
1043
+ * run inside the statement — so the envelope keeps describing the
1044
+ * filtered set and you can page through it. Build them with
1045
+ * `tenantFilter`:
1046
+ *
1047
+ * ```ts
1048
+ * const page = await authyon.environment.tenants.list({
1049
+ * filter: [
1050
+ * tenantFilter.in("public.kind", ["reseller", "partner"]),
1051
+ * tenantFilter.in("custom.cnpj", [a, b]),
1052
+ * ],
1053
+ * take: 100,
1054
+ * });
1055
+ * ```
1056
+ *
1057
+ * `parentId` narrows the page to one level of the tree — `children()`
1058
+ * and `roots()` below are the same call with that one option set.
1059
+ *
1019
1060
  * Against an Authyon API older than 2026-10-21 this route ignored
1020
- * skip/take/search and answered with a bare array.
1061
+ * skip/take/search and answered with a bare array; one older than
1062
+ * 2026-10-22 ignores `filter` and one older than 2026-10-31 ignores
1063
+ * `parentId`, which read as a page that is too wide rather than an error.
1064
+ */
1065
+ list: (params = {}) => this.request("/env/tenants", { envBearer: true, query: tenantListQuery(params) }),
1066
+ /**
1067
+ * One page of a tenant's direct sub-tenants — `list()` with `parentId`.
1068
+ *
1069
+ * Only one level: a node's own children carry `childCount`, so a tree
1070
+ * view asks again where that is above zero instead of reading the whole
1071
+ * subtree to draw the first level of it.
1072
+ */
1073
+ children: (parentTenantId, params = {}) => this.environment.tenants.list({ ...params, parentId: parentTenantId }),
1074
+ /**
1075
+ * One page of the environment's root tenants — `list()` with no parent.
1076
+ *
1077
+ * This is the first level of the tree, and the difference from `list()`
1078
+ * is worth keeping straight: `list()` returns every tenant at every
1079
+ * depth, which is what a flat picker wants and what a tree view must not
1080
+ * start from.
1081
+ */
1082
+ roots: (params = {}) => this.environment.tenants.list({ ...params, parentId: null }),
1083
+ /**
1084
+ * POST /env/tenants — create a tenant in the environment.
1085
+ *
1086
+ * `parentTenantId` nests it under an existing tenant. The environment's
1087
+ * `maxTenantDepth` has to allow the level — it ships as `1`, roots only,
1088
+ * so this answers `tenant.depth.not_allowed` until an operator raises it
1089
+ * in the console.
1021
1090
  */
1022
- list: (params = {}) => this.request("/env/tenants", { envBearer: true, query: params }),
1023
- /** POST /env/tenants — create a tenant in the environment. */
1024
1091
  create: (input) => this.request("/env/tenants", { method: "POST", envBearer: true, body: input }),
1025
- /** GET /env/tenants/{tenantId} — fetch a tenant by id. */
1092
+ /**
1093
+ * GET /env/tenants/{tenantId} — fetch a tenant by id.
1094
+ *
1095
+ * Returns `ancestors` as well, the chain above it root first, so a
1096
+ * breadcrumb costs this one call rather than one per level.
1097
+ */
1026
1098
  get: (tenantId) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}`, { envBearer: true }),
1027
1099
  /** PUT /env/tenants/{tenantId} — update a tenant. */
1028
1100
  update: (tenantId, input) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}`, {
@@ -1036,12 +1108,23 @@ var AuthyonServerClient = class {
1036
1108
  envBearer: true,
1037
1109
  body: input
1038
1110
  }),
1039
- /** POST /env/tenants/{tenantId}/disable — disable without removing tenant data. */
1111
+ /**
1112
+ * POST /env/tenants/{tenantId}/disable — disable without removing tenant
1113
+ * data.
1114
+ *
1115
+ * Disables the branch below it too. A sub-tenant left live under a
1116
+ * disabled parent would go on authenticating its users, which is the one
1117
+ * thing switching a tenant off is there to stop — so check `childCount`
1118
+ * before calling this on a node with children.
1119
+ */
1040
1120
  disable: (tenantId) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}/disable`, {
1041
1121
  method: "POST",
1042
1122
  envBearer: true
1043
1123
  }),
1044
- /** DELETE /env/tenants/{tenantId} — logically delete (disable) a tenant. */
1124
+ /**
1125
+ * DELETE /env/tenants/{tenantId} — logically delete (disable) a tenant,
1126
+ * and the branch below it. Same handler as `disable()`.
1127
+ */
1045
1128
  delete: (tenantId) => this.request(`/env/tenants/${encodeURIComponent(tenantId)}`, {
1046
1129
  method: "DELETE",
1047
1130
  envBearer: true
@@ -1539,6 +1622,86 @@ var AuthyonServerClientBuilder = class {
1539
1622
  };
1540
1623
  _options = new WeakMap();
1541
1624
 
1625
+ // src/client/tenantFilters.ts
1626
+ var TENANT_FILTER_MAX_VALUES = 25;
1627
+ var TENANT_FILTER_MAX_VALUE_LENGTH = 200;
1628
+ var TENANT_FILTER_MAX_DEPTH = 3;
1629
+ var SCOPES = ["public", "private", "custom"];
1630
+ var KEY_SEGMENT = /^[A-Za-z0-9_-]{1,64}$/;
1631
+ function assertPath(path2) {
1632
+ if (typeof path2 !== "string" || path2.length === 0) {
1633
+ throw new RangeError("Authyon: a filter path is required, e.g. public.kind.");
1634
+ }
1635
+ const [scope, ...keys] = path2.split(".");
1636
+ if (!SCOPES.includes(scope)) {
1637
+ throw new RangeError(
1638
+ `Authyon: unknown filter scope "${scope}" \u2014 use ${SCOPES.join(", ")} (e.g. public.kind).`
1639
+ );
1640
+ }
1641
+ if (keys.length === 0) {
1642
+ throw new RangeError(`Authyon: filter path "${path2}" needs a key after the scope.`);
1643
+ }
1644
+ if (keys.length > TENANT_FILTER_MAX_DEPTH) {
1645
+ throw new RangeError(
1646
+ `Authyon: filter path "${path2}" goes deeper than ${TENANT_FILTER_MAX_DEPTH} levels.`
1647
+ );
1648
+ }
1649
+ for (const key of keys) {
1650
+ if (!KEY_SEGMENT.test(key)) {
1651
+ throw new RangeError(
1652
+ `Authyon: invalid filter key "${key}" \u2014 letters, digits, "_" and "-", up to 64 characters.`
1653
+ );
1654
+ }
1655
+ }
1656
+ return path2;
1657
+ }
1658
+ function assertValue(value, forIn) {
1659
+ if (value === void 0 || value === null) {
1660
+ throw new RangeError("Authyon: a filter value is required.");
1661
+ }
1662
+ const text = String(value);
1663
+ if (text.length === 0) {
1664
+ throw new RangeError("Authyon: a filter value may not be empty.");
1665
+ }
1666
+ if (text.length > TENANT_FILTER_MAX_VALUE_LENGTH) {
1667
+ throw new RangeError(
1668
+ `Authyon: a filter value may hold at most ${TENANT_FILTER_MAX_VALUE_LENGTH} characters.`
1669
+ );
1670
+ }
1671
+ if (text.includes(",")) {
1672
+ throw new RangeError(
1673
+ forIn ? "Authyon: an `in` value may not contain a comma \u2014 pass separate values instead." : "Authyon: a filter value may not contain a comma."
1674
+ );
1675
+ }
1676
+ return text;
1677
+ }
1678
+ var tenantFilter = {
1679
+ /** `public.kind:eq:reseller` — the key equals this value. */
1680
+ eq(path2, value) {
1681
+ return `${assertPath(path2)}:eq:${assertValue(value, false)}`;
1682
+ },
1683
+ /** `public.kind:in:reseller,partner` — the key equals any of these (SQL IN). */
1684
+ in(path2, values) {
1685
+ if (!Array.isArray(values) || values.length === 0) {
1686
+ throw new RangeError("Authyon: `in` needs at least one value.");
1687
+ }
1688
+ if (values.length > TENANT_FILTER_MAX_VALUES) {
1689
+ throw new RangeError(`Authyon: \`in\` takes at most ${TENANT_FILTER_MAX_VALUES} values.`);
1690
+ }
1691
+ const unique = [...new Set(values.map((value) => assertValue(value, true)))];
1692
+ return `${assertPath(path2)}:in:${unique.join(",")}`;
1693
+ },
1694
+ /** `public.notes:like:nacional` — the key contains this text, case-insensitive.
1695
+ * The server escapes the LIKE metacharacters, so `100%` means `100%`. */
1696
+ like(path2, text) {
1697
+ return `${assertPath(path2)}:like:${assertValue(text, false)}`;
1698
+ },
1699
+ /** `custom.cnpj:exists` — the key is present, whatever its value. */
1700
+ exists(path2) {
1701
+ return `${assertPath(path2)}:exists`;
1702
+ }
1703
+ };
1704
+
1542
1705
  // ../../internal/core/authorization/ability.ts
1543
1706
  var AuthyonAbility = class {
1544
1707
  constructor(rules = [], detectSubjectType = defaultSubjectType) {
@@ -1602,12 +1765,29 @@ function createAuthyonAbility(source = {}, options = {}) {
1602
1765
  return new AuthyonAbility(createAuthyonRules(source, options), options.detectSubjectType);
1603
1766
  }
1604
1767
  function hasPermission(source, requiredPermission) {
1605
- const requirement = permissionToRule(requiredPermission);
1606
- if (!requirement || typeof requirement.action !== "string" || typeof requirement.subject !== "string") {
1607
- return false;
1608
- }
1768
+ const required = requiredPermission?.trim() ?? "";
1769
+ if (!isWellFormedPermission(required)) return false;
1609
1770
  const permissionSource = isPermissionList(source) ? { permissions: source } : source;
1610
- return createAuthyonAbility(permissionSource).can(requirement.action, requirement.subject);
1771
+ const granted = [
1772
+ ...permissionSource.permissions ?? [],
1773
+ ...permissionSource.scope?.split(/\s+/).filter(Boolean) ?? []
1774
+ ];
1775
+ return granted.some((permission) => grants(permission.trim(), required));
1776
+ }
1777
+ function grants(granted, required) {
1778
+ if (!isWellFormedPermission(granted)) return false;
1779
+ if (isFullWildcard(granted)) return true;
1780
+ const grantedSegments = granted.split(":");
1781
+ const requiredSegments = required.split(":");
1782
+ if (grantedSegments.length !== requiredSegments.length) return false;
1783
+ return grantedSegments.every(
1784
+ (segment2, index) => segment2 === "*" || segment2 === requiredSegments[index]
1785
+ );
1786
+ }
1787
+ function isWellFormedPermission(permission) {
1788
+ if (!permission) return false;
1789
+ const segments = permission.split(":");
1790
+ return segments.length >= 2 && segments.every((segment2) => segment2.length > 0);
1611
1791
  }
1612
1792
  function hasPermissionGroup(source, group) {
1613
1793
  const hasAll = (group.allOf ?? []).every((permission) => hasPermission(source, permission));
@@ -1622,13 +1802,23 @@ function createAuthyonRules(source = {}, options = {}) {
1622
1802
  ...source.permissions ?? [],
1623
1803
  ...source.scope?.split(/\s+/).filter(Boolean) ?? []
1624
1804
  ]);
1625
- const rules = [...permissions].map(permissionToRule).filter(isAbilityRule);
1805
+ const rules = [...permissions].map(grantToRule).filter(isAbilityRule);
1626
1806
  for (const role of /* @__PURE__ */ new Set([...source.roles ?? [], ...options.roles ?? []])) {
1627
1807
  rules.push(...(options.roleRules?.[role] ?? []).map(cloneRule));
1628
1808
  }
1629
1809
  rules.push(...(options.rules ?? []).map(cloneRule));
1630
1810
  return rules;
1631
1811
  }
1812
+ function grantToRule(permission) {
1813
+ const normalized = permission.trim();
1814
+ if (normalized && isFullWildcard(normalized)) {
1815
+ return { action: "manage", subject: "all" };
1816
+ }
1817
+ return permissionToRule(normalized);
1818
+ }
1819
+ function isFullWildcard(permission) {
1820
+ return permission.split(":").every((segment2) => segment2 === "*");
1821
+ }
1632
1822
  function permissionToRule(permission) {
1633
1823
  const normalized = permission.trim();
1634
1824
  if (!normalized) return null;
@@ -1845,6 +2035,32 @@ function unauthenticated() {
1845
2035
  "A valid bearer token is required"
1846
2036
  );
1847
2037
  }
2038
+
2039
+ // ../../internal/core/authorization/tenantPermissions.ts
2040
+ var TenantPermissions = {
2041
+ /** Rename the tenant and change its settings. */
2042
+ SettingsManage: "tenants:settings:manage",
2043
+ /** Invite an address to the tenant. */
2044
+ MembersInvite: "tenants:members:invite",
2045
+ /** Remove a member from the tenant. */
2046
+ MembersRemove: "tenants:members:remove"
2047
+ };
2048
+ var SubtenantPermissions = {
2049
+ /** Read any tenant below one you belong to. */
2050
+ TreeRead: "subtenants:tree:read",
2051
+ /** Rename a tenant below yours, and add or remove its members. */
2052
+ TreeManage: "subtenants:tree:manage",
2053
+ /** Create a tenant underneath one you belong to. */
2054
+ TreeCreate: "subtenants:tree:create",
2055
+ /**
2056
+ * Make a tenant below yours the ACTIVE tenant of the session — acting inside
2057
+ * it rather than on it from outside. Deliberately not the same permission as
2058
+ * {@link SubtenantPermissions.TreeManage}: administering a sub-tenant through
2059
+ * the management endpoints and operating as that sub-tenant are different
2060
+ * powers, and granting the first should not hand over the second.
2061
+ */
2062
+ TreeSwitch: "subtenants:tree:switch"
2063
+ };
1848
2064
  // Annotate the CommonJS export names for ESM import in node:
1849
2065
  0 && (module.exports = {
1850
2066
  AuthorizationError,
@@ -1853,10 +2069,16 @@ function unauthenticated() {
1853
2069
  AuthyonError,
1854
2070
  AuthyonServerClient,
1855
2071
  AuthyonServerClientBuilder,
2072
+ CLIENT_IP_HEADER,
1856
2073
  ErrorCodes,
1857
2074
  FetchHttpAdapter,
1858
2075
  JwksTokenVerifier,
1859
2076
  LoggingHttpAdapter,
2077
+ SubtenantPermissions,
2078
+ TENANT_FILTER_MAX_DEPTH,
2079
+ TENANT_FILTER_MAX_VALUES,
2080
+ TENANT_FILTER_MAX_VALUE_LENGTH,
2081
+ TenantPermissions,
1860
2082
  TenantScopedClient,
1861
2083
  TokenVerificationError,
1862
2084
  UserScopedClient,
@@ -1869,5 +2091,6 @@ function unauthenticated() {
1869
2091
  createExpressAuthorizationMiddleware,
1870
2092
  hasPermission,
1871
2093
  hasPermissionGroup,
1872
- normalizeClientIp
2094
+ normalizeClientIp,
2095
+ tenantFilter
1873
2096
  });
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-UA7HdjtD.cjs';
2
- export { b as AcceptTenantInviteInput, c as AccessTokenSource, d as Approval, e as ApprovalAssurance, f as ApprovalPayload, g as ApprovalStatus, h as ApprovalWebAuthnOptions, i as AuditEvent, j as AuthyonJwksDiscoveryOptions, k as AuthyonJwtClaims, l as AuthyonServerClientOptions, C as ClientCredentials, m as ClientRequestContext, n as ConfirmApprovalInput, o as ConsumedApproval, p as CreateApprovalInput, q as CreateCredentialInput, r as CreateOrganizationInput, s as CreatePermissionInput, t as CreateTenantCredentialInput, u as CreateUserInput, v as CredentialCreator, w as CredentialDetail, x as CredentialListOptions, y as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, z as HttpAdapterRequest, B as HttpLogEvent, D as HttpLogger, I as IntrospectResult, G as InviteTenantMemberInput, J as IssuePasswordResetInput, K as JsonWebKeySet, L as JwksTokenVerifier, M as JwksTokenVerifierOptions, N as LoggingHttpAdapter, O as LoginActivity, P as OpenIdConfiguration, Q as Organization, R as OtpCheckResult, S as Paged, T as PaginationOptions, U as PasswordResetCompleted, V as PasswordResetIssued, W as PasswordResetPreview, X as Permission, Y as PermissionsByRole, Z as ReservedPermissions, _ as Role, $ as RoleGrant, a0 as RoleInput, a1 as RoleList, a2 as RolePermissions, a3 as SafeJwtAlgorithm, a4 as SecurityMethods, a5 as SubjectApprovals, a6 as SubjectSecurity, a7 as TenantClientValidationResult, a8 as TenantCredentialIssued, a9 as TenantCredentialSummary, aa as TenantInvite, ab as TenantInviteAccepted, ac as TenantInviteInput, ad as TenantInviteIssued, ae as TenantInvitePreview, af as TenantInviteStatus, ag as TenantMember, ah as TenantMemberPage, ai as TenantMembership, aj as TenantScopedClient, ak as TokenResult, al as TokenVerificationError, am as TokenVerificationErrorCode, an as UpdateOrganizationInput, ao as User, ap as UserScopedClient, aq as ValidateResult, ar as VerifiedAccessToken, as as createClient, at as normalizeClientIp } from './authyonServerClient-UA7HdjtD.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-DcA5oKZT.cjs';
1
+ import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-CW46xIRD.cjs';
2
+ export { b as AcceptTenantInviteInput, c as AccessTokenSource, d as Approval, e as ApprovalAssurance, f as ApprovalPayload, g as ApprovalStatus, h as ApprovalWebAuthnOptions, i as AuditEvent, j as AuthyonJwksDiscoveryOptions, k as AuthyonJwtClaims, l as AuthyonServerClientOptions, m as AuthyonTenantClaim, C as CLIENT_IP_HEADER, n as ClientCredentials, o as ClientRequestContext, p as ConfirmApprovalInput, q as ConsumedApproval, r as CreateApprovalInput, s as CreateCredentialInput, t as CreateOrganizationInput, u as CreatePermissionInput, v as CreateTenantCredentialInput, w as CreateUserInput, x as CredentialCreator, y as CredentialDetail, z as CredentialListOptions, B as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, D as HttpAdapterRequest, G as HttpLogEvent, I as HttpLogger, K as IntrospectResult, L as InviteTenantMemberInput, M as IssuePasswordResetInput, N as JsonWebKeySet, J as JwksTokenVerifier, O as JwksTokenVerifierOptions, P as LoggingHttpAdapter, Q as LoginActivity, R as OpenIdConfiguration, S as Organization, T as OtpCheckResult, U as Paged, V as PaginationOptions, W as PasswordResetCompleted, X as PasswordResetIssued, Y as PasswordResetPreview, Z as Permission, _ as PermissionsByRole, $ as ReservedPermissions, a0 as Role, a1 as RoleGrant, a2 as RoleInput, a3 as RoleList, a4 as RolePermissions, a5 as SafeJwtAlgorithm, a6 as SecurityMethods, a7 as SubjectApprovals, a8 as SubjectSecurity, a9 as TENANT_FILTER_MAX_DEPTH, aa as TENANT_FILTER_MAX_VALUES, ab as TENANT_FILTER_MAX_VALUE_LENGTH, ac as TenantAncestor, ad as TenantClientValidationResult, ae as TenantCredentialIssued, af as TenantCredentialSummary, ag as TenantFilterExpression, ah as TenantFilterValue, ai as TenantInvite, aj as TenantInviteAccepted, ak as TenantInviteInput, al as TenantInviteIssued, am as TenantInvitePreview, an as TenantInviteStatus, ao as TenantListOptions, ap as TenantMember, aq as TenantMemberPage, ar as TenantMembership, as as TenantScopedClient, at as TokenResult, au as TokenVerificationError, av as TokenVerificationErrorCode, aw as UpdateOrganizationInput, ax as User, ay as UserScopedClient, az as ValidateResult, aA as VerifiedAccessToken, aB as createClient, aC as normalizeClientIp, aD as tenantFilter } from './authyonServerClient-CW46xIRD.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-BLENxur8.cjs';
4
4
  import 'jose';
5
5
 
6
6
  declare const ErrorCodes: {
@@ -94,4 +94,54 @@ declare class AuthyonServerClientBuilder {
94
94
  build(): AuthyonServerClient;
95
95
  }
96
96
 
97
- export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
97
+ /**
98
+ * The permission values the tenant surface checks, as constants.
99
+ *
100
+ * They are strings on the wire and nothing forces you through here — the point
101
+ * is that a rename shows up as a type error instead of as a 403 nobody can
102
+ * explain. `tenants:settings:manage` is exactly that case: it used to be
103
+ * written `tenants:manage`, a two-segment value the API could not even store,
104
+ * so the endpoint requiring it refused every caller.
105
+ */
106
+ declare const TenantPermissions: {
107
+ /** Rename the tenant and change its settings. */
108
+ readonly SettingsManage: "tenants:settings:manage";
109
+ /** Invite an address to the tenant. */
110
+ readonly MembersInvite: "tenants:members:invite";
111
+ /** Remove a member from the tenant. */
112
+ readonly MembersRemove: "tenants:members:remove";
113
+ };
114
+ /**
115
+ * What lets a member of one tenant reach the tenants beneath it.
116
+ *
117
+ * A separate domain, not a suffix on `tenants:…`, and the reason is worth
118
+ * knowing before you grant one: permissions match per segment, so naming these
119
+ * `tenants:tree:manage` would have handed every role already holding
120
+ * `tenants:*:*` power over the whole subtree the day the hierarchy shipped — a
121
+ * widening that appears in no diff. `subtenants:…` is only covered by `*:*:*`,
122
+ * which is explicit superuser.
123
+ *
124
+ * Reaching down is opt-in at every level: holding `tenants:settings:manage` on
125
+ * a parent grants nothing below it, and each of these is granted at the node
126
+ * the caller belongs to, never at the target.
127
+ */
128
+ declare const SubtenantPermissions: {
129
+ /** Read any tenant below one you belong to. */
130
+ readonly TreeRead: "subtenants:tree:read";
131
+ /** Rename a tenant below yours, and add or remove its members. */
132
+ readonly TreeManage: "subtenants:tree:manage";
133
+ /** Create a tenant underneath one you belong to. */
134
+ readonly TreeCreate: "subtenants:tree:create";
135
+ /**
136
+ * Make a tenant below yours the ACTIVE tenant of the session — acting inside
137
+ * it rather than on it from outside. Deliberately not the same permission as
138
+ * {@link SubtenantPermissions.TreeManage}: administering a sub-tenant through
139
+ * the management endpoints and operating as that sub-tenant are different
140
+ * powers, and granting the first should not hand over the second.
141
+ */
142
+ readonly TreeSwitch: "subtenants:tree:switch";
143
+ };
144
+ type TenantPermission = (typeof TenantPermissions)[keyof typeof TenantPermissions];
145
+ type SubtenantPermission = (typeof SubtenantPermissions)[keyof typeof SubtenantPermissions];
146
+
147
+ export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode, type SubtenantPermission, SubtenantPermissions, type TenantPermission, TenantPermissions };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-UA7HdjtD.js';
2
- export { b as AcceptTenantInviteInput, c as AccessTokenSource, d as Approval, e as ApprovalAssurance, f as ApprovalPayload, g as ApprovalStatus, h as ApprovalWebAuthnOptions, i as AuditEvent, j as AuthyonJwksDiscoveryOptions, k as AuthyonJwtClaims, l as AuthyonServerClientOptions, C as ClientCredentials, m as ClientRequestContext, n as ConfirmApprovalInput, o as ConsumedApproval, p as CreateApprovalInput, q as CreateCredentialInput, r as CreateOrganizationInput, s as CreatePermissionInput, t as CreateTenantCredentialInput, u as CreateUserInput, v as CredentialCreator, w as CredentialDetail, x as CredentialListOptions, y as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, z as HttpAdapterRequest, B as HttpLogEvent, D as HttpLogger, I as IntrospectResult, G as InviteTenantMemberInput, J as IssuePasswordResetInput, K as JsonWebKeySet, L as JwksTokenVerifier, M as JwksTokenVerifierOptions, N as LoggingHttpAdapter, O as LoginActivity, P as OpenIdConfiguration, Q as Organization, R as OtpCheckResult, S as Paged, T as PaginationOptions, U as PasswordResetCompleted, V as PasswordResetIssued, W as PasswordResetPreview, X as Permission, Y as PermissionsByRole, Z as ReservedPermissions, _ as Role, $ as RoleGrant, a0 as RoleInput, a1 as RoleList, a2 as RolePermissions, a3 as SafeJwtAlgorithm, a4 as SecurityMethods, a5 as SubjectApprovals, a6 as SubjectSecurity, a7 as TenantClientValidationResult, a8 as TenantCredentialIssued, a9 as TenantCredentialSummary, aa as TenantInvite, ab as TenantInviteAccepted, ac as TenantInviteInput, ad as TenantInviteIssued, ae as TenantInvitePreview, af as TenantInviteStatus, ag as TenantMember, ah as TenantMemberPage, ai as TenantMembership, aj as TenantScopedClient, ak as TokenResult, al as TokenVerificationError, am as TokenVerificationErrorCode, an as UpdateOrganizationInput, ao as User, ap as UserScopedClient, aq as ValidateResult, ar as VerifiedAccessToken, as as createClient, at as normalizeClientIp } from './authyonServerClient-UA7HdjtD.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-DfFCoDQ6.js';
1
+ import { H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonServerClient } from './authyonServerClient-CW46xIRD.js';
2
+ export { b as AcceptTenantInviteInput, c as AccessTokenSource, d as Approval, e as ApprovalAssurance, f as ApprovalPayload, g as ApprovalStatus, h as ApprovalWebAuthnOptions, i as AuditEvent, j as AuthyonJwksDiscoveryOptions, k as AuthyonJwtClaims, l as AuthyonServerClientOptions, m as AuthyonTenantClaim, C as CLIENT_IP_HEADER, n as ClientCredentials, o as ClientRequestContext, p as ConfirmApprovalInput, q as ConsumedApproval, r as CreateApprovalInput, s as CreateCredentialInput, t as CreateOrganizationInput, u as CreatePermissionInput, v as CreateTenantCredentialInput, w as CreateUserInput, x as CredentialCreator, y as CredentialDetail, z as CredentialListOptions, B as CredentialPermissionsInput, E as EnvironmentUser, F as FetchHttpAdapter, D as HttpAdapterRequest, G as HttpLogEvent, I as HttpLogger, K as IntrospectResult, L as InviteTenantMemberInput, M as IssuePasswordResetInput, N as JsonWebKeySet, J as JwksTokenVerifier, O as JwksTokenVerifierOptions, P as LoggingHttpAdapter, Q as LoginActivity, R as OpenIdConfiguration, S as Organization, T as OtpCheckResult, U as Paged, V as PaginationOptions, W as PasswordResetCompleted, X as PasswordResetIssued, Y as PasswordResetPreview, Z as Permission, _ as PermissionsByRole, $ as ReservedPermissions, a0 as Role, a1 as RoleGrant, a2 as RoleInput, a3 as RoleList, a4 as RolePermissions, a5 as SafeJwtAlgorithm, a6 as SecurityMethods, a7 as SubjectApprovals, a8 as SubjectSecurity, a9 as TENANT_FILTER_MAX_DEPTH, aa as TENANT_FILTER_MAX_VALUES, ab as TENANT_FILTER_MAX_VALUE_LENGTH, ac as TenantAncestor, ad as TenantClientValidationResult, ae as TenantCredentialIssued, af as TenantCredentialSummary, ag as TenantFilterExpression, ah as TenantFilterValue, ai as TenantInvite, aj as TenantInviteAccepted, ak as TenantInviteInput, al as TenantInviteIssued, am as TenantInvitePreview, an as TenantInviteStatus, ao as TenantListOptions, ap as TenantMember, aq as TenantMemberPage, ar as TenantMembership, as as TenantScopedClient, at as TokenResult, au as TokenVerificationError, av as TokenVerificationErrorCode, aw as UpdateOrganizationInput, ax as User, ay as UserScopedClient, az as ValidateResult, aA as VerifiedAccessToken, aB as createClient, aC as normalizeClientIp, aD as tenantFilter } from './authyonServerClient-CW46xIRD.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-Clf0Jx-U.js';
4
4
  import 'jose';
5
5
 
6
6
  declare const ErrorCodes: {
@@ -94,4 +94,54 @@ declare class AuthyonServerClientBuilder {
94
94
  build(): AuthyonServerClient;
95
95
  }
96
96
 
97
- export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode };
97
+ /**
98
+ * The permission values the tenant surface checks, as constants.
99
+ *
100
+ * They are strings on the wire and nothing forces you through here — the point
101
+ * is that a rename shows up as a type error instead of as a 403 nobody can
102
+ * explain. `tenants:settings:manage` is exactly that case: it used to be
103
+ * written `tenants:manage`, a two-segment value the API could not even store,
104
+ * so the endpoint requiring it refused every caller.
105
+ */
106
+ declare const TenantPermissions: {
107
+ /** Rename the tenant and change its settings. */
108
+ readonly SettingsManage: "tenants:settings:manage";
109
+ /** Invite an address to the tenant. */
110
+ readonly MembersInvite: "tenants:members:invite";
111
+ /** Remove a member from the tenant. */
112
+ readonly MembersRemove: "tenants:members:remove";
113
+ };
114
+ /**
115
+ * What lets a member of one tenant reach the tenants beneath it.
116
+ *
117
+ * A separate domain, not a suffix on `tenants:…`, and the reason is worth
118
+ * knowing before you grant one: permissions match per segment, so naming these
119
+ * `tenants:tree:manage` would have handed every role already holding
120
+ * `tenants:*:*` power over the whole subtree the day the hierarchy shipped — a
121
+ * widening that appears in no diff. `subtenants:…` is only covered by `*:*:*`,
122
+ * which is explicit superuser.
123
+ *
124
+ * Reaching down is opt-in at every level: holding `tenants:settings:manage` on
125
+ * a parent grants nothing below it, and each of these is granted at the node
126
+ * the caller belongs to, never at the target.
127
+ */
128
+ declare const SubtenantPermissions: {
129
+ /** Read any tenant below one you belong to. */
130
+ readonly TreeRead: "subtenants:tree:read";
131
+ /** Rename a tenant below yours, and add or remove its members. */
132
+ readonly TreeManage: "subtenants:tree:manage";
133
+ /** Create a tenant underneath one you belong to. */
134
+ readonly TreeCreate: "subtenants:tree:create";
135
+ /**
136
+ * Make a tenant below yours the ACTIVE tenant of the session — acting inside
137
+ * it rather than on it from outside. Deliberately not the same permission as
138
+ * {@link SubtenantPermissions.TreeManage}: administering a sub-tenant through
139
+ * the management endpoints and operating as that sub-tenant are different
140
+ * powers, and granting the first should not hand over the second.
141
+ */
142
+ readonly TreeSwitch: "subtenants:tree:switch";
143
+ };
144
+ type TenantPermission = (typeof TenantPermissions)[keyof typeof TenantPermissions];
145
+ type SubtenantPermission = (typeof SubtenantPermissions)[keyof typeof SubtenantPermissions];
146
+
147
+ export { AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, AuthyonServerClient, AuthyonServerClientBuilder, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode, type SubtenantPermission, SubtenantPermissions, type TenantPermission, TenantPermissions };